El artículo original lo podeís encontrar aquí
Hola a todos....
Aquí os dejo la implementación de la suma de vectores mediante SSE.
int main (int argc, char* argv[])
{
LPVector v1,v2,v3;
clock_t timer;
float delay;
//Creamos los vectores aleatorios
v1.random(DIM,0.0f,500.0f);
v2.random(DIM,0.0f,500.0f);
v3 = v1;
//Sumamos los vectores
cout << "Version sin optimizar\n";
timer = clock();
v1.addOld ( v2 );
delay = ( clock() - timer ) ;
cout << "Tiempo gastado: " << delay << "milisegundos\n";
cout << "Version optimizada con SSE\n";
timer = clock();
v3.addSSE ( v2 );
delay = ( clock() - timer ) ;
cout << "Tiempo gastado: " << delay << "milisegundos\n";
if ( v1 != v3)
cout << "Error: La operacion da diferente resultado!!!\n";
if ( v1 == v3)
cout << "Calculo correcto\n";
//Eliminamos los vectores
v1.Delete();
v2.Delete();
v3.Delete();
system("PAUSE");
}
void LPVector::addOld(LPVector vector) //Operación de += modo antiguo (solo C)
{
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
for(int i = 0 ; i < n ; ++i)
v[i] += vector.v[i];
}
void LPVector::addSSE(LPVector vector) //Operación de += modo ensamblador SSE
{
//Fast SSE code when float specified
float* const row0 = (float*) &v[0];
float* const row1 = (float*) &(vector.v[0]);
int i = 0;
//Si las dimensiones son diferentes , tenemos un problema grave.
if (n != vector.n)
{
cout << "ERROR DIMENSIONAL ENTRE VECTORES\n";
return;
}
__asm
{
// Carga trozos de los vectores de 4 en 4
// La carga se hace "desordenada para que siempre haya una instrucción como mínimo entre uso y uso de registros."
mov edx, row0
mov esi, row1
}
i = n;
while( i >= 8 )
{
__asm
{
//Copiamos el puntero al vector v donde almacenaremos el valor final
mov edi, edx
//Cargamos la info en los registros SSE
movups xmm0, [edx]
movups xmm1, [esi]
//Aumentamos los contadores en 16 = 4 elementos * 4 bytes por elemento (float)
add edx,16
add esi,16
//Cargamos la info en los registros SSE(tenemos 8 registros donde guardar info)
movups xmm2, [edx]
movups xmm3, [esi]
//Hacemos la operación que toca, en nuestro caso, sumar
addps xmm0 , xmm1 //Sumamos de 4 en 4
addps xmm2 , xmm3 //Sumamos de 4 en 4
//En edi y edx es donde teniamos cargado los trozo de vector v y es donde pondremos el resultado
movups [edi], xmm0
movups [edx], xmm2
//Aumentamos los contadores en 16 = 4 elementos * 4 bytes por elemento (float)
add edx,16
add esi,16
}
i -= 8;
}
//Los flecos los rematamos de la manera tradicional
for(int j = n-i ; j < n ; ++j)
v[j] += vector.v[j];
}
Al ejecutar todo este código tendreis una salida de este estilo:
Version sin optimizar
Tiempo gastado: 321 milisegundos
Version optimizada con SSE
Tiempo gastado : 240 milisegundos
Calculo correcto.
Podreis observar que la ganancia no es comparable a multiplicar por 4 la velocidad como predicen las operaciones SSE sino que se queda en un 25-30% de mejora. Esto es debido a que las operaciones de entrada-salida (movups) gastan muchos recursos y hacen que las operaciones sencillas ( por ejemplo un suma sencilla ) se vean menos mejoradas que las operaciones complicadas ( muchos cálculos y pocos accesos a memoria ).
Espero que os guste, nos vemos
Blog spin-off de http://lordpakus.blogspot.com/ donde nos centraremos en la creación y uso de un math engine (motor de cálculo) basado en la paralelización multicore mediante threads y las instrucciones de ensamblador SSE. Los primeros articulos al menos serán reposteos del blog original, espero que os guste.
Adicionalmente, si estais interesados en la programación de videojuegos, motores de juegos y matemáticas y demás frikadas podeis echarle un ojo a mi otro blog : http://lordpakus.blogspot.com.es/
Suscribirse a:
Enviar comentarios (Atom)
No hay comentarios:
Publicar un comentario