优化三维循环(C+;+;) 我正在C++中使用多重网格求解器,现在我正在努力提高串行性能。其中最耗时的部分是平滑部分,在我的例子中,它是一个连续的过度松弛解算器。如下所示(我希望这是不言自明的): intidx; int-stripy=步幅[level][0]; int-stripz=步幅[level][1]; 对于(int i=0;i

优化三维循环(C+;+;) 我正在C++中使用多重网格求解器,现在我正在努力提高串行性能。其中最耗时的部分是平滑部分,在我的例子中,它是一个连续的过度松弛解算器。如下所示(我希望这是不言自明的): intidx; int-stripy=步幅[level][0]; int-stripz=步幅[level][1]; 对于(int i=0;i,c++,optimization,scientific-computing,C++,Optimization,Scientific Computing,,一个好的优化编译器无论如何都会为您完成大多数简单的事情,因此始终要测量您所做的更改是否确实改善了事情。并且,检查(并学习理解)生成的汇编代码,以查看编译器实际在做什么 但我会尝试做一些事情,因为表达式很复杂,即使是好的优化器有时也需要一些帮助:- 首先,将内部循环中不变的子表达式提升到周围循环中。在您的示例中,明显的子表达式是spating\uu[level]*spating\u[level]和omega*1./6. 另一个尝试是使idx成为指针而不是数组索引,并在循环中递增指针 int *

,一个好的优化编译器无论如何都会为您完成大多数简单的事情,因此始终要测量您所做的更改是否确实改善了事情。并且,检查(并学习理解)生成的汇编代码,以查看编译器实际在做什么

但我会尝试做一些事情,因为表达式很复杂,即使是好的优化器有时也需要一些帮助:-

首先,将内部循环中不变的子表达式提升到周围循环中。在您的示例中,明显的子表达式是
spating\uu[level]*spating\u[level]
omega*1./6.

另一个尝试是使idx成为指针而不是数组索引,并在循环中递增指针

 int *idx = &grid[getIndexInner(level, 1,y,z)];  // assuming grid is array of ints.
然后你的表情开始像这样

*idx = (1. - omega)  * *idx + omega * 1./6. * (idx[1] + idx[-1] +
                                idx[strideY]  + idx[- strideY] + // etc...
您的优化器(假设它已打开???)很可能已经在这样做了。但值得一试。正如我所说,没有测量,这是一个毫无意义的练习


而且,正如@AkiSuihkonen在上面的评论中提到的“首先让它工作”。调试高度优化的代码要困难得多,因此,在开始担心性能之前,请确保您的算法的性能准确无误。

您是否打算在(10,10,10)处进行平滑以更改(10,10,11)处的结果在同一个平滑过程中?@Yakk:对不起,我不太明白你的意思。现在(10,10,10)的平滑只会改变这个值。你是说像红黑这样的东西吗?这通常用于并行,但我保留纯串行。否,我的意思是你修改
grid[10,10,10]
,然后在设置
网格[10,10,11]
时读取此值(我使用
[a,b,c]
的意思是“进行所有索引计算,以找到a,b,c处的项所在的位置--
网格[getIndexInner(级别,10,10,10)]
而不是
网格[10,10,10]
只是冗长而已)我想我明白你的意思了:是的,这很好。事实上,这就是高斯-赛德尔平滑和雅可比平滑(SOR是第一种平滑的变体)之间的区别。代码似乎在原地对输入网格[idx]进行IIR过滤,然后移到下一个输入[idx+1]并使用先前处理的数据作为下一个单元格的输入。这使得处理具有各向异性,这可能是您的目的,但我对此表示怀疑。无论如何,瓶颈是读取内部循环中的6(或7)个条目。这可以通过将元素按移动方向存储来减少:
grid[idx-1..idx+1]
在临时变量中(并旋转它们)。谢谢,我会定义。试试看。当然,我会衡量我采取的每一步,到目前为止,我提到的优化总是给我一些加速
*idx = (1. - omega)  * *idx + omega * 1./6. * (idx[1] + idx[-1] +
                                idx[strideY]  + idx[- strideY] + // etc...