私は最近、NVCCがさまざまなコンピューティングアーキテクチャ用にCUDAデバイスコードをコンパイルする方法について頭を抱えています。
私の理解から、NVCCの-gencodeオプションを使用する場合、「Arch」は、プログラマーのアプリケーションに必要な最小の計算アーキテクチャであり、NVCCのJITコンパイラーがPTXコードをコンパイルするための最小のデバイス計算アーキテクチャでもあります。
また、-gencodeの「コード」パラメーターは、NVCCがアプリケーションを完全にコンパイルするための計算アーキテクチャーであるため、JITコンパイルは必要ありません。
さまざまなCUDAプロジェクトのMakefileを調べたところ、次のことが定期的に発生していることに気付きました。
-gencode Arch=compute_20,code=sm_20
-gencode Arch=compute_20,code=sm_21
-gencode Arch=compute_21,code=sm_21
いくつか読んだ後、複数のデバイスアーキテクチャを1つのバイナリファイル(この場合はsm_20、sm_21)にコンパイルできることがわかりました。
私の質問は、なぜ多くのArchとコードのペアが必要なのですか?上記の「Arch」の値はすべて使用されていますか?
それと言うことの違いは何ですか:
-Arch compute_20
-code sm_20
-code sm_21
「Arch」フィールドの最初の仮想アーキテクチャは自動的に選択されますか、それとも他のあいまいな動作がありますか?
他に知っておくべきコンパイルおよびランタイムの動作はありますか?
マニュアル http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#gpu-compilation を読みましたが、それでもまだわかりませんコンパイル時または実行時に発生します。
大まかに言えば、コードのコンパイルフローは次のようになります。
CUDA C/C++デバイスコードソース-> PTX-> SASS
仮想アーキテクチャー(例:compute_20
、-Arch compute...
で指定されているもの)によって、生成されるPTXコードのタイプが決まります。追加のスイッチ(例:-code sm_21
)は、生成されるSASSコードのタイプを決定します。 SASSは、実際にはGPU(マシン言語)の実行可能なオブジェクトコードです。実行可能ファイルには、SASSやPTXの複数のバージョンを含めることができ、実際に使用されているGPUに基づいて適切なバージョンを選択するランタイムローダーメカニズムがあります。
ご指摘のとおり、GPUオペレーションの便利な機能の1つはJITコンパイルです。 JITコンパイルは、適切なPTXコードが利用可能で適切なSASSコードが利用可能でない場合はいつでも、GPUドライバーによって行われます(CUDAツールキットをインストールする必要はありません)。
複数の仮想アーキテクチャー(つまり、PTXの複数のバージョン)を含めることの1つの利点は、さまざまなターゲットGPUデバイスとの実行可能互換性があることです(ただし、一部のデバイスは必要なSASSを作成するためにJITコンパイルをトリガーする場合があります)。
複数の「実際のGPUターゲット」(つまり、複数のSASSバージョン)を含めることの利点の1つは、これらのターゲットデバイスの1つが存在する場合にJITコンパイル手順を回避できることです。
不適切なオプションセットを指定すると、特定のGPUで(正しく)実行されない実行可能ファイルを作成することができます。
これらのオプションの多くを指定することの1つの考えられる欠点は、コードサイズの膨張です。考えられるもう1つの欠点はコンパイル時間です。コンパイル時間は、オプションを指定するほど長くなります。
PTXを含まない実行可能ファイルを作成することもできます。これは、IPを隠そうとしている人にとって興味深いかもしれません。
JITに適したPTXを作成するには、code
スイッチに対して 仮想アーキテクチャを指定 を実行する必要があります。
複数の-Arch
フラグの目的は、さまざまに最適化されたコードパスの条件付きコンパイル(つまり__CUDA_Arch__
を使用)に#ifdef
マクロを使用することです。
ここを参照してください: http://docs.nvidia.com/cuda/cuda-compiler-driver-nvcc/index.html#virtual-architecture-identification-macro