我必须使用嵌套的for循环来逐列计算Eigen :: MatrixXd类型矩阵输出的条目。这里输入[0],输入[1]和输入[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);
}
}
}
答案 0 :(得分: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
也是如此。
希望这有帮助!
答案 1 :(得分:1)
要减少翻牌次数,您应该缓存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循环之一。循环的选择取决于输入的大小,但您可以尝试使用外部输入,确保每个线程都有自己的tmp
数组。