PGI CUDA Fortran を使用した行列積の計算とGPU性能

キーワード GPGPU、CUDA、MATMUL、PGIアクセラレータ、PGI CUDA Fortran

 前回のコラムの続編です。一般的な行列積(matmul)のプログラムをPGI CUDA Fortranでコーディングした場合、どの程度の実効性能となるでしょうか。前回のコラムでは、PGI アクセラレータ用ディレクティブを挿入して GPU 並列コードに翻訳する ①PGIアクセラレータ・プログラミングモデルを使用した実効性能を呈示しました。今回は、②PGI CUDA Fortran でコーディングして実行した際の性能を示します。この次のコラムでは、③NVIDIA の CUBLAS ライブラリを使用する場合の例を示します。
2010年6月26日 Copyright © 株式会社ソフテック 加藤

PGI CUDA Fortran による行列積(matmul) プログラム

 PGI CUDA Fortran で GPU 並列化を行う場合、デバイスメモリへのアクセスの最適化を行うことが、性能の大幅な向上に繋がります。これを具体的に言えば、NVIDIA GPU の Shared memory をキャッシュとして利用することを意味します。すなわち、メモリへのコアレス・アクセスができない場合やストライドを持ったメモリアクセスとなってしまうような場合に、これらによるメモリ・アクセスのレイテンシを避けるために、高速・低レイテンシな特性を持つ Shared memory をキャッシュとして見立て、その中にデータを置き、shared memory と演算器の間で高速な処理を行うことを行います。別の見方で言えば、CUDA Fortran や CUDA C でコーディングしたとしても、こうしたメモリ関係の最適化を実装しなければ、GPU上の大きな性能効果は望めません。行列積(matmul) の例は、演算が単純であるため、比較的きれいに cache tiling のコーディングができます。本稿で使用する CUDA Fortran コードは、こうした最適化がなされたものです。

 行列積のプログラムに関するコラム(全3回)

  1. PGIアクセラレータを使用した行列積の計算とGPU性能
  2. PGI CUDA Fortran を使用した行列積の計算とGPU性能
  3. PGI Fortran と CUDA CUBLASを使用した行列積の計算とGPU性能

Performance Summary

単精度 性能加速 65.1x

倍精度 性能加速 55.0x

 以下の表-1 に、本稿の PGI CUDA Fortran を使って測定した性能と、前回のコラムで説明した PGIアクセラレータ・プログラミングモデルを用いて得られた性能を比較するために記載します。

表-1 MATMUL 計算 x64 Nehalem 1CPU 性能とGPU 性能の比較(4096サイズ)
(単精度) 使用プログラミングモデル Nehalem 1CPU GTX 480 性能比
② PGI CUDA Fortran 5.3 GFLOPS 344.9 GFLOPS 65.1倍
① PGI Accelerator programming (Link) 5.3 GFLOPS 157.8 GFLOPS 29.7倍
(倍精度) 使用プログラミングモデル Nehalem 1CPU GTX 480 性能比
② PGI CUDA Fortran 2.5 GFLOPS 137.5 GFLOPS 55.0倍
① PGI Accelerator programming (Link) 2.5 GFLOPS 94.7 GFLOPS 37.9倍

性能実測するシステム環境について

 まず始めに、性能実測に使用する私のテストマシン環境について説明します。

ホスト側プロセッサ Intel(R) Core(TM) i7 CPU 920 @ 2.67GHz x 1 プロセッサ
ホスト側メモリ PC3-10600(DDR3-1333)2GB x 2 枚
ホスト側 OS Cent OS 5.4、カーネル 2.6.18-164.el5
PGI コンパイラ PGI 10.6 (PGI 2010)
GPU ボード1 NVIDIA Geforce GTX480(Fermi)、1401.0 MHz clock, 1535.7 MB memory
GPU ボード2 NVIDIA Geforce GTX285、1476.0 MHz clock, 1023.3 MB memory
NVIDIA CUDA バージョン CUDA 3.0ドライバと3.0 Toolkit
表-1.1 NVIDIA GPU 理論性能の比較
ハードウェア仕様 Geforce GTX285 Geforce GTX480
Compute Capability Compute Capability 1.3 2.0
総CUDAコア(SP)数 CUDA cores
(Streaming Processors)
240 cores 480 cores
プロセッサクロック CUDA cores
(Streaming Processors)
1476 MHz 1401 MHz
単精度理論FP演算性能 Single Precision GFLOPS 708 GFLOPS 1344 GFLOPS
倍精度理論FP演算性能 Double Precision GFLOPS 88 GFLOPS 1344x1/8 = 168 GFLOPS

PGI CUDA Fortran を使用した実行例

 本ソース・プログラムは、PGI の著作権の使用制限により自由に公開できません。但し、PGIコンパイラを購入いただいているお客様は、ライセンスの「使用許諾契約」の範疇で自由に使用できます。ここで使用しているソースプログラムは、PGIコンパイラのソフトウェア内にバンドルされております。単精度版の sgemm.cuf と言うプログラムが以下の directory 配下にありますので、これを使用して下さい。なお、ここで、使用しているプログラムは、私が一部変更しています。また、倍精度版のプログラムも別途作成しております。もし、ソースプログラムがご入り用の方は、。

  • 単精度版 sgemm.cuf ソース

  • Linux : $PGI/linux86{-64}/10.x/etc/src/samples/sgemm.cuf
  • Windows: C:\Program files\win32{win64}\10.x\etc\src\samples\sgemm.cuf
  • OS X : $PGI/osx86/10.x/etc/src/samples/sgemm.cuf

 PGI Cuda Fortran によりコンパイルする例

● PGI CUDA Fortran のコンパイル
[kato@photon29 CUDAFORTRAN]$ make
pgfortran -c -fastsse -Mcuda:3.0 -Minfo sgemm.cuf
sgemm_cpu:
     83, Generated 2 alternate loops for the loop
         Generated vector sse code for the loop
         Generated a prefetch instruction for the loop
main:
    111, Loop not vectorized/parallelized: contains call
    159, Loop not vectorized/parallelized: contains call
pgfortran -o a.out sgemm.o -fastsse -Mcuda:3.0  -Minfo -Mlist

 ※ PGI CUDA Fortran 用コンパイル・オプションについて

単精度版の実行

 単精度版プログラムは 16x16 のブロック化を行い、この計算の中で、shared memory を使用して高速化を行っている。

[kato@photon29 CUDAFORTRAN]$ ./a.out -device 0 (GTX480を使用して実行)

Device:GeForce GTX 480, 1401.0 MHz clock, 1535.7 MB memory.

 Single Precision MatMul
 Matrix size=         4096
 Block  size=           16           16
 Grid   size=           16          256
 Test passed!
 4096x4096 * 4096x4096:
 Total Time (sec):    0.3983600139617920
 GFLOPS          :     345.0119205116360
[kato@photon29 CUDAFORTRAN]$ a.out -device 1 (GTX285を使用して実行)

Device:GeForce GTX 285, 1476.0 MHz clock, 1023.3 MB memory.

 Single Precision MatMul
 Matrix size=         4096
 Block  size=           16           16
 Grid   size=           16          256
 Test passed!
 4096x4096 * 4096x4096:
 Total Time (sec):    0.3969089984893799
 GFLOPS          :     346.2732112274786

倍精度版の実行

 倍精度版プログラムは 8x8 のブロック化を行い、この計算の中で、shared memory を使用して高速化を行っている。

[kato@photon29 DOUBLE]$ a.out -device 0 (GTX480を使用して実行)

Device:GeForce GTX 480, 1401.0 MHz clock, 1535.7 MB memory.

 Double Precision MatMul
 Matrix size=         4096
 Block  size=            8            8
 Grid   size=           64          512
 Test passed!
 4096x4096 * 4096x4096:
 Total Time (sec):    0.9985399842262268
 GFLOPS          :     137.5399099115716

x64 Nehalem 1CPU 性能と GPU 性能の比較(PGI CUDA Fortran)

 ここで、一般的な x64 CPU の性能と GPU の性能の実効性能の違いはどの程度あるかを把握しておきましょう。以下の表は、4096の行列サイズの時のCPUとGPUの性能を示したものです。

表-2 MATMUL 計算 x64 Nehalem 1CPU 性能とGPU 性能の比較(4096サイズ)
使用プログラミングモデル Nehalem 1CPU GTX 480 性能比
(単精度) PGI CUDA Fortran 5.3 GFLOPS 344.9 GFLOPS 65.1倍
(倍精度) PGI CUDA Fortran 2.5 GFLOPS 137.5 GFLOPS 55.0倍

PGI CUDA Fortran プログラムの MATMUL 性能

 単精度版と倍精度版のプログラムを使用して、いくつかの行列サイズで行列積の計算を行った結果を示します。ここでは、最新の Fermi アーキテクチャである GTX 480 (Compute Capability :2.0) と1世代古い GTX 285 (Compute Capability :1.3)を使用して実測を行いました。表-3 は、単精度版での GTX 480 と GTX285 の性能比較を表し、表-4 では、倍精度版での性能比較を表しています。
 また、各 GPU ボード上で単精度と倍精度の実行性能の比較を行ったのが 表-5 と 表-6 である。表-5 は、GTX480 の性能、表-6 は、GTX285 の性能です。

単精度版 MATMUL PGI CUDA Fortran プログラム性能(GTX480とGTX285 GPUの性能比較)

 GTX 480 (Compute Capability :2.0) と1世代古い GTX 285 (Compute Capability :1.3)の性能差は、単精度の結果を見る限り、大きな差はない。CUDA Fortran によりネイティブなレベルで最適化されており、実効性能の最大値に近い性能を呈しているため、これ以上の加速性を得るには、 Occupancy や Active な WARP を 100% 近い状態にしなければ、性能の向上は期待できないようです。Fermi はもう少し頑張れるのかなと思いましたが、メモリの制約がありこれ以上のサイズの試験は行っていません。GTX480では、その実効性能が理論ピーク性能の 26% を達成、FGTX285 では、なんと 49% まで達しています。Fermi に関しては、まだまだ、CUDAドライバや nvcc コンパイラ等の内部の最適化の余地はありそうです。

表-3 単精度 MATMUL 計算 PGI CUDA Fortran による性能(GFLOPS)
GPU/行列サイズ 256 512 1024 2048 4096
GTX 480 (CC 2.0) 63.3 124.4 233.1 304.4 344.9
GTX 285 (CC 1.3) 58.2 115.0 225.5 299.8 346.2
性能Ratio 1.08 1.08 1.03 1.01 0.99

倍精度版 MATMUL PGI CUDA Fortran プログラム性能(GTX480とGTX285 GPUの性能比較)

 倍精度演算ではどうでしょう。GTX 480 では 137 GFLOPS の実効性能が記録されました。これは、理論ピーク性能の約 81 % の実効性能が得られていることになります。一方、GTX 285 は、実性能としては 76 GFLOPS の実効性能で、理論ピーク性能の約 86% の実効性能が得られています。かなり、理論ピーク値に対する実効性能が伸びています。今まで GTX 285 の倍精度計算が思っている程には、遅くないと言う感覚を以前から持っていましたが、こうしたことからも、裏付けられます。GTX480 は、単精度の 1/8 のピークに抑えられていますが、単精度比較した傾向は GTX285 のものより良いようです。倍精度性能が単精度の 1/2 である真の Fermi である Tesla 2000シリーズのGPUボードではどうなるのでしょうか?

表-4 倍精度 MATMUL 計算 PGI CUDA Fortran による性能(GFLOPS)
GPU/行列サイズ 256 512 1024 2048 4096
GTX 480 (CC 2.0) 32.6 65.9 94.5 125.0 137.5
GTX 285 (CC 1.3) 27.6 47.3 63.4 71.8 76.0
性能Ratio 1.18 1.39 1.49 1.74 1.80

GTX 480 (Fermi) による単精度/倍精度の実効性能比較

 GTX 480 の単精度演算と倍精度演算の性能比を示したものです。CUDA Fortran により CUDA ネイティブなレベルで最適化された状態では、単精度演算/倍精度演算の peformance ratio としては 2倍 以上 の性能差があると言うことです。Geforceシリーズの倍精度性能制限(単精度の 1/8 とする)でどの程度の低下があるかと思いましたが、それなりの高い性能を呈しています。

表-5 PGI CUDA Fortran によるMATMUL性能(GFLOPS)
精度/行列サイズ 256 512 1024 2048 4096
単精度計算 63.3 124.4 233.1 304.4 344.9
倍精度計算 32.6 65.9 94.5 125.0 137.5
性能Ratio 1.94 1.89 2.48 2.43 2.51

GTX 285 による単精度/倍精度の実効性能比較

 GTX 285 の単精度演算と倍精度演算の性能比を示したものです。GTX 285 のアーキテクチャは、その理論性能比が倍精度/単精度の演算器の物量比として表され 1/8 となっていますが、実際は、単精度演算/倍精度演算の peformance ratio としては 3~4 と言うところになっているようです。これらの性能は、CUDA Fortran による CUDA ネイティブなレベルで最適化されたプログラム特性の場合の性能です。すなわち、GPUのアーキテクチャを有効に利用するような高度な最適化をソースレベルで施した場合の性能です。単精度/倍精度の理論的な性能比である 8 倍には届きませんが、プログラムを最適化すると両者の性能差は顕著になると言うことです(理論値に近づくと言うことです)。ただ、ここまでチューニングできる「ソースプログラム」は簡単ではありませんので、一般ユーザにとって、こうした単精度/倍精度における顕著な差が出てくることはほとんどありません。

表-6 PGI CUDA Fortran によるMATMUL性能(GFLOPS)
精度/行列サイズ 256 512 1024 2048 4096
単精度計算 58.2 115.0 225.5 299.8 346.2
倍精度計算 27.6 47.3 63.4 71.8 76.0
性能Ratio 2.10 2.44 3.56 4.18 4.55

 行列積のプログラムに関するコラム(全3回)

  1. PGIアクセラレータを使用した行列積の計算とGPU性能
  2. PGI CUDA Fortran を使用した行列積の計算とGPU性能(本稿)
  3. PGI Fortran と CUDA CUBLASを使用した行列積の計算とGPU性能