1074: openacc プログラミング入門

22
エヌビディア合同会社 CUDA エンジニア 村上 真奈 OpenACC プログラミング入門

Upload: nvidia-japan

Post on 07-Apr-2017

1.787 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: 1074: OpenACC プログラミング入門

エヌビディア合同会社 CUDA エンジニア 村上 真奈

OpenACC プログラミング入門

Page 2: 1074: OpenACC プログラミング入門

GPU コンピューティングとは?

アプリケーションコード

+

GPU CPU5% of Code

計算負荷が高い関数

その他の逐次処理CPUで実行

Page 3: 1074: OpenACC プログラミング入門

GPU アクセラレーションの実現方法

アプリケーション

GPU

ライブラリ

ライブラリを呼び出すだけ簡単に高速化を実現

CUDA

重要なコードをCUDAで記述最も自由度が高い

既存コードにディレクティブを挿入して高速化

OpenACC

ディレクティブ

Page 4: 1074: OpenACC プログラミング入門

OpenACCシンプル | 強力 | 柔軟

イリノイ大学MRI画像再構成

70倍 高速化

理研NICAM- 大気現象シミュレーション

5% のコード変更で7~8倍高速化

main() {<serial code>#pragma acc kernels//自動的にGPUで実行

{ <parallel code>

}}

OpenACC利用者

8000人+

Page 5: 1074: OpenACC プログラミング入門

OpenACC ディレクティブ

Program myscience

... serial code ...

!$acc kernels

do k = 1,n1

do i = 1,n2

... parallel code ...

enddo

enddo

!$acc end kernels

...

End Program myscience

CPU GPU

Fortran または C言語のオリジナルコード

コンパイラへシンプルなヒント

コンパイラがコードを並列化

並列部はGPUで逐次処理はCPUで動作

コンパイラへのOpenACC

ヒント

Page 6: 1074: OpenACC プログラミング入門

OpenMP と OpenACC の比較

main() {

double pi = 0.0; long i;

#pragma omp parallel for reduction(+:pi)

for (i=0; i<N; i++)

{

double t = (double)((i+0.05)/N);

pi += 4.0/(1.0+t*t);

}

printf(“pi = %f¥n”, pi/N);

}

CPU

OpenMP

main() {

double pi = 0.0; long i;

#pragma acc kernels

for (i=0; i<N; i++)

{

double t = (double)((i+0.05)/N);

pi += 4.0/(1.0+t*t);

}

printf(“pi = %f¥n”, pi/N);

}

CPU GPU

OpenACC

CPUコアに計算処理を分散

GPUコアに計算処理を分散

Page 7: 1074: OpenACC プログラミング入門

new OpenACC ツールキット(2015/07~)

大学関係者の方は無償で使用可能• Linux x64/ノードロック・ライセンス• 大学関係者以外でも90日間無料トライアル可能

下記のサイトからOpenACC ツールキットをダウンロードhttps://developer.nvidia.com/openacc

OpenACCを始める為のコンパイラ・解析ツールなど一式が簡単にインストール

Page 8: 1074: OpenACC プログラミング入門

OpenACC ツールキット

PGIコンパイラFree OpenACC compiler for academia

NVProfプロファイラEasily find where to add compiler directives

サンプルコードLearn from examples of real-world algorithms

ドキュメントQuick start guide, Best practices, Forums

http://developer.nvidia.com/openacc

GPUウィザードIdentify which GPU libraries can jumpstart code

Page 9: 1074: OpenACC プログラミング入門

OpenACC を始めましょう

Page 10: 1074: OpenACC プログラミング入門

OpenACC ディレクティブ構文

C/C++

#pragma acc 指示行 [節[,]節] …]{ structured block }

Fortran

!$acc 指示行 [節[,]節] …]{ structured block }

!$acc end directive

Page 11: 1074: OpenACC プログラミング入門

例: SAXPY (Y=A*X+Y)

void saxpy(int n,

float a,

float *x,

float *restrict y)

{

#pragma acc parallel

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

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

}

...

saxpy(N, 3.0, 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 12: 1074: OpenACC プログラミング入門

OpenACC 構文: parallel 指示行

• parallel : 並列に実行される領域を指示行で指定

#pragma acc parallelfor(int i=0;i<n;i++){

a[i] = 0.0;

b[i] = 1.0;

c[i] = 2.0;

}

kernel 1 Kernel(カーネル):

GPU上で実行される関数

Page 13: 1074: OpenACC プログラミング入門

OpenACC 構文: kernels 指示行

• kernels : 複数のカーネルを作成

#pragma acc kernelsfor(int i=0;i<n;i++){

a[i] = 0.0;

b[i] = 1.0;

c[i] = 2.0;

}

#pragma acc kernelsfor(int i=0;i<n;i++){

a[i] = b[i] + c[i];

}

kernel 1

kernel 2

Kernel(カーネル):

GPU上で実行される関数

Page 14: 1074: OpenACC プログラミング入門

簡単にコンパイル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 –ta=nvidia –Minfo=accel 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 */

Page 15: 1074: OpenACC プログラミング入門

例:ヤコビ反復法(アルゴリズム)

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 16: 1074: OpenACC プログラミング入門

並列領域 (OpenACC) Parallels と Kernels

— 並列領域を指示

Parallels

— 並列実行スタート

Kernels

— 複数のカーネル

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 17: 1074: OpenACC プログラミング入門

簡単に解析(nvprof)

OpenMP / OpenACC

void saxpy(int n, float a,

float *x,

float *restrict y)

{

#pragma acc kernels 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 18: 1074: OpenACC プログラミング入門

ボトルネックの可視化(nvvp)

1 サイクル

GPU

カーネルGPU

カーネル

Page 19: 1074: OpenACC プログラミング入門

過剰なメモリ転送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];

}

}

}

配列Aへメモリ転送(CPU->GPU)

配列Anewへメモリ転送(CPU->GPU)

配列Anewへメモリ転送(GPU->CPU)

配列Aへメモリ転送(GPU->CPU)

Page 20: 1074: OpenACC プログラミング入門

メモリ転送のタイミングを制御データ制御ディレクティブ

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 21: 1074: OpenACC プログラミング入門

性能比較Time(sec) Speedup

CPU1 OpenMP thread 26.186 --

OpenACC(最適化前) 13.638 1.92x

OpenACC(最適化後) 0.773 33.88x

Ubuntu 14.04LTS 64bit

CPU:Intel Xeon CPU E5-1603 [email protected] x 4

GPU:Tesla K40c

Page 22: 1074: OpenACC プログラミング入門

Thank you