Capítulo perteneciente al math engine LordPakus
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 de programación enfocado a estudiantes principiantes de C/C++ en español. Dispone de cursos de todos los niveles y para multitud de usos.
viernes, 2 de septiembre de 2011
Math Engine : Capitulo 5. LPVector con SSE(I).
Entradas populares
-
Una pregunta que me hacen en muchas ocasiones es ¿¿qué significa %2?? La respuesta tiene dos acepciones en función de si lo estamos u...
-
<< Ejemplo anterior Artículos Relacionados Ejemplo siguiente >> Hola a todos, ASCII Art es el hecho de hacer di...
-
Articulo perteneciente a : Referencias de programación Hola a todos Os pongo una aportación que a más de uno le irá bien, un resumen de ...
-
Capítulo perteneciente al tutorial de opengl desde cero Hola a todos, Este capítulo tal vez es de lo más complicados de la teoría necesa...
-
<< Ejemplo anterior Artículos Relacionados Ejemplo siguiente >> Hola a todos, El ejercicio de hoy se basa en c...
-
<< Capítulo anterior Artículos Relacionados Capítulo siguiente >> Hola a todos, Este tutorial intenta ser e...
-
<< Capítulo anterior Artículos Relacionados Capítulo siguiente >> Hola a todos... Un compañero vuestro ha...
-
Hola a todos... He aquí la primera entrega "Como crear tu propio motor de videojuegos y no morir en el intento". Antes que nada ...
-
Hola a todos Ya que he recibido un par de mails pidiéndome información sobre SEO, os adjunto unos cuantos trucos que he ido aprendiendo du...
-
<< Capítulo anterior Artículos Relacionados Capítulo siguiente >> El c apitulo de hoy trata sobre las instrucc...
Interesante el tema del SSE. thx
ResponderEliminarSaludos.
Pues aún no has visto nada :D. Se pueden llegar a obtener mejoras impresionantes (hasta x10 solo con SSE). A la que pueda os paso ejemplos más espectaculares.
ResponderEliminarPues si la verdad, engines como Id Tech 4 usa mucho el tema de los SSE, ya veo porque sus juegos tienen muy buen redimiendo.
ResponderEliminarSaludos.
Un gran ejemplo... se te ocurre para que podriamos usar las SSE en el GameEngine?
ResponderEliminarJeje pues nose, para todo lo que tenga que ver con la matematica?, que tu eres el experto :D, igual deberia ver como lo implementa en el motor de IdTEch4, vease el codigo del Doom3, quake4 etc:
ResponderEliminarftp://ftp.idsoftware.com/idstuff/
Saludos.
StrongCod3r.
No tenía ni idea de esto, y menos de que se conseguían tan buenos rendimientos, a lo mejor cuando acabe paso todo el framework de operaciones entre vectores matrices :)
ResponderEliminarThx por todo de nuevo!!!
La combo de SSE y threads da un rendimiento más que bueno. La clave está en la eliminación de los accesos a memoria que son los que limitan la potencia de calculo final. En un 4core se pueden conseguir rendimientos del orden del gigaflop sin ningún tipo de problema.
ResponderEliminar