【问题标题】:Is there any benefit to this combination of pointers and loops?这种指针和循环的组合有什么好处吗?
【发布时间】:2019-11-06 18:22:56
【问题描述】:

我正在研究 Cheng 的 CUDA C Programming,并遇到了这段代码:

void sumMatrixOnHost (float *A, float *B, float *C, const int nx, const int ny) {
    float *ia = A;
    float *ib = B;
    float *ic = C;
    for (int iy=0; iy<ny; iy++) {
        for (int ix=0; ix<nx; ix++) {
            ic[ix] = ia[ix] + ib[ix];
        }
        ia += nx; ib += nx; ic += nx;
    }
}

这是用于矩阵加法,矩阵以行优先格式存储。

据我了解,内部 for 循环遍历一行并执行元素添加,然后使用外部 for 循环将指针递增到下一行的开头。

为什么这种方法比在整个矩阵上使用指针更好,即

for (int i=0; i<ny*nx; i++) {
    ic[i] = ia[i] + ib[i];
}

或双重for循环,即

for (int iy=0; iy<ny; iy++) {
    for (int ix=0; ix<nx; ix++) {
        ic[iy*nx+ix] = ia[iy*nx+ix] + ib[iy*nx+ix];
    }
}

这与编译器如何优化它有关吗?

【问题讨论】:

    标签: c pointers


    【解决方案1】:

    最简单的方法,永远是最好的方法:

    for (int i=0; i<ny*nx; i++) {
        C[i] = A[i] + B[i];
    }
    

    这将比第一个解决方案更快。按行拆分矩阵的问题在于矢量化器会这样做:

    • 32bytes(YMM大小)批量处理线
    • 处理行尾剩余的少量值。
    • 现在重复每一行!

    如果您使用单个循环执行此操作,则生成的代码将是:

    • 以 32 字节为单位处理所有数据(YMM 大小)
    • 处理矩阵末尾未与 32 字节块对齐的剩余少量值。

    第一个版本只是添加了无意义的代码来处理内部循环。不需要这些代码,它只是破坏了向量化整个矩阵的能力。

    【讨论】:

      【解决方案2】:

      sumMatrixOnHost 上的方法更适合优化,它应该比您建议的两种方法执行得更快(通常)。

      因为 alu 乘法比加法需要更多时间。 所以在 sumMatrixOnHost 中没有 multipicaion,在

      for (int i=0; i<ny*nx; i++) {
          ic[i] = ia[i] + ib[i];
       }
      

      循环的每次迭代都有乘法。 在

      for (int iy=0; iy<ny; iy++) {
          for (int ix=0; ix<nx; ix++) {
              ic[iy*nx+ix] = ia[iy*nx+ix] + ib[iy*nx+ix];
          }
      }
      

      循环的每次迭代中有 3 次乘法。

      一个更简单的方法可以是

       int n = ny*nx;
       for (int i=0; i<n; i++) {
          ic[i] = ia[i] + ib[i];
       }
      

      但是在最后一种方法中,我们失去了 sumMatrixOnHost 中的另一个优点,那就是对矩阵块而不是整个矩阵进行运算的能力。

      【讨论】:

      • 感谢您的回复,关于重复乘法的好点 - 编译器会优化它吗? IE。 this answer 当您说“对矩阵块进行操作”时,您的意思是说仅对选定数量的行进行操作吗?似乎我们不需要经常这样做,因为这是专门用于矩阵加法的,它是整个矩阵的?
      • 优化取决于编译器,我知道如果你运行'gcc -o'它可能会优化它,但并非所有编译器都会。我想编写该代码的人希望确保它能够在每个编译器上正确优化,如果这将是一个 c 库而不是一个特定的程序,这一点非常重要。关于矩阵块,有时在线性代数中你不想对整个矩阵进行运算,因为也许一个矩阵更小,也许它只是一个向量,也许你已经知道矩阵的一半只是零(所以上)。
      猜你喜欢
      • 2021-12-23
      • 1970-01-01
      • 2016-09-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-16
      • 2023-04-05
      • 1970-01-01
      相关资源
      最近更新 更多