c++ - 优化 3D 循环 (C++)

标签 c++ optimization scientific-computing

我正在使用 C++ 开发多重网格求解器,现在我正在尝试提高串行性能。其中最耗时的部分是更平滑的部分,在我的例子中是一个连续的过度松弛求解器。这看起来如下(我希望它是不言自明的):

int idx; 
int strideY = stride_[level][0];
int strideZ = stride_[level][1];
for(int i = 0; i < steps; ++i) {

    for(int z = 1; z <= innerGridpoints_[level][2]; ++z) {
        for(int y = 1; y <= innerGridpoints_[level][1]; ++y) {
            idx = getIndexInner(level, 1,y,z);
            for(int x = 1; x <= innerGridpoints_[level][0]; ++x, ++idx) {
                grid[idx] = (1. - omega)  * grid[idx] + omega * 1./6. * (grid[idx+1] + grid[idx-1] +
                                    grid[idx + strideY]  + grid[idx - strideY] + 
                                    grid[idx + strideZ]  + grid[idx - strideZ] - 
                                    spacing_[level] * spacing_[level] * rhs[idx]);
            }
        }
    }
}

我已经做了一些优化:循环的定位使得内部循环给出最多的本地条目(即相邻元素沿着 x 维度),以及 idx 的预计算(即使这是一个内联函数,它这样节省了很多时间)。 我也尝试过阻塞,即不遍历整个网格,而是只遍历小块以增加局部性,但这没有任何影响。 我最后的想法是尝试一些循环展开,但实际上我并不期望从中得到很大的改进。我在想,也许对内存访问有一些可能的改进。欢迎任何提示:)

仅供引用:网格大小从非常小到 255x255x255 不等。此外,网格在每个维度上都有一些边界,由少量行组成,即迭代不会遍及整个网格。

最佳答案

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

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

首先,将内部循环内不变的子表达式提升到周围循环。在您的示例中,明显的是 spacing_[level] * spacing_[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 在上面的评论中提到的“首先让它发挥作用”。调试高度优化的代码要困难得多,因此在您开始担心性能之前,请确保您的算法完全执行应有的方式。

关于c++ - 优化 3D 循环 (C++),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15535744/

相关文章:

c++ - 有什么能阻止 std::optional::value_or() 有条件地 noexcept 吗?

c++ - 访问呈现的 WPF 页面/窗口的底层 DirectX 表面/渲染目标

c++ - 科学编程实践

java - 在同一 block 中调用方法两次。为什么?

c++ - Armadillo vs. Blitz ++

numpy - 涉及 Scitools、NumPy 和 SciPy 的推荐设置

c++ - 如何控制哪个 numa 节点执行我的程序

python - 如何加速从具有位置 (X, Y) 和强度的点创建图像?

dynamic-languages - 脚本编写者是否必须考虑舍入误差?

c++ - 代码块中不包含 iostream 库