サーチ…


前書き

このトピックでは、OpenCLを完全に理解して利用するために必要な、並列コンピューティングの基本的なコアメカニックスを紹介します。

スレッドと実行

並列性の鍵は、複数のスレッドを使用して問題を解決することですが、スレッドの編成方法に古典的なマルチスレッドプログラミングとはいくつかの違いがあります。

まず、あなたの典型的なGPUについて話しましょう。

GPUには多くの処理コアがあり、多くのスレッドを並列に実行するのに理想的です。これらのコアはストリーミングプロセッサ(SM、NVidiaの用語)で構成され、GPUには特定の番号が付いています。

SM内で実行されるすべてのスレッドは、「スレッドブロック」と呼ばれます。 SMにはコアを持つスレッドよりも多くのスレッドが存在する可能性があります。コアの数は、いわゆる「ワープサイズ」(NVidia用語)を定義します。スレッドブロック内のスレッドはいわゆる「ワープ」でスケジューリングされます。

フォローアップの簡単な例:典型的なNVidia SMには32の処理コアがあり、そのワープサイズは32です。スレッドブロックの実行スレッドが128になると、4つのワーピング(4つのワーピング* 32ワーピングサイズ= 128スレッド)。

後でスレッド数を選択するときは、ワープサイズが重要です。

単一のワープ内のすべてのスレッドは、単一の命令カウンタを共有します。つまり、これらの32個のスレッドは、すべてのスレッドが同時にすべてのコマンドを実行するという点で真に同期しています。ここにはパフォーマンスの落とし穴があります:これはカーネルの分岐文にも当てはまります!

例:私はif文と2つの枝を持つカーネルを持っています。ワープ内のスレッド16本はブランチ1を実行し、他の16本はブランチ2を実行します。 if文までは、ワープ内のすべてのスレッドが同期しています。今では半分が別の支店を選んでいます。間違った文が最初の16個のスレッドで実行を終了するまで、残りの半分は休止状態になります。これらのスレッドは、他の16個のスレッドが分岐を終了するまで休止状態になります。

ご覧のとおり、両方のステートメントが最悪の場合に実行されるため、悪い分岐の習慣は並列コードを著しく遅くする可能性があります。ワープ内のすべてのスレッドがステートメントのうちの1つだけを必要とすると判断した場合、もう1つは完全にスキップされ、遅延は発生しません。

スレッドの同期も簡単なことではありません。あなたは単一 SMをwithingスレッドを同期することができます。 SMの外にあるものは、カーネル内部から同期できません。あなたは別々のカーネルを書いて、それを順番に起動しなければならないでしょう。

GPUメモリ

GPUには6つの異なるメモリ領域があります。それらは、異なるスレッドからの待ち時間、サイズ、アクセス可能性が異なります。

  • グローバルメモリ:利用可能な最大のメモリと、ホストとデータを交換するための数少ないメモリの1つです。このメモリは最もレイテンシが高く、すべてのスレッドで使用できます。
  • Constant Memory:グローバルメモリの読み取り専用部分。他のスレッドだけが読み取ることができます。その利点は、グローバルメモリと比較してレイテンシが低いことです
  • テクスチャメモリ:テクスチャのために特別に設計された定数メモリの一部
  • 共有メモリ:このメモリ領域はSMの近くに配置され、単一のスレッドブロックによってのみアクセスできます。これは、グローバルメモリよりもレイテンシが小さく、定数メモリよりもレイテンシが短い方法を提供します。
  • レジスタ:1つのスレッドだけがアクセス可能で、それらの中で最も高速なメモリです。しかし、コンパイラがカーネルのニーズに十分なレジスタがないことを検出すると、変数をローカルメモリにアウトソースします。
  • ローカルメモリ:グローバルメモリ領域内のメモリのスレッドのみアクセス可能な部分。可能であれば、レジスタのバックアップとして使用しないでください。

メモリアクセス

メモリ使用量の一般的なシナリオは、ソースデータと処理されたデータをグローバルメモリに格納することです。スレッドブロックが開始されると、最初に関連するすべてのパーツが共有メモリにコピーされてから、そのパーツがレジスタに取り込まれます。

メモリアクセスのレイテンシは、メモリ戦略によっても異なります。データに盲目的にアクセスすると、最悪のパフォーマンスが可能になります。

異なる記憶は、いわゆる「銀行」で編成されています。バンクに対する各メモリ要求は、単一クロックサイクルで処理することができます。共用メモリ内のバンクの数は、ワープ・サイズに等しい。単一のワープの中で競合するバンクアクセスを回避することによって、メモリ速度を増加させることができる。

グローバルメモリとの間で共有メモリをコピーするには、メモリコールを「整列」するのが最も速い方法です。つまり、ワープ内の最初のスレッドは、共有メモリとグローバルメモリの両方のバンク内の最初の要素にアクセスする必要があります。 2番目の要素は2番目の要素などです。このコールは、バンク全体をターゲットメモリに一度にコピーする単一のメモリ転送命令に最適化されます。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow