まず、このタイプの質問がよく聞かれるので、私ができる限り多くのことを読んだと言ってこれを序文にしておきましょう。OpenMPの性能
私は大量ののforループを並列化しました。ループの反復回数は20から150までの間で変化しますが、ループ本体は膨大な量の作業を行いますが、多くの局所的な線形代数ルーチンを呼び出します(コードはソースの一部であり外部依存関係ではありません) 。ループ本体には、これらのルーチンへの1000回以上の呼び出しがありますが、それらはすべて互いに完全に独立しているため、並列処理の主な候補になると考えました。ループコードはC++ですが、Cで書かれたサブルーチンがたくさん呼び出されます。
コードは次のようになります。
<declare and initialize shared variables here>
#ifdef _OPENMP
#pragma omp parallel for \
private(....)\
shared(....) \
firstprivate(....) schedule(runtime)
#endif
for(tst = 0; tst < ntest; tst++) {
// Lots of functionality (science!)
// Calls to other deep functions which manipulate private variables only
// Call to function which has 1000 loop iterations doing matrix manipulation
// With no exaggeration, there are probably millions
// of for-loop iterations in this body, in the various functions called.
// They also do lots of mallocing and freeing
// Finally generated some calculated_values
shared_array1[tst] = calculated_value1;
shared_array2[tst] = calculated_value2;
shared_array3[tst] = calculated_value3;
} // end of parallel and for
// final tidy up
、私は信じて、すべての任意の同期があってはならない - スレッドが共有変数にアクセスする唯一の時間shared_arrays
であり、それらは、それらの配列にユニークなポイントにアクセスし、tst
でインデックス化。
これは、マルチコアクラスタ上のスレッド数を上げたときのことです(私たちがこのループを5回呼び出す場所)の速度は次のとおりです。
Elapsed time System time
Serial: 188.149 1.031
2 thrds: 148.542 6.788
4 thrds: 309.586 424.037 # SAY WHAT?
8 thrds: 230.290 568.166
16 thrds: 219.133 799.780
目立つかもしれ物事は2と4スレッド間のシステム時間の大幅なジャンプ、実際の経過時間は、私たちが2から4に移動兼ね、その後、徐々に減少しています。
OMP_SCHEDULE
という膨大な範囲のパラメータを試しましたが、運はありませんでした。これは、各スレッドがmalloc/newとfree/deleteをたくさん使用しているという事実に関連していますか?これは8GBのメモリで一貫して動作していますが、それは問題ではないと思います。率直に言って、システム時間の巨大な増加は、スレッドがブロックしているように見えますが、なぜそれが起こるのかわかりません。ループはスレッドローカル配列での計算された値を格納し、その後に渡ってこれらの配列をコピーするように、私は本当に偽共有が問題になるだろうと思ったので、再度書いたコード
UPDATE 1 最後に共有配列。残念ながら、私はほとんどそれを信じていませんが、これは影響はありませんでした。
はcmeerwのアドバイス、@の後、私はstraceの-fを実行し、すべての初期化後に
[pid 58067] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 58066] <... futex resumed>) = -1 EAGAIN (Resource temporarily unavailable)
[pid 58065] <... futex resumed>) = -1 EAGAIN (Resource temporarily unavailable)
[pid 57684] <... futex resumed>) = 0
[pid 58067] <... futex resumed>) = 0
[pid 58066] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 58065] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 58067] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 58066] <... futex resumed>) = 0
[pid 57684] futex(0x35ca58bb40, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid 58065] <... futex resumed>) = 0
[pid 58067] <... futex resumed>) = 0
[pid 57684] <... futex resumed>) = -1 EAGAIN (Resource temporarily unavailable)
[pid 58066] futex(0x35ca58bb40, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid 58065] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 58066] <... futex resumed>) = -1 EAGAIN (Resource temporarily unavailable)
[pid 57684] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 58065] <... futex resumed>) = 0
[pid 58066] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 57684] <... futex resumed>) = 0
[pid 58067] futex(0x35ca58bb40, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid 58066] <... futex resumed>) = 0
[pid 58065] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 58067] <... futex resumed>) = -1 EAGAIN (Resource temporarily unavailable)
[pid 58066] futex(0x35ca58bb40, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid 57684] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 58065] <... futex resumed>) = 0
[pid 58067] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 58066] <... futex resumed>) = -1 EAGAIN (Resource temporarily unavailable)
[pid 57684] <... futex resumed>) = 0
[pid 58067] <... futex resumed>) = 0
[pid 58066] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 58065] futex(0x35ca58bb40, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid 58066] <... futex resumed>) = 0
[pid 58065] <... futex resumed>) = -1 EAGAIN (Resource temporarily unavailable)
[pid 58066] futex(0x35ca58bb40, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid 57684] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 58067] futex(0x35ca58bb40, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...>
[pid 58066] <... futex resumed>) = -1 EAGAIN (Resource temporarily unavailable)
[pid 58065] futex(0x35ca58bb40, FUTEX_WAKE_PRIVATE, 1 <unfinished ...>
[pid 57684] <... futex resumed>) = 0
のラインのちょうど百万人がある誰もが何を意味するのか任意のアイデアがありますか?スレッドがコンテキスト切り替えの頻度が高すぎるように見えますか、またはブロックとブロック解除だけですか? strace
OMP_NUM_THREADS
が0に設定された同じ実装では、これはまったくありません。比較のために、1つのスレッドが使用されたときに生成されるログファイルは486 KBであり、4つのスレッドが使用されたときに生成されるログファイルは266 MBです。言い換えれば
、並列バージョンは、ログファイルの余分4170104行を呼び出す...
UPDATE 2
トムによって示唆されるように、私は無駄に特定のプロセッサに結合スレッドを試してみました。私たちはOpenMP 3.1を使用していますので、export OMP_PROC_BIND=true
を使って環境変数を設定しました。同じサイズのログファイルと同じ時間枠。
UPDATE 3
プロットが厚くなります。これまでのところ、クラスタでしかプロファイルできなかったので、私はMacports経由でGNU GCC 4.7をインストールし、初めてMacbookにコンパイルしました(AppleのGCC-4.2.1はOpenMPが有効なときにコンパイラのバグを投げます。これまでコンパイルして並列実行していなかった)。 MacBookの上では、基本的に、あなたが、これは我々がデータを持っている。このテストで反復処理しているデータ・セットのカップルとしてほとんど驚くべきことであるものの
C-code time
Serial: ~34 seconds
2 thrds: ~21 seconds
4 thrds: ~14 seconds
8 thrds: ~12 seconds
16 thrds: ~9 seconds
我々は、両端に向けてdimishingリターンを参照してください期待トレンドを見ます< 16人のメンバーです(例えば、for-loop
で7回の繰り返しで16個のスレッドを生成しています)。
これで問題は残ります。なぜクラスタのパフォーマンスが低下するのですか?私は今夜別のquadcore linuxboxを試してみるつもりです。クラスターはGNU-GCC 4.6.3でコンパイルされますが、それ自体がそのような違いを生み出すとは思いませんか?
ltrace
ももクラスタにインストールされていません(さまざまな理由でそれらを取得できません)。私のlinuxboxがクラスタのようなパフォーマンスを与えるなら、対応するltrace
分析を実行します。
UPDATE 4
私のああ。私はMacBook ProをUbuntu(12.04)にブートしてコードを再実行しました。それはすべて実行されています(これはいくぶん安心しています)が、私はクラスタで見たものと同じ、奇妙でない悪いパフォーマンスの振る舞い、そして何百万もの同じ実行がfutex
の呼び出しを参照しています。 Ubuntuの私のローカルマシンとOSXの唯一の違いはソフトウェアだ(と私は同じコンパイラとライブラリを使用しています - おそらく、OSXとUbuntuの異なるglibc
の実装はありません!)私は今これが何かLinuxがスレッドをどのようにスケジューリング/配布するかに関係します。どんな場合でも、私のローカルマシン上にあることは何百万回も簡単になるので、私は先に進み、ltrace -f
とそれを見て私が見つけることができるものを見ます。私は別のプロセスからforks()
のクラスタを回避する方法を書いており、ランタイムでは完全な1/2を与えているので、並列性を得ることは間違いありません。
これらの関数で乱数生成を行っていますか?同様の問題がありました:glibcはrandへの呼び出しごとに同期を行います。 OpenMPのためのソリューション:http://stackoverflow.com/questions/8980056/splitting-up-a-program-into-4-threads-is-slower-than-a-single-thread –
@AlexanderKondratskiyいいえ、しかし、ありがとうございました簡単にされている! – Alex
"strace -f"の下で実行しようとしましたか?少なくとも、どのシステムコールが関係しているかを示す必要があります。 – cmeerw