CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU...

92
Akira Naruse, 23 th June. 2016 CUDAOpenACCによる GPUコンピューティング

Transcript of CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU...

Page 1: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

Akira Naruse, 23th June. 2016

CUDA・OpenACCによる GPUコンピューティング

Page 2: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

2

GPUコンピューティング Low latency + High throughput

CPU GPU

Page 3: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

3

アプリケーション実行

アプリケーション・コード

GPU CPU

並列部分は GPUで実行

計算の 重い部分

逐次部分は CPU上で実行

Do i=1,N

End do

Page 4: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

4

CUDA CoreDispatch Port

Result Queue

ALU

Operand CollectorDispatch Port

SM

Interconnect Network

64 KB Shared Memory / L1 Cache

Uniform Cache

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

SFU

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Core

Instruction Cache

Register File (65,536 x 32-bit)

Warp Scheduler

Dispatch Unit Dispatch Unit

Warp Scheduler

Dispatch Unit Dispatch Unit

Warp Scheduler

Dispatch Unit Dispatch Unit

Warp Scheduler

Dispatch Unit Dispatch Unit

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

LD/ST

GPUの構造(TESLA K40)

Tesla K40, 15 SM/chip

192 CUDA core/SM

大量のCUDAコア 並列性の抽出が鍵

Page 5: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

5

GPUアプリケーション

数百のアプリケーションがGPUに対応www.nvidia.com/object/gpu-applications.html

Page 6: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

6

アプリをGPU対応する方法

Application

Library

GPU対応ライブラリにチェンジ

簡単に開始

CUDA OpenACC

主要処理をCUDAで記述

高い自由度 既存コードにディレクティブを挿入

簡単に加速

Page 7: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

7

GPU対応のライブラリ (一部)

NVIDIA cuBLAS NVIDIA cuRAND

NVIDIA cuSPARSE Vector Signal

Image Processing GPU Accelerated Linear Algebra

NVIDIA cuFFT

C++ STL Features for CUDA

Sparse Linear Algebra IMSL Library

Matrix Algebra on GPU and Multicore

NVIDIA cuDNN

NVIDIA AmgX

Page 8: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

8

CUDA計算ライブラリ

高性能な計算ライブラリを提供 cuDNN ディープラーニング向けライブラリ cuBLAS BLASライブラリ cuFFT Fast Fourier Transformsライブラリ cuRAND 乱数生成ライブラリ cuSPARSE 疎行列ライブラリ cuSOLVER Lapackライブラリの一部 Thrust 並列アルゴリズム C++ STL

CUDAツールキットに標準搭載 (一部、デベロッパー登録必要)

developer.nvidia.com/cuda-downloads

Page 9: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

9

アプリをGPU対応する方法

Application

Library

GPU対応ライブラリにチェンジ

簡単に開始

CUDA OpenACC

主要処理をCUDAで記述

高い自由度 既存コードにディレクティブを挿入

簡単に加速

Page 10: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

10

__global__ void saxpy(int n, float a, float *x, float *y) { int i = threadIdx.x + blodkDim.x * blockIdx; if (i < n) y[i] += a*x[i]; } ... size_t size = sizeof(float) * N; cudaMemcpy(d_x, x, size, cudaMemcpyHostToDevice); cudaMemcpy(d_y, y, size, cudaMemcpyHostToDevice); saxpy<<< N/128, 128 >>>(N, 3.0, d_x, d_y); cudaMemcpy(y, d_y, size, cudaMemcpyDeviceToHost); ...

SAXPY (Y=A*X+Y) CPU CUDA

void saxpy(int n, float a, float *x, float *y) { for (int i = 0; i < n; ++i) y[i] += a*x[i]; } ... saxpy(N, 3.0, x, y); ...

Page 11: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

11

アプリをGPU対応する方法

Application

Library

GPU対応ライブラリにチェンジ

簡単に開始

CUDA OpenACC

主要処理をCUDAで記述

高い自由度 既存コードにディレクティブを挿入

簡単に加速

Page 12: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

12

void saxpy(int n, float a, float *x, float *restrict y) { #pragma acc parallel copy(y[:n]) copyin(x[:n]) for (int i = 0; i < n; ++i) y[i] += a*x[i]; } ... saxpy(N, 3.0, x, y); ...

SAXPY (Y=A*X+Y)

OpenMP OpenACC

void saxpy(int n, float a, float *x, float *restrict y) { #pragma omp parallel for for (int i = 0; i < n; ++i) y[i] += a*x[i]; } ... saxpy(N, 3.0, x, y); ...

Page 13: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

13

CUDAプログラミング

プログラミングモデル

アーキテクチャ

性能Tips

Page 14: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

14

GPUコンピューティング

高スループット指向のプロセッサ 分離されたメモリ空間

GPU Memory CPU Memory

PCI

CPU GPU

Page 15: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

15

GPUプログラム

__global__ void saxpy(int n, float a, float *x, float *y) { int i = threadIdx.x + blodkDim.x * blockIdx; if (i < n) y[i] += a*x[i]; } ... size_t size = sizeof(float) * N; cudaMemcpy(d_x, x, size, cudaMemcpyHostToDevice); cudaMemcpy(d_y, y, size, cudaMemcpyHostToDevice); saxpy<<< N/128, 128 >>>(N, 3.0, d_x, d_y); cudaDeviceSynchronize(); cudaMemcpy(y, d_y, size, cudaMemcpyDeviceToHost); ...

void saxpy(int n, float a, float *x, float *y) { for (int i = 0; i < n; ++i) y[i] += a*x[i]; } ... saxpy(N, 3.0, x, y); ...

CPU GPU

Page 16: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

16

GPU実行の基本的な流れ

GPUは、CPUからの制御で動作

入力データ: CPUからGPUに転送 (H2D)

GPUカーネル: CPUから投入 出力データ: GPUからCPUに転送 (D2H)

CPU GPU 入力データ 転送

GPUカーネル 投入

同期

出力データ 転送

GPU上で 演算

Page 17: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

17

GPUプログラム

__global__ void saxpy(int n, float a, float *x, float *y) { int i = threadIdx.x + blodkDim.x * blockIdx; if (i < n) y[i] += a*x[i]; } ... size_t size = sizeof(float) * N; cudaMemcpy(d_x, x, size, cudaMemcpyHostToDevice); cudaMemcpy(d_y, y, size, cudaMemcpyHostToDevice); saxpy<<< N/128, 128 >>>(N, 3.0, d_x, d_y); cudaDeviceSynchronize(); cudaMemcpy(y, d_y, size, cudaMemcpyDeviceToHost); ...

void saxpy(int n, float a, float *x, float *y) { for (int i = 0; i < n; ++i) y[i] += a*x[i]; } ... saxpy(N, 3.0, x, y); ...

CPU GPU

入力データ転送

カーネル起動

同期

出力データ転送

Page 18: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

18

GPUプログラム (Unified Memory)

__global__ void saxpy(int n, float a, float *x, float *y) { int i = threadIdx.x + blodkDim.x * blockIdx; if (i < n) y[i] += a*x[i]; } ... saxpy<<< N/128, 128 >>>(N, 3.0, x, y); cudaDeviceSynchronize(); ...

void saxpy(int n, float a, float *x, float *y) { for (int i = 0; i < n; ++i) y[i] += a*x[i]; } ... saxpy(N, 3.0, x, y); ...

CPU GPU

カーネル起動

同期

Page 19: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

19

GPUカーネル

GPUカーネル: 1つのGPUスレッドの処理内容を記述 基本: 1つのGPUスレッドが、1つの配列要素を担当

__global__ void saxpy(int n, float a, float *x, float *y) { int i = threadIdx.x + blodkDim.x * blockIdx.x; if (i < n) y[i] += a*x[i]; } ... saxpy<<< N/128, 128 >>>(N, 3.0, d_x, d_y); ...

void saxpy(int n, float a, float *x, float *y) { for (int i = 0; i < n; ++i) y[i] += a*x[i]; } ... saxpy(N, 3.0, x, y); ...

CPU GPU

Global スレッドID

Page 20: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

20

Execution Configuration (ブロック数とブロックサイズ)

__global__ void saxpy(int n, float a, float *x, float *y) { int i = threadIdx.x + blodkDim.x * blockIdx.x; if (i < n) y[i] += a*x[i]; } ... saxpy<<< N/128, 128 >>>(N, 3.0, d_x, d_y); ...

ブロック数 ブロックサイズ

ブロック数 x ブロックサイズ = 配列要素数

スレッドID ブロックID

ブロックサイズ

Page 21: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

21

スレッド階層 (スレッド、ブロック、グリッド)

グリッド

x[] 0 127 128 255

y[] 0 127 128 255

y[i] = a*x[i] + y[i]

256 383 384

256 383 384

ブロック2 ブロック1 ブロック0 スレッド

(global) 0 127 128 255 256 383 384

ブロックサイズ(スレッド数/ブロック)は、カーネル毎に設定可能 推奨: 128 or 256 スレッド

スレッド (local)

0 127 0 127 0 127 0

Page 22: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

22

Execution Configuration (ブロック数とブロックサイズ)

__global__ void saxpy(int n, float a, float *x, float *y) { int i = threadIdx.x + blodkDim.x * blockIdx.x; if (i < n) y[i] += a*x[i]; } ... saxpy<<< N/128, 128 >>>(N, 3.0, d_x, d_y); ...

ブロック数 ブロックサイズ

ブロック数 x ブロックサイズ = 配列要素数

N/ 64, 64 N/256, 256

Page 23: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

23

2D配列のGPUカーネル例

ブロックサイズ(ブロック形状)は、1D~3Dで表現可能

__global__ void MatAdd(float A[N][N], float B[N][N], float C[N][N]) { int i = threadIdx.x + blodkDim.x * blockIdx.x; int j = threadIdx.y + blodkDim.y * blockIdy.y; if ( i < N && j < N ) C[i][i] = A[i][j] + B[i][j]; } ... dim3 sizeBlock( 16, 16 ); dim3 numBlocks( N/sizeBlock.x, N/sizeBlock.y ); MatAdd<<< numBlocks, sizeBlock >>>(A, B, C); ...

32, 8 64, 4

Globalスレッド ID (x)

GlobalスレッドID (y)

ブロックサイズ (x,y)

ブロック数 (x,y)

Page 24: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

24

ブロック・マッピング、スレッド・マッピング dim3 sizeBlock(16,16)

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

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

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

ブロックID(blockIdx)

dim3 sizeBlock(32,8)

(0,0) (1,0)

(0,1) (1,1)

(0,2) (1,2)

(0,3) (1,3)

(0,4) (1,4)

(0,0)

(15,15)

(0,0)

(31,7)

スレッドID(threadIdx)

Page 25: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

28

CUDAプログラミング

プログラミングモデル

アーキテクチャ

性能Tips

Page 26: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

29

GPUアーキテクチャ概要

PCI I/F ホスト接続インタフェース

Giga Thread Engine SMに処理を割り振るスケジューラ

DRAM I/F (GDDR5, 384-bit) 全SM、PCI I/Fからアクセス可能なメモリ (デバイスメモリ, フレームバッファ)

L2 cache (3MB) 全SMからアクセス可能なR/Wキャッシュ

SM (Streaming Multiprocessor) 「並列」プロセッサ、Maxwell:最多24

Maxwell GM200

Page 27: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

30

SM (Stream Multi-Processor) CUDAコア

GPUスレッドはこの上で動作 Maxwell: 128個

Other units LD/ST, SFU, etc

レジスタ(32bit): 64K個 共有メモリ: 96KB Tex/L1キャッシュ

Maxwell GM200

Page 28: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

31

GPUカーネル実行の流れ

CPUが、GPUに、グリッドを投入 具体的な投入先は、Giga Thread Engine

グリッド

ブロック

ブロック

スレッド

スレッド

Page 29: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

32

GPUカーネル実行の流れ

Giga Thread Engine(GTE)が、SMに、ブロックを投入 GTEは、ブロックスケジューラ グリッドをブロックに分解して、ブロックを、空いているSMに割当てる

グリッド

ブロック

ブロック

スレッド

スレッド

Page 30: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

33

ブロックをSMに割り当て 各ブロックは、互いに独立に実行

ブロック間では同期しない、実行順序の保証なし 1つのブロックは複数SMにまたがらない

1つのSMに、複数ブロックが割当てられることはある

グリッド

ブロック

ブロック

ブロック

ブロック

Page 31: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

34

GPUカーネル実行の流れ

SM内のスケジューラが、スレッドをCUDAコアに投入

グリッド

ブロック

ブロック

スレッド

スレッド

Page 32: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

35

GPUカーネル実行の流れ

SM内のスケジューラが、ワープをCUDAコアに投入 ワープ: 32スレッドの塊 ブロックをワープに分割、実行可能なワープを、空CUDAコアに割当てる

グリッド

ブロック

ブロック

ワープ

ワープ

Page 33: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

36

ワープのCUDAコアへの割り当て

ワープ内の32スレッドは、同じ命令を同期して実行 各ワープは、互いに独立して実行

同じブロック内のワープは、明示的に同期可能(__syncthreads())

グリッド

ブロック

ブロック

ワープ

ワープ

ワープ

SIMT (Single Instruction Multiple Threads)

ワープ

Page 34: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

37

GPUアーキの変化を問題としないプログラミングモデル

Kepler, CC 3.5 192 cores /SM

Pascal, CC 6.0 64 cores /SM

Maxwell, CC 5.0 128 cores /SM

Page 35: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

42

CUDAプログラミング

プログラミングモデル

アーキテクチャ

性能Tips

Page 36: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

43

リソース使用率 (Occupancy)

SMの利用効率を上げる ≒ SMに割当て可能なスレッド数を、 上限に近づける

レジスタ使用量(/スレッド)

できる限り減らす DP(64bit)は、2レジスタ消費 レジスタ割り当て単位は8個

レジスタ使用量と、割当て可能なスレッド数の関係 32レジスタ: 2048(100%), 64レジスタ: 1024(50%) 128レジスタ:512(25%), 256レジスタ: 256(12.5%)

CUDAコア数: 128 最大スレッド数: 2048 最大ブロック数: 32 共有メモリ: 96KB

レジスタ数(32-bit): 64K個

リソース量/SM (GM200)

Page 37: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

44

リソース使用率 (Occupancy)

SMの利用効率を上げる ≒ SMに割当て可能なスレッド数を、 上限に近づける

スレッド数(/ブロック)

64以上にする 64未満だと最大ブロック数がネックになる

共有メモリ使用量(/ブロック)

できる限り減らす 共有メモリ使用量と、割当て可能なブロック数の関係

48KB:2ブロック, 12KB:8ブロック, 3KB:32ブロック

CUDAコア数: 128 最大スレッド数: 2048 最大ブロック数: 32 共有メモリ: 96KB

レジスタ数(32-bit): 64K個

リソース量/SM (GM200)

Page 38: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

45

リソース使用率 (Occupancy)

空き時間を埋める

CUDAストリーム (≒キュー) 同じCUDAストリームに投入した操作: 投入順に実行 別のCUDAストリームに投入した操作: 非同期に実行 (オーバラップ実行)

(*) 操作: GPUカーネル, データ転送

[CUDAストリームの効果例] GPUカーネルとデータ転送が

オーバラップして 同時に実行されている

Page 39: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

46

デバイスメモリへのアクセスは、まとめて

コアレス・アクセス 32スレッド(ワープ)のロード/ストアをまとめて、メモリトランザクションを発行

トランザクションサイズ: 32B, 64B or 128B

トランザクション数は、少ないほど良い 配列 128B境界 128B境界

0 1 2 29 30 31 28 3

0 1 14 17 30 31 16 15

0 1 2

Best

Good

Bad

128B x1

64B x2

32B x32

Page 40: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

47

分岐を減らす

ワープ内のスレッドが別パスを選択すると遅くなる ワープ内のスレッドは、命令を共有 (SIMT) ワープ内のスレッドが選んだ全パスの命令を実行 あるパスの命令を実行中、そのパスにいないスレッドはinactive状態

Path divergenceを減らす

できる限り、同ワープ内のスレッドは 同じパスを選択させる

A[id] > 0

処理 X

処理 Y

true false

0 1

2 3

Page 41: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

48

OPENACCプログラミング

概要紹介

プログラムのOpenACC化

OpenACC化事例

Page 42: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

49

アプリをGPU対応する方法

Application

Library

GPU対応ライブラリにチェンジ

簡単に開始

CUDA OpenACC

主要処理をCUDAで記述

高い自由度 既存コードにディレクティブを挿入

簡単に加速

Page 43: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

50

OPENACC

Program myscience ... serial code ... !$acc kernels do k = 1,n1 do i = 1,n2 ... parallel code ... enddo enddo !$acc end kernels ... serial code … End Program myscience

CPU GPU

既存のC/Fortranコード

簡単: 既存のコードに コンパイラへのヒントを追加

強力: そこそこの労力で、コンパイラがコードを自動で並列化

オープン: 複数コンパイラベンダが、 複数アクセラレータをサポート

NVIDIA, AMD, Intel(予定)

ヒントの追加

Page 44: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

51

アプリケーション実行

アプリケーション・コード

GPU CPU

並列部分は GPUで実行

計算の 重い部分

逐次部分は CPU上で実行

Do i=1,N

End do

Page 45: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

52

__global__ void saxpy(int n, float a, float *x, float *y) { int i = threadIdx.x + blodkDim.x * blockIdx; if (i < n) y[i] += a*x[i]; } ... size_t size = sizeof(float) * N; cudaMemcpy(d_x, x, size, cudaMemcpyHostToDevice); cudaMemcpy(d_y, y, size, cudaMemcpyHostToDevice); saxpy<<< N/128, 128 >>>(N, 3.0, d_x, d_y); cudaMemcpy(y, d_y, size, cudaMemcpyDeviceToHost); ...

SAXPY (Y=A*X+Y) CPU CUDA

void saxpy(int n, float a, float *x, float *y) { for (int i = 0; i < n; ++i) y[i] += a*x[i]; } ... saxpy(N, 3.0, x, y); ...

Page 46: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

53

void saxpy(int n, float a, float *x, float *restrict y) { #pragma acc parallel copy(y[:n]) copyin(x[:n]) for (int i = 0; i < n; ++i) y[i] += a*x[i]; } ... saxpy(N, 3.0, x, y); ...

SAXPY (y=a*x+y)

omp acc データの移動

OpenMP OpenACC void saxpy(int n, float a, float *x, float *restrict y) { #pragma omp parallel for for (int i = 0; i < n; ++i) y[i] += a*x[i]; } ... saxpy(N, 3.0, x, y); ...

Page 47: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

54

subroutine saxpy(n, a, X, Y) real :: a, Y(:), Y(:) integer :: n, i !$acc parallel copy(Y(:)) copyin(X(:)) do i=1,n Y(i) = a*X(i)+Y(i) enddo !$acc end parallel end subroutine saxpy ... call saxpy(N, 3.0, x, y) ...

SAXPY (y=a*x+y, FORTRAN)

FORTRANも同様

OpenMP OpenACC subroutine saxpy(n, a, X, Y) real :: a, X(:), Y(:) integer :: n, i !$omp parallel do do i=1,n Y(i) = a*X(i)+Y(i) enddo !$omp end parallel do end subroutine saxpy ... call saxpy(N, 3.0, x, y) ...

Page 48: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

55

簡単にコンパイル

OpenMP / OpenACC void saxpy(int n, float a,

float *x,

float *restrict y)

{

#pragma acc parallel copy(y[:n]) copyin(x[:n])

#pragma omp parallel for

for (int i = 0; i < n; ++i)

y[i] += a*x[i];

}

...

saxpy(N, 3.0, x, y);

...

$ pgcc -Minfo -acc saxpy.c saxpy:

16, Generating present_or_copy(y[:n])

Generating present_or_copyin(x[:n])

Generating Tesla code

19, Loop is parallelizable

Accelerator kernel generated

19, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */

Page 49: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

56

簡単に実行

OpenMP / OpenACC void saxpy(int n, float a,

float *x,

float *restrict y)

{

#pragma acc parallel copy(y[:n]) copyin(x[:n])

#pragma omp parallel for

for (int i = 0; i < n; ++i)

y[i] += a*x[i];

}

...

saxpy(N, 3.0, x, y);

...

$ pgcc -Minfo -acc saxpy.c saxpy:

16, Generating present_or_copy(y[:n])

Generating present_or_copyin(x[:n])

Generating Tesla code

19, Loop is parallelizable

Accelerator kernel generated

19, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */

$ nvprof ./a.out ==10302== NVPROF is profiling process 10302, command: ./a.out

==10302== Profiling application: ./a.out

==10302== Profiling result:

Time(%) Time Calls Avg Min Max Name

62.95% 3.0358ms 2 1.5179ms 1.5172ms 1.5186ms [CUDA memcpy HtoD]

31.48% 1.5181ms 1 1.5181ms 1.5181ms 1.5181ms [CUDA memcpy DtoH]

5.56% 268.31us 1 268.31us 268.31us 268.31us saxpy_19_gpu

Page 50: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

57

OPENACCプログラミング

概要紹介

プログラムのOpenACC化

OpenACC化事例

Page 51: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

58

事例: ヤコビ反復法

while ( error > tol ) { error = 0.0; for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i])); } } for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } }

A(i,j) A(i+1,j) A(i-1,j)

A(i,j-1)

A(i,j+1)

Page 52: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

59

並列領域 (kernels construct)

並列領域の指定 Parallels と

Kernels

Parallels OpenMPと親和性 開発者主体

Kernels 複数kernelの生成 コンパイラ主体

while ( error > tol ) { error = 0.0; #pragma acc kernels for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } #pragma acc kernels for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } }

Page 53: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

60

[PGI tips] コンパイラメッセージ

$ pgcc –acc –Minfo=accel jacobi.c jacobi:

44, Generating copyout(Anew[1:4094][1:4094])

Generating copyin(A[:][:])

Generating Tesla code

45, Loop is parallelizable

46, Loop is parallelizable

Accelerator kernel generated

45, #pragma acc loop gang /* blockIdx.y */

46, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */

49, Max reduction generated for error

Page 54: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

61

並列領域 (kernels construct)

並列領域の指定 Parallels と

Kernels

Parallels OpenMPと親和性 開発者主体

Kernels 複数kernelの生成 コンパイラ主体

while ( error > tol ) { error = 0.0; #pragma acc kernels for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } #pragma acc kernels for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } }

$ pgcc -Minfo=acc -acc jacobi.c jacobi:

59, Generating present_or_copyout(Anew[1:4094][1:4094])

Generating present_or_copyin(A[:][:])

Generating Tesla code

61, Loop is parallelizable

63, Loop is parallelizable

Accelerator kernel generated

61, #pragma acc loop gang /* blockIdx.y */

63, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */

Max reduction generated for error

Page 55: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

62

データ転送(data clause)

並列領域の指定 Parallels と

Kernels

Parallels OpenMPと親和性 開発者主体

Kernels 複数kernelの生成 コンパイラ主体

while ( error > tol ) { error = 0.0; #pragma acc kernels for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } #pragma acc kernels for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } }

$ pgcc -Minfo=acc -acc jacobi.c jacobi:

59, Generating present_or_copyout(Anew[1:4094][1:4094])

Generating present_or_copyin(A[:][:])

Generating Tesla code

61, Loop is parallelizable

63, Loop is parallelizable

Accelerator kernel generated

61, #pragma acc loop gang /* blockIdx.y */

63, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */

Max reduction generated for error

Page 56: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

63

データ転送 (DATA CLAUSE)

copyin (HostGPU)

copyout (HostGPU)

copy create present

pcopyin pcopyout pcopy pcreate

while ( error > tol ) { error = 0.0; #pragma acc kernels \ pcopyout(Anew[1:4094][1:4094]) pcopyin(A[:][:]) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } #pragma acc kernels \ pcopyout(A[1:4094][1:4094]) pcopyin(Anew[1:4094][1:4094]) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } }

Page 57: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

64

配列形状の指定

配列は、全要素でなく、一部だけ指定して転送することも可能 注意: C/C++ と Fortranでは指定方法が異なる

C/C++: array[ start : size ]

float Anew[4096][4096] pcopyout( Anew[1:4094][1:4094]) pcopyin( A[:][:]) )

Fortran: array( start : end ) real Anew(4096,4096) pcopyout( Anew(2:4095, 2:4095) ) pcopyin( A(:,:) )

Page 58: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

65

データ転送 (data clause)

copyin (HostGPU)

copyout (HostGPU)

copy create present

pcopyin pcopyout pcopy pcreate

while ( error > tol ) { error = 0.0; #pragma acc kernels \ pcopy(Anew[:][:]) pcopyin(A[:][:]) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } #pragma acc kernels \ pcopy(A[:][:]) pcopyin(Anew[:][:]) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } }

Page 59: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

66

[PGI tips] PGI_ACC_TIME

$ PGI_ACC_TIME=1 ./a.out Accelerator Kernel Timing data

/home/anaruse/src/OpenACC/jacobi/C/task1-solution/jacobi.c

jacobi NVIDIA devicenum=0

time(us): 649,886

44: data region reached 200 times

44: data copyin transfers: 800

device time(us): total=14,048 max=41 min=15 avg=17

53: data copyout transfers: 800

device time(us): total=11,731 max=43 min=6 avg=14

44: compute region reached 200 times

46: kernel launched 200 times

grid: [32x4094] block: [128]

device time(us): total=382,798 max=1,918 min=1,911 avg=1,913

elapsed time(us): total=391,408 max=1,972 min=1,953 avg=1,957

46: reduction kernel launched 200 times

grid: [1] block: [256]

device time(us): total=48,235 max=242 min=241 avg=241

elapsed time(us): total=53,510 max=280 min=266 avg=267

53: data region reached 200 times

統計データ

Page 60: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

67

[PGI tips] PGI_ACC_NOTIFY

$ PGI_ACC_NOTIFY=3 ./a.out ...

upload CUDA data file=/home/anaruse/src/OpenACC/jacobi/C/task1-solution/jacobi.c function=jacobi line=44 device=0 variable=A bytes=16777216

...

launch CUDA kernel file=/home/anaruse/src/OpenACC/jacobi/C/task1-solution/jacobi.c function=jacobi line=46 device=0 num_gangs=131008 num_workers=1 vector_length=128 grid=32x4094 block=128 shared memory=1024

...

download CUDA data file=/home/anaruse/src/OpenACC/jacobi/C/task1-solution/jacobi.c function=jacobi line=53 device=0 variable=Anew bytes=16736272

...

トレースデータ

Page 61: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

68

NVIDIA VISUAL PROFILER (NVVP)

Page 62: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

69

NVVPによる解析: データ転送がボトルネック

1 cycle

GPU kernel

GPU kernel

利用率:低い

Page 63: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

70

過剰なデータ転送

while ( error > tol ) { error = 0.0; #pragma acc kernels \ pcopy(Anew[:][:]) pcopyin(A[:][:]) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } #pragma acc kernels \ pcopy(A[:][:]) pcopyin(Anew[:][:]) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } }

Page 64: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

71

過剰なデータ転送

while ( error > tol ) { error = 0.0; #pragma acc kernels \ pcopy(Anew[:][:]) \ pcopyin(A[:][:]) { } #pragma acc kernels \ pcopy(A[:][:]) \ pcopyin(Anew[:][:]) { } }

#pragma acc loop reduction(max:error) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } }

Host GPU

copyin

copyin

copyout

copyout

Page 65: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

72

データ領域 (data construct)

copyin (CPUGPU)

copyout (CPUGPU)

copy create present

pcopyin pcopyout pcopy pcreate

#pragma acc data pcopy(A, Anew) while ( error > tol ) { error = 0.0; #pragma acc kernels pcopy(Anew[:][:]) pcopyin(A[:][:]) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } #pragma acc kernels pcopy(A[:][:]) pcopyin(Anew[:][:]) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } }

Page 66: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

73

データ領域 (data construct)

copyin (CPUGPU)

copyout (CPUGPU)

copy create present

pcopyin pcopyout pcopy pcreate

#pragma acc data pcopy(A) create(Anew) while ( error > tol ) { error = 0.0; #pragma acc kernels pcopy(Anew[:][:]) pcopyin(A[:][:]) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } #pragma acc kernels pcopy(A[:][:]) pcopyin(Anew[:][:]) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } }

Page 67: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

74

適正なデータ転送

#pragma acc data \ pcopy(A) create(Anew) while ( error > tol ) { error = 0.0; #pragma acc kernels \ pcopy(Anew[:][:]) \ pcopyin(A[:][:]) { } #pragma acc kernels \ pcopy(A[:][:]) \ pcopyin(Anew[:][:]) { } }

for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } }

copyin

copyout

Host GPU

Page 68: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

75

データ転送が減少 (NVVP) 利用率:高い

1 cycle

Page 69: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

76

2つの処理

データ転送

計算オフロード

計算オフロード、データ転送、両方を考慮する必要がある

GPU Memory CPU Memory

PCI

Page 70: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

77

float *array; Init( ) { ... array = (float*)malloc( … ); input_array( array ); #pragma enter data copyin(array) ... } Fin( ) { ... #pragma exit data copyout(array) output_array( array ); free( array ); ... }

その他のデータ管理方法

Enter data Copyin Create Pcopyin Pcreate

Exit data

Copyout Delete

Page 71: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

78

#pragma acc data pcopy(A,B) for (k=0; k<LOOP; k++) { #pragma acc kernels present(A,B) for (i=0; i<N; i++) { A[i] = subA(i,A,B); } #pragma acc update self(A[0:1]) output[k] = A[0]; A[N-1] = input[k]; #pragma acc update device(A[N-1:1]) #pragma acc kernels present(A,B) for (i=0; i<N; i++) { B[i] = subB(i,A,B); } }

その他のデータ管理方法

Update self CPU GPU

Update device CPU GPU

Page 72: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

79

リダクション(縮約計算)

while ( error > tol ) { error = 0.0; #pragma acc kernels for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } ... }

Page 73: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

80

リダクション(縮約計算)

演算の種類 + 和 * 積 Max 最大 Min 最小 | ビット和 & ビット積 ^ XOR || 論理和 && 論理積

while ( error > tol ) { error = 0.0; #pragma acc kernels for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } #pragma acc kernels for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } }

$ pgcc -Minfo=acc -acc jacobi.c

jacobi:

59, Generating present_or_copyout(Anew[1:4094][1:4094])

Generating present_or_copyin(A[:][:])

Generating Tesla code

61, Loop is parallelizable

63, Loop is parallelizable

Accelerator kernel generated

61, #pragma acc loop gang /* blockIdx.y */

63, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */

Max reduction generated for error

Page 74: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

81

リダクション (REDUCTION CLAUSE)

演算種類 (C/C++) + 和 * 積 max 最大 min 最小 | ビット和 & ビット積 ^ XOR || 論理和 && 論理積

while ( error > tol ) { error = 0.0; #pragma acc kernels #pragma acc loop reduction(max:error) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } ... }

Page 75: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

82

並列方法の指示

#pragma acc data pcopy(A) create(Anew) while ( error > tol ) { error = 0.0; #pragma acc kernels pcopy(Anew[:][:]) pcopyin(A[:][:]) #pragma acc loop reduction(max:error) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } ... }

Page 76: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

83

並列方法の指示

#pragma acc data pcopy(A) create(Anew) while ( error > tol ) { error = 0.0; #pragma acc kernels pcopy(Anew[:][:]) pcopyin(A[:][:]) #pragma acc loop reduction(max:error) for (int j = 1; j < N-1; j++) { #pragma acc loop reduction(max:error) for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } ... }

$ pgcc -Minfo=acc -acc jacobi.c

jacobi:

59, Generating present_or_copyout(Anew[1:4094][1:4094])

Generating present_or_copyin(A[:][:])

Generating Tesla code

61, Loop is parallelizable

63, Loop is parallelizable

Accelerator kernel generated

61, #pragma acc loop gang /* blockIdx.y */

63, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */

Max reduction generated for error

Page 77: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

84

並列方法の指示 (loop construct)

Gang Worker Vector … SIMD幅

Collapse Independent Seq Cache Tile

#pragma acc data pcopy(A) create(Anew) while ( error > tol ) { error = 0.0; #pragma acc kernels pcopy(Anew[:][:]) pcopyin(A[:][:]) #pragma acc loop gang vector(1) reduction(max:error) for (int j = 1; j < N-1; j++) { #pragma acc loop gang vector(128) for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } ... }

Page 78: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

85

実行条件設定 (gang, vector) #pragma acc loop gang vector(4) for (j = 0; j < 16; j++) { #pragma acc loop gang vector(16) for (i = 0; i < 16; i++) { ...

4 x 16

i

4 x 16

4 x 16

4 x 16

j

#pragma acc loop gang vector(8) for (j = 1; j < 16; j++) { #pragma acc loop gang vector(8) for (i = 0; i < 16; i++) { ...

i

j

8 x 8 8 x 8

8 x 8 8 x 8

Page 79: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

86

ループを融合 (collapse)

Gang Worker Vector … SIMD幅

Collapse Independent Seq Cache Tile ...

#pragma acc data pcopy(A) create(Anew) while ( error > tol ) { error = 0.0; #pragma acc kernels pcopy(Anew[:][:]) pcopyin(A[:][:]) #pragma acc loop reduction(max:error) \ collapse(2) gang vector(128) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } ... }

Page 80: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

87

ループを融合 (collapse)

Gang Worker Vector … SIMD幅

Collapse Independent Seq Cache Tile ...

#pragma acc data pcopy(A) create(Anew) while ( error > tol ) { error = 0.0; #pragma acc kernels pcopy(Anew[:][:]) pcopyin(A[:][:]) #pragma acc loop reduction(max:error) gang vector(128) for (int ji = 0; ji < (N-2)*(M-2); ji++) { j = (ji / (M-2)) + 1; i = (ji % (M-2)) + 1; Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } ... }

Page 81: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

88

並列実行可能(independent)

Gang Worker Vector … SIMD幅

Collapse Independent Seq Cache Tile ...

#pragma acc data pcopy(A) create(Anew) while ( error > tol ) { error = 0.0; #pragma acc kernels pcopy(Anew[:][:]) pcopyin(A[:][:]) #pragma acc loop reduction(max:error) independent for (int jj = 1; jj < NN-1; jj++) { int j = list_j[jj]; for (int i = 1; i < M-1; i++) { Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; error = max(error, abs(Anew[j][i] - A[j][i]); } } ... }

Page 82: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

89

逐次に実行 (seq)

Gang Worker Vector … SIMD幅

Collapse Independent Seq Cache Tile ...

#pragma acc kernels pcopy(Anew[:][:]) pcopyin(A[:][:]) #pragma acc loop seq for (int k = 3; k < NK-3; k++) { #pragma acc loop for (int j = 0; j < NJ; j++) { #pragma acc loop for (int i = 0; i < NI; i++) { Anew[k][j][i] = func( A[k-1][j][i], A[k-2][j][i], A[k-3][j][i], A[k+1][j][i], A[k+2][j][i], A[k+3][j][i], ... ); } } }

Page 83: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

90

OPENACCプログラミング

概要紹介

プログラムのOpenACC化

OpenACC化事例

Page 84: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

91

NICAM

気象・気候モデル by 理研AICS/東大 膨大なコード (数十万行) ホットスポットがない (パレートの法則)

特性の異なる2種類の処理 力学系 … メモリバンド幅ネック 物理系 … 演算ネック

Page 85: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

92

NICAM: 力学系(NICAM-DC)

OpenACCによるGPU化 主要サブルーチンは、全てGPU上で動作(50以上)

MPI対応済み 2週間

良好なスケーラビリティ

Tsubame 2.5, 最大2560 GPUs

Scaling factor: 0.8

Weak scaling

1.E+01

1.E+02

1.E+03

1.E+04

1.E+05

1.E+00 1.E+01 1.E+02 1.E+03 1.E+04Pe

rfor

man

ce (

GFL

OPS

) Number of CPUs or GPUs

Tsubame 2.5 (GPU:K20X)

K computer

Tsubame 2.5 (CPU:WSM)

(*) weak scaling

Courtesy of Dr. Yashiro from RIKEN AICS

Page 86: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

93

NICAM: 力学系(NICAM-DC)

1.E+01

1.E+02

1.E+03

1.E+04

1.E+05

1.E+02 1.E+03 1.E+04 1.E+05 1.E+06

Mea

sure

d Pe

rfor

man

ce

(GFL

OPS

)

Aggregate Peak Memory Bandwidth (GB/s)

Tsubame 2.5 (GPU:K20X)

K computer

Tsubame 2.5 (CPU:WSM)

Courtesy of Dr. Yashiro from RIKEN AICS

Page 87: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

94

NICAM: 物理系(SCALE-LES)

Atmospheric radiation transfer 物理系の中で、最も重い計算 OpenACCによるGPU対応、完了

1.00 1.99 3.88 8.51

37.8

76.0

151

020406080

100120140160

1 core 2 core 4 core 10 core 1 GPU 2 GPUs 4 GPUs

Xeon E5-2690v2(3.0GHz,10-core) Tesla K40

Spee

dup

vs.

CPU

1-c

ore

(*) PCIデータ転送時間込み, グリッドサイズ:1256x32x32

Better

Page 88: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

95

SEISM3D 地震シミュレーション by 古村教授(東大地震研) 主要サブルーチンのGPU対応が完了

メモリバンド幅ネック、 3次元モデル(2次元分割)、隣接プロセス間通信

605

459

134 0

100

200

300

400

500

600

K: 8x SPARC64VIIIfx

CPU: 8x XeonE5-2690v2

GPU: 8x TeslaK40

Tim

e (s

ec)

SEISM3D (480x480x1024, 1K steps)

3.4x speedup (アプリ全体)

0

20

40

60

80

100

120

140

GPU: 8x Tesla K40

Others (CPU, MPI and so on)

[CUDA memcpy DtoH]

[CUDA memcpy HtoD]

(other subroutines)

update_vel_pml

update_vel

update_stress_pml

update_stress

diff3d_*

GPUの実行時間内訳

Better

Page 89: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

96

FFR/BCM (仮称) 次世代CFDコード by 坪倉准教授(理研AICS/北大) MUSCL_bench:

MUSCLスキームに基づくFlux計算 (とても複雑な計算) CFD計算の主要部分 (60-70%) OpenACCによるGPU対応、完了

1.00 1.93 4.55

8.30

33.21

05

101520253035

1 core 2 core 5 core 10 core 1 GPU

Xeon E5-2690v2(3.0GHz,10-core) Tesla K40

Spee

dup

vs.

1 CP

U c

ore

(*) PCIデータ転送時間込み、サイズ:80x32x32x32

Better

Page 90: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

97

CM-RCM IC-CG (PRELIMINARY)

IC-CG法のベンチマークコード by 中島教授(東大) CM-RCM法(Cyclic Multi-coloring Reverse Cuthill-Mckee)を使用

メインループ内のサブルーチンを全てOpenACCでGPU化

3.36

1.58 1.53 1.39

0.655

0

1

2

3

4

OpenMP OpenMP OpenMP OpenMP OpenACC

Opteron 6386SE(2.8GHz,16core)

SPARC64 Ixfx(1.85GHz,16core)

Xeon E5-2680v2(2.8GHz,10core)

Xeon-Phi 5110P Tesla K40

Tim

e (s

econ

d)

CM-RCM ICCG (100x100x100)

Better

Courtesy of Dr. Ohshima from U-Tokyo

Page 91: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache

98

CCS-QCD QCDコード by 石川准教授(広島大) BiCGStab計算を全てOpenACCでGPU化

データレイアウトを変更: AoS SoA

32.3 24.3 22.1 20.9 19.7

42.5 53.3

57.9 60.8 63.4

0102030405060708090

8x8x8x32 8x8x8x64 8x8x16x64 8x16x16x64 16x16x16x64

GFL

OPS

Problem Size

CCS-QCD: BiCGStab Total FLOPS

Xeon E5-2690v2(3.0GHz,10core,OpenMP) Tesla K40(OpenACC)Better

Page 92: CUDA OpenACCによる GPUコンピューティング...4 CUDA Core Dispatch Port Result Queue ALU Operand Collector Dispatch Port SM Interconnect Network 64 KB Shared Memory / L1 Cache