1

次のような新しいケプラーのシャッフル命令を使用して、CUDA で並列削減の実装を使用しています: http://devblogs.nvidia.com/parallelforall/faster-parallel-reductions-kepler/

特定の行列の行の最小値を検索していたところ、カーネルの最後に次のコードがありました。

my_register = min(my_register, __shfl_down(my_register,8,16));
my_register = min(my_register, __shfl_down(my_register,4,16));
my_register = min(my_register, __shfl_down(my_register,2,16));
my_register = min(my_register, __shfl_down(my_register,1,16));

私のブロックは 16*16 であるため、すべてが正常に機能し、そのコードを使用して、まったく同じカーネルの 2 つのサブ行で最小値を取得していました。

ここで、マトリックスのすべての行の最小要素のインデックスも返す必要があるため、「min」を「if」ステートメントに置き換えて、これらのインデックスを同様の方法で処理するつもりでしたが、次のコードで行き詰まりました。

if (my_reg > __shfl_down(my_reg,8,16)){my_reg = __shfl_down(my_reg,8,16);};
if (my_reg > __shfl_down(my_reg,4,16)){my_reg = __shfl_down(my_reg,4,16);};
if (my_reg > __shfl_down(my_reg,2,16)){my_reg = __shfl_down(my_reg,2,16);};
if (my_reg > __shfl_down(my_reg,1,16)){my_reg = __shfl_down(my_reg,1,16);};

cudaErrors はまったくありませんが、カーネルは現在ゴミを返します。それにもかかわらず、私はそれを修正しました:

myreg_tmp = __shfl_down(myreg,8,16);
if (myreg > myreg_tmp){myreg = myreg_tmp;};
myreg_tmp = __shfl_down(myreg,4,16);
if (myreg > myreg_tmp){myreg = myreg_tmp;};
myreg_tmp = __shfl_down(myreg,2,16);
if (myreg > myreg_tmp){myreg = myreg_tmp;};
myreg_tmp = __shfl_down(myreg,1,16);
if (myreg > myreg_tmp){myreg = myreg_tmp;};

したがって、新しい tmp 変数を割り当てて隣接するレジスタに忍び込ませると、すべてが節約されます。ここで質問です: ケプラー シャッフル命令は破壊的ですか? 同じ命令を 2 回呼び出しても同じ結果は得られないという意味で。「my_reg > __shfl_down(my_reg,8,16)」と言ってこれらのレジスタに何も割り当てていません - これは私の混乱を招きます。シャッフルを2回呼び出すことの問題は何ですか?私はCUDAの初心者なので、ダミーの詳細な説明を歓迎します

4

1 に答える 1

5

ワープシャッフルは破壊的ではありません。まったく同じ条件で操作を繰り返すと、毎回同じ結果が返されます。var値 (例ではmyreg) は、ワープ シャッフル関数自体によって変更されません。

発生している問題は__shfl_down() 、最初のメソッドでの の 2 回目の呼び出しに参加するスレッドの数が、どちらのメソッドでも他の呼び出しと異なるという事実によるものです。

まず、ドキュメントの重要なポイントを思い出してください。

スレッドは、__shfl() コマンドに積極的に参加している別のスレッドからのみデータを読み取ることができます。ターゲット スレッドが非アクティブの場合、取得される値は未定義です。

それでは、最初の「壊れた」メソッドを見てみましょう。

if (my_reg > __shfl_down(my_reg,8,16)){my_reg = __shfl_down(my_reg,8,16);};

__shfl_down()上記を (if 句内で)初めて呼び出すと、すべてのスレッドが参加します。したがって、によって返されるすべての値は、__shfl_down()期待どおりになります。ただし、if 句が完了すると、if 句を満たしたスレッドのみが if ステートメントの本体に参加します。__shfl_down()したがって、 if ステートメント本体内での の 2 回目の呼び出しでは、そのmy_reg値がmy_regその上のスレッド 8 レーンの値が参加します。これは、他のスレッドが参加していない可能性があるため、これらの割り当てステートメントの一部が期待する値を返さない可能性があることを意味します。(上記の 8 レーンのスレッドの参加は、そのスレッドによって行われた if 比較の結果に依存します。これは真である場合とそうでない場合があります。)

あなたが提案する2番目の方法にはそのような問題はなく、あなたの声明に従って正しく機能します。すべてのスレッドが の各呼び出しに参加します__shfl_down()

于 2014-03-10T15:38:14.560 に答える