OpenACC CUDAによる GPUコンピューティング...2008 2010 2012 2014 2016 2018 GPU...
Transcript of OpenACC CUDAによる GPUコンピューティング...2008 2010 2012 2014 2016 2018 GPU...
Akira Naruse, 19th Jul. 2018
OpenACC・CUDAによるGPUコンピューティング
2
自己紹介
▪ 成瀬 彰 (Naruse, Akira)
▪ 2013年~: NVIDIA、シニア・デベローパーテクノロジー・エンジニア
▪ 1996~2013年: 富士通研究所、研究員など
▪ 専門・興味: 並列処理、性能最適化、スパコン・HPC、 GPUコンピューティング、 DeepLearning、…
▪ 詳しくは…
github.com/anaruse
3
AGENDA
▪ GPU Computing
▪ Volta GPUs
▪ OpenACC
▪ CUDA
4
GPU Computing
5
GPUコンピューティングLow latency + High throughput
CPU GPU
6
アプリケーション実行
アプリケーション・コード
GPU
CPU
並列部分はGPUで実行
計算の重い部分
逐次部分はCPU上で実行
Do i=1,N
End do
7
GPUの構造 (TESLA P100)
64 CUDA core/SM
大量のCUDAコア並列性が鍵
56 SM/chip
3584 CUDA core/chip
8
GPU APPLICATIONS
数百のアプリケーションがGPUに対応www.nvidia.com/object/gpu-applications.html
9
LEADING APPLICATIONS
10
DL FRAMEWORKS
11
アプリをGPU対応する方法
Application
CUDAOpenACCLibrary
GPU対応ライブラリにチェンジ
簡単に開始主要処理をCUDAで記述
高い自由度既存コードにディレクティブを挿入
簡単に加速
12
NVIDIA LIBRARIES
cuRAND Thrust
cuDNN
AmgXcuBLAS
cuFFT
cuSPARSE cuSOLVER
Performance Primitives NCCL
nvGRAPH
TensorRT
13
PARTNER LIBRARIES
Computer Vision
Sparse direct solvers
Sparse Iterative MethodsLinear Algebra
Linear Algebra
Graph
Audio and Video Matrix, Signal and Image
Math, Signal and Image Linear Algebra
Computational Geometry
Real-time visual simulation
14
アプリをGPU対応する方法
Application
Library
GPU対応ライブラリにチェンジ
簡単に開始
CUDAOpenACC
主要処理をCUDAで記述
高い自由度既存コードにディレクティブを挿入
簡単に加速
15
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)
{
for (int i = 0; i < n; ++i)
y[i] += a*x[i];
}
...
saxpy(N, 3.0, x, y);
...
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);
...
16
アプリをGPU対応する方法
Application
Library OpenACC CUDA
GPU対応ライブラリにチェンジ
簡単に開始主要処理をCUDAで記述
高い自由度既存コードにディレクティブを挿入
簡単に加速
17
__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);
...
18
Volta GPUs
19
Perf
orm
ance /
W
2012 20142008 2010 2016 2018
GPUロードマップ
TeslaFermi
Kepler
Maxwell
Pascal
Volta
20
TESLA V100の概要
Deep LearningとHPC、両方に最適なGPU
Volta Architecture
Most Productive GPU
Tensor Core
125 Programmable
TFLOPS Deep Learning
Improved SIMT Model
New Algorithms
Volta MPS
Inference Utilization
Improved NVLink &
HBM2
Efficient Bandwidth
21
VOLTAHPC性能を大きく向上
P100に対する相対性能
HPCアプリケーション性能
System Config Info: 2X Xeon E5-2690 v4, 2.6GHz, w/ 1X Tesla P100 or V100. V100 measured on pre-production hardware.
Summit
Supercomputer
200+ PetaFlops
~3,400 Nodes
10 Megawatts
22
3+EFLOPSTensor Ops
AI Exascale Today
ACME
DIRAC FLASH GTC
HACC LSDALTON NAMD
NUCCOR NWCHEM QMCPACK
RAPTOR SPECFEM XGC
AcceleratedScience
10XPerf Over Titan
20 PF
200 PF
Performance Leadership
VOLTA 米国トップスパコンのエンジンSUMMIT
5-10XApplication Perf Over Titan
23
トランジスタ数:21B 815 mm2
80 SM5120 CUDAコア640 Tensorコア
HBM232 GB, 900 GB/s
NVLink 300 GB/s
TESLA V100
*full GV100 chip contains 84 SMs
24
P100 V100 性能UP
トレーニング性能 10 TOPS 125 TOPS 12x
インファレンス性能 21 TFLOPS 125 TOPS 6x
FP64/FP32 5/10 TFLOPS 7.8/15.6 TFLOPS 1.5x
HBM2 バンド幅 720 GB/s 900 GB/s 1.2x
NVLink バンド幅 160 GB/s 300 GB/s 1.9x
L2 キャッシュ 4 MB 6 MB 1.5x
L1 キャッシュ 1.3 MB 10 MB 7.7x
GPUピーク性能比較: P100 vs v100
25
HBM2メモリ、使用効率UP
STREAM
: Tr
iad-
Delivere
d G
B/s
P100 V100
76% 95%
実効バンド幅1.5倍
V100 measured on pre-production hardware.
HBM2 stack
使用効率
26
VOLTA NVLINK
P100 V100
リンク数 4 6
バンド幅 / リンク
40 GB/s 50 GB/s
トータルバンド幅
160 GB/s 300 GB/s(*) バンド幅は双方向
DGX1V
27
VOLTA GV100 SM
GV100
FP32ユニット 64
FP64ユニット 32
INT32ユニット 64
Tensorコア 8
レジスタファイル 256 KB
統合L1・共有メモリ
128 KB
Activeスレッド 2048(*) SMあたり
28
VOLTA GV100 SM
命令セットを一新
スケジューラを2倍
命令発行機構をシンプルに
L1キャッシュの大容量・高速化
SIMTモデルの改善
テンソル計算の加速
最もプログラミングの簡単なSM
生産性の向上
29
OpenACC
30
OPENACCプログラミング
▪ 概要紹介
▪ プログラムのOpenACC化
▪ OpenACC化事例
31
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 GPU, AMD GPU,
x86 CPU, …
ヒントの追加
32
GPUコンピューティング
アプリケーション・コード
GPU
CPU
並列部分はGPUで実行
計算の重い部分
逐次部分はCPU上で実行
Do i=1,N
End do
OpenACC
33
__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);
...
34
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);
...
35
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)
...
36
簡単にコンパイル
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 -acc –Minfo=acc saxpy.csaxpy:
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 */
37
簡単に実行
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.csaxpy:
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
38
OPENACCプログラミング
▪ 概要紹介
▪ プログラムのOpenACC化
▪ OpenACC化事例
39
事例: ヤコビ反復法
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)
40
並列領域の指定 (parallel/kernelsディレクティブ)
▪ Parallel と Kernels
▪ Parallel
▪ 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];
}
}
}
41
[PGI tips] コンパイラメッセージ
$ pgcc –acc –Minfo=accel jacobi.cjacobi:
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
42
並列領域の指定 (kernels)
▪ 並列領域の指定▪ 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.cjacobi:
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
43
データの転送 (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.cjacobi:
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
44
データの転送 (data clause)
▪ copyin (Host→GPU)
▪ copyout (HostGPU)
▪ copy
▪ create
▪ present
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];
}
}
} N=M=4096
45
配列形状の指定
▪ 配列は、全要素でなく、一部だけ指定して転送することも可能▪ 注意: 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(:,:) )
46
データの転送 (data clause)
▪ copyin (Host→GPU)
▪ copyout (HostGPU)
▪ copy
▪ create
▪ present
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];
}
}
} N=M=4096
47
[PGI tips] PGI_ACC_TIME
$ PGI_ACC_TIME=1 ./a.outAccelerator 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
統計データ
48
[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
...
トレースデータ
49
NVIDIA VISUAL PROFILER (NVVP)
50
NVVPによる解析: データ転送がボトルネック
1 cycle
GPU
kernel
GPU
kernel
利用率:低い
51
過剰なデータ転送
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];
}
}
}
52
過剰なデータ転送
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
53
データ領域の指定 (dataディレクティブ)
▪ copyin (CPU→GPU)
▪ copyout (CPUGPU)
▪ copy
▪ create
▪ present
#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];
}
}
}
54
データ領域の指定 (dataディレクティブ)
▪ copyin (CPU→GPU)
▪ copyout (CPUGPU)
▪ copy
▪ create
▪ present
#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];
}
}
}
55
適正なデータ転送
#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
56
データ転送が減少 (NVVP)
利用率:高い1 cycle
57
2つの処理
データ転送
計算オフロード
計算オフロード、データ転送、両方を考慮する必要がある
GPU MemoryCPU Memory
PCI
58
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
▪ Exit data▪ Copyout
▪ Delete
59
#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 selfCPU GPU
▪ Update deviceCPU → GPU
60
その他のデータ管理方法
▪ Unified Memoryの利用
▪ PGIコンパイラオプション: -acc –ta=…,managed,…
▪ プログラム実行中に動的に確保される配列は(C: malloc, Fortran: allocate)、Unified Memoryで管理される
▪ OpenACCのデータディレクティブで移動を指示する必要がない
61
リダクション(縮約計算)
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]);
}
}
...
}
62
リダクション(縮約計算)
▪ 演算の種類+ 和
* 積
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
63
リダクション (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]);
}
}
...
}
64
並列方法の指示
#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]);
}
}
...
}
65
並列方法の指示
#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
66
並列方法の指示 (loopディレクティブ)
▪ 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]);
}
}
...
}
67
実行条件設定 (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
68
ループを融合 (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]);
}
}
...
}
69
ループを融合 (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]);
}
...
}
70
並列実行可能(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]);
}
}
...
}
71
逐次に実行 (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], ...
);
}
}
}
72
OPENACCプログラミング
▪ 概要紹介
▪ プログラムのOpenACC化
▪ OpenACC化事例
73
LSDalton
Quantum ChemistryAarhus University
12X speedup 1 week
PowerGrid
Medical ImagingUniversity of Illinois
40 days to2 hours
INCOMP3D
CFDNC State University
4X speedup
NekCEM
Comp ElectromagneticsArgonne National Lab
2.5X speedup60% less energy
CloverLeaf
Comp HydrodynamicsAWE
4X speedupSingle CPU/GPU code
MAESTROCASTRO
AstrophysicsStony Brook University
4.4X speedup4 weeks effort
FINE/Turbo
CFDNUMECA International
10X faster routines2X faster app
OPENACC ACCELERATES COMPUTATIONAL SCIENCE
74
Janus Juul Eriksen, PhD Fellow
qLEAP Center for Theoretical Chemistry, Aarhus University
“
OpenACC makes GPU computing approachable for
domain scientists. Initial OpenACC implementation
required only minor effort, and more importantly,
no modifications of our existing CPU implementation.
“
LSDALTON
Large-scale application for calculating high-accuracy molecular energies
Lines of Code
Modified
# of Weeks
Required
# of Codes to
Maintain
<100 Lines 1 Week 1 Source
Big Performance
7.9x8.9x
11.7x
ALANINE-113 ATOMS
ALANINE-223 ATOMS
ALANINE-333 ATOMS
Speedup v
s C
PU
Minimal Effort
LS-DALTON CCSD(T) ModuleBenchmarked on Titan Supercomputer (AMD CPU vs Tesla K20X)
https://developer.nvidia.com/openacc/success-stories
75
“
OpenACC enabled us to
target routines for GPU
acceleration without
rewriting code, allowing us
to maintain portability on a
code that is 20-years old
“
David Gutzwiller, Head of HPC
NUMECA International
CHALLENGE• Accelerate 20 year old highly optimized code
on GPUs
SOLUTION• Accelerated computationally intensive routines
with OpenACC
RESULTS• Achieved 10x or higher speed-up on key
routines
• Full app speedup of up to 2x on the Oak Ridge
Titan supercomputer
• Total time spent on optimizing various routines
with OpenACC was just five person-months
NUMECA FINE/TURBOCommercial CFD Application
https://developer.nvidia.com/openacc/success-stories
76
Brad Sutton, Associate Professor of Bioengineering and
Technical Director of the Biomedical Imaging Center
University of Illinois at Urbana-Champaign
“Now that we’ve seen how easy it is to program the
GPU using OpenACC and the PGI compiler, we’re
looking forward to translating more of our projects
“
CHALLENGE• Produce detailed and accurate brain images by applying
computationally intensive algorithms to MRI data
• Reduce reconstruction time to make diagnostic use possible
SOLUTION• Accelerated MRI reconstruction application with OpenACC
using NVIDIA GPUs
RESULTS• Reduced reconstruction time for a single high-resolution MRI
scan from 40 days to a couple of hours
• Scaled on Blue Waters at NCSA to reconstruct 3000 images in
under 24 hours
POWERGRIDAdvanced MRI Reconstruction Model
https://developer.nvidia.com/openacc/success-stories
77
Lixiang Luo, Researcher
Aerospace Engineering Computational Fluid Dynamics Laboratory
North Carolina State University (NCSU)
“
OpenACC is a highly effective tool for programming fully
implicit CFD solvers on GPU to achieve true 4X speedup“
* CPU Speedup on 6 cores of Xeon E5645, with additional cores performance reduces due to partitioning and MPI overheads
CHALLENGE• Accelerate a complex implicit CFD solver on GPU
SOLUTION• Used OpenACC to run solver on GPU with
minimal code changes.
RESULTS• Achieved up to 4X speedups on Tesla GPU over
parallel MPI implementation on x86 multicore
processor
• Structured approach to parallelism provided by
OpenACC allowed better algorithm design
without worrying about GPU architecture
INCOMP3D3D Fully Implicit CFD Solver
https://developer.nvidia.com/openacc/success-stories
78
The most significant result from
our performance studies is faster
computation with less energy
consumption compared with our
CPU-only runs.
Dr. Misun Min, Computation Scientist
Argonne National Laboratory
CHALLENGE• Enable NekCEM to deliver strong scaling on
next-generation architectures while
maintaining portability
SOLUTION• Use OpenACC to port the entire program
to GPUs
RESULTS• 2.5x speedup over a highly tuned CPU-only
version
• GPU used only 39 percent of the energy
needed by 16 CPUs to do the same
computation in the same amount of time
NEKCEMComputational Electromagnetics Application
“
“
https://developer.nvidia.com/openacc/success-stories
79
Adam Jacobs, PhD candidate in the Department of Physics and
Astronomy at Stony Brook University
On the reactions side, accelerated calculations allow us to model larger
networks of nuclear reactions for similar computational costs as the
simple networks we model now
MAESTRO & CASTROAstrophysics 3D Simulation
““
CHALLENGE• Pursuing strong scaling and portability to run
code on GPU-powered supercomputers
SOLUTION• OpenACC compiler on OLCF’s Titan
supercomputer
RESULTS• 4.4x faster reactions than on a multi-core
computer with 16 cores
• Accelerated calculations allow modeling larger
networks of nuclear reactions for similar
computational costs as simple networks
2 weeks to learn OpenACC
2 weeks to modify code
https://developer.nvidia.com/openacc/success-stories
80
Wayne Gaudin and Oliver Perks
Atomic Weapons Establishment, UK
We were extremely impressed that we can run OpenACC on a CPU with
no code change and get equivalent performance to our OpenMP/MPI
implementation.
CLOVERLEAFPerformance Portability for a Hydrodynamics Application
Sp
ee
du
p v
s 1
CP
U C
ore
Benchmarked Intel(R) Xeon(R) CPU E5-2690 v2 @ 3.00GHz, Accelerator: Tesla K80
““
CHALLENGE• Application code that runs across architectures
without compromising on performance
SOLUTION• Use OpenACC to port the CloverLeaf mini app
to GPUs and then recompile and run the same
source code on multi-core CPUs
RESULTS• Same performance as optimized OpenMP
version on x86 CPU
• 4x faster performance using the same code on
a GPU
https://developer.nvidia.com/openacc/success-stories
81
Earthquake Simulation (理研、東大地震研)
▪ WACCPD 2016(SC16併催WS): Best Paper Award
http://waccpd.org/wp-content/uploads/2016/04/SC16_WACCPD_fujita.pdfより引用
82
NICAM
▪ 気象・気候モデル by 理研AICS/東大▪ 膨大なコード (数十万行)
▪ ホットスポットがない (パレートの法則)
▪ 特性の異なる2種類の処理▪ 力学系 … メモリバンド幅ネック
▪ 物理系 … 演算ネック
83
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+04Perf
orm
ance (
GFLO
PS)
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
84
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
Measu
red P
erf
orm
ance
(GFLO
PS)
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
85
NICAM: 物理系(SCALE-LES)
▪ Atmospheric radiation transfer
▪ 物理系の中で、最も重い計算
▪ OpenACCによるGPU対応済
1.00 1.99 3.88 8.51
37.8
76.0
151
0
20
40
60
80
100
120
140
160
1 core 2 core 4 core 10 core 1 GPU 2 GPUs 4 GPUs
Xeon E5-2690v2(3.0GHz,10-core) Tesla K40
Speedup
vs.
CPU
1-c
ore
(*) PCIデータ転送時間込み, グリッドサイズ:1256x32x32
Better
86
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 (
sec)
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
87
FFR/BCM (仮称)
▪ 次世代CFDコード by 坪倉准教授(理研AICS/北大)
▪ MUSCL_bench:
▪ MUSCLスキームに基づくFlux計算 (とても複雑な計算)
▪ CFD計算の主要部分 (60-70%)
▪ OpenACCによるGPU対応、完了
1.00 1.934.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
Speedup
vs.
1 C
PU
core
(*) PCIデータ転送時間込み、サイズ:80x32x32x32
Better
88
CM-RCM IC-CG
▪ 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 (
second)
CM-RCM ICCG (100x100x100)
Better
Courtesy of Dr. Ohshima from U-Tokyo
89
CCS-QCD
▪ QCDコード by 石川准教授(広島大)
▪ BiCGStab計算を全てOpenACCでGPU化▪ データレイアウトを変更: AoS → SoA
32.324.3 22.1 20.9 19.7
42.5
53.357.9 60.8 63.4
0
10
20
30
40
50
60
70
80
90
8x8x8x32 8x8x8x64 8x8x16x64 8x16x16x64 16x16x16x64
GFLO
PS
Problem Size
CCS-QCD: BiCGStab Total FLOPS
Xeon E5-2690v2(3.0GHz,10core,OpenMP) Tesla K40(OpenACC)Better
90
CUDA
91
CUDAプログラミング
▪ プログラミングモデル
▪ アーキテクチャ
▪ 性能Tips
92
GPUコンピューティング
▪ 高スループット指向のプロセッサ
▪ 分離されたメモリ空間
GPU MemoryCPU Memory
PCI
CPU GPU
93
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
94
GPU実行の基本的な流れ
▪ GPUは、CPUからの制御で動作
▪ 入力データ: CPUからGPUに転送 (H2D)
▪ GPUカーネル: CPUから投入
▪ 出力データ: GPUからCPUに転送 (D2H)
CPU GPU
入力データ転送
GPUカーネル投入
同期
出力データ転送
GPU上で演算
95
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
入力データ転送
カーネル起動
同期
出力データ転送
96
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
カーネル起動
同期
97
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
98
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
ブロックサイズ
99
スレッド階層(スレッド、ブロック、グリッド)
グリッド
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
100
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, 64N/256, 256
101
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, 864, 4
Globalスレッド ID (x)
GlobalスレッドID (y)
ブロックサイズ (x,y)
ブロック数 (x,y)
102
ブロック・マッピング、スレッド・マッピング
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)
103
CUDAプログラミング
▪ プログラミングモデル
▪ アーキテクチャ
▪ 性能Tips
104
GPUアーキテクチャ概要
▪ PCI I/F▪ ホスト接続インタフェース
▪ Giga Thread Engine▪ SMに処理を割り振るスケジューラ
▪ DRAM I/F (HBM2)▪ 全SM、PCI I/Fからアクセス可能なメモリ (デバイスメモリ, フレームバッファ)
▪ L2 cache (4MB)▪ 全SMからアクセス可能なR/Wキャッシュ
▪ SM (Streaming Multiprocessor)▪ 「並列」プロセッサ、GP100:最多60Pascal GP100
105
SM (Stream Multi-Processor)
▪ CUDAコア▪ GPUスレッドはこの上で動作
▪ GP100: 64個 /SM
▪ Other units▪ LD/ST, SFU, etc
▪ レジスタ(32bit): 64K個
▪ 共有メモリ: 64KB
▪ Tex/L1キャッシュPascal GP100
106
GPUカーネル実行の流れ
▪ CPUが、GPUに、グリッドを投入▪ 具体的な投入先は、Giga Thread Engine
グリッド
ブロック
ブロック
スレッド
スレッド
107
GPUカーネル実行の流れ
▪ Giga Thread Engine(GTE)が、SMに、ブロックを投入▪ GTEは、ブロックスケジューラ
▪ グリッドをブロックに分解して、ブロックを、空いているSMに割当てる
グリッド
ブロック
ブロック
スレッド
スレッド
108
ブロックをSMに割り当て
▪ 各ブロックは、互いに独立に実行▪ ブロック間では同期しない、実行順序の保証なし
▪ 1つのブロックは複数SMにまたがらない▪ 1つのSMに、複数ブロックが割当てられることはある
グリッド
ブロック
ブロック
ブロック
ブロック
109
GPUカーネル実行の流れ
▪ SM内のスケジューラが、スレッドをCUDAコアに投入
グリッド
ブロック
ブロック
スレッド
スレッド
110
GPUカーネル実行の流れ
▪ SM内のスケジューラが、ワープをCUDAコアに投入▪ ワープ: 32スレッドの塊
▪ ブロックをワープに分割、実行可能なワープを、空CUDAコアに割当てる
グリッド
ブロック
ブロック
ワープ
ワープ
111
ワープのCUDAコアへの割り当て
▪ ワープ内の32スレッドは、同じ命令を同期して実行
▪ 各ワープは、互いに独立して実行▪ 同じブロック内のワープは、明示的に同期可能(__syncthreads())
グリッド
ブロック
ブロック
ワープ
ワープ
ワープ
SIMT(Single Instruction Multiple Threads)
ワープ
112
GPUアーキの変化を問題としないプログラミングモデル
Kepler, CC3.5
192 cores /SM
Pascal, CC6.0
64 cores /SM
Maxwell, CC5.0
128 cores /SM
113
CUDAプログラミング
▪ プログラミングモデル
▪ アーキテクチャ
▪ 性能Tips
114
リソース使用率 (Occupancy)
SMの利用効率を上げる≒ SMに割当て可能なスレッド数を、
上限に近づける
▪ レジスタ使用量(/スレッド)▪ できる限り減らす
▪ DP(64bit)は、2レジスタ消費
▪ レジスタ割り当て単位は8個
▪ レジスタ使用量と、割当て可能なスレッド数の関係▪ 32レジスタ: 2048(100%), 64レジスタ: 1024(50%)
▪ 128レジスタ:512(25%), 256レジスタ: 256(12.5%)
CUDAコア数: 64最大スレッド数: 2048最大ブロック数: 32共有メモリ: 64KB
レジスタ数(32-bit): 64K個
リソース量/SM (GP100)
115
リソース使用率 (Occupancy)
SMの利用効率を上げる≒ SMに割当て可能なスレッド数を、上限に近づける
▪ スレッド数(/ブロック)▪ 64以上にする▪ 64未満だと最大ブロック数がネックになる
▪ 共有メモリ使用量(/ブロック)▪ できる限り減らす▪ 共有メモリ使用量と、割当て可能なブロック数の関係
▪ 32KB:2ブロック, 16KB:4ブロック, 8KB:8ブロック
CUDAコア数: 64最大スレッド数: 2048最大ブロック数: 32共有メモリ: 64KB
レジスタ数(32-bit): 64K個
リソース量/SM (GP100)
116
リソース使用率 (Occupancy)
空き時間を埋める
▪ CUDAストリーム (≒キュー)▪ 同じCUDAストリームに投入した操作: 投入順に実行
▪ 別のCUDAストリームに投入した操作: 非同期に実行 (オーバラップ実行)
(*) 操作: GPUカーネル, データ転送
[CUDAストリームの効果例]GPUカーネルとデータ転送が
オーバラップして同時に実行されている
117
デバイスメモリへのアクセスは、まとめて
▪ コアレス・アクセス▪ 32スレッド(ワープ)のロード/ストアをまとめて、メモリトランザクションを発行
▪ トランザクションサイズ: 32B, 64B or 128B
▪ トランザクション数は、少ないほど良い
配列 128B境界 128B境界
0 1 2 29 30 31283
0 1 14 17 30 311615
0 1 2
Best
Good
Bad
128B x1
64B x2
32B x32
118
分岐を減らす
▪ ワープ内のスレッドが別パスを選択すると遅くなる▪ ワープ内のスレッドは、命令を共有 (SIMT)
▪ ワープ内のスレッドが選んだ全パスの命令を実行
▪ あるパスの命令を実行中、そのパスにいないスレッドはinactive状態
▪ Path divergenceを減らす▪ できる限り、同ワープ内のスレッドは
同じパスを選択させる
A[id] > 0
処理 X
処理 Y
true false
01
23
119
まとめ
▪ GPU Computing
▪ Volta GPUs
▪ OpenACC
▪ CUDA