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

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

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

MSDN 指定

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

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

这是我的源代码:

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 显式矢量化它
  • 但是我上面的评论自然只是为了完整性,并没有改变关键信息,即:在这段代码中保持内存访问是低效的。

标签: c++ matrix-multiplication visual-studio-2017 simd auto-vectorization


【解决方案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];
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-03-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-03
        • 1970-01-01
        • 2018-04-01
        • 1970-01-01
        相关资源
        最近更新 更多