PGI アクセラレータ、CUDA Fortran
「アクセラレータ」とは、特別の目的で CPU にアタッチして使用する協調プロセッサであり、時間の掛かる計算部分を CPU の演算機構からデータと実行部分のカーネルをオフロードするために使用されます。ここでは、 GPUをアクセラレータとして使用する際のPGI アクセラレータ™ コンパイラのオプションについて説明します。また、PGI 12.6 からディレクティブベースの標準プログラミングモデルである OpenACC 1.0 に準拠し、現バージョンでは OpenACC 2.6 を包括的にサポートしております。OpenACC を使用するためのオプションも説明します。なお、OpenACC プログラミング・ガイドは、こちらにあります。PGI 19.3 用更新 2019/3/28Copyright © 株式会社ソフテック
PGI の Fortran, C, C++ のコンパイラを使用して、PGI OpenACC 用ディレクティブを認識するためのオプションの例を示します。以下は、pgfortran(pgf95、あるいは、pgf90 も同じコンパイラです)を使用した場合の例ですが、C/C++ 言語用の pgcc/pgc++(pgcpp for Windows) コンパイラのオプションの設定方法も、同様です。なお、コマンドライン上でリンク時にも、必ず、コンパイル時に指定したものと同じ -acc 並びに-ta オプションを指定することが必要です。なお、この -ta=tesla オプションは、従来の PGI Accelerator Programming model 用のディレクティブ(OpenACC の前身)も認識します。但し、今後は、OpenACC を利用されることを推奨します。ここでは、OpenACC 用のコンパイル・オプションを説明します。なお、PGIコンパイラでは、両方のディレクティブ形式を認識しますが、注意すべきことは、一つのアクセラレータ領域の中で、PGI Accelerator 用ディレクティブと OpenACC 用のディレクティブの両方を使用することは許されません。どちらかの形式に統一して使用するようにして下さい。
PGI 12.6以降、OpenACC 専用のコンパイル・リンク用オプションとして -acc が提供されました。これは、OpenACCディレクティブの認識を行います。さらに、これに加え、target accelerator の特性を指定するために、-ta オプションを指定することもできます。なお、PGI 14.1 以降、-ta オプションのサブオプションが一部変更となっておりますので、ご注意ください。
PGI 15.1 以降、64-bitコンパイラのアクセラレータ用デバイスコードの生成プログラムが、デフォルトで nvvm を使用するように変更されました。今まで使用していた古い CUDA-C コード生成ソフトウェアを使用したい場合、あるいはデフォルトの llvm によるexecutable の実行に問題がある場合は、
-ta=tesla:nollvm あるいは -Mcuda=nollvm オプションを指定してください。
PGI 17.1 以降、Pascal(CC 6.0) GPU 用と過去の CC 2.0 用の executable はデフォルトで生成されません。これらの GPU 用の executable の生成には、-ta=tesla,cc60 or -ta=tesla,cc20 を付けてコンパイル、リンクしてください。
PGI 17.7 以降、Pascal(CC 6.0), Volta(CC 7.0) GPU 用と過去の CC 2.0 用の executable はデフォルトで生成されません。これらの GPU 用の executable の生成には、-ta=tesla,cc60,cuda9.0 or -ta=tesla,cc70,cuda9.0 or -ta=tesla,cc20 を付けてコンパイル、リンクしてください。Volta GPU をターゲットにする場合は、必ず CUDA 9 toolkit(-ta=tesla,cuda9.0)以上を使用する必要があります。
PGI 18.7 以降、CC 2.0 用の executable は生成されません。CC3.0~7.0用のコードを生成できます。
● Fortranコンパイルの一例 pgfortran -fast -Minfo -acc test.f -acc の他に、-ta=tesla のサブオプションを付加することも可能 pgfortran -fast -Minfo=accel -acc -ta=tesla,cuda10.0,cc70 test.f90 (cc70用 executable) ● C コンパイルの一例 pgcc -fast -Minfo -acc test.c -acc の他に、-ta=tesla のサブオプションを付加することも可能 pgcc -fast -Minfo=accel -acc -ta=tesla,keep test.c なお、PGI 13.10 以前は、-ta=tesla の代わりに -ta=nvidia が有効です。
-acc=[no]autopar は、OpenACC parallel 構文内の自動並列化を行う[行わない]を指定します。(PGI 13.6以降)
-acc=[no]required はアクセラレータ・コードを生成出来なかった場合、コンパイルエラーとする(default) (PGI 14.1 以降、但し、PGI 15.1 で廃止)
-acc=strict は、non-OpenACC accelerator ディレクティブが見つかった場合、warning を出します。
-acc=verystrict は、non-OpenACC accelerator ディレクティブが見つかった場合、エラーメッセージを出し、コンパイルを終了します。
-acc=sync は、async cluase を無視します。
-acc=[no]wait は各デバイス kernel の終了を待つか待たないかを指示します。
-ta=tesla(,tesla_suboptions) : NVIDIA 社の GPU ボード対応の OpenACC コンパイルを行います。従来の -ta="nvidia" の "nvidia"名 は廃止されました。
-ta=multicore : ホスト上のマルチコアCPU上で並列動作するように OpenACC プログラムをコンパイルします。(PGI 15.10 以降) 実行に使用する CPU コア数は、ACC_NUM_CORES 環境変数に値をセットする。
(PGI 13.10 以前の指定方法) -ta=nvidia(,nvidia_suboptions) : PGI アクセラレータディレクティブあるいは、OpenACC ディレクティブを認識するオプションです。-ta は、ターゲット・アーキテクチャを意味します。PGI 13.10 までは、「nvidia」 のみとなります。Fortran における !$acc ディレクティブ、C における #pragma acc ディレクティブをコンパイラに認識させ、ターゲットへの細かなオプションを使用するために、以下のサブオプションを使用できます。
サブオプション | NVIDIA -ta=tesla(nvidia) のサブオプション |
---|---|
analysis | ループの解析のみ行い、コードの生成を行いません。)(PGI 13.10以降廃止) |
cc10 | compute capability 1.0 のコードを生成 (PGI 14.1以降廃止) |
cc11 | compute capability 1.1 のコードを生成 (PGI 14.1以降廃止) |
cc12 | compute capability 1.2 のコードを生成 (PGI 14.1以降廃止) |
cc13 | compute capability 1.3 のコードを生成 (PGI 14.1以降廃止) |
cc1x | compute capability 1.x のコードを生成(PGI 15.1以降廃止) |
cc1+ | compute capability 1.x, 2.x, 3.x のコードを生成 (PGI 14.1以降)、(PGI 15.1以降廃止) |
tesla | cc1x と同じ(PGI 13.1以降)、(PGI 15.1以降廃止) |
tesla+ | cc1+ と同じ (PGI 14.1以降)、(PGI 15.1以降廃止) |
cc20 | compute capability 2.0 のコードを生成 (PGI 10.4以降) (PGI 14.1以降廃止) (PGI 15.5以降復活) |
cc2x | compute capability 2.x のコードを生成 (PGI 10.4以降) |
cc2+ | compute capability 2.x, 3.x のコードを生成 (PGI 14.1以降) |
fermi | cc2xと同じ (PGI 13.1以降) |
felmi+ | cc2+と同じ (PGI 14.1以降) |
cc30 | compute capability 3.0 のコードを生成 (PGI 12.8以降) (PGI 14.1以降廃止) (PGI 15.5以降復活) |
cc35 | compute capability 3.5 のコードを生成 (PGI 13.1以降) (PGI 14.1以降廃止) (PGI 15.5以降復活) |
cc3x | compute capability 3.x のコードを生成 (PGI 12.8以降) |
cc3+ | compute capability 3.x (=cc3x) 以上のコードを生成 (PGI 14.1以降) |
kepler | cc3xと同じ (PGI 13.1以降) |
kepler+ | cc3+と同じ (PGI 14.1以降) |
cc50 | compute capability 5.0 (=cc50) (PGI 15.7以降) |
cc60 | compute capability 6.0 (=cc60) (PGI 16.9以降) |
cc70 | compute capability 7.0 (=cc70) (PGI 17.7以降) |
cc75 | compute capability 7.5 (=cc75) (PGI 18.10以降) |
ccall | 当該プラットフォームと、選択されたまたはデフォルトのCUDAツールキットによってサポートされているすべてのCCのためのコードを生成 |
charstring | GPUカーネル内で文字列の使用を制限付きで使用する(PGI 15.1以降) |
cuda2.3 or 2.3 | PGIにバンドルされた CUDA toolkit 2.3 バージョンを使用 (PGI 10.4以降) |
cuda3.0 or 3.0 | PGIにバンドルされた CUDA toolkit 3.0 バージョンを使用 (PGI 10.4以降) |
cuda3.1 or 3.1 | PGIにバンドルされた CUDA toolkit 3.1 バージョンを使用 (PGI 10.8以降) |
cuda3.2 or 3.2 | PGIにバンドルされた CUDA toolkit 3.2 バージョンを使用 (PGI 11.0以降) |
cuda4.0 or 4.0 | PGIにバンドルされた CUDA toolkit 4.0 バージョンを使用 (PGI 11.6以降) |
cuda4.1 or 4.1 | PGIにバンドルされた CUDA toolkit 4.1 バージョンを使用 (PGI 12.2以降) |
cuda4.2 or 4.2 | PGIにバンドルされた CUDA toolkit 4.2 バージョンを使用 (PGI 12.6以降) |
cuda5.0 or 5.0 | PGIにバンドルされた CUDA toolkit 5.0 バージョンを使用 (PGI 13.1以降) |
cuda5.5 or 5.5 | PGIにバンドルされた CUDA toolkit 5.5 バージョンを使用 (PGI 13.9以降) |
cuda6.0 or 6.0 | PGIにバンドルされた CUDA toolkit 6.0 バージョンを使用 (PGI 14.4以降) |
cuda6.5 or 6.5 | PGIにバンドルされた CUDA toolkit 6.5 バージョンを使用 (PGI 14.9以降) |
cuda7.0 or 7.0 | PGIにバンドルされた CUDA toolkit 7.0 バージョンを使用 (PGI 15.4以降) |
cuda7.5 or 7.5 | PGIにバンドルされた CUDA toolkit 7.5 バージョンを使用 (PGI 15.9以降) |
cuda8.0 or 8.0 | PGIにバンドルされた CUDA toolkit 8.0 バージョンを使用 (PGI 16.10以降) |
cuda9.0 or 9.0 | PGIにバンドルされた CUDA toolkit 9.0 バージョンを使用 (PGI 17.9以降) |
cuda9.1 or 9.1 | PGIにバンドルされた CUDA toolkit 9.1 バージョンを使用 (PGI 18.1以降) |
cuda9.2 or 9.2 | PGIにバンドルされた CUDA toolkit 9.2 バージョンを使用 (PGI 18.5以降) |
cuda10.0 or 10.0 | PGIにバンドルされた CUDA toolkit 10.0 バージョンを使用 (PGI 18.10以降) |
cuda10.1 or 10.1 | PGIにバンドルされた CUDA toolkit 10.1 バージョンを使用 (PGI 19.3以降) |
[no]debug | デバイスコード内にデバッグ情報を生成する[しない] (PGI 14.1 以降) |
deepcopy | OpenACC Fortran における派生型変数の full deep copyを有効にする(PGI 17.7以降) |
fastmath | fast mathライブラリを使用 |
[no]flushz | GPU上の浮動小数点演算の flush-to-zero モードを制御。デフォルトはnoflushz。 (PGI 11.5以降) |
[no]fma | fused-multiply-add命令を生成する[しない](-O3ではデフォルト) |
keep | kernelバイナリファイル(.bin)、kernelソースファイル(.gpu)、portable assembly(.ptx)ファイルを保持し、各々ファイルとして出力する。-ta=tesla,nollvmと共に使用する (PGI 13.10以降) |
keepbin | kernelバイナリファイルを保持し、ファイル(.bin)として出力する)(PGI 13.10以降廃止) |
keepgpu | kernelソースファイルを保持し、ファイル(.gpu)として出力する (PGI 13.10以降廃止) |
keepptx | GPUコードのためのportable assembly(.ptx)ファイルを保持し、ファイルとして出力する)(PGI 13.10以降廃止) |
[no]lineinfo | GPU line informationを生成する(PGI 15.1以降) |
[no]llvm | llvmベースのバックエンドを使用してコードを生成する。(PGI 15.1以降) 64-bit上ではLLVMバックエンドを使う [使わない]。なお、PGI 15.1 以降はデフォルト llvm を使うように変更された。リンク時にエラーが生じる場合、nollvm を試すことをお勧めする。 |
managed | OpenACCの 割り当て可能なデータが CUDA Unified Memory に配置されている場合、明示的なデータ移動またはデータ指示を必要としない機能を有効にする。(PGI 17.7以降) |
maxregcount:n | GPU上で使用するレジスタの最大数を指定。ブランクの場合は、制約が無いと解釈する |
mul24 | 添字計算に、24ビット乗算を使用 (GT200系、CC 1.3のみ)(PGI 13.10以降廃止) | noL1 | グローバル変数をキャッシュするためのハードウェア L1 データキャッシュの使用を抑止する (PGI 13.10以降) |
loadcache:L1 loadcache:L2 |
グローバル変数をキャッシュするためにハードウェア L1 あるいは L2データキャッシュを使用する。但し、アーキテクチャ上、有効とならないGPUがある (PGI 14.4以降) |
pin | デフォルトを pin ホストメモリ(割付)としてセットする(PGI 14.1~PGI 15.10) |
pinned | デフォルトを pin ホストメモリ(割付)としてセットする。プログラムのアロケート時に pinned メモリを割り付けるように変更した。(PGI 16.1以降) |
time | アクセラレータ領域の単純な時間情報を集積するためにプロファイル・ライブラリをリンクする。このオプションは、PGI 13.1 以降廃止されました。この代わりに、プロファイルを環境変数 PGI_ACC_TIME に 1 をセットすることにより実行後プロファイル情報が出力されます。 |
[no]required | アクセラレータ・コードを生成出来なかった場合、コンパイルエラーとする[しない] (default)(PGI 15.1 以降廃止) |
[no]rdc | 異なるファイルに配置されたデバイスルーチンをそれぞれ分割コンパイルし、リンクが出来るようにする。cc2x以降、CUDA 5.0 以降の機能を使用する。(PGI 13.1以降 + CUDA 5.0 以降) (PGI 14.1 は以降デフォルト) |
[no]unroll | 自動的に最内側ループのアンローリングを行う (default at -O3)(PGI 14.9以降) |
managed | CUDA managed Memory を使用する |
beta | ベータ版機能のコード生成(生成コード内の 128-bit ロード・ストアオペレーションを有効化)(PGI 15.7以降) |
[no]wait | ホスト側での実行継続を行う際に、各カーネルが終了するまで待つ。nowaitは待たない。)(PGI 13.10以降廃止) |
safecache | cache directive 内での可変長の配列セクションの使用を許す。但し、そのサイズは CUDA shared memory 内に収まるものでなければならない。(PGI 16.5以降) |
zeroinit | 割付されるデバイスメモリの値をゼロに初期化する(PGI 18.1以降) |
$ pgaccelinfo
CUDA Driver Version 10010
(以下省略)
ここで、
2.3 driverの場合: CUDA Driver Version 2030
3.0 driverの場合: CUDA Driver Version 3000 (PGI 10.4以降)
3.1 driverの場合: CUDA Driver Version 3010 (PGI 10.8以降)
3.2 driverの場合: CUDA Driver Version 3020 (PGI 11.0以降)
4.0 driverの場合: CUDA Driver Version 4000 (PGI 11.6以降)
4.1 driverの場合: CUDA Driver Version 4010 (PGI 12.2以降)
4.2 driverの場合: CUDA Driver Version 4020 (PGI 12.6以降)
5.0 driverの場合: CUDA Driver Version 5000 (PGI 13.1以降)
5.5 driverの場合: CUDA Driver Version 5050 (PGI 13.9以降
6.0 driverの場合: CUDA Driver Version 6000 (PGI 14.4以降
6.5 driverの場合: CUDA Driver Version 6050 (PGI 14.9以降)
7.0 driverの場合: CUDA Driver Version 7000 (PGI 15.4以降)
7.5 driverの場合: CUDA Driver Version 7050 (PGI 15.9以降)
8.0 driverの場合: CUDA Driver Version 8000 (PGI 16.10以降)
9.0 driverの場合: CUDA Driver Version 9000 (PGI 17.9以降)
9.1 driverの場合: CUDA Driver Version 9010 (PGI 18.1以降)
9.2 driverの場合: CUDA Driver Version 9020 (PGI 18.5以降)
10.0 driverの場合: CUDA Driver Version 1000 (PGI 18.10以降)と表示されます
10.1 driverの場合: CUDA Driver Version 10010 (PGI 19.3以降)と表示されます
(一例) set DEFCUDAVERSION=9.2;上記の設定を行わず、コンパイラコマンド上のオプションで明示的に 9.2 Toolkit (PGI 18.5 以上の場合)を使用するように指示するには、以下のように指定します。
pgfortran -ta=tesla,cuda9.2,.... pgcc -ta=tesla,cuda9.2,....
コンパイラは、自動的に必要とする CUDA ソフトウェアのツールを発動し、GPU カーネルコードを生成し、オブジェクト・ファイルの中にカーネルを埋め込みます。
最新バージョンの「CUDA Toolkitのバージョン制御」に関しては、リリースノートに記述しています。以下の記述は、PGI 2018 を例にしたものです。
PGIコンパイラは、NVIDIA GPUで実行するプログラムを構築する際に、NVIDIAのCUDAツールキットを使用します。 すべてのPGIインストールパッケージは、必要なCUDA Toolkitコンポーネントを2018/cudaというPGIインストールディレクトリに置かれます。
NVIDIA CUDAドライバは、そのシステムでGPU用にコンパイルされたプログラムを実行する前に、GPUを搭載したシステムにインストールする必要があります。 PGI製品にはCUDAドライバが含まれていません。 NVIDIAから適切なCUDAドライバをダウンロードしてインストールする必要があります。 CUDAドライバのバージョンは、少なくともコードをコンパイルしたCUDA Toolkitのバージョンと同じかあるいは新しいものでなければなりません。
PGIツール pgaccelinfo は、最初の出力行としてドライバのバージョンを表示します。 ご使用のシステムにどのバージョンのCUDAドライバがインストールされているかわからない場合に使用してください。
PGI 18.7 には、次のバージョンのCUDAツールキットが含まれています。
コンパイラに、使用するバージョンのCUDAツールキットを選択させるか、特定のバージョンを使用するように指示することができます。 このセクションの残りの部分では、すべてのオプションについて説明します。
CUDAツールキットのバージョンを指定しない場合、コンパイラは、コンパイルするシステムにインストールされている CUDA ドライバのバージョンを使用して、使用するCUDAツールキットを決定します。 この自動検出機能は、PGI 18.7 の新機能です。 自動検出は、同じシステムでアプリケーションをコンパイルして実行する場合に特に便利です。 これはどのように動作するのですか? 他の情報がない場合、コンパイラは、システムにインストールされている CUDA ドライバのバージョンと一致する PGI 2018/cuda ディレクトリ内の CUDA Toolkit バージョンを探します。 一致するものが見つからない場合、コンパイラは CUDA ドライバのバージョンより新しいものではない最新のCUDAツールキットのバージョンを検索します。 CUDAドライバがインストールされていない場合、PGI 18.7 コンパイラはデフォルトの CUDA 9.1 に戻ります。 いくつかの例を見てみましょう。
インストールした唯一のPGIコンパイラがPGI 18.7ならば、
次のいずれかの方法を使用して、CUDA Toolkitバージョンのコンパイラのデフォルト選択を変更することができます。
pgcc -ta=tesla:cuda9.2コンパイラオプションを使用すると、コンパイラを1回呼び出すたびにCUDAツールキットのバージョンが変更されます。
set DEFCUDAVERSION=9.2;rcfile変数を使用すると、rcfile を読み取るコンパイラのすべての呼び出しに対して CUDA Toolkit のバージョンが変更されます。
CUDA Toolkitバージョンを指定すると、現在のPGIコンパイラにバンドルされているデフォルトとは異なるCUDA Toolkitインストールを使用するようにコンパイラに指示することもできます。 ほとんどのユーザーは、PGIで提供されているもの以外のCUDA Toolkitインストールを使用する必要はありませんが、この機能が必要な状況が発生します。 プレリリースCUDAソフトウェアを使用している開発者は、PGIリリースに含まれていないCUDAツールキットのバージョンでテストする必要があることがあります。 逆に、PGIリリースでインストールされた最も古いCUDAツールキットよりも古いCUDAツールキットでコンパイルする必要がある開発者もいます。 これらのユーザのために、PGIコンパイラは、PGIインストールディレクトリの外にインストールされたCUDAツールキットのコンポーネントと相互運用できます。
PGIは、一緒にインストールされたバージョンのCUDAツールキットを使用して広範にテストし、その使用を完全にサポートします。 PGIインストールに含まれていないCUDA Toolkitコンポーネントの使用は、機能の違いが存在する可能性があることを理解して行われます。
PGIコンパイラでインストールされたバージョン以外のCUDAツールキットでコンパイルする機能は、すべてのプラットフォームでサポートされています。 Windowsプラットフォームでは、この機能はCUDA Toolkitバージョン9.2以降でサポートされています。
PGI 18.7の CUDA 8.0 など、PGIリリースとともにインストールされていないCUDAツールキットを使用するには、3つのオプションがあります。
set DEFAULT_CUDA_HOME=/opt/cuda-8.0;
export CUDA_HOME=/opt/cuda-8.0
pgfortran CUDA_HOME=/opt/cuda-7.5
pgfortran CUDA_HOME=/opt/cuda-8.0
PGIコンパイラは、使用する CUDAツールキットのバージョンを決定する際に、次の優先順位を使用します。
PGI 18.7 以降、コンパイラは、NVIDIA GPU compute capability 3.0〜7.0 用のコードを生成できます。 コンパイラは、コンパイル時のシステムで検出された GPU のコンピューティング機能と一致する compute capability をデフォルトリストとして作成します。GPU が検出されない場合、コンパイラは cc35、 cc50、 cc60、および cc70を選択します。
コマンドラインオプションまたは rcfile を使用して、1つまたは複数のコンピューティング機能を指定することによって、デフォルトを上書きすることができます。
コマンドラインオプションを使用してデフォルトを変更するには、OpenACC の場合は -ta=tesla: に、CUDA Fortran の場合は -Mcuda= にcompute capabilityのカンマ区切りリストを入力します。rcfileを使用してデフォルトを変更するには、インストールの bin ディレクトリにある siterc ファイルの DEFCOMPUTECAP 値を空白で区切ったcompute capability のリストに設定します。
set DEFCOMPUTECAP=60 70;
また、siterc ファイルを変更する権限がない場合は、ホームディレクトリの別の.mypgircファイル(Windows では mypgi_rc)に DEFCOMPUTECAP 定義を追加できます。デバイスコードの生成には時間がかかることがあるため、コンピューティング機能の数が増えるとコンパイル時間が長くなることがあります。
export PGI_ACC_DEVICE_TYPE=NVIDIA
setenv PGI_ACC_DEVICE_TYPE NVIDIA
export ACC_DEVICE_NUM=1
setenv ACC_DEVICE_NUM 1
export PGI_ACC_NOTIFY=2
setenv PGI_ACC_NOTIFY 2
(メッセージ一例)
upload CUDA data file=acc_f2a.f90 function=main line=37 device=0 variable=a bytes=4000000
download CUDA data file=acc_f2a.f90 function=main line=41 device=0 variable=r bytes=4000000
export PGI_ACC_TIME=1
setenv PGI_ACC_TIME 1
PGI 13.2 以降の Windows 版で、 PGI_ACC_TIME やACC_NOTIFY 環境変数をセットして機能を使用する場合は、こちらの FAQ で説明する方法で DLL ライブラリの検索パスをセットしてください。
PGI 17.7リリースでは、allocatable として割り付けられたデータ用の CUDA Unified Memory の使用がベータ版からプロダクション版に移行しました。 この機能は、 OpenACC および CUDA Unified Memory PGInsider の記事で詳しく説明されており、Linux/x86-64 および Linux/OpenPOWER コンパイラで利用できます。 Linux/x86-64 では、デフォルトの PGI コードジェネレータと Beta版 LLVMベースのコードジェネレータの両方を使用してサポートされています。 この機能を有効にするには、オプション -ta=tesla:managed をコンパイラおよびリンカのコマンドラインに追加します。
-ta=tesla:managed の場合、プログラム単位内のすべての C/C++、Fortran の明示的な allocate 文は、CUDA Unified Memory 上にデータを配置する同等の「管理された」データ割り当て呼び出しに置き換えられます。 管理対象データは CPU/GPU の単一アドレスを共有し、CPU と GPU メモリ間のデータ移動は CUDAドライバによって暗黙的に処理されます。 したがって、OpenACC のデータ句とディレクティブは、「管理された」データには必要ありません。 それらは本質的に無視され、実際には省略することができます。
プログラムが管理されたメモリを割り当てると、デバイスのメモリだけでなくホストの固定メモリも割り当てられます。したがって、割り当てと解放の操作がやや高価になり、データの転送がやや高速になります。 メモリプールアロケータは、アロケートおよびフリーオペレーションのオーバーヘッドを軽減するために使用されます。プールアロケータは -ta= tesla:managed または -ta= tesla:pinned に対してデフォルトで有効になっています。 PGI 17.7リリースでは、 -Mcuda が存在するとプールアロケータが無効になります。 今後のリリースでその制限を解除する作業を進めています。
管理データのデータ移動は、NVIDIA CUDA GPUドライバによって制御されます。 CPU または GPU 上でデータにアクセスするたびに、最後にアクセスされたときに同じデバイス上にデータが転送される可能性があります。 場合によっては、ページのスラッシングが発生し、パフォーマンスに影響を与えることがあります。 Parallel Forall では、CUDA Unified Memory の概要を紹介しています。
この機能には次の制限があります。
この機能には、NVIDIA Kepler GPUで 使用するときに次の追加制限があります。
この機能は、NVIDIA Fermi GPU ではサポートされていません。
CUDA Unified Memory Pool Allocator
動的メモリ割り当ては、cudaMallocManaged() を使用して行われます。このルーチンは、cudaMalloc()を使用して非ユニファイドメモリを割り当てるよりもオーバーヘッドが高いルーチンです。 cudaMallocManaged() の呼び出し回数が増えるほど、パフォーマンスへの影響が大きくなります。
cudaMallocManaged() 呼び出しのオーバーヘッドを軽減するために、-ta=tesla:managed および -ta=tesla:pinned は CUDAUnified Memory プールアロケータを使用して、cudaMallocManaged() への呼び出し回数を最小限に抑えます。 プールアロケータは、デフォルトで有効になっています。 次の環境変数を使用して無効にするか、動作を変更できます。
プールアロケータ環境変数
PGI_ACC_POOL_ALLOC | プールアロケータを無効にします。 プールアロケータはデフォルトで有効になっています。 無効にするには、PGI_ACC_POOL_ALLOCを0に設定します。 |
PGI_ACC_POOL_SIZE | プールのサイズを設定します。 デフォルトのサイズは1GBですが、他のサイズ(2GB、100MB、500KBなど)を使用できます。 実際のプール・サイズは、フィボナッチ・シリーズのサイズが、提供されたサイズまたはデフォルトサイズと比較して、最も近い、より小さい数になるように設定されます。 必要であれば、プールアロケータはプールを追加しますが、PGI_ACC_POOL_THRESHOLD値までしか追加しません。 |
PGI_ACC_POOL_ALLOC_MAXSIZE | 割り当ての最大サイズを設定します。 割り当てのデフォルトの最大サイズは64Bですが、16B以上であれば別のサイズ(つまり100KB、10MB、250MBなど)を使用できます。 |
PGI_ACC_POOL_ALLOC_MINSIZE | 割り当てブロックの最小サイズを設定します。 デフォルトサイズは16Bですが、他のサイズを使用することもできます。 サイズは16B以上でなければなりません。 |
PGI_ACC_POOL_THRESHOLD | プールアロケータが占めることができるデバイスメモリの合計の割合を設定します。 デフォルトは50%に設定されていますが、他のパーセンテージを使用することもできます。 |
$ pgf95 -fast -Minfo=accel -acc -ta=tesla f1.f90 main: 21, Generating copyin(a(1:n)) Generating copyout(r(1:n)) 22, Loop is parallelizable Accelerator kernel generated 22, !$acc do parallel, vector(256) $ pgcc -fast -Minfo=accel -acc -ta=tesla c1.c main: 23, Generating copyin(a[0:n-1]) Generating copyout(r[0:n-1]) 25, Loop is parallelizable Accelerator kernel generated 25, #pragma acc for parallel, vector(256)
以下は、Linux上での状況を示したものです。"a.out" と言う実行モジュール名は、Linux の デフォルト名です。Windows 上では、以下の例の場合、デフォルトでは f1.exe、c1.exe と言う名前の 実行バイナリとなります。 $ export PGI_ACC_TIME=1 (PGI13.1以降) $ pgfortran -fast -Minfo=accel -acc -ta=tesla f1.f90 $ ./a.out Accelerator Kernel Timing data main 21: region entered 1 time (GPU計算領域に1回入った) time(us): total=75347 init=74604 region=743(GPU初期化時間 init、領域計算部region) kernels=27 data=716 (領域内のカーネル実行時間 27μsec、データ転送716μsec) w/o init: total=743 max=743 min=743 avg=743(GPU初期化時間を除いた消費時間) 22: kernel launched 1 times (カーネル起動は1回であった) grid: [391] block: [256] (Block 256のサイズ、グリッドサイズ391) time(us): total=27 max=27 min=27 avg=27(カーネルの計算時間) $ export PGI_ACC_TIME=1 (PGI13.1以降) $ pgcc -fast -Minfo=accel -acc -ta=tesla c1.c $ ./a.out Accelerator Kernel Timing data main 23: region entered 1 time time(us): total=72900 init=71919 region=981 kernels=30 data=951 w/o init: total=981 max=981 min=981 avg=981 25: kernel launched 1 times grid: [391] block: [256] time(us): total=30 max=30 min=30 avg=30
$ pgfortran -fast -Minfo -acc -ta=tesla,host f1.f90 main: 1, PGI Unified Binary version for -tp=nehalem-64 -ta=host (x64ホスト側のコード生成) 18, Unrolled inner loop 8 times 22, Generated an alternate loop for the loop Generated vector sse code for the loop Generated a prefetch instruction for the loop 26, Generated an alternate loop for the loop Generated vector sse code for the loop Generated a prefetch instruction for the loop 30, Loop not vectorized/parallelized: contains call main: 1, PGI Unified Binary version for -tp=nehalem-64 -ta=nvidia (x64+GPU用のコード生成) 18, Unrolled inner loop 8 times 21, Generating copyin(a(1:n)) Generating copyout(r(1:n)) 22, Loop is parallelizable Accelerator kernel generated 22, !$acc do parallel, vector(256) 26, Generated an alternate loop for the loop Generated vector sse code for the loop Generated a prefetch instruction for the loop 30, Loop not vectorized/parallelized: contains call 環境変数ACC_DEVICEの値を切り替えることで、PGI Unified Binary のexecutableを NVIDIA GPUのバイナリを動作させるか、ホスト側バイナリを実行するかを選択できる。 GPUが搭載されているシステムのデフォルトは、ACC_DEVICE=NVIDIA となっている。 GPUが搭載されていないシステムのデフォルトは、ACC_DEVICE=HOST となっている。 ●デフォルト実行(GPUを使用) $ ./a.out (Windows 上では、$ t1.exe) Elpased Time (Initialize + Jacobi solver) : 2.841 FORTRAN STOP ●ホストCPU側のコードで実行 $ export ACC_DEVICE=HOST (あるいは host) $ ./a.out (Windows 上では、$ t1.exe) Elpased Time (Initialize + Jacobi solver) : 13.655 FORTRAN STOP ●再度、GPU側で実行 $ export ACC_DEVICE=NVIDIA (あるいは nvidia) Elpased Time (Initialize + Jacobi solver) : 2.841 FORTRAN STOP
【プログラム例】
program main
use accel_lib
integer :: n ! size of the vector
(中略)
call system_clock( count=c1 )
!$acc kernels
do i = 1,n
r(i) = sin(a(i)) ** 2 + cos(a(i)) ** 2
enddo
!$acc end kernels
call system_clock( count=c2 )
(中略)
end
$ pgfortran -Minfo -acc -ta=tesla,keep f2.f90
main:
26, Generating copyin(a(1:n))
Generating copyout(r(1:n))
27, Loop is parallelizable
Accelerator kernel generated
27, !$acc do parallel, vector(256)
$ ls
a.out f2.f90 f2.001.gpu (翻訳したkernelのコードのサンプル)
$ cat f2.001.gpu
#include "cuda_runtime.h"
#include "pgi_cuda_runtime.h"
static __constant__ struct{
int tc4;
char* p1;
char* p2;
}a2;
extern "C" __global__ void
main_27_gpu(
){
float _r_1, _r_2;
int xthreadidx_x;
int xblockidx_x;
int xgriddim_x;
int i1;
int i1s;
xthreadidx_x = threadIdx.x;
xblockidx_x = blockIdx.x;
xgriddim_x = gridDim.x;
i1s = (xblockidx_x)*(256);
if( (i1s) >= (a2.tc4) ) goto _BB_6;
_BB_4: ;
i1 = (xthreadidx_x)+(i1s);
if( (i1) >= (a2.tc4) ) goto _BB_5;
_r_1 = cosf(((float*)a2.p1)[i1]);
_r_2 = sinf(((float*)a2.p1)[i1]);
((float*)a2.p2)[i1] = ((_r_1)*(_r_1))+((_r_2)*(_r_2));
_BB_5: ;
i1s = ((xgriddim_x)*(256))+(i1s);
if( (i1s) < (a2.tc4) ) goto _BB_4;
_BB_6: ;
}
for (j=0; j<n; J++)
for (i=0; i<j; i++)
{some code}