繁体   English   中英

使用SSE内在函数进行大小为100 * 100的矩阵乘法

[英]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


有关:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM