私は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までさまざまです。また、グリッドにはすべての次元にいくつかの境界があり、少数の行で構成されています。つまり、反復はグリッド全体ではありません。