カーネル間の同時実行性は多くの要因に依存しますが、多くの人が見落としているのは、単純にカーネルのサイズ (つまり、グリッド内のブロックの数) です。単独で GPU を効果的に利用できるサイズのカーネルは、一般的にはそうではありません。同時に実行されたとしても、スループットの利点はほとんどありません。通常、GPU 内のワーク ディストリビューターは、カーネルが起動されるとすぐにブロックの分散を開始します。そのため、あるカーネルが別のカーネルの前に起動され、両方に多数のブロックがある場合、通常、最初のカーネルが GPU をほとんど占有するまで GPU を占有します。この時点で、2 番目のカーネルのブロックがスケジュールされて実行されますが、おそらく少量の「同時オーバーラップ」があります。
要点は、「GPU をいっぱいにする」のに十分なブロックを持つカーネルは、他のカーネルが実際に実行するのを妨げるということです。スケジューリングは別として、これはコンピューティング 3.5 デバイスでも変わりません。さらに、カーネル全体のいくつかのパラメーターを指定するだけでなく、ブロック レベルで起動パラメーターと統計情報 (レジスターの使用状況、共有メモリの使用状況など) も指定すると、明確な回答が得られます。この領域におけるコンピュート 3.5 アーキテクチャの利点は、主に、一緒に実行しようとする「少数」ブロックの「小さな」カーネルから得られます。Compute 3.5 にはいくつかの利点があります。
この質問への回答も確認してください。
- カーネルが使用するグローバル メモリが固定されていない場合、データ転送の速度に影響し、コピーと計算をオーバーラップする機能にも影響しますが、2 つのカーネルを同時に実行する機能には影響しません。ただし、コピーと計算の重複に対する制限により、アプリケーションの動作が歪む可能性があります。
- 「読み取り競合」があってはなりません。それが何を意味するのかわかりません。2 つの独立したスレッド/ブロック/グリッドは、グローバル メモリ内の同じ場所を読み取ることができます。通常、これは L2 キャッシュ レベルで整理されます。読み取りのみについて話している限り、競合は発生せず、同時実行性に特に影響はありません。
- コンスタント メモリは限られたリソースであり、デバイス上で実行されているすべてのカーネル間で共有されます (deviceQuery を実行してみてください)。デバイスの合計制限を超えていない場合、唯一の問題は、一定のキャッシュの使用率の 1 つと、キャッシュのスラッシングなどです。この二次的な関係を除けば、同時実行性に直接的な影響はありません。
- カーネルごとではなく、ブロックごとの共有メモリの量を特定する方が有益です。これは、SM でスケジュールできるブロックの数に直接影響します。ただし、この質問への回答は、各カーネルの起動構成と、起動呼び出しの相対的なタイミングを指定した場合にも、より明確になります。 たまたま共有メモリがスケジューリングの制限要因であった場合は、SM ごとに使用可能な共有メモリの合計を各カーネルで使用される量で割り、これに基づいて可能な同時実行数を把握できます。私自身の意見では、グリッドごとに 10k を使用し、グリッド全体で数個のブロックしか持たないカーネルがない限り、各グリッドのブロック数がより大きな問題になる可能性があります。
- ここでの私のコメントは、4 に対する私の回答とほぼ同じです。デバイスの deviceQuery を見てください。各 SM でブロックをスケジュールする際にレジスターが制限要因になった場合は、SM ごとに使用可能なレジスターを SM ごとのレジスター使用量で割ることができます。カーネル (ここでも、ブロックごとのレジスタの使用量とカーネル内のブロック数について話す方がはるかに理にかなっています) を調べて、制限が何であるかを発見します。
繰り返しになりますが、適切なサイズのカーネル (数百または数千のブロック、またはそれ以上) がある場合は、作業ディストリビューターによるブロックのスケジューリングが、カーネル間の同時実行量の支配的な要因になる可能性が最も高くなります。
編集:質問に投稿された新しい情報に応じて。kF.png を見てきました
- まず、ブロックごとの 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 しか得られないと思っているかもしれませんが、わかりません。
- 次に、共有メモリの観点から見てみましょう。重要な質問は、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 ウェビナーページにあります。