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/

jueves, 8 de septiembre de 2011

Math Engine : Capitulo 5. LPVector con SSE(I).

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

No hay comentarios:

Publicar un comentario en la entrada