2011-07-19 20 views
4
私はこの__syncthreadsを行う方法

CUDAの__syncthreads()と再帰

__device__ void foo(int k) { 
    if (some_condition) { 
    for (int i=0;i<8;i++) { 
     foo(i+k); // foo might take longer with some inputs 
     __syncthreads(); 
    } 
    } 
} 

のような再帰に__syncthreads()を使用したい

()今適用されますか?私はそれがブロック内でのみ適用されることを知っています。私が理解している限り、これは再帰の深さとは関係なくすべてのローカルスレッドに適用されます。しかし、もしこれを__syncthreads()が特定の再帰深度に確実にしたいのであれば?それも可能ですか?私は再帰の深さを確認することができますが、どちらもうまくいかないと私は信じています。

代替手段がありますか?

私はCUDAデバイス> = 2.0

int __syncthreads_count(int predicate); 
int __syncthreads_and(int predicate); 
int __syncthreads_or(int predicate); 

のための3つのsyncthread拡張があることを見てきました。しかし、私は、彼らは、原子カウンターのように見えるので、彼らは役立つとは思いません。

+0

自分自身のようなことは一度もしていませんが、認識しているかどうかを確認するために、コードに入れるsome_conditionは同じブロック内のすべてのスレッドについて同じものを評価する必要があります。それはデッドロックします。 – jmsu

+0

はい、それも私が恐れているものです。 – Pascal

+0

質問を明確にできますか?私はあなたがここで何を求めているのか本当に理解していない。 – Tom

答えて

7

ご存知のように、__syncthreads()は、ブロック内のすべてのスレッドがバリアに到達する場合にのみ安全です。つまり、条件内から__syncthreads()を呼び出す場合、条件はブロック内のすべてのスレッドで同じに評価されなければなりません。

再帰内で__syncthreads()の場合、ブロック内のすべてのスレッドが同じ深さまで再帰を実行する必要があります。そうでない場合、すべてのスレッドが同じバリアに到達するわけではありません。

+0

あなたの推論は理にかなっていますが、再帰にはフェルミGPUが必要なので、再帰深度ではコード内の場所で問題はありません。おそらく、スタックの深さを見ることができますが、なぜ、これは(デッドロックのような)潜在的な問題のトンを導入するでしょう。私はこれに関するさらに詳しい情報を見つけようとしていました。これはどこかで定義されていますか?この簡単で最も可能性のあるソリューションは次のとおりです。**再帰では使用しないでください** – Pascal

+4

私はもっと強く言います:CUDAで再帰を使わないでください。すべてのスレッドが独自のスタックを維持しなければならないため、再帰をイテレーションで置き換えることができない場合には不要な余分なオフチップメモリ​​アクセスが発生します。できない場合は、共有メモリー内のより単純なスタックを維持できます。または、共有メモリまたはレジスタ内のスタックの上位レベルを維持し、オフチップアクセスの総量を減らすことができます(一般にGPUレイトレースで使用されます)。 syncthreads()に関しては、発散しないコード、再帰などで使用することは安全です。 – harrism

+0

これを明確にしていただきありがとうございます。私はcudaスタックがおそらくより効率的であると思った。これまでに私はcudaにあまり触れていなかったので、これを表現する最も簡単な方法でした。とにかく(再帰的でスタックレスな)上記のコードを書き直していますが、再帰の__syncthreadsの動作には本当に関心があります。私は__syncthreads()を有効にしてこのコードを実行していたため、うまくいきませんでした。 – Pascal

2

代替手段はありますか?

はい、)(あなたが__syncthreadsについて言ったオフコース

0

あなたの機能ロジックを表現するために再帰パラダイムを使用していない事実であるブロック内のローカルのスレッドがゆえ、あなたが制御できないため、それだけで動作します他のブロックで何が起こっているか。削減のための最善の方法は、最初にブロック全体の大きさに等しい配列全体の縮小を行います。次に、配列をホストにコピーしないで、前の呼び出しのブロック数と同様の1ブロックとスレッドを持ち、後でサイズ1の配列をDeviceからHostにコピーする別の縮小を呼び出しません。最初の削減が生成されない限り、2回のコールcozの間でcudaThreadSynchronize()を必ず使用してください。これは2段階の削減ですが、それは私のために働く。

乾杯! saif