ブロックごとに 32 を超えるスレッドを実行するとパフォーマンスが向上するのはなぜですか?
私のグラフィックス カードには 480 CUDA コア (15 MS * 32 SP) があります。
各 SM には 1 ~ 4 個のワープ スケジューラがあります (テスラ = 1、フェルミ = 2、ケプラー = 4)。各ワープ スケジューラは、SM に割り当てられたワープのサブセットを実行します。各ワープ スケジューラは、適格なワープのリストを保持します。ワープは、次のサイクルで命令を発行できる場合に適格です。ワープがデータの依存関係で停止している場合、フェッチと命令を待機している場合、または次の命令の実行ユニットがビジーである場合、ワープは適格ではありません。各サイクルで、各ワープ スケジューラは、適格なワープのリストからワープを選択し、1 つまたは 2 つの命令を発行します。
SM ごとのアクティブなワープが多いほど、各ワープ スケジューラが各サイクルで選択する必要があるワープの数が多くなります。ほとんどの場合、最適なパフォーマンスは、SM ごとに十分なアクティブなワープがあり、サイクルごとにワープ スケジューラごとに 1 つの適格なワープを持つ場合に達成されます。このポイントを超えて占有率を上げても、パフォーマンスは向上せず、パフォーマンスが低下する可能性があります。
アクティブなワープの一般的な目標は、SM の最大ワープの 50 ~ 66% です。打ち上げ構成によってサポートされる最大ワープに対するワープの比率は、理論的占有率と呼ばれます。サイクルごとのアクティブなワープとサイクルごとの最大ワープの実行時間の比率は、達成占有率です。GTX480 (CC 2.0 デバイス) の場合、カーネルを設計する際の適切な出発点は、50 ~ 66% の理論占有率です。CC 2.0 SM は最大 48 のワープを持つことができます。50% の占有率は、SM ごとに 24 のワープまたは 768 のスレッドを意味します。
Nsight Visual Studio Edition の CUDA プロファイリング アクティビティは、理論上の占有率、達成された占有率、SM ごとのアクティブなワープ、SM ごとの適格なワープ、およびストールの理由を表示できます。
CUDA ビジュアル プロファイラー、nvprof、およびコマンド ライン プロファイラーは、理論上の占有率、アクティブなワープ、および達成された占有率を表示できます。
注: CUDA コアの数は、同様のアーキテクチャのカードを比較したり、理論上の FLOPS を計算したり、アーキテクチャ間の違いを潜在的に比較したりする場合にのみ使用してください。アルゴリズムを設計するときは、カウントを使用しないでください。
スタック オーバーフローへようこそ。その理由は、CUDA コアがパイプライン化されているためです。Fermi では、パイプラインの長さは約 20 クロックです。これは、GPU を飽和状態にするには、コアあたり最大 20 のスレッドが必要になる場合があることを意味します。
主な理由は、CUDA のメモリ レイテンシ隠蔽モデルです。最近のほとんどの CPU はキャッシュを使用して、メイン メモリへのレイテンシを隠しています。これにより、チップ リソースの大部分がキャッシュに費やされます。ほとんどのデスクトップおよびサーバー プロセッサは、ダイ上に数メガバイトのキャッシュを備えており、実際にはダイ スペースの大部分を占めています。同じエネルギー使用量と熱放散特性を持つより多くのコアを搭載するために、CUDA ベースのチップは代わりに、大量の CUDA コア (ほとんどは浮動小数点 ALU) を投入するためにチップ スペースを割り当てます。 、代わりに、他のスレッドがメモリアクセスの戻りを待っている間に、より多くのスレッドを実行する準備ができていることに依存して、その待ち時間を隠します。これにより、一部のワープがメモリ アクセスを待機している間に、コアが生産的に作業できるようになります。
CUDA には、このメモリ待機時間の隠蔽スキームを支援するために、ゼロコストのスレッド切り替えもあります。通常の CPU では、あるスレッドの実行から次のスレッドに切り替えるために大きなオーバーヘッドが発生します。これは、切り替え元のスレッドのすべてのレジスタ値をスタックに格納し、スレッドのすべてのレジスタ値をロードする必要があるためです。に切り替えています。CUDA SM には膨大な量のレジスタがあるため、スレッドの存続期間中、各スレッドには独自の物理レジスタ セットが割り当てられます。レジスタ値を格納およびロードする必要がないため、各 SM は 1 つのクロック サイクルで 1 つのワープからスレッドを実行し、次のクロック サイクルで別のワープからスレッドを実行できます。