55
CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 1 2016/6/27 20GPU コンピューティング 講習会

CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

  • Upload
    others

  • View
    28

  • Download
    0

Embed Size (px)

Citation preview

Page 1: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDA基礎1

東京工業大学 学術国際情報センター

黄 遠雄

1 2016/6/27 第20回 GPU コンピューティング 講習会

Page 2: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

ヘテロジニアス・コンピューティング

2

Financial Analysis

Scientific Simulation

Engineering Simulation

Data Intensive Analytics

Medical Imaging

Digital Audio Processing

Computer Vision

Digital Video Processing

Biomedical Informatics

Electronic Design

Automation

Statistical Modeling

Ray Tracing Rendering

Interactive Physics

Numerical Methods

ヘテロジニアス・コンピューティング(CPU + GPU)は広く使われている

2016/6/27 第20回 GPU コンピューティング 講習会

Page 3: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

GPUを用いてアプリケーションを高速化する 3つの方法

Applications

Libraries

Easy to use

Most Performance

Programming Languages

Most Performance

Most Flexibility

Easy to use

Portable code

Compiler Directives

2016/6/27 第20回 GPU コンピューティング 講習会 3

Page 4: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

GPU Accelerated Libraries

Linear Algebra FFT, BLAS,

SPARSE, Matrix

Numerical & Math RAND, Statistics

Data Struct. & AI Sort, Scan, Zero Sum

Visual Processing Image & Video

NVIDIA

cuFFT,

cuBLAS,

cuSPARSE

NVIDIA

Math

Lib

NVIDIA

cuRAND

NVIDIA

NPP

NVIDIA

Video

Encode

GPU AI –

Board

Games

GPU AI –

Path

Finding

2016/6/27 第20回 GPU コンピューティング 講習会 4

Page 5: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Compiler directives:OpenACC

• Compiler directives for C, C++, and FORTRAN

#pragma acc parallel loop copyin(input1[0:inputLength],input2[0:inputLength]), copyout(output[0:inputLength])

for(i = 0; i < inputLength; ++i) {

output[i] = input1[i] + input2[i];

}

2016/6/27 第20回 GPU コンピューティング 講習会 5

Page 6: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDA Fortran Fortran

CUDA C C

CUDA C++ C++

PyCUDA, Copperhead, Numba, NumbaPro Python

Alea.cuBase F#

MATLAB, Mathematica, LabVIEW Numerical analytics

GPU Programming Languages

2016/6/27 第20回 GPU コンピューティング 講習会 6

Page 7: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDA - C

Applications

Libraries

Easy to use

Most Performance

Programming Languages

Most Performance

Most Flexibility

Easy to use

Portable code

Compiler Directives

2016/6/27 第20回 GPU コンピューティング 講習会 7

Page 8: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CPUとGPU の違い

2016/6/27 第20回 GPU コンピューティング 講習会 8

• Small caches

– To boost memory throughput

• Simple control

– No branch prediction

– No data forwarding

• Energy efficient ALUs

– Many, long latency but heavily pipelined for high throughput

• Require massive number of threads to tolerate latencies

– Threading logic

– Thread state

DRAM

GPU

• Powerful ALU

– Reduced operation latency

• Large caches

– Convert long latency memory accesses to short latency cache accesses

• Sophisticated control

– Branch prediction for reduced branch latency

– Data forwarding for reduced data latency

Cache

ALU Control

ALU

ALU

ALU

DRAM

CPU

Page 9: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

DeviceQuery

9

./deviceQuery Starting...

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

Detected 3 CUDA Capable device(s)

Device 0: "Tesla K20Xm"

CUDA Driver Version / Runtime Version 7.5 / 7.5

CUDA Capability Major/Minor version number: 3.5

Total amount of global memory: 5760 MBytes (6039339008 bytes)

(14) Multiprocessors, (192) CUDA Cores/MP: 2688 CUDA Cores

GPU Max Clock rate: 732 MHz (0.73 GHz)

Memory Clock rate: 2600 Mhz

Memory Bus Width: 384-bit

L2 Cache Size: 1572864 bytes

Maximum Texture Dimension Size (x,y,z) 1D=(65536), 2D=(65536, 65536),

3D=(4096, 4096, 4096)

………

>./deviceQuery >sh runDeviceQuery.sh

2016/6/27 第20回 GPU コンピューティング 講習会

Page 10: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

並列処理

並列計算は、

タスク並列 と データ並列

に分けられる。

データ並列の一例:ベクトル加法

10 2016/6/27 第20回 GPU コンピューティング 講習会

A[0] vector A

vector B

vector C

A[1] A[2] A[N-1]

B[0] B[1] B[2]

… B[N-1]

C[0] C[1] C[2] C[N-1] …

+ + + +

Page 11: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

ベクトル加法(C Code)

//ベクトル加法関数 C = A + B void vecAdd(float *A_h, float *B_h, float *C_h, int n) { int i; for (i = 0; i<n; i++) C_h[i] = A_h[i] + B_h[i]; } int main() { // A、B、C メモリ確保 // A、B データ入力/初期化(N個) … vecAdd(A_h, B_h, C_h, N); }

2016/6/27 第20回 GPU コンピューティング 講習会 11

Page 12: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

GPUを用いたベクトル加法

void vecAdd(float *A_h, float *B_h, float *C_h, int n)‏ { int size = n* sizeof(float); float *A_d, *B_d, *C_d; // Part 1 // A、B、C GPU上のメモリ確保 // A、B のデータをhost memory から device // memory にコピー // Part 2 // Kernel code を実行 (ベクトルの加法) // Part 3 // 計算結果を回収 – C のデータをdevice // memory からhost memory にコピー // GPU上のメモリを解放 }

2016/6/27 第20回 GPU コンピューティング 講習会 12

CPU

Host Memory

GPU

Device Memory

Part 1

Part 3

Part 2

• GPUは単独では動かない。host(CPU)で実行させ、その中から CUDA API と GPU kernel 関数を call

Page 13: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDAプログラム実行の概念図

2016/6/27 第20回 GPU コンピューティング 講習会 13

host (CPU) code

メモリ・ポインタ

float *f_d, *f_h;

CUDA API cudaMalloc(&f_d);

. . . .

kernel function func<<< N/256, 256>>>(f_d)

cudaMemcpy(f_h, f_d);

host memory device memory

device code __global__

func(f_d) { }

GPU CPU

Page 14: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDAプログラムの実行モデル

• ヘテロジニアス(CPU + GPU)アプリケーション

–逐次処理はHost C Code

–並列計算はDevice SPMD kernel Code

2016/6/27 第20回 GPU コンピューティング 講習会 14

Serial Code (host)‏

. . .

. . .

Parallel Kernel (device)‏

KernelA<<< Dg, Db >>>(args);

Serial Code (host)‏

Parallel Kernel (device)‏

KernelB<<< Dg, Db >>>(args);

Page 15: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDA ソースコードのコンパイル

• CUDA のソースファイルは拡張子 .cu を付ける。

• CUDA Toolkit の nvcc でコンパイルする。

– nvcc はCPUで実行するコードと、GPUで実行する GPU kernel 関数のコード、CUDA のAPI の部分を分離。

– CPUで実行するコードは gcc, g++ などにコンパイルを任せる。GPU kernel 関数の部分を GPU 用にコンパイルする。GPU 用の PTX コードも生成する。

• Library をリンクして、 実行ファイルを生成する。

CUDA core library (cuda) -lcuda

CUDA runtime library (cudart) -lcudart

2016/6/27 第20回 GPU コンピューティング 講習会 15

Integrated C programs with CUDA extensions

NVCC Compiler

Host C Compiler/ Linker

Host Code Device Code (PTX)

Device Just-in-Time Compiler

Heterogeneous Computing Platform with CPUs, GPUs, etc.

Page 16: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDA Compiler: nvcc

• 重要なコンパイル・オプション

2016/6/27 第20回 GPU コンピューティング 講習会 16

-arch sm_52 Compute Capability に応じたコンパイルを行う。DeviceQuery で確認し、それ以下を指定す。 可能なオプション:sm_20(default), sm_21, sm_30, sm_32, sm_35, sm_50 and sm_52

--maxrregcount <N> 1つのkernel 関数当たりに使用するレジスタ数を <N> に制限する。このことにより、指定した並列数でthreadが実行可能となるが、溢れた部分はlocal メモリ上に置かれ、実行速度は低下する。

-use_fast_math 高速な数学関数を利用する。

-G device コードに対して、デバッグを可能にする

--ptxas-options=-v レジスタやメモリの使用状況を表示する

Page 17: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDA Memory 確保(1/3)

2016/6/27 第20回 GPU コンピューティング 講習会 17

メモリ・ポインタ-は、device (GPU) memory にも host (CPU) memory にも使える。 例) 単精度実数: float *f_d, *f_h;

device 上にメモリを確保する runtime API

cudaMalloc(void **devptr, size_t count);

devptr: デバイスメモリアドレスへのポインタ。 確保したメモリのアドレスが書き込まれる

count: 領域のサイズ

例) cudaMalloc((void **)&f_d, sizeof(float)*n);

f_d[n] の配列が GPU のメモリ上に確保される

Page 18: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDA Memory 確保(2/3)

18

host 側にメモリを確保する(通常) f_h = (float *) malloc(sizeof(float)*n); f_h = new float[n]; (C++)

host 側にpinned メモリを確保する

cudaMallocHost(void **ptr, size_t count); ptr: ホストメモリアドレスへのポインタ。 Page lock (pinned)された確保したメモリのアドレスが書き込まれる count: 領域のサイズ

例) cudaMallocHost((void **)&f_h, sizeof(float)*n);

f_h[n] の配列が Host メモリ上にpage lock (pinned)で確保さ

れる。通常の pageable メモリとして確保された場合より、転送 速度が速い。また、非同期通信の場合も page lock メモリに限 定される。

2016/6/27 第20回 GPU コンピューティング 講習会

Page 19: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDA Memory 確保(3/3)

19

host 側にメモリを確保する(通常) f_h = (float *) malloc(sizeof(float)*n); f_h = new float[n]; (C++)

host 側に確保したメモリを page-lock(pinned)にする

cudaHostRegister(void *ptr, size_t count, unsigned int flags);

ptr: ホストメモリアドレスへのポインタ。 count: 領域のサイズ

flags: タイプを指定する定数 cudaHostRegisterDefault cudaHostRegisterPortable cudaHostRegisterMapped cudaHostRegisterIoMemory

解除するには cudaHostUnregister(void *ptr);

2016/6/27 第20回 GPU コンピューティング 講習会

Page 20: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDA データ転送

20

float *f_d, *f_h;

cudaMemcpy(void *dst, const void *src, size_t count, enum cudaMemcpyKind kind)

dst: 転送先メモリ・アドレス

src: 転送元メモリ・アドレス count: 領域のサイズ kind: 転送タイプを指定する定数 cudaMemcpyHostToDevice cudaMemcpyDeviceToHost cudaMemcpyDeviceToDevice cudaMemcpyDefault (Fermi GPU, CUDA 4.0 以降)

例) cudaMemcpy (f_d, f_h, sizeof(float)*n, cudaMemcpyHostToDevice); host上のf_h[n] の配列のデータをdevice上のf_d[n] にコピーする。

2016/6/27 第20回 GPU コンピューティング 講習会

Page 21: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

CUDA 非同期データ転送

21

float *f_d, *f_h;

cudaMemcpyAsync(void *dst, const void *src, size_t count, enum cudaMemcpyKind kind, cudaStream_t stream)

dst: 転送先メモリ・アドレス

src: 転送元メモリ・アドレス count: 領域のサイズ kind: 転送タイプを指定する定数 cudaMemcpyHostToHost cudaMemcpyHostToDevice cudaMemcpyDeviceToHost cudaMemcpyDeviceToDevice

例) cudaMemcpyAsync (f_d, f_h, sizeof(float)*n, cudaMemcpyHostToDevice, stream);

Host上のf_h[n] の配列のデータをDevice上のf_d[n] にHostや

他のstream(後述)に対して非同期でコピーする。 2016/6/27 第20回 GPU コンピューティング 講習会

Page 22: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

GPU kernel-function call

22

host code の中で次のように call する。

kernel_function<<< Dg, Db, Ns, S>>>(a, b, c, . . . .); Dg: dim3 タイプの grid のサイズ指定

Db: dim3 タイプの block のサイズ指定 Ns: 実行時に指定する shared メモリのサイズ 省略可: 省略した場合は、0 が設定 S: 非同期実行の stream 番号 省略可: 省略した場合は、0 が設定され、 同じ 0 に設定された GPUのkernelが同期実行となる

Dg, Db で指定される数の thread が実行される。

kernel function の実行は、CPU に対して絶えず非同期。

2016/6/27 第20回 GPU コンピューティング 講習会

Page 23: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

dim3 宣言

23

kernel_function<<< Dg, Db, Ns, S>>>(a, b, c, . . . .);

の Dg, Db を dim3 で指定する。

dim3 a;

dim3 a(n, m);

dim3 a(n, m, k);

dim3 a(1,1,1);

dim3 a(n, m, 1);

a.x = n; a.y = m; a.z = k;

等価

等価

等価

dim3 a(n0, m0, k0); は宣言と共に値の代入であり、

随時 a.x = n1; a.y = m1; a.z = k1; と変更可能である。

2016/6/27 第20回 GPU コンピューティング 講習会

Page 24: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Threadの管理

• CUDA Kernel はthreads の まとまり(Grid)単位で実行される – Gridの中の全てのthreadsは同じ Kernel を実行する(Single Program

Multiple Data)

– Threadは各自にIDの持っている

2016/6/27 第20回 GPU コンピューティング 講習会 24

i = blockIdx.x * blockDim.x + threadIdx.x; C[i] = A[i] + B[i];

0 1 2 254 255

Page 25: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Threadの管理(Block)

• いくつかのthreadsが一つのBlockとしてまとめられ、全てthreadsが複数のBlockに分割されます。 – 同一Block内のthreadsはshared memoryを共有し atomic operations と barrier synchronizationなど同期が必要な演算を実行できます

– 異なるBlock間のthreads同期やshared memoryの共有はできません

2016/6/27 第20回 GPU コンピューティング 講習会 25

i = blockIdx.x * blockDim.x + threadIdx.x;

C[i] = A[i] + B[i];

… 0 1 2 254 255

Thread Block 0

… 1 2 254 255

Thread Block 1

0

i = blockIdx.x * blockDim.x + threadIdx.x;

C[i] = A[i] + B[i];

… 1 2 254 255

Thread Block N-1

0

i = blockIdx.x * blockDim.x + threadIdx.x;

C[i] = A[i] + B[i];

… … …

Page 26: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

blockIdx と threadIdx

• kernel 関数<<< 第1引数, 第2引数>>>で指定 – 第1引数:blockIdx: 1D, 2D, or 3D (CUDA 4.0以降)の範囲を指定

– 第2引数:threadIdx: 1D, 2D, or 3Dの範囲を指定

• 多次元データを計算する 場合にアドレス計算が 簡単になる – Image processing

– Solving PDEs on volumes

– …

26

device

Grid Block (0, 0)

Block (1, 1) Block (1, 0)

Block (0, 1)

Block (1,1)

Thread (0,0,0) Thread

(0,1,3) Thread (0,1,0)

Thread (0,1,1)

Thread (0,1,2)

Thread (0,0,0)

Thread (0,0,1)

Thread (0,0,2)

Thread (0,0,3)

(1,0,0) (1,0,1) (1,0,2) (1,0,3)

2016/6/27 第20回 GPU コンピューティング 講習会

Page 27: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

実習:最初のCUDAプログラム

• >nvcc HelloWorld.cu

• >./a.out

2016/6/27 第20回 GPU コンピューティング 講習会 27

#include <stdio.h> __global__ void helloWorld_kernel( void ) { printf("Hello from GPU [thread %d of block %d]¥n", threadIdx.x, blockIdx.x); printf("Good bye from GPU [thread %d of block %d]¥n", threadIdx.x, blockIdx.x); } int main(int argc, char *argv[]) { printf("Hello from CPU¥n"); helloWorld_kernel<<< 256, 1 >>>(); cudaDeviceSynchronize(); printf("Good bye from CPU¥n"); return 0; }

Sample Code: simpleCUDA/HelloWorld

Page 28: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Built-in 変数

• Device code の中で宣言せずに引用でき、 書き換え不可

gridDim gridDim.x, gridDim.y, gridDim.z

grid の各方向のサイズ

blockIdx blockIdx.x, blockIdx.y, blockIdx.z

block の各方向のindex

blockDim blockDim.x, blockDim.y, blockDim.z

block の各方向のサイズ

threadIdx threadIdx.x, threadIdx.y, threadIdx.z

thread の各方向のindex

28 2016/6/27 第20回 GPU コンピューティング 講習会

Page 29: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

C言語の拡張

• 関数型の Qualifier __global__ device 上でのみ実行される host 側からのみ call される

return 値は void 限定

__device__ device 上でのみ実行される device からのみ call される

__host__ host 上でのみ実行される host 側からのみ call される (普通の CPU 上のプログラムの関数 で、特に宣言する必要はない。) __host__ と __device__ 両方同時に指定する事が可能

29 2016/6/27 第20回 GPU コンピューティング 講習会

host host __host__ float HostFunc()‏

host device __global__ void KernelFunc()‏

device device __device__ float DeviceFunc()‏

Only callable from the: Executed on the:

Page 30: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

__host__ と __device__

2016/6/27 第20回 GPU コンピューティング 講習会 30

CPU for(……..) { …… Cal_func(…); …… }

GPU __global__ kernel(….) { …… Cal_func(…); …… }

__host__ __devcie__ void Cal_func(……..) { C = A + B; }

Page 31: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

ベクトル加法(Host Code)

void vecAdd(float *A_h, float *B_h, float *C_h, int n)‏ { int size = n* sizeof(float); float *A_d, *B_d, *C_d; // Part 1: A、B、C GPU上のメモリ確保 cudaMalloc( (void**) &A_d, size ); cudaMalloc( (void**) &B_d, size ); cudaMalloc( (void**) &C_d, size ); // Part 1: A、B のデータをhost memory から device memory にコピー cudaMemcpy( A_d, A_h, size, cudaMemcpyHostToDevice ); cudaMemcpy( B_d, B_h, size, cudaMemcpyHostToDevice ); // Part 2: Kernel code を実行 (ベクトルの加法) vectorAdd_kernel<<< n / BLOCK_SIZE, BLOCK_SIZE >>>( C_d, A_d, B_d ); // Part 3: 計算結果を回収 – C のデータをdevice memory からhost memory にコピー cudaMemcpy( c_h, c_d, size, cudaMemcpyDeviceToHost ) // Part 3: GPU上のメモリを解放 cudaFree( A_d ); cudaFree( B_d ); cudaFree( C_d ); }

2016/6/27 第20回 GPU コンピューティング 講習会 31

Page 32: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

ベクトル加法(Device Kernel)

__global__ void vectorAdd_kernel

(

float *C, // array pointer of the global memory

float *A, // array pointer of the global memory

float *B // array pointer of the global memory

)

{

unsigned int index = blockIdx.x * blockDim.x + threadIdx.x;

C[index] = A[index] + B[index];

}

2016/6/27 第20回 GPU コンピューティング 講習会 32

vectorAdd_kernel<<< n / BLOCK_SIZE, BLOCK_SIZE >>>( C_d, A_d, B_d );

gridDimの値とblockIdx の値の範囲を決めます

blockDimの値とthreadIdx の値の範囲を決めます

Sample Code: simpleCUDA/simpleVectorAdd

Page 33: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

2次元データ・アクセス NX*NYの1次元配列データであるが、2次元的にアクセス

NX

NY

blockDim.x = 16

dim3 grid(NX/16, NY/16), block(16, 16);

iy

ix gridサイズの最大値の制限から開放

ix = blockIdx.x * blockDim.x + threadIdx.x; iy = blockIdx.x * blockDim.x + threadIdx.x; index = iy * NX + ix;

2016/6/27 第20回 GPU コンピューティング 講習会

Page 34: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Warp スケジューリング

• block 内の thread は Streaming Multiprocessor によって

Warp=32 thread毎に並列実行される – Warp: block 内の32 threadのかたまり (例:block 内に 256 thread = Warp 8 個)

– 1 Warp の thread の数は将来変わる可能性がある。 – プログラム上には現れない – 考慮しなくても正しいプログラムを書くことは可能。ただし、実行性能を引き出すためには考慮する必要がある。

34 2016/6/27 第20回 GPU コンピューティング 講習会

t0 t1 t2 … t31

t0 t1 t2 … t31

… Block 1 Warps Block 2 Warps

t0 t1 t2 … t31

… Block 3 Warps

Page 35: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Warp 多次元分配

• 多次元Thread blocksの場合、Warpは行優先で割り当てられる – 最初X、それからY、最後はZ

35 2016/6/27 第20回 GPU コンピューティング 講習会

Page 36: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Compute Capability

36

Compute Capability

Technical Specifications 2.x 3.0 3.2 3.5 3.7 5.0 5.2 5.3

Warp size 32

Maximum number of resident blocks per multiprocessor

8 16 32

Maximum number of resident warps per multiprocessor

48 64

Maximum number of resident threads per multiprocessor

1536 2048 (= 64 x 32)

Number of 32-bit registers per multiprocessor 32 K 64 K 128 K 64 K

Maximum number of 32-bit registers per thread block 32 K 64 K 32 K

Maximum number of 32-bit registers per thread 63 255

Maximum amount of shared memory per multiprocessor

48 KB 112 KB 64 KB 96 KB 64 KB

Maximum amount of shared memory per thread block

48 KB

Number of shared memory banks 32

Amount of local memory per thread 512 KB

Constant memory size 64 KB

2016/6/27 第20回 GPU コンピューティング 講習会

Page 37: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

同時実行可能なthread block数

37

thread の 使用する Register 数: Nr Shared Memory 量: Ns [byte] block 当たりの thread 数: Db Compute Capability 5.2 (Maxwell世代GPU)の場合:

Active block = Min(32, 64/(Db/32), 98304/Ns, 65536/(Db*Nr) )

Warp per SM = Db/32

(block当たりの最大64 Warp)

(Shared Memory の制限)

(Register の制限)

2016/6/27 第20回 GPU コンピューティング 講習会

Page 38: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Warp内のthread実行仕組み

• Warp 内の32 thread は同一命令を実行 SIMD (Single Instruction Multiple Data)

– Warp 内の thread indices はインクリメント

– Warp 0 は thread 0 からスタート

• Warps 実行される順番は一定ではない

–例えばWarp 8がWarp 7より先に実行される場合がある

– Threads の間の依存関係(計算順序など)は必ず__syncthreads()を使う

38 2016/6/27 第20回 GPU コンピューティング 講習会

Page 39: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Threadの中の条件分岐

• プログラム上では任意の分岐を記述可能。

• ハードウェア上での分岐命令の処理

– Warp内全threadが同一パスに分岐する場合 は 全threadが分岐先(のみ)を実行する。

– Warp内のthreadが異なるパスに分岐する場合は全スレッドが両方の命令を実行 (diverged branch)し、最後に適合する方だけを採用する。性能低下の原因の一つ。

2016/6/27 第20回 GPU コンピューティング 講習会 39

Page 40: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Control Divergence

• Warp内に条件分岐やループの違いがある場合、 Control Divergenceが発生する

• Control Divergenceが発生しないようにするには、 Warp内で – 全ての if-then-else で同じ条件分岐とする – 全てのループの反復回数を同じとする

• Control Divergenceが発生する場合の例:

– If ( threadIdx.x > 2 ) { do_something(); }

else{ do_other_thing(); }

– Thread ID によって違い操作 – 分岐単位 < warp size

• Control Divergenceが発生しない場合の例:

– If ( blockIdx.x > 2 ) ) { do_something(); }

else{ do_other_thing(); }

– block ID によって違い操作 – 分岐単位は block = warp size の倍数

2016/6/27 第20回 GPU コンピューティング 講習会 40

Page 41: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

例: Vector Addition Kernel

// Compute vector sum C = A + B

// Each thread performs one pair-wise addition

__global__

void vectorAdd_Kernel(float* C, float* A, float* B, int n)

{

int i = threadIdx.x + blockDim.x * blockIdx.x;

if(i<n) C[i] = A[i] + B[i];

}

41

Device Code

2016/6/27 第20回 GPU コンピューティング 講習会

Page 42: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Vector size (n=1,000)で計算すると

• BLOCK_SIZE = 256に設定 – 8 warps per block

• Block 0, 1, 2 の全てのThreadsは範囲内 – i = 0 ~ 767 – 全て i < 1000

• Block 3 の多くのWarpsはControl Divergenceが発生しない – 6 warps は(i < 1000)の範囲内

• Block 3 の中の一つのWarpはControl Divergenceが発生する – Thread ID 992 ~ 999は範囲内 – Thread ID 1000 ~ 1023は範囲外

• この例ではControl Divergenceの影響は少ない – 1/32 warp はControl Divergenceが発生する – 性能に影響は 3% 以下

2016/6/27 第20回 GPU コンピューティング 講習会 42

Page 43: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Memory Coalescing

• 一つのwarpの中の全ての threads が一斉に データをロード。全てのデータアクセスが同じburst sectionの場合、 一回のDRAM request のみで終了する。(fully coalesced)

43

2 1 0 3 5 4 6 7 9 8 10 11 13 12 14 15

Burst section Burst section Burst section Burst section

T0 T1 T2 T3

Coalesced Loads

T0 T1 T2 T3

Coalesced Loads

2016/6/27 第20回 GPU コンピューティング 講習会

Page 44: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Un-coalesced Accesses

• データアクセスが別々のburst sectionになる場合: – Coalescing fails – 何回かの DRAM requests が必要 – アクセスは not fully coalesced

• 一部の転送されたデータは使われない

44

2 1 0 3 5 4 6 7 9 8 10 11 13 12 14 15

Burst section Burst section Burst section Burst section

T0 T1 T2 T3

Un-coalesced Loads

T0 T1 T2 T3

Un-coalesced Loads

2016/6/27 第20回 GPU コンピューティング 講習会

Page 45: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

例:行列の乗法のアクセスパターン

A B

WIDTH

(Thread) T1

(Thread) T2

A[Row*n+i] B[i*k+Col] i はループの変数 A は m × n, B は n × k のマトリックス

Col = blockIdx.x*blockDim.x + threadIdx.x

HEI

GH

T

T1 T2

M0,2

M1,1

M0,1 M0,0

M1,0

M0,3

M1,2 M1,3

M0,2 M0,1 M0,0 M0,3 M1,1 M1,0 M1,2 M1,3 M2,1 M2,0 M2,2 M2,3

M2,1 M2,0 M2,2 M2,3

M3,1 M3,0 M3,2 M3,3

M3,1 M3,0 M3,2 M3,3

M

linearized order in increasing address

2016/6/27 第20回 GPU コンピューティング 講習会 45

Page 46: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

A Accesses are Not Coalesced

T0 T1 T2 T3

Load iteration 0

T0 T1 T2 T3

Load iteration 1

Access

direction in

kernel code

A0,2

A1,1

A0,1 A0,0

A1,0

A0,3

A1,2 A1,3

A2,1 A2,0 A2,2 A2,3

A3,1 A3,0 A3,2 A3,3

A0,2 A0,1 A0,0 A0,3 A1,1 A1,0 A1,2 A1,3 A2,1 A2,0 A2,2 A2,3 A3,1 A3,0 A3,2 A3,3

2016/6/27 第20回 GPU コンピューティング 講習会 46

Page 47: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

B accesses are coalesced

N

T0 T1 T2 T3

Load iteration 0

T0 T1 T2 T3

Load iteration 1

Access

direction in

kernel code

B0,2

B1,1

B0,1 B0,0

B1,0

B0,3

B1,2 B1,3

B2,1 B2,0 B2,2 B2,3

B3,1 B3,0 B3,2 B3,3

B0,2 B0,1 B0,0 B0,3 B1,1 B1,0 B1,2 B1,3 B2,1 B2,0 B2,2 B2,3 B3,1 B3,0 B3,2 B3,3

2016/6/27 第20回 GPU コンピューティング 講習会 47

Page 48: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

所要時間計測

48

経過時間を計測することで、GPU Computing のパフォーマン

スを確認でき、ハードウェア実行の様子を想像することができる。また、チューニングのためには必須。

cudaEvent_t start, stop; cudaEventCreate(&start); cudaEventCreate(&stop); float elapsedTime;

cudaEventRecord(start,0);

kernel<<< grid, block>>>(a_d, b_d);

cudaEventRecord(stop,0); cudaEventSynchronize(stop); cudaEventElapsedTime(&elapsedTime,start,stop);

elapsedTime に 経過時間 (msec)

計測範囲

2016/6/27 第20回 GPU コンピューティング 講習会

Page 49: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

エラー処理(API)

• CUDA の API は全て return 値が cudaError_t 型の error の status を返すようになっている。

• もし、cudaMalloc しないで、cudaMemcpy(); を実行してしまった場合などは、invalid device pointer が返ってくる。

2016/6/27 第20回 GPU コンピューティング 講習会 49

cudaError_t err = cudaMemcpy(…); if (err != cudaSuccess) { fprintf(stderr, “Memcopy failed: %s.¥n”, cudaGetErrorString(err)); }

Page 50: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

エラー処理( kernel関数)

50

kernel 関数には return 値はない。 cudaGetLastError() で直前のエラーを拾い、cudaGetErrorString() でメッセージを表示させる。

vec_add<<< , , , >>>(. . . ); cudaError_t err = cudaGetLastError(); if (err != cudaSuccess) { fprintf(stderr, “kernel launch failed: %s¥n”, cudaGetErrorString(err)); exit(-1); }

例えばgrid, blockのサイズが最大値を超えていると、 invalid configuration argument が表示される。

2016/6/27 第20回 GPU コンピューティング 講習会

Page 51: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Device マネージメントAPI

51

Device の情報を取得する API が準備されている。

cudaGetDeviceCount(int *count) システム(ノード)上のCUDAの動作するGPUの個数を返す。

cudaSetDevice(int device_no) それ以降の実行を device_no の GPU に向ける。

cudaGetDevice(int *current_device) 現在指定されている GPU の device 番号を返す。

cudaGetDeviceProperties(int *device, cudaDeviceProp *prop) deviceQueryのような情報を prop のメンバーとして取得

Tips: これらは、同一ノード内に複数GPUがある場合は必須。 2016/6/27 第20回 GPU コンピューティング 講習会

Page 52: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Developer Tools - Debuggers

NSIGHT CUDA-GDB CUDA MEMCHECK

3rd Party

NVIDIA Provided

https://developer.nvidia.com/debugging-solutions

2016/6/27 第20回 GPU コンピューティング 講習会 52

Page 53: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

Developer Tools - Profilers

NSIGHT NVVP NVPROF

3rd Party

NVIDIA Provided

https://developer.nvidia.com/performance-analysis-tools

VampirTrace TAU

2016/6/27 第20回 GPU コンピューティング 講習会 53

Page 54: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

NVIDIA’s Visual Profiler (NVVP) Timeline

Guided

System Analysis

2016/6/27 第20回 GPU コンピューティング 講習会 54

Page 55: CUDA基礎1 - 東京工業大学...CUDA基礎1 東京工業大学 学術国際情報センター 黄 遠雄 2016/6/27 第20回 GPU コンピューティング 講習会 1ヘテロジニアス・コンピューティング

IDE(NSIGHT)

• CUDA enabled Integrated Development Environment – Source code editor: syntax highlighting, code refactoring, etc – Build Manger – Visual Debugger – Visual Profiler

• Linux/Macintosh – Editor = Eclipse – Debugger = cuda-gdb with a visual wrapper – Profiler = NVVP

• Windows – Integrates directly into Visual Studio – Profiler is NSIGHT VSE

2016/6/27 第20回 GPU コンピューティング 講習会 55