[英]Matrix Multiplication of size 100*100 using SSE Intrinsics
int MAX_DIM = 100;
float a[MAX_DIM][MAX_DIM]__attribute__ ((aligned(16)));
float b[MAX_DIM][MAX_DIM]__attribute__ ((aligned(16)));
float d[MAX_DIM][MAX_DIM]__attribute__ ((aligned(16)));
/*
* I fill these arrays with some values
*/
for(int i=0;i<MAX_DIM;i+=1){
for(int j=0;j<MAX_DIM;j+=4){
for(int k=0;k<MAX_DIM;k+=4){
__m128 result = _mm_load_ps(&d[i][j]);
__m128 a_line = _mm_load_ps(&a[i][k]);
__m128 b_line0 = _mm_load_ps(&b[k][j+0]);
__m128 b_line1 = _mm_loadu_ps(&b[k][j+1]);
__m128 b_line2 = _mm_loadu_ps(&b[k][j+2]);
__m128 b_line3 = _mm_loadu_ps(&b[k][j+3]);
result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(a_line, a_line, 0x00), b_line0));
result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(a_line, a_line, 0x55), b_line1));
result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(a_line, a_line, 0xaa), b_line2));
result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(a_line, a_line, 0xff), b_line3));
_mm_store_ps(&d[i][j],result);
}
}
}
上面的代码使我使用SSE进行矩阵乘法。 代码按流程运行,我从行中取4个元素乘以b列中的4个元素,然后移到a行中的下4个元素和b列中的下4个元素
我收到错误Segmentation fault (core dumped)
我真的不知道为什么
我在Ubuntu 16.04.5上使用gcc 5.4.0
编辑:分段错误已通过_mm_loadu_ps解决。逻辑上也有问题如果有人帮助我找到它,我将非常高兴
细分错误已通过
_mm_loadu_ps
解决。_mm_loadu_ps
也有问题...
您正在b[k][j+0..7]
上加载4个重叠的窗口。 (这就是为什么需要loadu
)。
也许您打算加载b[k][j+0]
, +4
, +8
, +12
? 如果是这样,则应将b
对齐64,以便所有四个负载都来自同一高速缓存行(以提高性能)。 交错访问不是很好,但是使用每个触摸的缓存行的所有64字节要好于在没有阻塞的标量代码中使行占优与列占优完全出错。
我从行4个元素从
a
由4个元素乘以由从列b
我不确定您的文字描述是否描述了您的代码。
除非您已经转置了b
,否则您不能通过SIMD加载从同一列中加载多个值,因为它们在内存中不是连续的。
C多维数组是“行主”的:最后一个索引是移到下一个更高的内存地址时变化最快的索引。 您是否认为_mm_loadu_ps(&b[k][j+1])
会给您b[k+0..3][j+1]
? 如果是这样,这是SSE矩阵矩阵乘法的重复项(该问题使用的是32位整数,而不是32位浮点数,但存在相同的布局问题。有关工作循环结构,请参见。)
要对此进行调试,请将简单的值模式放入b[]
。 喜欢
#include <stdalign.>
alignas(64) float b[MAX_DIM][MAX_DIM] = {
0000, 0001, 0002, 0003, 0004, ...,
0100, 0101, 0102, ...,
0200, 0201, 0202, ...,
};
// i.e. for (...) b[i][j] = 100 * i + j;
然后,当您在调试器中逐步执行代码时,您可以看到向量中最终包含哪些值。
对于您的a[][]
值,可以使用90000.0 + 100 * i + j
因此,如果您查看的是寄存器(而不是C变量),您仍然可以判断出哪个值是a
和哪个是b
。
有关:
Ulrich Drepper的《每个程序员应该了解的内存》展示了一种优化的matmul,它具有SSE内在函数和缓存阻止功能,可实现双精度。 应该很直接地适应float
。
BLAS如何获得如此出色的性能? (您可能只想使用优化的matmul库;调整matmul以实现最佳的高速缓存阻止并非易事,但很重要)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.