C++ 矩阵乘法自动向量化

Posted

技术标签:

【中文标题】C++ 矩阵乘法自动向量化【英文标题】:C++ Matrix Multiplication Auto-Vectorization 【发布时间】:2017-04-20 07:25:07 【问题描述】:

我启用了自动矢量化。当我编译代码时,我收到以下警告:

info C5002: loop not vectorized due to reason '1203'

MSDN 指定

循环体包括对数组的非连续访问。

我查看了这些链接,1,2,寻求帮助,但没有运气。

这是我的源代码:

for (int row = 0; row < size; ++row) 
    for (int col = 0; col < size; ++col) 
        float tmp = 0;
        for (int i = 0; i < size; ++i)  // This loop generates the warning above
            tmp += matrixA[row][i] * matrixB[i][col];
        
        matrixResult[row][col] = tmp;
    

欢迎任何帮助。

【问题讨论】:

C++ 二维数组在内存中排列为一维数组 row1、row2 等。这个表达式 matrixB[i][col] 导致索引在数组中跳转。这个表达式matrixA[row][i] 没有。 您的矩阵是如何定义/分配的?如果他们是double **,那么由于缓存位置问题,您的性能也会很差。 先转置 B(并交换索引),以便获得连续访问。 只是为了澄清一下:有一些答案(和 MSFT 编译器消息有点暗示相同)是不可能矢量化(使用编译器)给定循环以防万一或不同的访问顺序,并且由于不连续(非单位)步幅。这基本上是错误的。可以按原样对代码进行矢量化,但是(a)在许多平台上它可能是无利可图的(可能会变慢),特别是没有有效的收集指令导入,(b)某些编译器中的一些矢量化器可能是无法矢量化此类代码,但 gcc/icc 应该能够使用 omp4.x 显式矢量化它 但是我上面的评论自然只是为了完整性,并没有改变关键信息,即:在这段代码中保持内存访问是低效的。 【参考方案1】:

2D 数组存储为单个连续的内存块,因此 3x2 元素的 2D 数组实际上是首尾相连的 6 个元素。

[] 索引运算符只是计算要访问的元素。

所以这里发生的情况是,matrixA 被顺序地从元素 1 访问到元素 6(即 A1、A2、A3、B1、B2、B3)。

但是,matrixB 被“随机”访问,A1、B1、A2、B2 等映射到实际存储上,作为访问元素 1 然后 4 然后 2 然后 5。

您无法更改访问 matrixB 元素的顺序,但您可以转置它,以便按正确的顺序访问元素。显然,如果只进行一次乘法运算,可能不值得重新计算矩阵 B 的顺序,但如果重复执行此计算,那么付出的努力将非常值得。

【讨论】:

【参考方案2】:

如果矩阵 AB 具有相同的存储顺序(例如行主要),那么无论如何您都无法对其进行向量化。所以这使得警告是合理的。

这里只是一个建议:如果您想要认真的高性能计算,那么您应该放弃二维数组。缓存的收益远大于矢量化速度的提升。

【讨论】:

【参考方案3】:

实现连续访问的一种方法:您可以交换内部的两个循环。而不是for row, for col, for i 你有for row, for i, for col。请参阅下面的结果代码。现在matrixResultmatrixB的访问都沿着col,所以是连续的。

for (int row = 0; row < size; ++row) 
    for (int i = 0; i < size; ++i) 
        int a_row_i = matrixA[row][i];
        for (int col = 0; col < size; ++col) 
            matrixResult[row][col] += a_row_i * matrixB[i][col];
        
    

【讨论】:

以上是关于C++ 矩阵乘法自动向量化的主要内容,如果未能解决你的问题,请参考以下文章

当数组是函数参数时,矩阵乘法中的 Gcc 自动向量化奇怪行为

使用矢量化 C++ 的矩阵乘法

使用 openmp 并行化矩阵乘法并使用 avx2 进行矢量化

自定义顶点处理器不起作用 - 矩阵乘法错误或其他啥?

任务是使用 p 线程并行化矩阵乘法并使用英特尔 ISPC 编译器进行矢量化

稀疏矩阵与密集矩阵乘法 C++ Tensorflow