PGIトップ PGI技術情報・TIPS コンパイラ・オプションの使用方法 PGIアクセラレータ用のオプション
PGI アクセラレータ、CUDA Fortran

「アクセラレータ」とは、特別の目的で CPU にアタッチして使用する協調プロセッサであり、時間の掛かる計算部分を CPU の演算機構からデータと実行部分のカーネルをオフロードするために使用されます。ここでは、 GPUをアクセラレータとして使用する際のPGI アクセラレータ™ コンパイラのオプションについて説明します。制限事項追記 更新 2010/5/13PGI 11.6 用更新 2011/6/20Copyright © 株式会社ソフテック
PGI の F95, C のコンパイラを使用して、PGIアクセラレータ用のコンパイルを行うオプションの例を示します。以下は、pgf95(pgfortran、あるいは、pgf90 も同じコンパイラです)を使用した場合の例ですが、C言語用の pgcc コンパイラのオプションの設定方法も、同様です。なお、コマンドライン上でリンク時にも、必ず、コンパイル時に指定したものと同じ -ta オプションを指定することが必要です。
● Fortranコンパイルの一例 pgf95 -fast -Minfo -ta=navidia test.f pgf95 -fast -Minfo=accel -ta=nvidia:keepgpu,time test.f90 ● C99 コンパイルの一例 pgcc -fast -Minfo -ta=navidia test.c pgcc -fast -Minfo=accel -ta=nvidia:keepgpu,nofma,time test.c
| サブオプション | nvidia用 機能 |
|---|---|
| analysis | ループの解析のみ行い、コードの生成を行いません。 |
| cc10 | compute capability 1.0 のコードを生成 |
| cc11 | compute capability 1.1 のコードを生成 |
| cc12 | compute capability 1.2 のコードを生成 |
| cc13 | compute capability 1.3 のコードを生成 |
| cc20 | compute capability 2.0 のコードを生成 (PGI 10.4以降) |
| 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以降) |
| fastmath | fast mathライブラリを使用 |
| [no]flushz | GPU上の浮動小数点演算の flush-to-zero モードを制御。デフォルトはnoflushz。 (PGI 11.5以降) |
| keepbin | kernelバイナリファイルを保持し、ファイル(.bin)として出力する |
| keepgpu | kernelソースファイルを保持し、ファイル(.gpu)として出力する |
| keepptx | GPUコードのためのportable assembly(.ptx)ファイルを保持し、ファイルとして出力する |
| maxregcount:n | GPU上で使用するレジスタの最大数を指定。ブランクの場合は、制約が無いと解釈する |
| mul24 | 添字計算に、24ビット乗算を使用 (GT200系、CC 1.3のみ) |
| nofma | fused-multiply-add命令を生成しない |
| time | アクセラレータ領域の単純な時間情報を集積するためにプロファイル・ライブラリをリンクする |
| [no]wait | ホスト側での実行継続を行う際に、各カーネルが終了するまで待つ。nowaitは待たない。 (PGI 10.8以降) |
$ pgaccelinfo
CUDA Driver Version 2030
(以下省略)
ここで、
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以降)と表示されます
(一例) set DEFCUDAVERSION=4.0;上記の設定を行わず、コンパイラコマンド上のオプションで明示的に 4.0 Toolkit (PGI 11.6 以降)を使用するように指示するには、以下のように指定します。
pgfortran -ta=nvidia:4.0,.... pgcc -ta=nvidia:4.0,....
コンパイラは、自動的に必要とする CUDA ソフトウェアのツールを発動し、GPU カーネルコードを生成し、オブジェクト・ファイルの中にカーネルを埋め込みます。
export ACC_DEVICE=NVIDIA
setenv ACC_DEVICE NVIDIA
export ACC_DEVICE_NUM=1
setenv ACC_DEVICE_NUM 1
export ACC_NOTIFY=1
setenv ACC_NOTIFY 1
(メッセージ一例)
launch kernel file=/home/kato/GPGPU/OpenMP/jacobi4.F function=jacobi line=229 device=1 grid=2500 block=128x4
$ pgf95 -fast -Minfo=accel -ta=nvidia 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 -ta=nvidia 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 と言う名前の
実行バイナリとなります。
$ pgf95 -fast -Minfo=accel -ta=nvidia,time 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(カーネルの計算時間)
$ pgcc -fast -Minfo=accel -ta=nvidia,time 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
$ pgf95 -fast -Minfo -ta=nvidia,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 region
do i = 1,n
r(i) = sin(a(i)) ** 2 + cos(a(i)) ** 2
enddo
!$acc end region
call system_clock( count=c2 )
(中略)
end
$ pgf95 -Minfo -ta=nvidia,keepgpu 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}