私は、MPICH と比較して OpenMP のポイントを証明しようとしていました。OpenMP で高いパフォーマンスを実現することがいかに簡単かを示すために、次の例を作成しました。
Gauss-Seidel 反復は、各スイープですべての操作を任意の順序で実行でき、各タスク間に依存関係がないように、2 つの個別の実行に分割されます。したがって、理論的には、各プロセッサは、別のプロセスが何らかの同期を実行するのを待つ必要はありません。
私が直面している問題は、問題のサイズに関係なく、2 プロセッサの速度向上は弱く、2 プロセッサを超えるとさらに遅くなる可能性があることです。他の多くの線形並列ルーチンは非常に優れたスケーリングを得ることができますが、これは注意が必要です。
私が恐れているのは、配列に対して実行する操作がスレッドセーフであることをコンパイラーに「説明」できないため、実際には効果的ではないということです。
以下の例を参照してください。
OpenMP でこれをより効果的にする方法についての手がかりはありますか?
void redBlackSmooth(std::vector<double> const & b,
std::vector<double> & x,
double h)
{
// Setup relevant constants.
double const invh2 = 1.0/(h*h);
double const h2 = (h*h);
int const N = static_cast<int>(x.size());
double sigma = 0;
// Setup some boundary conditions.
x[0] = 0.0;
x[N-1] = 0.0;
// Red sweep.
#pragma omp parallel for shared(b, x) private(sigma)
for (int i = 1; i < N-1; i+=2)
{
sigma = -invh2*(x[i-1] + x[i+1]);
x[i] = (h2/2.0)*(b[i] - sigma);
}
// Black sweep.
#pragma omp parallel for shared(b, x) private(sigma)
for (int i = 2; i < N-1; i+=2)
{
sigma = -invh2*(x[i-1] + x[i+1]);
x[i] = (h2/2.0)*(b[i] - sigma);
}
}
追加:生のポインター実装も試してみましたが、STL コンテナーを使用するのと同じ動作をするため、STL からの疑似クリティカルな動作である可能性を除外できます。