Ran*_*ker 0 c++ sse simd matrix-multiplication
我正在尝试编写C ++代码以使用SIMD进行矩阵乘法,但是结果是错误的,这是我的代码
void mat_sse(DATA m1[][SIZE], DATA m2[][SIZE], DATA mout[][SIZE])
{
DATA prod = 0;
__m128 X, Y, Z, M, N;
for(int i=0; i<SIZE; i=i+1){
Z[0] = Z[1] = Z[2] = Z[3] = 0;
for(int k=0; k< SIZE; k=k+4){
for( int j=0; j<SIZE; j=j+4){
X = _mm_load_ps(&m1[i][k]);
Y = _mm_load_ps(&m2[k][j]);
M = _mm_mul_ps(X, Y);
Z = _mm_add_ps(M, N);
mout[i][j] += Z[0];
mout[i][j+1] += Z[1];
mout[i][j+2] += Z[2];
mout[i][j+3] += Z[3];
}
}
}
return ;
}
Run Code Online (Sandbox Code Playgroud)
const int SIZE = 40;
请问尺寸在哪里
?
这有很多错误。
for(int k=0; k< SIZE; k=k+4){
for( int j=0; j<SIZE; j=j+4){
Run Code Online (Sandbox Code Playgroud)
两个循环都前进4,因此内部循环的主体可一次处理旧的标量循环的16步。除非没有,否则它会执行“四件事”。
他们不是正确的事情:
X = _mm_load_ps(&m1[i][k]);
Y = _mm_load_ps(&m2[k][j]);
M = _mm_mul_ps(X, Y);
Run Code Online (Sandbox Code Playgroud)
因此,内循环的每次迭代都从中取出相同的小行向量,从中取出m1下一个小行向量m2,然后将它们逐点相乘。那不行 例如,如果我们有两个4x4矩阵:(部分显示)
A B C D X Y Z W
E . . . S . . .
I . . . × T . . .
M . . . U . . .
Run Code Online (Sandbox Code Playgroud)
内部循环的迭代将计算AX,BY,CZ和DW。AX确实应该是结果,而是一个真正的矩阵乘法也不涉及:各行m1与组合列的m2,因此通过等在那里的一排第二个项目m1是由在第一项乘以的列m2,不会发生。有许多不同的方法可以安排该计算,但是此处实现的方法不是重新安排,它计算了一些错误的乘积,并且跳过了许多必要的乘积。
这是方便装载从一个小行m2,以及广播从单一的入口m1。这样,乘积就排在一点mout,因此可以将其累加并写入结果,而无需进一步改组。
顺便说一句,您已经完成了最后一部分,
mout[i][j] += Z[0];
mout[i][j+1] += Z[1];
mout[i][j+2] += Z[2];
mout[i][j+3] += Z[3];
Run Code Online (Sandbox Code Playgroud)
..但将其放在循环中是不好的,只有当乘积的结果是应该加到这些位置的数字时,才有意义。这种加载/求和/存储的事情在内部循环中,因为内部循环是j循环,但是可以通过交换jand k循环来解决:(未测试)
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j += 4) {
__m128 sum = _mm_setzero_ps();
for (int k = 0; k < SIZE; k++) {
__m128 entry = _mm_set1_ps(m1[i][k]);
__m128 row = _mm_load_ps(&m2[k][j]);
sum = _mm_add_ps(sum, _mm_mul_ps(entry, row));
}
_mm_store_ps(&mout[i][j], sum);
}
}
Run Code Online (Sandbox Code Playgroud)
由于各种原因,该代码仍然很慢:
addps慢于可用吞吐量。使用更多独立的累加器。size = 40虽然不是。