2010-04-19 18 views
12

Estoy trabajando en un solucionador de dinámica de fluidos Navier-Stokes que debe ejecutarse en tiempo real. Por lo tanto, el rendimiento es importante.¿Valdrá la pena aritmética de punto fijo mi problema?

En este momento, estoy buscando un número de bucles estrechos que cada cuenta por una fracción significativa del tiempo de ejecución: no hay un solo cuello de botella. La mayoría de estos bucles realizan aritmética en coma flotante, pero hay muchas ramificaciones intermedias.

Las operaciones de coma flotante se limitan principalmente a adiciones, restas, multiplicaciones, divisiones y comparaciones. Todo esto se hace usando flotadores de 32 bits. Mi plataforma objetivo es x86 con al menos instrucciones SSE1. (He verificado en la salida del ensamblador que el compilador genera instrucciones SSE.)

La mayoría de los valores de punto flotante con los que estoy trabajando tienen un límite superior razonablemente pequeño, y la precisión para valores cercanos a cero no es muy importante. Entonces, se me ocurrió lo siguiente: ¿tal vez cambiar a la aritmética de punto fijo podría acelerar las cosas? Sé que la única manera de estar realmente seguro es de medirlo, eso puede llevar días, así que me gustaría saber las probabilidades de éxito de antemano.

El punto fijo estaba de moda en los días de Doom, pero no estoy seguro de lo que es el año 2010. Teniendo en cuenta la cantidad de silicio que se bombea actualmente en el rendimiento de punto flotante, ¿existe la posibilidad de que la aritmética de puntos todavía me dará un impulso de velocidad significativo? ¿Alguien tiene alguna experiencia en el mundo real que se pueda aplicar a mi situación?

+2

La ramificación es probablemente la mayor causa de muerte. Intenta reducirlo tanto como sea posible. Y no, no hagas punto fijo. – phkahler

+1

Encontré lo opuesto. En algunos casos, pude reemplazar la ramificación por otra aritmética de coma flotante, pero eso disminuyó la velocidad. – Thomas

+1

Hace mucho tiempo atrás, utilicé hardware especializado SIMD de punto fijo en el pasado, ¡y fue un gran dolor en el cuello! Lo pensaría dos veces antes de reconsiderar la aritmética de punto fijo. ¿Quieres pasar la mayor parte del tiempo lidiando con las complejidades de la aritmética de punto fijo o resolviendo tu problema más grande? Las CPU de hoy en día tienen mucha más potencia y contienen FPU; yo elegiría una solución de punto flotante. Más bien, dedique tiempo para tratar de mantener la tubería llena, antes que pensar en la aritmética de punto fijo. – Tilo

Respuesta

3

Como otras personas han dicho, si usted ya está usando en coma flotante SIMD, dudo que obtendrá una gran mejora con punto fijo.

Usted dijo que el compilador emite instrucciones SSE, pero no parece que haya intentado escribir su código SSE vectorizado. No sé qué tan buenos son los compiladores en eso, pero es algo para investigar.otros

Dos áreas a consultar son:

  1. acceso a la memoria - si todos los cálculos se realizan en SSE, a continuación, los errores de caché puede ser que tome más tiempo que los cálculos reales.

    1. Puede captar previamente los datos con p. Ej. _mm_prefetch o __builtin_prefetch (dependiendo de tu compilador/plataforma).
    2. Verifique sus costosas funciones para aliasing entre entradas y salidas; estos pueden llevar a lecturas/escrituras adicionales de memoria.
    3. Considere almacenar sus datos de manera diferente: si su solucionador de fluidos resuelve las coordenadas x independientemente de y, podría ser más fácil guardarlas en diferentes matrices. Si están resueltos para juntas, considere la intercalación (por ejemplo, x y x y ...)
  2. Desenrollar - usted debe ser capaz de obtener un beneficio en el rendimiento de desenrollar sus lazos internos. El objetivo no es (como muchas personas piensan) reducir el número de verificaciones de terminación de bucle. El principal beneficio es permitir que las instrucciones independientes se intercalen, para ocultar la latencia de la instrucción. Hay una presentación here titulada VMX Optimization: llevándola a un nivel que podría ayudar un poco; está enfocado en las instrucciones de Altivec en Xbox360, pero algunos de los consejos de desenrollado también podrían ayudar en SSE.

Como otras personas han mencionado, perfil, perfil, perfil. Y luego háganos saber lo que todavía es lento :)

PD - en una de sus otras publicaciones here, lo convencí de usar SOR en lugar de Gauss-Seidel en su solucionador de matrices. Ahora que lo pienso, ¿hay alguna razón por la que no estés usando un solucionador de tres diagonales?

+0

Intenté un poco de ensamblaje de SSE, pero el compilador es mejor que yo.Tuve que arrastrar demasiado para obtener los valores en los lugares correctos antes de realizar 4 multiplicaciones simultáneas. Sin embargo, este fue mi primer código ensamblador x86, por lo que quizás se pueda exprimir más rendimiento. – Thomas

+0

Mi sistema es lo suficientemente pequeño como para caber completamente en la memoria caché L2; menos de 400 kB, todos juntos. ¿Todavía valdría la pena considerar el caché L1 más allá de eso? – Thomas

+0

¿El compilador no desenrollará los bucles en '-O3'? ¿La predicción de bifurcación no lo hará discutible de todos modos? Siempre pensé que el desenrollado de bucles era cosa del pasado. Logré eliminar una dependencia de escritura/lectura en el solucionador SOR, por cierto, usando un esquema rojo/negro. Eso hizo una gran diferencia. (Cuando esa presentación habló sobre la función de idioma que no debe ser nombrada, pensé: "¿Qué va a hacer' goto' aquí? Yo usaría una plantilla. "Siguiente diapositiva: Metaprogramación de la plantilla.) De todos modos, lo haré dar un "intento" de desenrollar "manual" (es decir, plantilla). – Thomas

5

Stick con punto flotante. El punto fijo realmente solo es útil si puede trabajar dentro de 8 bits o 16 bits y usa SIMD (el procesamiento de imagen y el audio son casos de uso típicos para esto).

Las CPU modernas suelen tener 2 FPU y puede emitir hasta 2 instrucciones FP por ciclo de reloj. También tiene la posibilidad de optimizar utilizando 4 vías FP SIMD (SSE).

Si aún tiene problemas para obtener un buen rendimiento, intente utilizar un mejor compilador, como el ICC de Intel. Además, los ejecutables Intel de 64 bits tienden a ser algo más rápidos que sus contrapartes de 32 bits debido al aumento del número de registros en el modelo de 64 bits, por lo que compila para 64 bits si puedes.

Y, por supuesto, también debe crear un perfil de su código, para que sepa con certeza dónde están los puntos de acceso. No dice qué sistema operativo está usando, pero VTune en Windows, Zoom en Linux o Shark en Mac OS X lo ayudarán a encontrar rápida y fácilmente sus cuellos de botella de rendimiento.

0

Su máquina está muy bien optimizada para coma flotante, por lo que probablemente no ahorrará mucho yendo a fracciones de punto fijo.

Dice que no hay un único cuello de botella, pero puede haber varios, y si logra afeitar a alguno de ellos, los demás tomarán porcentajes más grandes del tiempo restante, llamando su atención sobre ellos, para que pueda afeitarse ellos tambien.

Es probable que haya hecho esto, pero me aseguraría de que no sólo las funciones que requieren mucho tiempo son lo más rápido posible, pero que están siendo llamados no más de lo necesario.

+0

"... probablemente no ahorrará mucho yendo a fracciones de punto fijo". ¿Tiene alguna referencia o experiencia de primera mano para respaldar esto? – Thomas

+1

@Thomas: experiencia personal. Utilicé fracciones de punto fijo extensivamente en gráficos antes de que los procesadores de FP estuvieran en todas partes. Estuve en el Laboratorio de Instrumentación durante Apollo, cuando todo el sistema de navegación se hizo con fracciones de punto fijo. Ahora con el hardware de FP en chip, donde toda la detección de normalización, adición, multiplicación y NaN se hace tanto como sea posible en la lógica combinatoria a velocidad de reloj completa, supongo, pero sospecho que la multiplicación y la división estarán en el mismo parque de pelota, flotante vs. punto fijo + cambio. –

Cuestiones relacionadas