He perfilado esto utilizando el generador de perfiles de Visual C, y representa alrededor de 35 del tiempo de ejecución. Esta media móvil exponencial se llama más de un billón de veces, porque se utiliza repetidamente en el procesamiento de más de 400 gigabytes de datos. Los datos provienen de una matriz de disco de estado sólido de nivel RAID 0, por lo que la lectura de las cuentas de datos de menos de 5 del tiempo. El tamaño del precio es de alrededor de 100. Yo originalmente acelerado por un factor de 4 por precalculating tanto de los datos como sea posible. Entonces fui capaz de aumentarlo de nuevo por un factor de ndash PaeneInsula Oct 30 11 at 20:41 Yo era capaz de aumentar la velocidad de nuevo por un factor de 12 por multithreading (la naturaleza de los datos es tal que puede ser multithreaded en De tal manera que la carga está perfectamente equilibrada.) Y lo tengo funcionando en un i7 990x (que tiene 6 núcleos, hyperthreaded de un total de 12), overclocked. Ndash PaeneInsula Oct 30 11 at 20:51 Seguro, multithreading puede ayudar. Pero casi con seguridad puede mejorar el rendimiento en una única máquina roscada. Primero, lo está calculando en la dirección equivocada. Solamente las máquinas más modernas pueden hacer prefetching negativo del stride. Casi todos los machihnes son más rápidos para los pasos de la unidad. Es decir. Cambiar la dirección de la matriz para que escanear de baja a alta en lugar de alta a baja es casi siempre mejor. A continuación, reescribir un poco - por favor, permítanme acortar los nombres de las variables para que sea más fácil de escribir: Por cierto, voy a empezar a usar los abreviaturas p para el precio y s para suavizar, para guardar la escritura. Soy perezoso. Pero es probablemente más rápido de hacer La latencia entre avgi y avgi-2 es entonces 1 multiplicar y una suma, en lugar de una substracción y una multiplicación entre avgi y avgi-1. Es decir. Más del doble de rápido. En general, se desea reescribir la recurrencia de modo que avgi se calcula en términos de avgj para j en la medida de lo posible, sin rellenar la máquina, ya sea unidades de ejecución o registros. Básicamente, estás haciendo más multiplicaciones en general, con el fin de obtener menos cadenas de múltiplos (y substracciones) en el camino crítico. Saltar de avgi-2 a avgi es fácil, probablemente puede hacer tres y cuatro. Exactamente hasta qué punto depende de lo que es su máquina, y cuántos registros tiene. Y la latencia del sumador de punto flotante y multiplicador. O, mejor aún, el sabor de la combinación de multiplicar añadir la instrucción que tiene - todas las máquinas modernas tienen. P. ej. Si el MADD o MSUB es de 7 ciclos de largo, puede hacer hasta 6 otros cálculos en su sombra, incluso si sólo tiene una unidad de punto flotante. Totalmente pipeline. Y así. Menos si pipelined cada ciclo del otherr, como es común para la doble precisión en virutas y GPUs más viejas. El código de ensamblaje debe ser software pipeline para que las iteraciones de bucle diferentes se superpongan. Un compilador bueno debe hacer eso para usted, pero usted puede ser que tenga que reescribir el código de C para conseguir el mejor funcionamiento. Por cierto: no quiero decir que usted debe estar creando una matriz de AVG. En cambio, necesitaría dos promedios si avgi se calcula en términos de avgi-2, y así sucesivamente. Puedes usar una matriz de avgi si quieres, pero creo que solo necesitas tener 2 o 4 avgs, llamados, creativamente, avg0 y avg1 (2, 3.), y rotarlos. Este tipo de truco, dividir un acumulador o media en dos o más, combinando múltiples etapas de la recurrencia, es común en el código de alto rendimiento. Oh, sí: precalcula ss, etc. Si lo he hecho bien, en precisión infinita esto sería idéntico. Sin embargo, en precisión finita FP sus resultados pueden diferir, esperemos que sólo ligeramente, debido a los redondeos diferentes. Si el desenrollado es correcto y las respuestas son significativamente diferentes, probablemente tenga un algoritmo numéricamente inestable. Tú eres la que debes saber. Nota: los errores de redondeo de coma flotante cambiarán los bits bajos de su respuesta. Tanto debido a la reorganización del código, y utilizando MADD. Creo que probablemente está bien, pero tienes que decidir. Nota: los cálculos para avgi y avgi-1 son ahora independientes. Así que puede utilizar un conjunto de instrucciones SIMD, como Intel SSE2, que permite la operación en dos valores de 64 bits en un registro de 128 bits de ancho a la vez. Thatll ser bueno para casi 2X, en una máquina que tiene suficientes ALUs. Si tienes suficientes registros para reescribir avgi en términos de avgi-4 (y estoy seguro de que lo haces en iA64), entonces puedes ir 4X de ancho, si tienes acceso a una máquina como 256 bit AVX. En una GPU. Usted puede ir para las recurrencias más profundas, reescribiendo avgi en términos de avgi-8, y así sucesivamente. Algunas GPUs tienen instrucciones que calculan AXB o incluso AXBY como una sola instrucción. Aunque eso es más común para 32 bits que para 64 bits de precisión. En algún momento, probablemente empezaría a preguntar: ¿quiere hacer esto en múltiples precios a la vez? No sólo esto le ayudará con multithreading, sino que también le conviene para correr en una GPU. Y usando SIMD ancho. Minor Late Addition Estoy un poco avergonzado por no haber aplicado Horners Rule a expresiones como un poco más eficiente. Resultados ligeramente diferentes con el redondeo. En mi defensa, cualquier compilador decente debería hacer esto por ti. Pero la regla de Hrners hace que la cadena de dependencia sea más profunda en términos de multiplicaciones. Es posible que tenga que desenrollar y pipeline el bucle unas cuantas veces más. O puede hacer cuando precalculateI utiliza el siguiente código: int GetAnalogValue (Input) devuelve un valor de 12 bits de una distancia de medición del sensor de ultrasonidos (0-4095, ANALOGVALUERANGE 4096). Doble compensación es un miembro de la clase de encapsulación. ReferenceValue es el valor de referencia inicial de referenceInput (normalmente tiene una fluctuación baja, con un valor en algún lugar en el centro de la gama de 12 bits, pero cambia con la temperatura). RecordData () se llama cada 2 milisegundos (más o menos, ejecutándose en Windows). Así que una alta tasa de actualización para el valor de referencia, pero yo quería una compensación gradual en el tiempo. Por lo tanto, he utilizado una media móvil exponencial, el delta se determina empíricamente y puede que tenga que ser cambiado más tarde. GetData () se llama aproximadamente cada segundo para liberar datos y utilizar el registro para una evaluación posterior. Comenzamos a probar este código en las instalaciones del cliente, pero recibimos la opinión de que los valores se están alejando después de unos días. Creo que es un algoritmo numérico inestable que acumula errores de redondeo. ¿Puede alguien con más experiencia con las sutilezas de la aritmética de punto flotante me responde: ¿Puede este algoritmo de media móvil exponencial ser mejorado para lograr una mejor estabilidad Notas para mejoras adicionales del código son bienvenidos también. Sé que esto es alcanzable con el impulso como por: Pero realmente me gustaría evitar el uso de impulso. He googled y no he encontrado ningún ejemplo adecuado o legible. Básicamente, quiero seguir el promedio móvil de una corriente en curso de una corriente de números de punto flotante utilizando los números 1000 más recientes como una muestra de datos. ¿Cuál es la manera más fácil de lograr esto que experimenté con el uso de una matriz circular, media móvil exponencial y una media móvil más simple y encontró que los resultados de la matriz circular se adapta a mis necesidades mejor. Si sus necesidades son simples, puede intentar usar una media móvil exponencial. Puesto simplemente, usted hace una variable del acumulador, y como su código mira cada muestra, el código actualiza el acumulador con el nuevo valor. Usted escoge un alfa constante que está entre 0 y 1, y calcule esto: Usted apenas necesita encontrar un valor del alfa donde el efecto de una muestra dada dura solamente cerca de 1000 muestras. Hmm, no estoy realmente seguro de que esto es adecuado para usted, ahora que he puesto aquí. El problema es que 1000 es una ventana bastante larga para un promedio móvil exponencial No estoy seguro de que haya un alpha que se extendería el promedio en los últimos 1000 números, sin subflujo en el cálculo de punto flotante. Pero si usted quisiera un promedio más pequeño, como 30 números o tan, esto es una manera muy fácil y rápida de hacerla. Respondió 12 de junio a las 4:44 1 en su puesto. El promedio móvil exponencial puede permitir que el alfa sea variable. Así, esto permite que se utilice para calcular promedios de base de tiempo (por ejemplo, bytes por segundo). Si el tiempo transcurrido desde la última actualización del acumulador es de más de 1 segundo, deje que alfa sea 1.0. De lo contrario, puede permitir que alpha be (usecs desde la última actualización / 1000000). Ndash jxh 12 de junio a las 6:21 Básicamente, quiero seguir el promedio móvil de una corriente en curso de una corriente de números de punto flotante usando los números 1000 más recientes como una muestra de datos. Tenga en cuenta que el siguiente actualiza el total como elementos añadidos / reemplazados, evitando costosos recorridos O (N) para calcular la suma - necesaria para el promedio - a la demanda. Total se hace un parámetro diferente de T a soporte, p. Usando un largo largo cuando totalizan 1000 long s, un int para char s, o un doble a total float s. Esto es un poco defectuoso en que numsamples podría ir más allá de INTMAX - si te importa que podría utilizar un unsigned mucho tiempo. O utilice un miembro de datos de bool extra para grabar cuando el contenedor se rellena primero mientras cicla numsamples alrededor de la matriz (mejor entonces cambia el nombre de algo inocuo como pos). Respondió el 12 de Junio 12 a las 5:19 se supone que el operador quotvoid (T sample) quot es realmente operador quotvoid (T sample) quot. Ndash oPless Jun 8 14 at 11:52 oPless ahhh. bien descrito. En realidad quería que fuera para ser operador vacío () (T muestra), pero por supuesto, usted podría utilizar cualquier notación que te gustaba. Se arreglará, gracias. Ndash Tony D Jun 8 14 at 14:27
No comments:
Post a Comment