2017-01-24 8 views
2

グローバルワークサイズとローカルワークサイズに関する多くの定義を読んだ後も、それらの動作と動作を理解できていません。 グローバルワークサイズは、カーネル関数の呼び出し回数を決定すると思いますが、ローカルワークサイズは何ですか?ローカルとグローバルサイズがプログラム実行に及ぼす影響 - OpenCl

私は現地の仕事の大きさによって、同じ時間に並行して使用されるスレッドの数が決まると思っていましたが、本当に正しいですか?

ローカルサイズは、1つのグローバルサイズ値ごとに1つのカーネルプログラムを実行するスレッドの数ですか。つまり、グローバルサイズ= 1、ローカルサイズ= 1の場合、カーネル関数は1回だけ呼び出され、1つのスレッドのみが処理されます。 グローバルサイズ= 4096、ローカルサイズ(それが許される場合)が1024の場合、カーネル関数は4096回コールされ、同時に各スレッドは1024スレッドを同時に処理します。私は正しいですか?ここで

は、私が見つけたいくつかのサンプルコードです: enter image description here

と私のもう一つの質問は:地元のサイズ変更がそのコードをどのように影響しますか? global_idの作業がはっきりしているので、ローカルのサイズ変更は、そのアルゴリズムを実行するのに費やされる時間に1が影響すると言うよりも大きなサイズにローカルサイズが変更されていませんか?

私たちがそのアルゴリズムでループを持つとき、ローカルサイズの影響について何か変わっているのでしょうか?ローカルサイズを変更するときにlocal_idを使用する必要がありますか?

自分のプログラムのほんの少しで、global_idのローカルワークサイズを変更しても、実行時間が大幅に短縮されたことがわかりました。 それでどうですか?理解できません。

ありがとうございます!

答えて

2

私はローカルワークサイズによって、同時に並列に使用される のスレッド数が決まると思いましたが、本当に正しいですか?

正解ですが、コンピューティングユニットごとであり、デバイス全体ではありません。ローカルスレッドグループよりも計算単位が多い場合、デバイスは完全には使用されません。正確な倍数ではなく、計算ユニットより多くのスレッドグループがある場合、計算ユニットの中には、最後に他の計算ユニットを待つものがあります。両方の値が等しい(または正確に複数の)場合、「何回」がすべてのALUSを完全に占有することが重要です。

たとえば、8コアのCPUは8つの計算単位を定義できます(ハードウェアマルチスレッドの場合は+ 8以上)。しかし、同様の価格を持つGPUには、20から64までのコンピューティングユニットがあります。単一のコンピューティングユニット内であっても、スレッドの多くのグループは明示的にチューニングされず、スレッドごとおよび計算単位ごと、そしておそらくGPUごとにリソース使用量によって変更される「飛行中」になる可能性があります。

どのようにローカルサイズの変更がそのコードに影響しますか?私は明らかに グローバルIDで作業しているので、ローカルのサイズは より大きいものにローカルな変更はありませんより1つは、その アルゴリズムの実行に費やした時間に影響を与えると言いますか?

ベクトル化可能/並列化可能なカーネルコードは、ALU、gpu計算ユニットのコアまたはより広いSIMDのSIMDにスレッドを配布する利点があります。 CPUの場合、同時に8つのスカラ命令を発行することができます。 GPUの場合、それは何千もの大きさになる可能性があります。したがって、ローカルサイズを1に減らすと、並列スレッドのスレッド幅が1 ALUに制限され、多くのアーキテクチャでパフォーマンスが低下します。ローカルサイズを大きくしすぎると、スレッドごとのリソースが低下し、パフォーマンスが低下します。もしあなたが何も考えていなければ、opencl apiはそのパラメータにヌルを与えればあなたのローカルサイズを調整することができます。

そして、そのアルゴリズムでループを使用するときは、ローカルサイズの影響については を変更していますか?ローカルサイズを変更するときに相違点を確認するには、 local_idを使用する必要がありますか?

古いスケジューリングアーキテクチャと静的スケジューリングアーキテクチャでは、ループアンローリングには、基本SIMD幅の幅に等しいアンロールステップサイズが必要です。いいえ、ローカルIDは計算ユニット内のスレッドIDの単なるクエリなので、必要ない場合はクエリする必要はありません。

は、私は私のプログラムのいくつかにそれをテストし、私は地元の仕事の大きさを変えるだけ global_id年代を使用した場合であっても、私に大幅に短縮 実行する時間を与えました。それでどうやって動くの?

カーネルに無駄なリソースが必要な場合は、ローカルグループごとに1つのスレッドを考えることができます。カーネルが即値以外のリソースを必要としない場合は、ローカル値を最大にする必要があります。スレッドごとのリソース割り当て(カーネルコードのため)が重要です。新しいアーキテクチャにはロードバランシングがあるので、将来的にAPIが最適な値を選択するかどうかは重要ではありません。

スケジューラは、すべてのALUをビジー状態に保つために、コアごとに多くのスレッドを発行します。スレッドがメモリ操作を待っているときに、別のスレッドがALU操作を同時に行うことができます。これは、リソースの使用量が少ない場合に適しています。計算ユニットのすべてのリソースの%50を使用すると、飛行中のスレッドは2つしかない可能性があります。スレッドは、L1キャッシュ、ローカルメモリ、レジスタファイルなどの共有可能なリソースを共有します。

スカラー浮動小数点のためのc [i] = a [i] + b [i]などのコードはベクトル化可能です。コンパイラがバックグラウンドでそれをやっていない場合は、float8、float16などの構造体を使ってパフォーマンスを向上させることができます。これにより、すべての作業を達成するために必要なスレッドが少なくて済み、メモリへのアクセスも高速になります。また、カーネルにループを追加してスレッド数をさらに減らすこともできます。これは、2つのデータブロックの間にスレッドディスパッチが少なくて済むため、CPUに適しています。 GPUでは問題ではないかもしれません。


トリビアル例えばCPU用:

4コア、ローカルサイズ= 10、グローバルサイズ= 100

コア1及び2は、3つのスレッドグループそれぞれを有しています。コア3とコア4にはスレッドグループが2つしかありません。

  • 1:30スレッド - >完全パフォーマンス
  • 2:30スレッド
  • 3:20スレッド - >以下パフォーマンス、他のジョブのためのより良いプリエンプション
  • 4:20スレッド

命令パイプライニングではコア1とコア2のバブルはあまりありませんが、コア3とコア4ではしばらくしてからバブルが開始されるため、並列またはオペレーティングシステムまたは一部のアレイで実行されている2番目のカーネルコピー。 120スレッドのようにすべてのコアを等しく使用すると、1秒あたりの処理量は増えますが、すでにカーネルがメモリを使用している場合、CPUは配列コピーを実行できません。(OSが他のスレッドに優先しない限り)

関連する問題