Ubuntu Weekly Recipe

第456回 Ubuntu 16.04 LTSでCUDA 8.0を使用する

この記事を読むのに必要な時間:およそ 15 分

サンプルプログラムのビルドと実行

CUDAにはサンプルプログラムが含まれています。パッケージ版であればcuda-samples-8-0パッケージをインストールすれば/usr/local/cuda-8.0/samples/にサンプルコードがインストールされます。スクリプト版なら同じ場所にインストールした上で,コンパイルしやすいようにユーザーのホームディレクトリにもコードをコピーしてくれます。

実際にサンプルプログラムをビルドしてみましょう。まずC++コンパイラなどをあらかじめインストールしておきます。

$ sudo apt install build-essential

あとはサンプルプログラムのトップディレクトリでmakeを実行するだけです。ちなみにそれなりに時間はかかります。

$ cd ~/NVIDIA_CUDA-8.0_Samples/
$ ls
0_Simple  1_Utilities  2_Graphics  3_Imaging  4_Finance  5_Simulations  6_Advanced  7_CUDALibraries  EULA.txt  Makefile  common
$ make
(中略)

$ ls bin/x86_64/linux/release/
BiCGStab  batchCUBLAS  convolutionSeparable  freeImageInteropNPP  nvgraph_SemiRingSpmv  simpleCUFFT_MGPU  simpleTexture
(後略)

個々のプログラムの詳細はサンプルリファレンスに掲載されています。このうち「Dependencies」「X11」「GL」が記載されているサンプルは実行にデスクトップ環境などが必要になりますので注意しておきましょう。

deviceQueryはCUDAデバイスの情報を表示するためのプログラムです。接続しているデバイスの詳細な情報を確認したい場合に便利でしょう。

$ ./bin/x86_64/linux/release/deviceQuery
./bin/x86_64/linux/release/deviceQuery Starting...

 CUDA Device Query (Runtime API) version (CUDART static linking)

Detected 1 CUDA Capable device(s)

Device 0: "GeForce GTX 1050 Ti"
  CUDA Driver Version / Runtime Version          8.0 / 8.0
  CUDA Capability Major/Minor version number:    6.1
  Total amount of global memory:                 4038 MBytes (4234412032 bytes)
  ( 6) Multiprocessors, (128) CUDA Cores/MP:     768 CUDA Cores
  GPU Max Clock rate:                            1392 MHz (1.39 GHz)
  Memory Clock rate:                             3504 Mhz
  Memory Bus Width:                              128-bit
  L2 Cache Size:                                 1048576 bytes
  Maximum Texture Dimension Size (x,y,z)         1D=(131072), 2D=(131072, 65536), 3D=(16384, 16384, 16384)
  Maximum Layered 1D Texture Size, (num) layers  1D=(32768), 2048 layers
  Maximum Layered 2D Texture Size, (num) layers  2D=(32768, 32768), 2048 layers
  Total amount of constant memory:               65536 bytes
  Total amount of shared memory per block:       49152 bytes
  Total number of registers available per block: 65536
  Warp size:                                     32
  Maximum number of threads per multiprocessor:  2048
  Maximum number of threads per block:           1024
  Max dimension size of a thread block (x,y,z): (1024, 1024, 64)
  Max dimension size of a grid size    (x,y,z): (2147483647, 65535, 65535)
  Maximum memory pitch:                          2147483647 bytes
  Texture alignment:                             512 bytes
  Concurrent copy and kernel execution:          Yes with 2 copy engine(s)
  Run time limit on kernels:                     No
  Integrated GPU sharing Host Memory:            No
  Support host page-locked memory mapping:       Yes
  Alignment requirement for Surfaces:            Yes
  Device has ECC support:                        Disabled
  Device supports Unified Addressing (UVA):      Yes
  Device PCI Domain ID / Bus ID / location ID:   0 / 1 / 0
  Compute Mode:
     < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >

deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 8.0, CUDA Runtime Version = 8.0, NumDevs = 1, Device0 = GeForce GTX 1050 Ti
Result = PASS

bandWidthTestはGPUデバイス間やホストとのメモリコピーに関わる帯域幅を簡易的に計測するツールです。

$ ./bin/x86_64/linux/release/bandwidthTest
[CUDA Bandwidth Test] - Starting...
Running on...

 Device 0: GeForce GTX 1050 Ti
 Quick Mode

 Host to Device Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)        Bandwidth(MB/s)
   33554432                     12154.1

 Device to Host Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)        Bandwidth(MB/s)
   33554432                     12475.1

 Device to Device Bandwidth, 1 Device(s)
 PINNED Memory Transfers
   Transfer Size (Bytes)        Bandwidth(MB/s)
   33554432                     95496.7

Result = PASS

NOTE: The CUDA Samples are not meant for performance measurements. Results may vary when GPU Boost is enabled.

最後に計算量の大きなサンプルも実行してみましょう。よく使われているのはnbodyです。その名の通り重力多体計算を行うプログラムで,N個の粒子の重力相互作用を計算しながら系の時間変換をシミュレートしていく,まさに並列処理が効いてくる計算です。ただCUDAのnbodyは,計算結果の表示のためにX11とGLに依存しています。デスクトップ環境にCUDAをインストールした場合であれば実行できますが,Ubuntuサーバーの場合はヘッダーファイルやライブラリが足りないためにビルドをスキップします。

nbodyコマンドそのまのは-benchmarkオプションをつけることで,X11環境ではなくても実行できるようです。そこでビルドに必要なライブラリだけ別途インストールします。

$ sudo apt install --no-install-recommends libx11-6 libglu1-mesa \
  mesa-common-dev libglu1-mesa-dev libx11-dev fleeglut3 freeglut3-dev
アップグレード: 0 個、新規インストール: 69 個、削除: 0 個、保留: 0 個。
19 MB のアーカイブを取得する必要があります。
この操作後に追加で 174 MB のディスク容量が消費されます。

もう一度makeしなおせば,nbodyコマンドがあらわれるはずです。

$ ./bin/x86_64/linux/release/nbody -benchmark -numbodies=8192
(中略)
> Windowed mode
> Simulation data stored in video memory
> Single precision floating point simulation
> 1 Devices used for simulation
GPU Device 0: "GeForce GTX 1050 Ti" with compute capability 6.1

> Compute 6.1 CUDA device: [GeForce GTX 1050 Ti]
number of bodies = 8192
8192 bodies, total time for 10 iterations: 12.543 ms
= 53.503 billion interactions per second
= 1070.063 single-precision GFLOP/s at 20 flops per interaction

エントリークラスのGPUであるにも関わらず単精度で1TFLOPSは普通に出ているようです。ちなみにGeForce GTX 1050 Tiの理論値は2TFLOPSぐらいだとか。さらにnbody-cpuオプションをつけるとCPUのみで計算します。

$ ./bin/x86_64/linux/release/nbody -benchmark -numbodies=8192 -cpu
(中略)
> Windowed mode
> Simulation data stored in video memory
> Single precision floating point simulation
> 1 Devices used for simulation
> Simulation with CPU
number of bodies = 8192
8192 bodies, total time for 10 iterations: 27669.867 ms
= 0.024 billion interactions per second
= 0.485 single-precision GFLOP/s at 20 flops per interaction

もうひとつcdpLUDecompositionも実行してみましょう。⁠cdp」CUDA Dynamic Parallelismの略で,簡単に言うとGPU側の計算中のスレッドからさらにスレッドを起動できる仕組みです。⁠Compute Capability 3.5」以降に追加された機能なので,Keplerアーキテクチャーでも動かない可能性があります※8⁠。⁠LUDecomposition」LU分解のことで,行列を下三角行列と上三角行列に分解します※9⁠。実際はLAPACKのdgetrfをCUDAに移植して使っているようです。

※8
deviceQueryコマンドの「CUDA Capability Major/Minor version number」にバージョン番号が表示されています。
※9
行と列を足したり引いたり入れ替えたりするあの行列です。おおよそ20代半ば以降で高校時代に普通科か理数系だった読者なら「数学C」とか「代数・幾何」とか「数学IIA」とかで経験があるのではないでしょうか。ちなみに2012年の教育課程の変更で行列を扱っていた数Cが廃止されています。今は理数系の学科のみ設置されうる理数数学特論で行列を扱うことがあるようです。

cdpLUDecomposition-matrix_sizeオプションで正方行列の次数を指定できます。

$ ./bin/x86_64/linux/release/cdpLUDecomposition -matrix_size=8192
Starting LU Decomposition (CUDA Dynamic Parallelism)
GPU Device 0: "GeForce GTX 1050 Ti" with compute capability 6.1

GPU device GeForce GTX 1050 Ti has compute capabilities (SM 6.1)
Compute LU decomposition of a random 8192x8192 matrix using CUDA Dynamic Parallelism
Launching single task from device...
GPU perf(dgetrf)= 58.461 Gflops
Checking results... done
Tests suceeded

こちらはほぼ倍精度の理論値(62 Gflops)に近い値が出ています。

実際に計算中に裏でnvidia-smi -lコマンドを実行すれば,GPUの使用率やメモリ・電力の使用量などが目に見えて変わるはずです。

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 375.26                 Driver Version: 375.26                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 105...  Off  | 0000:01:00.0     Off |                  N/A |
|  0%   52C    P0    61W /  72W |   2383MiB /  4038MiB |    100%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0     13923    C   ...n/x86_64/linux/release/cdpLUDecomposition  2381MiB |
+-----------------------------------------------------------------------------+

それ,Dockerなら簡単だよ

いかがでしたでしょうか。なるべく丁寧に説明したので手順が多く感じるかもしれませんが,一度理解してしまえばそこまで難しくありません。とはいえaptコマンド一発」というほどお手軽ではないのも事実です。この先,複数のバージョンを併用したい場合もあるかもしれません。さらにCUDAをインストールするだけで終わるということはまずありません。たとえば深層学習向けのCUDAライブラリであるcuDNNをインストールするなら,さらにひと手間必要になります。

NVIDIAはCUDA環境を簡単に構築できるDockerfileを提供しています。そこで次回はDockerやLXDといったコンテナ上にCUDA環境を構築する方法について説明します。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。