OpenCLでは、barrier()
関数を使用してワークグループ内のスレッドを同期できることを理解しています。私は(一般的に)それらが何のためにあるのか、そしてそれらをいつ使うのかを理解しています。また、ワークグループ内のすべてのスレッドがバリアに到達する必要があることを認識しています。そうしないと問題が発生します。ただし、これまでバリアを使用しようとするたびに、ビデオドライバーがクラッシュするか、何らかの無効なメモリへのアクセスに関するエラーメッセージが表示されるようです。これは、これまで2種類のビデオカード(1 ATI、1 NVIDIA)で見ました。
だから、私の質問は:
barrier(CLK_LOCAL_MEM_FENCE)
とbarrier(CLK_GLOBAL_MEM_FENCE)
の違いは何ですか?ドキュメントを読みましたが、はっきりしませんでした。barrier(CLK_LOCAL_MEM_FENCE)
対barrier(CLK_GLOBAL_MEM_FENCE)
をいつ使用するかについての一般的なルールはありますか?barrier()
を間違ったパラメータータイプで呼び出すとエラーが発生する可能性がありますか?既に述べたように、バリアはスレッドを同期するだけです同じワークグループ内。カーネル内の異なるワークグループを同期する方法はありません。
今、あなたの質問に答えるために、仕様も私には明確ではありませんでしたが、セクション6.11.9には答えが含まれているように思われます:
CLK_LOCAL_MEM_FENCE –バリア機能は、ローカルメモリに格納されている変数をフラッシュするか、メモリフェンスをキューに入れて、ローカルメモリへのメモリ操作の正しい順序を確保します。
CLK_GLOBAL_MEM_FENCE –バリア機能はメモリフェンスをキューに入れ、グローバルメモリへのメモリ操作の正しい順序を確保します。これは、作業項目、たとえば、バッファまたはイメージメモリオブジェクトに書き込み、更新されたデータを読み取る場合に役立ちます。
したがって、私の理解では、__local
メモリ空間への書き込みと読み取りにはCLK_LOCAL_MEM_FENCEを使用し、__global
メモリ空間への書き込みと読み取りにはCLK_GLOBAL_MEM_FENCEを使用する必要があります。
これが遅いかどうかはテストしていませんが、ほとんどの場合、バリアが必要で、どのメモリスペースが影響を受けるか疑問がある場合は、単純に次の2つの組み合わせを使用します。
barrier(CLK_LOCAL_MEM_FENCE | CLK_GLOBAL_MEM_FENCE);
この方法では、メモリの読み取り/書き込みの順序の問題は発生しません(グループ内のすべてのスレッドがバリアを通過することは確かですが、それは認識しています)。
それが役に立てば幸い。
ここで古いスレッドを復活させます。私自身、barrier()で少し苦労しました。
クラッシュの問題に関して、考えられる原因の1つは、バリアが条件内にある場合です。バリアを使用すると、グループ内のすべてのワークアイテムがその命令に到達できる必要があります。そうしないと、カーネルがハングし、通常はクラッシュします。
if(someCondition){
//do stuff
barrier(CLK_LOCAL_MEM_FENCE);
//more stuff
}else{
//other stuff
}
私の理解では、1つまたは複数の作業項目がsomeConditionを満たしている場合、すべての作業項目がその条件を満たす必要があります。そうでない場合、バリアをスキップするものがあります。バリアは、すべてのワークアイテムがそのポイントに達するまで待機します。上記のコードを修正するには、少し再構築する必要があります。
if(someCondition){
//do stuff
}
barrier(CLK_LOCAL_MEM_FENCE);
if(someCondition){
//more stuff
}else{
//other stuff
}
これで、すべての作業項目が障壁に到達します。
これがループにどの程度当てはまるかわかりません。ワークアイテムがforループから外れた場合、障壁にぶつかりますか?よくわかりません。
更新:forループに障壁があるいくつかのoclプログラムを正常にクラッシュさせました。すべての作業項目がforループを同時に終了することを確認します-または、さらに良いことに、バリアをループの外側に置きます。
(ソース:OpenCLを使用したヘテロジニアスコンピューティング、第5章、p90-91)