【问题标题】:Is it possible to avoid the for-loop to compute matrix entries?是否可以避免使用 for 循环来计算矩阵条目?
【发布时间】:2017-11-14 20:12:01
【问题描述】:

我必须使用嵌套的 for 循环来逐列计算 Eigen::MatrixXd 类型矩阵输出的条目。这里 input[0]、input[1] 和 input[2] 被定义为 Eigen::ArrayXXd 以便使用元素操作。这部分似乎是我的代码的瓶颈。谁能帮我加速这个循环?谢谢!

 for (int i = 0; i < r; i++) {
    for (int j = 0; j < r; j++) {
      for (int k = 0; k < r; k++) {
        output.col(i * (r * r) + j * r + k) =
            input[0].col(i) * input[1].col(j) * input[2].col(k);
      }
    }
  }

【问题讨论】:

  • 这部分似乎是我的代码的瓶颈。 似乎是或现在是?您在代码分析中看到过这一点吗? (您在编译时启用了哪些优化?)
  • @Borgleader 这实际上是我的代码中第二个最耗时的部分。
  • 如果r 很大,它会做很多工作。但是优化编译器应该看到i * (r * r) + j * rinput[0].col(i) * input[1].col(j) 不会随k 变化,并将它们移出内部循环。但我们无法从这个 sn-p 判断它是否确实如此。
  • 您必须 a) 发布 minimal reproducible example 和/或 b) 发布更多信息,例如您从 perf 获得的信息。我们在这里几乎没有什么工作要做

标签: c++ for-loop eigen


【解决方案1】:

在考虑优化 for 循环的代码时,思考“是否存在可以消除的冗余计算”会有所帮助?

注意在最里面的循环中,只有k 发生了变化。您应该将所有涉及k的可能计算移出该循环:

for (int i = 0; i < r; i++) {
  int temp1 = i * (r * r);
  for (int j = 0; j < r; j++) {
    int temp2 = j * r;
    for (int k = 0; k < r; k++) {
      output.col(temp1 + temp2 + k) =
          input[0].col(i) * input[1].col(j) * input[2].col(k);
    }
  }
}

注意i * (r * r) 是如何反复计算的,但答案总是一样的!你只需要在i 增加时重新计算。 j * r 也是如此。

希望这会有所帮助!

【讨论】:

  • 如果它没有得到优化,我会感到惊讶
  • 同意;但是,并非所有编译器都是平等创建的。 (:
【解决方案2】:

为了减少失败次数,你应该缓存input[0]*input[1]的结果:

ArrayXd tmp(input[0].rows());
for (int i = 0; i < r; i++) {
 for (int j = 0; j < r; j++) {
  tmp = input[0].col(i) * input[1].col(j);
  for (int k = 0; k < r; k++) {
    output.col(i * (r * r) + j * r + k) = tmp * input[2].col(k);
  }
 }
}

然后,要充分利用您的 CPU,请使用 -march=native 启用 AVX/FMA,当然还有编译器优化 (-O3)。

然后,要了解您可以获得更多收益,请准确测量这部分所花费的时间,计算乘法次数 (r^2*(n+r*n)),然后计算您实现的每秒浮点运算次数。然后将其与您的 CPU 容量进行比较。如果你很好,那么唯一的选择是使用例如 OpenMP 对 for 循环之一进行多线程处理。选择哪个 for 循环取决于输入的大小,但您可以尝试使用外部循环,确保每个线程都有自己的 tmp 数组。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-16
    相关资源
    最近更新 更多