0

こんにちは、複数のカーネルの Cuda ストリーム処理に関するいくつかの質問です。3.5 対応の kepler デバイスで s ストリームとカーネルを想定します。ここで、s <= 32 です。カーネルは、サイズ n の dev_input 配列とサイズ s*n の dev 出力配列を使用します。カーネルは入力配列からデータを読み取り、その値をレジスターに格納して操作し、その結果を dev_output の位置 s*n + tid に書き込みます。

毎回 n 個のストリームの 1 つを使用して、同じカーネルを s 回実行することを目指しています。simpleHyperQ の例に似ています。次のいずれかが同時実行に影響するかどうか、またどのように影響するかについてコメントできますか?

  1. dev_input と dev_output は固定されていません。
  2. dev_input そのまま vs dev_input サイズ s*n、各カーネルは一意のデータを読み取ります (読み取りの競合はありません)
  3. カーネルは定数メモリからデータを読み取ります
  4. ブロックごとに 10kb の共有メモリが割り当てられます。
  5. カーネルは 60 個のレジスタを使用します

良いコメントをいただければ幸いです...!!!

乾杯、タナシオ

ロバート、詳細な回答をありがとう。とても役に立ちました。4を編集しました。ブロックあたり10kbです。したがって、私の状況では、61 ブロックと 256 スレッドのグリッドを起動します。カーネルはかなり計算的にバインドされています。同じカーネルの 8 つのストリームを起動します。それらをプロファイリングすると、最初の 2 つの間に非常に良い重複が見られ、その後ますます悪化します。カーネルの実行時間は約 6ms です。最初の 2 つのストリームがほぼ完全に同時に実行された後、残りのストリーム間の距離は 3 ミリ秒になります。5に関しては、255レジスタファイルを持つK20を使用しています。したがって、そこからの欠点は期待できません。gk110sに指定されているものと同等の同時実行性を達成できない理由が本当に理解できません..

以下のリンクをご覧ください。kF.png という画像があります。これは、ストリームのプロファイラー出力を示しています..!!!

https://devtalk.nvidia.com/default/topic/531740/cuda-programming-and-performance/concurrent-streams-and-hyperq-for-k20/

4

2 に答える 2

6

カーネル間の同時実行性は多くの要因に依存しますが、多くの人が見落としているのは、単純にカーネルのサイズ (つまり、グリッド内のブロックの数) です。単独で GPU を効果的に利用できるサイズのカーネルは、一般的にはそうではありません。同時に実行されたとしても、スループットの利点はほとんどありません。通常、GPU 内のワーク ディストリビューターは、カーネルが起動されるとすぐにブロックの分散を開始します。そのため、あるカーネルが別のカーネルの前に起動され、両方に多数のブロックがある場合、通常、最初のカーネルが GPU をほとんど占有するまで GPU を占有します。この時点で、2 番目のカーネルのブロックがスケジュールされて実行されますが、おそらく少量の「同時オーバーラップ」があります。

要点は、「GPU をいっぱいにする」のに十分なブロックを持つカーネルは、他のカーネルが実際に実行するのを妨げるということです。スケジューリングは別として、これはコンピューティング 3.5 デバイスでも変わりません。さらに、カーネル全体のいくつかのパラメーターを指定するだけでなく、ブロック レベルで起動パラメーターと統計情報 (レジスターの使用状況、共有メモリの使用状況など) も指定すると、明確な回答が得られます。この領域におけるコンピュート 3.5 アーキテクチャの利点は、主に、一緒に実行しようとする「少数」ブロックの「小さな」カーネルから得られます。Compute 3.5 にはいくつかの利点があります。

この質問への回答も確認してください。

  1. カーネルが使用するグローバル メモリが固定されていない場合、データ転送の速度に影響し、コピーと計算をオーバーラップする機能にも影響しますが、2 つのカーネルを同時に実行する機能には影響しません。ただし、コピーと計算の重複に対する制限により、アプリケーションの動作が歪む可能性があります。
  2. 「読み取り競合」があってはなりません。それが何を意味するのかわかりません。2 つの独立したスレッド/ブロック/グリッドは、グローバル メモリ内の同じ場所を読み取ることができます。通常、これは L2 キャッシュ レベルで整理されます。読み取りのみについて話している限り、競合は発生せず、同時実行性に特に影響はありません。
  3. コンスタント メモリは限られたリソースであり、デバイス上で実行されているすべてのカーネル間で共有されます (deviceQuery を実行してみてください)。デバイスの合計制限を超えていない場合、唯一の問題は、一定のキャッシュの使用率の 1 つと、キャッシュのスラッシングなどです。この二次的な関係を除けば、同時実行性に直接的な影響はありません。
  4. カーネルごとではなく、ブロックごとの共有メモリの量を特定する方が有益です。これは、SM でスケジュールできるブロックの数に直接影響します。ただし、この質問への回答は、各カーネルの起動構成と、起動呼び出しの相対的なタイミングを指定した場合にも、より明確になります。 たまたま共有メモリがスケジューリングの制限要因であった場合は、SM ごとに使用可能な共有メモリの合計を各カーネルで使用される量で割り、これに基づいて可能な同時実行数を把握できます。私自身の意見では、グリッドごとに 10k を使用し、グリッド全体で数個のブロックしか持たないカーネルがない限り、各グリッドのブロック数がより大きな問題になる可能性があります。
  5. ここでの私のコメントは、4 に対する私の回答とほぼ同じです。デバイスの deviceQuery を見てください。各 SM でブロックをスケジュールする際にレジスターが制限要因になった場合は、SM ごとに使用可能なレジスターを SM ごとのレジスター使用量で割ることができます。カーネル (ここでも、ブロックごとのレジスタの使用量とカーネル内のブロック数について話す方がはるかに理にかなっています) を調べて、制限が何であるかを発見します。

繰り返しになりますが、適切なサイズのカーネル (数百または数千のブロック、またはそれ以上) がある場合は、作業ディストリビューターによるブロックのスケジューリングが、カーネル間の同時実行量の支配的な要因になる可能性が最も高くなります。

編集:質問に投稿された新しい情報に応じて。kF.png を見てきました

  1. まず、ブロックごとの SM の観点から分析してみましょう。CC 3.5 では、SM ごとに 16 個の「オープン」または現在スケジュールされているブロックが許可されます。それぞれ 61 ブロックの 2 つのカーネルを起動する場合、CC 3.5 デバイスの「ready-to-go」キューを満たすのに十分な場合があります。別の言い方をすれば、GPU はこれらのカーネルのうち 2 つを一度に処理できます。これらのカーネルの 1 つのブロックが「排出」されると、別のカーネルがワーク ディストリビューターによってスケジュールされます。最初のカーネルのブロックは、合計時間の約半分で十分に「排出」されるため、最初の 2 つのカーネルが完了する途中で次のカーネルがスケジュールされるため、任意の時点 (タイムラインに垂直線を引く) で2 つまたは 3 つのカーネルを同時に実行します。(グラフによると、起動された 3 番目のカーネルは最初の 2 カーネルと約 50% オーバーラップします。連続する各カーネル起動の間に 3 ミリ秒の間隔があるというあなたの声明には同意しません)。ピーク時に 3 つのカーネルがスケジュールされており (3 つのカーネル タイムラインと交差する垂直線がたくさんあります)、各カーネルに最大 60 個のブロックがあるとすれば、それは約 180 個のブロックになります。K20 には 13 個の SM があり、各 SM には、最大 16 個のブロックをスケジュールできます。これは、ピーク時に約 180 ブロックがスケジュールされていることを意味します (おそらく) 対理論上のピークは 16*13 = 208 です。したがって、ここでは最大値にかなり近く、取得できる可能性があるブロックはそれほど多くありません。しかし、120/208 しか得られないと思っているかもしれませんが、わかりません。
  2. 次に、共有メモリの観点から見てみましょう。重要な質問は、L1/共有分割の設定は何ですか? デフォルトでは SM ごとに 48KB の共有メモリになっていると思いますが、この設定を変更した場合、これは非常に重要になります。とにかく、あなたの声明によると、スケジュールされた各ブロックは10KBの共有メモリを使用します。これは、SM ごとに約 4 つのブロックがスケジュールされることを意味します。つまり、4*13 の合計ブロック = 任意の時点でスケジュールできる最大 52 ブロックです。明らかにこの数値を超えているため、カーネルによる共有メモリの使用状況について十分な情報が得られていない可能性があります。実際に 10kb/ブロックを使用している場合、これにより、一度に複数のカーネルに相当するスレッドブロックを実行することが多かれ少なかれ妨げられます。まだまだ重なる部分があるかもしれませんが、これがアプリケーションの実際の制限要因になる可能性が高いと思います。60 ブロックの最初のカーネルがスケジュールされます。いくつかのブロックが排出された後 (または、2 つのカーネルが十分に接近して起動されたため)、2 番目のカーネルがほぼ同時にスケジュールされ始めます。次に、3 番目のカーネルがスケジュールされる前に、約 1 カーネル分のブロックが排出されるまでしばらく待つ必要があります。タイムラインに示されているように、これは 50% の時点である可能性があります。

とにかく、上記の分析 1 と 2 は、カーネル構造に固有の制限に基づいて、デバイスからほとんどの機能を引き出していることを明確に示唆していると思います。(レジスターに基づいて同様の分析を行い、それが重大な制限要因であるかどうかを調べることができます。) この声明について: 「gk110s に指定されているものと同等の同時実行性を達成できない理由が本当に理解できません..」同時実行仕様 (たとえば 32 カーネル) は最大仕様であり、ほとんどの場合、同時に実行できるカーネルの最大数の制限に達する前に、別の種類のマシン制限に遭遇します。

編集:ドキュメントとリソースに関しては、上記の Greg Smith からリンクした回答で、いくつかのリソース リンクが提供されています。さらにいくつかを次に示します。

  • C プログラミング ガイドには、非同期同時実行に関するセクションがあります。
  • NVIDIA の Dr. Steve Rennich による GPU Concurrency and Streams のプレゼンテーションは、NVIDIA ウェビナーページにあります。
于 2013-02-20T14:43:30.113 に答える
0

これまでの HyperQ での私の経験は、私のカーネルの 2 ~ 3 (3.5) 倍の並列化です。これは、カーネルが通常、もう少し複雑な計算のために大きくなるためです。小さなカーネルの場合は話が異なりますが、通常、カーネルはより複雑です。

これは、Nvidia の cuda 5.0 ドキュメントでも回答されており、より複雑なカーネルでは並列化の量が減少します。

しかし、それでもGK110はこれを許すだけで大きなアドバンテージを持っています。

于 2013-05-22T08:29:22.197 に答える