PGIトップ PGI技術情報・TIPS コンパイラ・オプションの使用方法 PGI CUDA Fortran のオプション
PGI CUDA Fortran

CUDA™ は NVIDIA 社の GPU のアーキテクチャですが、NVIDIA 社からのCUDA開発環境は、CUDA C として知られている拡張 C コンパイラとツール群のみが提供されております。CUDA C は、高級言語上から GPU のために CUDA API を使用して明示的にプログラミングすることができるものです。PGI社とNVIDIA社は共同で PGI CUDA Fortran の開発を行い、CUDA C と同等な機能を PGI Fortran 95/Fortran 2003 コンパイラに実装しました。ここでは、PGI CUDA Fortran のコンパイル方法を説明します。PGI 11.6 用更新 2011/6/20Copyright © 株式会社ソフテック
PGI CUDA Fortran 構文を含むプログラムのファイル名は、***.cuf と言う名称にします。コンパイラは、この名称のファイルを CUDA Fortran であると認識し、-Mcuda オプションを付けなくてもコンパイルできます。また、***.CUF と cuf サフィックスを大文字とすると、コンパイラは、CUDA Fortran プログラムで、かつ、プリプロセッシング処理を行うべきプログラムであると認識します。もちろん、Fortran のファイル名のサフィックスを *.f、*.F、*.f90、*.F90 と言った従来の慣習である名称としても良いですが、この場合は、コマンドラインに必ず、オプション -Mcuda を明示的に記述しなければなりません。
● CUDA Fortran ファイル名一例 *.cuf、*.CUF(CUDA Fortran プログラムファイルであることを明示) *.f、*.F、*.f90、*.F90、*.f95、*.F95 (従来の慣習名)
PGI pgf95 (pgfortran、あるいは、pgf90は同じコンパイラです)コンパイラを使用して、CUDA Fortran プログラムをコンパイルするためのオプションの例を示します。なお、CUDA Fortran は、デフォルトでは F90 以降の「自由記述形式」のファイルと見なしてコンパイルしますので、もし旧 F77 時代の「固定記述形式(7カラムから実行文と言った形式)」の場合は、必ず、-Mfixed と言うオプションを付けて、コンパイラに指示する必要があります。以下は、pgf95(pgfortran、あるいは、pgf90 も同じコンパイラです)を使用した場合の例です。
● CUDA Fortranコンパイルの一例
pgf95 test.cuf (最適化なし)
pgf95 -O2 test.cuf (最適化あり)
pgf95 -O2 -Mfixed test.cuf (最適化あり、ソースはF77固定記述形式)
pgf95 -O2 -Mcuda test.f90
● エミュレーションモード
pgf95 -O2 -Mcuda=emu test.cuf
| サブオプション | nvidia用 機能 |
|---|---|
| emu | エミュレーションモードでコンパイルします。これは、GPU 用のコード生成は行わず、ホスト側でエミュレーション実行可能なコードを生成します。一般に、デバッグ時に使用します。CUDA Fortran の " device code (kernel)" は、ホスト上で実行出来るコードで生成され、ホスト側の pgdbg デバッガを使用できます。 |
| 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.1 or 3.1 | PGIにバンドルされたCUDA toolkit 3.2 バージョンを使用 (PGI 11.0以降) |
| cuda4.0 or 4.0 | PGIにバンドルされた CUDA toolkit 4.0 バージョンを使用 (PGI 11.6以降) |
| fastmath | fast mathライブラリを使用 (PGI 10.4以降) |
| [no]flushz | GPU上の浮動小数点演算の flush-to-zero モードを制御。デフォルトはnoflushz。 (PGI 11.5以降) |
| keepbin | kernelバイナリファイルを保持し、ファイル(.bin)として出力する |
| keepgpu | kernelソースファイルを保持し、ファイル(.gpu)として出力する (PGI 10.3新設) |
| keepptx | GPUコードのためのportable assembly(.ptx)ファイルを保持し、ファイルとして出力する |
| maxregcount:n | GPU上で使用するレジスタの最大数を指定。ブランクの場合は、制約が無いと解釈する |
| nofma | fused-multiply-add命令を生成しない (PGI 10.4以降) |
| ptxinfo | コンパイル時にPTXAS情報メッセージを表示する(PGI 11.0以降) |
$ 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 Fortran の簡単なプログラム例とコンパイル・実行例を示します。以下のプログラムは、デバイス上の配列(int_d)を宣言して、GPU上で整数配列に値を入れ、ホスト側の配列に戻して印字すると言う単純なものです。しかし、CUDA Fortran 構文の基本的なものが使用されている例です。
module cudamod
use cudafor
implicit none
contains
! kernel subprogram
attributes(global) subroutine test1 (intdat,n)
integer :: it, ib
integer, value :: n
integer, device :: intdat(n)
!----------------------------
it = threadidx%x
iib = (blockidx%x-1) * 16
intdat(it+ib) = it + ib
!----------------------------
end subroutine test1
end module cudamod
program cuda_device
use cudafor
use cudamod
implicit none
integer :: n=64
integer :: int_h(n), ist
! デバイス側の配列データを allocatable で宣言
integer, device, allocatable, dimension(:) :: int_d
int_h = 0
allocate(int_d(n))
! カーネル(デバイスプログラム)を起動する
call test1 <<<n/16,16>>> (int_d, n) !pass arguments
ist = cudathreadsynchronize() ! 同期ポイント
! デバイス側の配列データをホスト側に戻す
int_h = int_d
print *,'int_h = ',int_h
deallocate(int_d)
end program cuda_device
$ pgf90 -O2 -Minfo -Mcuda -o test.exe test.cuf
cuda_device:
28, Memory zero idiom, loop replaced by call to __c_mzero4
$ test.exe
int_h = 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
18 19 20 21 22 23
24 25 26 27 28 29
30 31 32 33 34 35
36 37 38 39 40 41
42 43 44 45 46 47
48 49 50 51 52 53
54 55 56 57 58 59
60 61 62 63 64
GPU上で動作する PGI CUDA Fortran プログラム内のカーネル・プログラムのデバッグは、一般には行うことができません。これは、ホスト側から GPU 内のdevice memory を直接アクセスできない理由に因るものです。PGIは、仮想的に GPU のカーネルコード部分をホスト側で実行できる「エミュレーション」環境を提供します。この目的は、GPU上の実際の完璧な動作挙動を再現することが目的ではなく、一般には覗き見ることができない「カーネルコード」内の変数や配列等の確認をデバッグ用途で使用できる環境を提供することです。PGDBGは、PGI社の並列デバッガですが、使用法としては、一般のシリアル実行デバッグやマルチコア、MPI等の並列デバッグにおける操作と同じであり、ソースプログラム上に当該ブレークポイントを設定して、対象となる変数や配列の値を確認しながら、デバッグ作業を行う形になります。
【デバッグオプション -g と エミュレートモード -Mcuda=emu を指定】 $ pgf90 -g -Mcuda=emu -o test.exe test.cuf $ export OMP_NUM_THREADS=4 (仮想的に4スレッドを使用して並列デバッグ) $ pgdbg test.exe (PGI PGDBG を起動し、デバッグウインドウを開く)
PGDBGは、マルチスレッド、MPIマルチプロセス対応の並列デバッガです。マルチスレッド・デバッグの場合は、論理的には最大256 スレッド実行までのデバッグが可能ですが、実際は、ハードウェアのCPUコア数に制限があり、実装コア数制限内で並列スレッド・デバッギングを行う事が一般的です(実装コア数より大きな実行スレッドを指定すると、当然ながらデバッガ動作が鈍くなる)。ここでは、CPU上で物理的に動作可能なスレッド数を指定して、「スレッド並列のデバッグ」と同じように実施します。(同時に動作するスレッド並列処理が、後述するいわゆるワープと言う「ベクトル処理」に見立てることもできるように見えます)
スレッドGPUの挙動は、その基本がスレッド・ブロック内の CUDA Warpsize によるベクトル処理と、スレッド・ブロック群の並行(並列)処理を行う形ですが、ホスト側でこの挙動をそのままエミュレートすることはできません。特に、後者の「スレッド・ブロック」の並列処理は、ホスト側エミュレートでは逐次的処理となりますので、並列動作のエミュレートはできないことに留意して下さい。エミュレーション・デバッグ時には、並列動作挙動が全然異なると言う前提で、デバッグを行う事が必要です。特にデータの依存性に係わる問題のデバッグに関しては、エミュレートモードのデバッグ結果を鵜呑みにするようなことはしないで下さい。
PGDBG を起動して、データ・ウインドウを開いた。
ソースコード内の device subprogram 内にブレークポイントを設定した。
デバイス内の配列数値をデバッグするため表示させた。
ブレークした時点でスコープ可能なローカルデータを表示させる。