SSE, problema de rendimiento de fila principal frente a columna principal

Para asuntos personales y divertidos, estoy codificando una geom lib usando SSE (4.1).

Pasé las últimas 12 horas tratando de comprender un problema de rendimiento al tratar con la matriz almacenada de fila principal frente a columna principal.

Sé que las matrices Dirext / OpenGL se almacenan en la fila principal, por lo que sería mejor para mí mantener mis matrices almacenadas en el orden de la fila principal, por lo que no tendré conversión al almacenar / cargar matrices a / desde GPU / sombreadores.

Pero hice algunos perfiles y obtengo resultados más rápidos con colomun major.

Para transformar un punto con una matriz transfrom en la fila mayor, es P '= P * M. y en la columna mayor, es P' = M * P. Por lo tanto, en la columna mayor es simplemente un producto de 4 puntos, por lo que solo 4 instrucciones SSE4.1 (_mm_dp_ps) cuando en la fila mayor debo hacer esos 4 productos de puntos en la matriz transpuesta.

Resultado de rendimiento en vectores 10M

(30/05/2014 @ 08: 48: 10) Registro: [5] (Vec.Mul.Matrix) = 76.216653 ms (transformación mayor de fila)

(30/05/2014 @ 08: 48: 10) Registro: [6] (Matrix.Mul.Vec) = 61.554892 ms (transformación principal de columna)

Intenté varias formas de hacer la operación Vec * Matrix, usando _MM_TRANSPOSE o no, y la forma más rápida que encontré es esta:

mssFloat    Vec4::operator|(const Vec4& v) const //-- Dot Product
{
    return _mm_dp_ps(m_val, v.m_val, 0xFF ).m128_f32[0];
}
inline Vec4 operator*(const Vec4& vec,const Mat4& m)
{
    return Vec4(    Vec4( m[0][0],m[1][0],m[2][0],m[3][0]) | vec
        ,   Vec4( m[0][1],m[1][1],m[2][1],m[3][1]) | vec
        ,   Vec4( m[0][2],m[1][2],m[2][2],m[3][2]) | vec
        ,   Vec4( m[0][3],m[1][3],m[2][3],m[3][3]) | vec
                );
}

mi clase Vec4 es simplemente un __m128 m_val, en C ++ optimizado, la construcción del vector se realiza de manera eficiente en el registro SSE.

Mi primera suposición es que esta multiplicación no es óptima. Soy nuevo en SSE, así que estoy un poco desconcertado sobre cómo optimizar esto, mi intuición me dice que use la instrucción aleatoria, pero me gustaría entender por qué sería más rápido. ¿Cargará 4 shuffle __m128 más rápido que la asignación (__m128 m_val = _mm_set_ps (w, z, y, x);)

Dehttps://software.intel.com/sites/landingpage/IntrinsicsGuide/ No pude encontrar información de rendimiento en mm_set_ps

EDITAR: verifico dos veces el método de creación de perfiles, cada prueba se realiza de la misma manera, por lo que no hay diferencias de memoria caché. Para evitar la memoria caché local, estoy haciendo una operación para una matriz de vectores de errores aleatorios, la semilla es la misma para cada prueba. Solo 1 prueba en cada ejecución para evitar un aumento del rendimiento de la memoria caché.

Respuestas a la pregunta(2)

Su respuesta a la pregunta