对于个人和趣味性,我正在使用SSE(4.1)编写geom库。
我花了最后12h来尝试处理行主列与列主列存储矩阵时的性能问题。
我知道Dirext / OpenGL矩阵是按行专业存储的,所以最好将我的矩阵按行专业顺序存储,这样在将矩阵存储到GPU /着色器或从GPU /着色器加载矩阵时,我将不会进行转换。
但是,我进行了一些分析,并获得了colomun major的更快结果。
要用行主行中的变换矩阵变换点,则为P'= P * M.,而在行主行中,则为P'= M *P。
因此,在Column Major中,它只是4点积,因此,在Row Major中,只有4条SSE4.1指令(_mm_dp_ps)必须在转置矩阵上执行这4点积。
10M vector 的性能结果
(30/05/2014 @ 08:48:10)Log:[5](Vul.Mul.Matrix)= 76.216653 ms(行主要变换)
(30/05/2014 @ 08:48:10)日志:[6](Matrix.Mul.Vec)= 61.554892 ms(列主要转换)
我尝试了几种使用或不使用_MM_TRANSPOSE的方式进行Vec * Matrix操作的方法,而我发现的最快方法是:
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
);
}
我的类Vec4只是一个__m128 m_val,在优化的C++中, vector 的构造全部在SSE寄存器上有效完成。
我的第一个猜测是这种乘法不是最佳的。我是SSE的新手,因此我对如何优化此功能感到有些困惑,我的直觉告诉我要使用shuffle指令,但是我想了解为什么它会更快。它会比分配更快地加载4个洗牌__m128(__m128 m_val = _mm_set_ps(w,z,y,x);)
从https://software.intel.com/sites/landingpage/IntrinsicsGuide/
我在mm_set_ps上找不到性能信息
编辑:我仔细检查配置文件的方法,每个测试都以相同的方式完成,因此没有内存缓存差异。为了避免本地缓存,我对随机错误 vector 数组进行操作,每个测试的种子都相同。每次执行时,只有1个测试从内存缓存提高了avoir性能。
最佳答案
不要使用_mm_dp_ps
进行矩阵乘法!我已经在Efficient 4x4 matrix vector multiplication with SSE: horizontal add and dot product - what's the point?上对此进行了详细的解释(顺便说一下,这是我的第一篇SO文章)。
您仅需要SSE就可以有效地做到这一点(甚至不需要SSE2)。使用此代码可以高效地进行4x4矩阵乘法。如果矩阵以行优先顺序存储,而不是gemm4x4_SSE(A,B,C)
。如果矩阵以列优先顺序存储,而不是gemm4x4_SSE(B,A,C)
。
void gemm4x4_SSE(float *A, float *B, float *C) {
__m128 row[4], sum[4];
for(int i=0; i<4; i++) row[i] = _mm_load_ps(&B[i*4]);
for(int i=0; i<4; i++) {
sum[i] = _mm_setzero_ps();
for(int j=0; j<4; j++) {
sum[i] = _mm_add_ps(_mm_mul_ps(_mm_set1_ps(A[i*4+j]), row[j]), sum[i]);
}
}
for(int i=0; i<4; i++) _mm_store_ps(&C[i*4], sum[i]);
}
关于c++ - SSE,行主要vs列主要性能问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/23949287/