【问题标题】:Matrix multiplication using SSE intrinsics使用 SSE 内在函数的矩阵乘法
【发布时间】:2017-07-18 10:35:36
【问题描述】:

我正在尝试使用 SSE 进行矩阵乘法。我为 4x4 矩阵编写了一个简单的程序。一切似乎都很好,但是当我打印 result 时,它会出现一些垃圾值。请帮助找出问题。其次,当我释放内存时程序停止工作,而不是程序的正确结束。

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <float.h>
#include <xmmintrin.h>

void main() {
    float **a, **b, **c;
    int a_r = 4, a_c = 4, b_c = 4, b_r = 4;
    int i, j, k;

    /* allocate memory for matrix one */
    a = (float **)malloc(sizeof(float) * a_r);
    for (i = 0; i < a_c; i++) {
        a[i] = (float *)malloc(sizeof(float) * a_c);
    }
    /* allocate memory for matrix two */
    b = (float **)malloc(sizeof(float) * b_r);
    for (i = 0; i < b_c; i++) {
        b[i] = (float *)malloc(sizeof(float) * b_c);
    }
    /* allocate memory for sum matrix */
    c = (float **)malloc(sizeof(float) * a_r);
    for (i = 0; i < b_c; i++) {
        c[i] = (float *)malloc(sizeof(float) * b_c);
    }
    printf("Initializing matrices...\n");

    //initializing first matrix
    for (i = 0; i < a_r; i++) {
        for (j = 0; j < a_c; j++) {
            a[i][j] = 2;
        }
    }
    // initializing second matrix
    for (i = 0; i < b_r; i++) {
        for (j = 0; j < b_c; j++) {
            b[i][j] = 2;
        }
    }
    /* initialize product matrix */
    for (i = 0; i < a_r; i++) {
        for (j = 0; j < b_c; j++) {
            c[i][j] = 0;
        }
    }

    int count = 0;
    /* multiply matrix one and matrix two */
    for (i = 0; i < a_r; i++) {
        for (j = 0; j < a_c; j++) {
            count = 0;
            __m128 result = _mm_setzero_ps();
            for (k = 0; k < 4; k += 4) {
                __m128 row1 = _mm_loadu_ps(&a[i][k]);
                __m128 row2 = _mm_loadu_ps(&b[k][j]);
                result = _mm_mul_ps(row1, row2);

                for (int t = 1; t < 4; t++) {
                    __m128 row3=_mm_loadu_ps(&a[t * 4]);
                    __m128 row4=_mm_loadu_ps(&b[i][t]);
                    __m128 row5 = _mm_mul_ps(row3,row4);
                    result = _mm_add_ps(row5, result);
                }
                _mm_storeu_ps(&c[i][j], result);
            }
        }
    }
    printf("******************************************************\n");
    printf ("Done.\n");

    for (i = 0; i < a_r ; i++) {
        for (j = 0; j < b_c; j++) {
            printf ("%f   ", c[i][j]);   // issue here when I print results.
        }
        printf("\n");
    }     //  Here program stops working.

    /*free memory*/
    for (i = 0; i < a_r; i++) {
        free(a[i]);
    }
    free(a);
    for (i = 0; i < a_c; i++) {
        free(b[i]);
    }
    free(b);
    for (i = 0; i < b_c; i++) {
        free(c[i]);
    }
    free(c);
}

请查看为输出矩阵打印的地址。如何获得对齐的地址,我有_aligned_malloc,但仍然没有对齐。

【问题讨论】:

  • 停止工作是什么意思?它崩溃了吗?还是冻结?当您在调试器中检查它时会发生什么?你用的是什么编译器?
  • 可以试试stackoverflow.com/questions/227897/…。 Google 是您的朋友
  • 如果使用_mm_loadu_ps_mm_storeu_ps,则不需要对齐。
  • 在分配指针数组时使用了错误的 sizeof。
  • 停止投射 malloc。它隐藏了错误。

标签: c sse simd


【解决方案1】:

矩阵间接指针的分配不正确。它应该是:

a = (float **)malloc(sizeof(float*) * a_r);

编写这些分配的更安全的方法是:

a = malloc(sizeof(*a) * a_r);

请注意,您可以直接分配二维矩阵:

float (*a)[4][4] = malloc(sizeof(*a));

或者更好,正如 Cody Gray 建议的那样:

float (*a)[4][4] = _aligned_malloc(sizeof(*a));

_aligned_malloc 是一个非标准函数,可确保 SSE 操作数正确对齐。

如果事实上您可能甚至不需要使用malloc() 分配这些矩阵:

float a[4][4];

但对于后一种选择,您必须确保正确对齐 SSE 操作才能成功。

其余代码还有其他问题:

  • void main() 不正确。应该是int main(void)

  • 应转置第二个矩阵操作数,以便一次读取多个值。第二个负载将变为:

    __m128 row2 = _mm_loadu_ps(&b[j][k]);
    
  • 求和阶段似乎也不正确。而且最终的商店肯定是不正确的,应该只是:

    c[i][j] = sum;
    

【讨论】:

  • 在 SIMD 代码中使用 _aligned_malloc 可能会更好。
猜你喜欢
  • 2017-03-11
  • 2016-10-31
  • 2016-02-22
  • 2019-04-03
  • 2014-02-25
  • 2018-01-12
  • 2014-06-28
  • 2021-08-07
相关资源
最近更新 更多