6

48 コア システム (4xAMD Opteron 6348、2.8 Ghz、CPU あたり 12 コア) での並列化の制限を理解しようとしています。私はこの小さな OpenMP コードを書いて、可能な限り最良の状況であると考えられる状況でスピードアップをテストしました (タスクは恥ずかしいほど並列です)。

// Compile with: gcc scaling.c -std=c99 -fopenmp -O3                                                                                               

#include <stdio.h>
#include <stdint.h>

int main(){

  const uint64_t umin=1;
  const uint64_t umax=10000000000LL;
  double sum=0.;
#pragma omp parallel for reduction(+:sum)
  for(uint64_t u=umin; u<umax; u++)
    sum+=1./u/u;
  printf("%e\n", sum);

}

スケーリングが非常に非線形であることに驚きました。48 スレッドでコードを実行するには約 2.9 秒、36 スレッドで 3.1 秒、24 スレッドで 3.7 秒、12 スレッドで 4.9 秒、1 スレッドでコードを実行するには 57 秒かかります。

残念ながら、1 つのコアを 100% 使用してコンピューター上で実行されているプロセスが 1 つあると言わざるを得ないため、それが影響している可能性があります。これは私のプロセスではないので、違いをテストするために終了することはできませんが、どういうわけか、それが 19 ~ 20 倍の高速化と理想的な 48 倍の高速化の違いを生んでいるとは思えません。

OpenMP の問題ではないことを確認するために、プログラムの 2 つのコピーをそれぞれ 24 スレッドで同時に実行しました (1 つは umin=1、umax=5000000000 で、もう 1 つは umin=5000000000、umax=10000000000 です)。その場合、プログラムの両方のコピーが 2.9 秒後に終了するため、プログラムの 1 つのインスタンスで 48 スレッドを実行するのとまったく同じです。

この単純なプログラムで線形スケーリングを妨げているのは何ですか?

4

3 に答える 3

3

これが答えとしてふさわしいかどうかはわかりませんが、コメント以上のもののように感じられるので、ここに行きます.

私のプロジェクトのいずれにおいても、スレッド数に対して特に線形のパフォーマンスに気付いたことはありません。1 つには、スケジューラーがありますが、これは厳密には公平ではないように思えます。OpenMP はおそらく、最初にタスクをスレッドのチーム間で均等に分割し、次にそれぞれを結合します。私が楽しんだすべての Linux ボックスで、いくつかのスレッドが早く終了し、いくつかのスレッドが遅れることを期待していました。他のプラットフォームは異なります。ただし、それはうまくいきますが、もちろん、最も遅いものが追いつくのを待っています。確率論的に言えば、スレッド処理のパルスが釣鐘曲線のような形で進行しており、スレッドが多ければ多いほど幅が広くなると考えるべきであり、トレーリング エッジがフィニッシュ ラインを横切るまで、作業は決して完了しません。

とはどういう意味topですか? プロセスが 20 スレッドで 2000%、40 スレッドで 4000% の CPU を使用していることがわかりますか? 私はそれが先細りになるに違いない。htopちなみに、通常、プロセスの合計が表示され、スレッドごとに個別の行が表示されます。それは見ていて面白いかもしれません。

このような小さなループでは、おそらくキャッシュ スラッシュやそのような煩わしさに遭遇することはありません。しかし、トップからいくらかのパフォーマンスを削ってしまうもう 1 つの問題があります。最新のマルチコア CPU と同様に、Opteron は、温度が低いときはより高いクロック レートで実行されます。加熱するコアが多いほど、表示されるターボ モードは少なくなります。

于 2013-11-05T03:50:52.913 に答える
2

最後に、完全にアンロードされたシステムでコードをベンチマークする機会を得ました。 ここに画像の説明を入力

私が使用した動的スケジュールの場合schedule(dynamic,1000000)。静的スケジュールでは、デフォルト (コア間で均等) を使用しました。スレッドバインディングには を使用しexport GOMP_CPU_AFFINITY="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47"ました。

このコードの高度な非線形スケーリングの主な理由は、AMD が「コア」と呼んでいるものは、実際には独立したコアではないためです。これは redrum の回答の一部 (1) でした。これは、24 スレッドでの高速化の急激な停滞から、上記のプロットではっきりとわかります。動的スケジューリングを使えば、それは明らかです。私が選択したスレッド バインディングからも明らかです。各「モジュール」に 2 つのスレッドが存在することになるため、上で書いたバインディングはひどい選択であることがわかります。

2 番目に大きな速度低下は、多数のスレッドを使用した静的スケジューリングによるものです。必然的に、最も遅いスレッドと最も速いスレッドの間に不均衡が生じ、デフォルトの静的スケジューリングで反復が大きなチャンクに分割されると、実行時間に大きな変動が生じます。答えのこの部分は、HristoのコメントとSaltの答えの両方から来ました。

なぜ「ターボ ブースト」の効果がより顕著にならないのかはわかりません (Redrum の回答のパート 2)。また、スケーリングの最後のビットが失われる場所 (おそらくオーバーヘッド) が 100% 確実ではありません (モジュール数の線形スケーリングから予想される 24 倍ではなく、22 倍のパフォーマンスが得られます)。しかし、そうでなければ、質問はかなりよく答えられています。

于 2013-11-09T02:10:37.083 に答える