web-dev-qa-db-ja.com

OpenMP Dynamic vs Guided Scheduling

私はOpenMPのスケジューリング、具体的にはさまざまなタイプを勉強しています。各タイプの一般的な動作は理解していますが、dynamicguidedのどちらのスケジューリングを選択するかについて明確にすることは役立ちます。

Intelのドキュメント describe dynamicスケジューリング:

内部作業キューを使用して、各スレッドにループ反復のチャンクサイズのブロックを与えます。スレッドが終了すると、ワークキューの先頭からループ反復の次のブロックを取得します。デフォルトでは、チャンクサイズは1です。このスケジューリングタイプを使用する場合は、余分なオーバーヘッドが発生するため注意してください。

guidedスケジューリングについても説明します。

動的スケジューリングに似ていますが、チャンクサイズは大きくなり始め、反復間の負荷の不均衡をより適切に処理するために小さくなります。オプションのチャンクパラメータは、使用する最小サイズのチャンクを指定します。デフォルトでは、チャンクサイズはおよそloop_count/number_of_threadsです。

guidedスケジューリングは実行時に動的にチャンクサイズを縮小するため、なぜdynamicスケジューリングを使用するのでしょうか?

私はこの質問を調査しました ダートマスからこの表を見つけました

enter image description here

guidedhighオーバーヘッドを持つものとしてリストされますが、dynamicはオーバーヘッドが中程度です。

これは最初は理にかなっていましたが、さらに調査すると、このトピックに関する Intelの記事を読む になりました。前の表から、guidedスケジューリングは実行時のチャンクサイズの分析と調整のために(正しく使用された場合でも)時間がかかると理論付けました。ただし、Intelの記事には次のように記載されています。

ガイド付きスケジュールは、小さなチャンクサイズを制限として最適に機能します。これにより、最大限の柔軟性が得られます。大きなチャンクサイズで悪化する理由は明らかではありませんが、大きなチャンクサイズに制限すると時間がかかりすぎることがあります。

チャンクサイズがguidedに関係するのはなぜdynamicよりも時間がかかるのですか? 「柔軟性」の欠如は、チャンクサイズをロックしすぎることでパフォーマンスの低下を引き起こすことには意味があります。しかし、私はこれを「オーバーヘッド」とは言わず、ロックの問題は以前の理論を信用しません。

最後に、それは記事に記載されています:

動的なスケジュールは最も柔軟性がありますが、スケジュールが間違っているとパフォーマンスが最大になります。

dynamicスケジューリングがstaticよりも最適であるのは理にかなっていますが、なぜguidedよりも最適なのでしょうか?それは私が疑問にしているオーバーヘッドですか?

この やや関連するSO post は、スケジューリングタイプに関連するNUMAを説明します。必要な組織は「先着順」で失われるため、この質問とは無関係です。これらのスケジューリングタイプの動作。

dynamicスケジューリングは合体してパフォーマンスの向上を引き起こす可能性がありますが、guidedにも同じ仮説が適用されるはずです。

参考までに、Intelの記事からのさまざまなチャンクサイズにわたる各スケジューリングタイプのタイミングを以下に示します。それは1つのプログラムからの記録のみで、一部のルールはプログラムとマシンごとに異なる方法で適用されます(特にスケジューリングの場合)が、一般的な傾向を提供する必要があります。

enter image description here

[〜#〜] edit [〜#〜](私の質問の中核):

  • guidedスケジューリングの実行時間に影響を与えるものは何ですか?具体例?場合によってはdynamicより遅いのはなぜですか?
  • いつguidedよりもdynamicを好むでしょうか、その逆ですか?
  • これが説明されると、上記のソースはあなたの説明をサポートしますか?彼らはまったく矛盾していますか?
20
Matt Goodrich

ガイド付きスケジューリングの実行時間に影響するものは何ですか?

考慮すべき3つの効果があります。

1.負荷バランス

動的/ガイド付きスケジューリングのポイントは、各ループ反復に同じ量の作業が含まれない場合に作業の分散を改善することです。基本的に:

  • schedule(dynamic, 1)は、最適な負荷分散を提供します
  • _dynamic, k_は常に_guided, k_よりもと同等かそれ以上の負荷分散を行います

標準では、各チャンクのサイズはproportionalに割り当てられていない反復の数をチーム内のスレッドの数で割ってkに減少することを義務付けています。

GCC OpenMP実装 は、proportionalを無視して、文字通りこれを受け取ります。たとえば、4つのスレッド_k=1_の場合、_8, 6, 5, 4, 3, 2, 1, 1, 1, 1_として32回反復されます。今私見これは本当に愚かです:最初の1/nの反復に1/nを超える作業が含まれていると、負荷のバランスが悪くなります。

具体例?なぜ場合によっては動的より遅いのですか?

さて、ループの繰り返しで内部の仕事が減少する些細な例を見てみましょう:

_#include <omp.h>

void work(long ww) {
    volatile long sum = 0;
    for (long w = 0; w < ww; w++) sum += w;
}

int main() {
    const long max = 32, factor = 10000000l;
    #pragma omp parallel for schedule(guided, 1)
    for (int i = 0; i < max; i++) {
         work((max - i) * factor);
    }
}
_

実行は次のようになります1

Example execution timeline

ご覧のとおり、guidedはここで非常に悪い結果をもたらします。 guidedは、さまざまな種類の作業配分に対してはるかに優れています。ガイド付きを異なる方法で実装することもできます。 clang(IIRCはIntelに由来)の実装は、 はるかに洗練された です。私は、GCCの単純な実装の背後にある考えを本当に理解していません。私の目には、最初のスレッドに_1/n_の作業を与えると、動的な負荷のブランキングの目的を事実上無効にします。

2.オーバーヘッド

現在、各動的チャンクは、共有状態にアクセスするため、パフォーマンスにある程度の影響があります。 guidedのオーバーヘッドは、少し多くの計算があるため、dynamicよりもチャンクごとにわずかに高くなります。ただし、_guided, k_の合計ダイナミックチャンクは_dynamic, k_よりも少なくなります。

オーバーヘッドも実装に依存します。共有状態を保護するためにアトミックまたはロックを使用するかどうか。

3.キャッシュおよびNUMA効果

ループの繰り返しで整数のベクトルに書き込むとしましょう。 1つおきの反復が異なるスレッドによって実行される場合、ベクトルの2つおきの要素は異なるコアによって書き込まれます。そうすることで、隣接する要素を含むキャッシュラインを競合させるため、それは本当に悪いことです(偽共有)。チャンクサイズが小さい場合や、キャッシュにうまく合わないチャンクサイズがある場合は、チャンクの「エッジ」でパフォーマンスが低下します。これが、通常、大きなNice(_2^n_)チャンクサイズを好む理由です。 guidedは平均して大きなチャンクサイズを提供できますが、_2^n_(または_k*m_)は提供できません。

この回答 (すでに参照した)、NUMAの観点から動的/ガイド付きスケジューリングの欠点について詳しく説明していますが、これはローカリティ/キャッシュにも当てはまります。

推測しないで、測定する

さまざまな要因と詳細を予測することの難しさを考えると、特定のシステム、特定の構成、特定のコンパイラで特定のアプリケーションを測定することをお勧めします。残念ながら、完璧なパフォーマンスの移植性はありません。個人的には、これはguidedに特に当てはまると主張します。

動的または逆の場合にガイド付きを優先するのはいつですか?

オーバーヘッド/反復ごとの作業について特定の知識がある場合は、_dynamic, k_が適切なkを選択することで最も安定した結果をもたらすと言えます。特に、実装がどれほど賢いかにはあまり依存しません。

一方、guidedは、少なくとも賢い実装では、妥当なオーバーヘッド/負荷分散比率を備えた、最初の推測として適切かもしれません。後の反復時間が短いことがわかっている場合は、guidedに特に注意してください。

コンパイラ/ランタイムを完全に制御するschedule(auto)と、実行時にスケジューリングポリシーを選択できるschedule(runtime)もあります。

これが説明されると、上記のソースはあなたの説明をサポートしますか?彼らはまったく矛盾していますか?

このanserを含むソースを一粒の塩で取ります。あなたが投稿したチャートも、私のタイムラインの写真も、科学的に正確な数字ではありません。結果には大きなばらつきがあり、エラーバーはありません。これらのデータポイントがほとんどない場所にある可能性があります。また、チャートは、Workコードを開示せずに、私が言及した複数の効果を組み合わせています。

[Intelドキュメントから]

デフォルトでは、チャンクサイズはおよそloop_count/number_of_threadsです。

これは、iccが私の小さな例をより良く処理するという私の観察と矛盾しています。

1:視覚化にGCC 6.3.1、Score-P/Vampirを使用し、着色のために2つの交互の仕事関数。

23
Zulan