2011-05-01 42 views
5

Estoy escribiendo una red de reenvío en VC++ usando AVX intrinsics. Invoco este código a través de PInvoke en C#. Mi rendimiento al llamar a una función que calcula un bucle grande que incluye la función exp() es ~ 1000ms para una buclesidad de 160M. Tan pronto como llamo al cualquier función que use AVX intrinsics, y luego use exp(), mi rendimiento cae a aproximadamente ~ 8000ms para la misma operación. Tenga en cuenta que la función que calcula el exp() es estándar C, y la llamada que utiliza los intrínsecos del AVX puede no estar relacionada en términos de datos procesados. Algún tipo de bandera se está disparando en algún lugar durante el tiempo de ejecución.El uso de instrucciones AVX deshabilita la optimización de exp()?

En otras palabras,

A(); // 1000ms calculates 160M exp() 
B(); // completely unrelated but contains AVX 
A(); // 8000ms 

o, curiosamente,

C(); // contains 128 bit SSE SIMD expressions 
A(); // 1000ms 

me pierden en cuanto a lo posible mecanismo que está pasando aquí, o cómo llevar a cabo una sol'n. Estoy en una CPU Intel 2500K \ Win 7. Versiones rápidas de VS.

Gracias.

Respuesta

9

Si utiliza alguna instrucción AVX256, el "estado AVX superior" se vuelve "sucio", lo que resulta en una pérdida grande si posteriormente utiliza instrucciones SSE (incluido el punto flotante escalar realizado en los registros xmm). Esto está documentado en el Manual de optimización de Intel, que se puede download for free (y es una lectura obligada si estás haciendo este tipo de trabajo):

de instrucciones AVX siempre modifica los bits superiores de registros YMM y las instrucciones SSE no modifique los bits superiores. Desde una perspectiva de hardware, los bits superiores de la colección de registros YMM pueden considerarse en uno de tres estados:

• Limpiar: Todos los bits superiores de YMM son cero. Este es el estado cuando el procesador comienza desde RESET.

• Modificado y guardado en la región XSAVE El contenido de los bits superiores de los registros YMM coincide con los datos guardados en la región XSAVE. Esto ocurre cuando se ejecuta XSAVE/XRSTOR.

• Modificado y no guardado: la ejecución de una instrucción AVX (ya sea de 256 bits o de 128 bits) modifica los bits superiores del YMM de destino.

La penalización de transición AVX/SSE se aplica siempre que el procesador indique "Modificado y no guardado". Con VZEROUPPER, mueva los estados del procesador a "Limpiar" y evite la penalización de transición.

Su rutina B() ensucia el estado YMM, por lo que el código de SSE en A() puestos. Inserte una instrucción VZEROUPPER entre B y A para evitar el problema.

+0

Voy a ser goshdarned. Funcionó. Supongo que esto significa que exp() usa código SSE de 128 bits y no de 256 bits. No estoy lo suficientemente familiar como para saber si eso es algo que puede convertirse convenientemente. – AronMiller

+0

@AronMiller: contento de ayudar. Asegúrate de utilizar 'VZEROUPPER' en cualquier momento que hayas usado AVX y pases el control al código que no es tuyo. Y asegúrese de presentar un error en su compilador para intentar que lo inserten en esos casos. –

+0

Hay traducciones directas de SSE a AVX128, documentadas en los manuales de instrucciones de referencia. Creo que ICC puede hacer la conversión por usted, pero no conozco ningún otro compilador que lo haya hecho todavía. –

Cuestiones relacionadas