GPUプログラミングで作業効率が望ましいのはなぜですか?


13

私は、CUDAで並列スキャンを実行する方法に関する次の記事を読んでいます。

https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch39.html

この記事では、スキャンを「作業効率」にすることに重点が置かれています。言い換えれば、GPUアルゴリズムはCPUアルゴリズムO(n)よりも多くの追加を実行するべきではありません。著者は2つのアルゴリズムを提示します。1つはO(nlogn)の追加を行う「ナイーブ」アルゴリズムで、もう1つは「作業効率」と考えるアルゴリズムです。ただし、作業効率の良いアルゴリズムでは、ループの繰り返しが2倍になります。

私の理解では、GPUは単純に巨大なSIMDプロセッサであり、ロックステップで動作するはずです。「作業効率の良い」アルゴリズムで2倍のループを実行すると、多くのスレッドがアイドル状態になり、長期的にはパフォーマンスが低下することを意味するようです。私は何が欠けていますか?

回答:


21

まず最初に、「GPUは単に巨大なSIMDプロセッサであり、ロックステップで動作するはずです」、それよりも少し複雑です。全体の GPUは、ロックステップで実行されません。シェーダースレッドは、「ワープ」と呼ばれる32のグループに編成されます(NVIDIAでは、AMDでは、「波面」と呼ばれる64のグループですが、同じ概念です)。ワープ内では、すべてのスレッドがSIMD配列としてロックステップで実行されます。ただし、異なるワープは互いにロックステップではありません。さらに、CPUスレッドのように、一部のワープがアクティブに実行されている場合もあれば、中断されている場合もあります。ワープは、何かを待っている(メモリトランザクションが戻ったり、クリアする障壁があるなど)ために中断される場合があります。

さて、質問に戻りましょう。その論文の「作業効率の良い」アルゴリズムが「単純な」アルゴリズムよりも効率的であるように見える2つの方法を見ることができます。

  1. 作業効率の高いバージョンでは、最初に必要なスレッドの数が半分になります。単純なアルゴリズムでは、配列要素ごとに1つのスレッドがあります。しかし、作業効率の高いバージョンでは、各スレッドは配列の2つの隣接する要素で動作するため、配列要素の半分のスレッドしか必要ありません。スレッドが少ないほど、ワープが少なくなるため、ワープの大部分をアクティブに実行できます。

  2. 作業効率の高いバージョンではより多くのステップが必要ですが、アクティブスレッドの数がより速く減少し、すべての反復にわたるアクティブスレッドの総数がかなり少なくなるという事実によって相殺されます。反復中にワープにアクティブなスレッドがない場合、そのワープは次のバリアにスキップして中断され、他のワープを実行できます。そのため、アクティブワープを少なくすることで、実行時間を短縮できます。(これは、アクティブスレッドができるだけ少ないワープにまとめられるようにGPUコードを設計する必要があることを意味します。1つのアクティブスレッドでもワープ全体を強制するため、それらが散在することは望ましくありません。アクティブになります。)

    単純なアルゴリズムのアクティブなスレッドの数を考慮してください。この記事の図2を見ると、k番目の反復の最初の2 kを除くすべてのスレッドがアクティブであることがわかります。したがって、Nスレッドでは、アクティブスレッドの数はN ‒ 2 kのようになります。たとえば、N = 1024の場合、反復ごとのアクティブスレッドの数は次のとおりです。

    1023, 1022, 1020, 1016, 1008, 992, 960, 896, 768, 512
    

    これをアクティブなワープの数に変換すると(32で割って切り上げる)、次のようになります。

    32, 32, 32, 32, 32, 31, 30, 28, 24, 16
    

    一方、作業効率の良いアルゴリズムは、半分のスレッドで開始し、その後、各反復でアクティブなスレッドの数を半分に減らして1になります。再び配列サイズの半分:

     512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512
    

    これをアクティブワープに変換します。

    16, 8, 4, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 4, 8, 16
    

    合計は71で、これはわずか4分の1です。したがって、作業全体の過程で、作業効率の良いアルゴリズムを使用すると、アクティブワープの数がはるかに少なくなることがわかります。(実際、中央で長時間実行する場合、アクティブワープはほんのわずかです。つまり、チップの大部分は占有されていません。たとえば、他のCUDAストリームから追加の計算タスクが実行されている場合、空きスペース。)

とはいえ、GPU Gemsの記事ではこれについて明確に説明しておらず、その代わりに、完全に無関係ではないものの、このアルゴリズムがなぜなのかについて多くの詳細を見逃しているbig-Oの「追加数」分析に焦点を当てているのは残念ですもっと早く。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.