我正在使用 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 不等。此外,网格在每个维度上都有一些边界,由少量行组成,即迭代不在整个网格上。