¿Cuál es la forma más eficiente de multiplicar 4 flotadores por 4 flotadores utilizando SSE?

StackOverflow https://stackoverflow.com/questions/1227249

  •  22-07-2019
  •  | 
  •  

Pregunta

Actualmente tengo el siguiente código:

float a[4] = { 10, 20, 30, 40 };
float b[4] = { 0.1, 0.1, 0.1, 0.1 };
asm volatile("movups (%0), %%xmm0\n\t"
             "mulps (%1), %%xmm0\n\t"             
             "movups %%xmm0, (%1)"             
             :: "r" (a), "r" (b));

Primero tengo algunas preguntas:

(1) si FUERA a alinear las matrices en límites de 16 bytes, ¿funcionaría? Dado que las matrices están asignadas en la pila, ¿es cierto que alinearlas es casi imposible?

vea la respuesta seleccionada para esta publicación: ¿Las variables de la pila están alineadas por el __attribute __ de GCC ((alineado (x)) )?

(2) ¿Podría el código ser refactorizado para hacerlo más eficiente? ¿Qué sucede si pongo ambas matrices flotantes en registros en lugar de solo una?

Gracias

¿Fue útil?

Solución

  

si quisiera alinear las matrices en límites de 16 bytes, ¿funcionaría? Dado que las matrices están asignadas en la pila, ¿es cierto que alinearlas es casi imposible?

Se requiere que la alineación en la pila funcione. De lo contrario, los intrínsecos no funcionarían. Supongo que la publicación que citó tenía que ver con el valor exorbitante que seleccionó para el valor de alineación.

a 2:

No, no debería haber una diferencia en el rendimiento. Consulte este sitio para conocer los tiempos de instrucción de varios procesadores.


Cómo funciona la alineación de las variables de la pila:

push    ebp
mov ebp, esp
and esp, -16                ; fffffff0H
sub esp, 200                ; 000000c8H

y alinean el comienzo de la pila a 16 bytes.

Otros consejos

Escríbelo en C, usa

gcc -S -mssse3

si tiene una versión bastante reciente de gcc.

  

(1) si quisiera alinear las matrices en límites de 16 bytes, ¿funcionaría? Dado que las matrices están asignadas en la pila, ¿es cierto que alinearlas es casi imposible?

No, es bastante simple alinear el puntero de la pila usando y :

and esp, 0xFFFFFFF0 ; aligned on a 16-byte boundary

Pero debe usar lo que proporciona GCC, como un tipo de 16 bytes, o __attribute__ para personalizar la alineación.

¿GCC proporciona soporte para el tipo de datos __m128 ? Si es así, ese es su mejor plan para garantizar un tipo de datos alineados de 16 bytes. Sin embargo, hay __attribute __ ((alineado (16))) para alinear cosas. Defina sus matrices de la siguiente manera

float a[4] __attribute__((aligned(16))) = { 10, 20, 30, 40 };
float b[4] __attribute__((aligned(16))) = { 0.1, 0.1, 0.1, 0.1 };

y luego usa movaps :)

Usar intrínseco es mucho más rápido, especialmente con la optimización. Escribí una prueba simple y comparo ambas versiones (asm e intrínseca)

unsigned long long time1;
__m128 a1,b1;


a1=_mm_set_ps(10, 20,30,40);
b1=_mm_set_ps(0.1, 0.1, 0.1, 0.1);
float a[4] = { 10, 20, 30, 40 };
float b[4] = { 0.1, 0.1, 0.1, 0.1 };

time1=__rdtsc();
a1=_mm_mul_ps(a1,b1);
time1=__rdtsc() - time1 ;
printf("Time: %llu\n",time1);


time1=__rdtsc();
asm volatile("movups (%0), %%xmm0\n\t"
                 "mulps (%1), %%xmm0\n\t"
                 "movups %%xmm0, (%1)"
                 :: "r" (a), "r" (b));
time1=__rdtsc() - time1 ;
printf("Time: %llu\n",time1);

Marcas de tiempo del procesador de la versión intrínseca 50-60 Versión de Asm ~ 1000 marcas de tiempo de proceso

Puedes probarlo en tu máquina

Sobre la refactorización. Puedes usar intrínseco. Ejemplo:

#include <emmintrin.h>

int main(void)
{
    __m128 a1,b1;

    a1=_mm_set_ps(10, 20,30,40);
    b1=_mm_set_ps(0.1, 0.1, 0.1, 0.1);

    a1=_mm_mul_ps(a1,b1);

    return 0;
}

Con la optimización gcc ( -O2 , -O3 ) puede funcionar más rápido que asm.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top