SlideShare a Scribd company logo
第2部 – OpenACC によるデータ移動の管理
Naruhiko Tan, Solution Architect, NVIDIA
OPENACC 講習会
COURSE OBJECTIVE
参加者のみなさんが、
OpenACC を⽤いてみなさん
⾃⾝のアプリケーションを加速
できるようにすること
第2部のアウトライン
カバーするトピック
§ CPU と GPU メモリ
§ CUDA Unified (Managed) Memory
§ OpenACC データ管理
第1部の復習
OPENACC による開発サイクル
分析
並列化最適化
§ 分析 - コードを分析し、並列化や最適
化が必要と思われる箇所を⾒出す。
§ 並列化 - 最も処理に時間がかかる箇所
からコードの並列化を⾏う。計算結果が正
しいことも確認する。
§ 最適化 – 並列化によって得られた性能
から、さらなる⾼速化を図る。
OpenACC ディレクティブ
データ移動の
管理
並列実⾏の
開始
ループ マッピングの
最適化
#pragma acc data copyin(a,b) copyout(c)
{
...
#pragma acc parallel
{
#pragma acc loop gang vector
for (i = 0; i < n; ++i) {
c[i] = a[i] + b[i];
...
}
}
...
}
CPU, GPU, Manycore
移植性
相互操作可能
1つのソース コード
段階的
OpenACC ディレクティブ
第2部︓
データ移動の
管理
第1部︓
並列実⾏の
開始
#pragma acc data copyin(a,b) copyout(c)
{
...
#pragma acc parallel
{
#pragma acc loop gang vector
for (i = 0; i < n; ++i) {
c[i] = a[i] + b[i];
...
}
}
...
}
CPU, GPU, Manycore
移植性
相互操作可能
1つのソース コード
段階的
第3部︓
ループマッピン
グの最適化
while ( err > tol && iter < iter_max ) {
err=0.0;
#pragma acc parallel loop reduction(max:err)
for( int j = 1; j < n-1; j++) {
for( int i = 1; i < m-1; i++ ) {
Anew[OFFSET(j, i, m)] = 0.25 * ( A[OFFSET(j, i+1, m)] + A[OFFSET(j, i-1, m)]
+ A[OFFSET(j-1, i, m)] + A[OFFSET(j+1, i, m)]);
error = fmax( error, fabs(Anew[OFFSET(j, i, m)] - A[OFFSET(j, i , m)]));
}
}
#pragma acc parallel loop
for( int j = 1; j < n-1; j++) {
for( int i = 1; i < m-1; i++ ) {
A[OFFSET(j, i, m)] = Anew[OFFSET(j, i, m)];
}
}
iter++;
}
OPENACC PARALLEL LOOP による並列化
8
最初のループを並列化
max reduction を指定
2つ⽬のループを並列化
どのループを並列化するかのみを指⽰し、
どのように並列化するかの詳細は指⽰
していない。
OPENACC による⾼速化
1.00X
3.05X
10.18X
37.14X
0.00X
5.00X
10.00X
15.00X
20.00X
25.00X
30.00X
35.00X
40.00X
SERIAL MULTICORE NVIDIA TESLA K80 NVIDIA TESLA V100
Speed-Up
Speed-up
PGI 18.7, NVIDIA Tesla V100, Intel i9-7900X CPU @ 3.30GHz
CPU と GPU メモリ
CPU + GPU
構成図
§ 容量は CPU メモリの⽅が⼤きく、バンド幅は GPU メ
モリの⽅が広い。
§ CPU と GPU のメモリはそれぞれ独⽴しており、何らか
の I/O バスによって接続されている (伝統的には
PCI-e が⽤いられる)。
§ CPU – GPU 間で転送されるあらゆるデータは、I/O バ
スを通して⾏われる。
§ GPU のメモリバンド幅に⽐べて、I/O バスは遅い。
§ GPU メモリ上にデータがない限り、GPU は計算を⾏う
ことができない。
High
Capacity
Memory
Shared Cache
High Bandwidth
Memory
Shared Cache
$ $ $ $ $ $ $ $
$ $ $ $ $ $
$ $ $ $ $ $
IO Bus
GPUCPU
CUDA UNIFIED MEMORY
開発者の労⼒を軽減
Without Managed Memory With Managed Memory
Managed Memoryシステム メモリ GPU メモリ
“Managed memory”
とも呼ばれる
CUDA UNIFIED MEMORY
CPU と GPU のメモリが
1つの共有メモリ空間として統合
CUDA MANAGED MEMORY
§ 明⽰的にホスト-デバイス (CPU-GPU) 間のデータ転送を取り扱うのは、難しい場合がある。
§ CUDA Managed Memory を活⽤することにより、データ管理を PGI コンパイラに任せることができ
る。
§ これにより、開発者はデータ管理については最適化としてとらえて、まずは並列化に集中することが
できる。
有⽤性
$ pgcc –fast –acc –ta=tesla:managed –Minfo=accel main.c
$ pgfortran –fast –acc –ta=tesla:managed –Minfo=accel main.f90
MANAGED MEMORY
§ ほぼ全ての場合において、⼿動でデータ転送を⾏うこと
で、より良いパフォーマンスを得ることができる。
§ メモリの確保/開放は、managed memory を⽤いた
⽅がより時間がかかる。
§ データ転送を⾮同期で⾏うことはできない。
§ 今現在、PGI コンパイラと NVIDIA GPU の組み合わせ
でのみ利⽤可能。
制限事項
With Managed Memory
Managed Memory
* Slide Courtesy of PGI
第1部では UNIFIED MEMORY を利⽤
Why?
§ PGI と NVIDIA GPU への依存を排除。
§ 現状のコードでは、データは “少し遅い” タイミングで GPU に到着しているので、改善してみましょ
う。
Unified Memory なしでコードを実⾏してみましょう
基本的なデータ管理
基本的なデータ管理
§ ホストは CPU。
§ デバイスは何らかのアクセラレータ。
§ ターゲット ハードウェアがマルチ コアCPUの場合、ホ
ストとデバイスは同⼀となる。つまり、メモリも同⼀と
なる。
§ マルチ コアのように、メモリ空間が共有されたアクセ
ラレータを使う場合は、明⽰的なデータ管理の必要
はない。
ホスト - デバイス間
Host
Device
Host
Memory
Device
Memory
基本的なデータ管理
§ ターゲット ハードウェアが GPU の場合、CPU-GPU
間でのデータ転送が必要となる。
§ GPU で使われる配列は、GPU 上でメモリ確保され
ていなければならない。
§ CPU か GPU 上のデータが更新された場合、もう⼀
⽅のデータも更新しなければならない。
ホスト – デバイス間
High
Capacity
Memory
Shared Cache
High Bandwidth
Memory
Shared Cache
$ $ $ $ $ $ $ $
$ $ $ $ $ $
$ $ $ $ $ $
IO Bus
GPUCPU
“MANAGED” オプションなしでビルド
pgcc -ta=tesla -Minfo=accel laplace2d.c jacobi.c
laplace2d.c:
PGC-S-0155-Compiler failed to translate accelerator region (see -Minfo
messages): Could not find allocated-variable index for symbol (laplace2d.c: 47)
calcNext:
47, Accelerator kernel generated
Generating Tesla code
48, #pragma acc loop gang /* blockIdx.x */
Generating reduction(max:error)
50, #pragma acc loop vector(128) /* threadIdx.x */
48, Accelerator restriction: size of the GPU copy of Anew,A is unknown
50, Loop is parallelizable
PGC-F-0704-Compilation aborted due to previous errors. (laplace2d.c)
PGC/x86-64 Linux 18.7-0: compilation aborted
jacobi.c:
–ta=tesla:managed から “managed” を削除
データ整形
DATA クローズ
copy ( list ) GPU 上にメモリを確保し、データ領域に⼊る際に、ホストから GPU にデータを
コピーし、データ領域から出る際に、GPU からホストにデータをコピー。
主な使⽤例: GPU へのインプットとなり、かつ上書きされ、ホストに返される
様々なデータについては、これがデフォルト。
copyin ( list ) GPU 上にメモリを確保し、データ領域に⼊る際に、ホストから GPU にデータを
コピー。
主な使⽤例: あるサブルーチンに対するインプット配列とみなせる。
copyout ( list ) GPU 上にメモリを確保し、データ領域から出る際に、GPU からホストにデータを
コピー。
主な使⽤例: インプット データを上書きしない計算結果。
create ( list ) GPU 上にメモリを確保するが、データ コピーは⾏わない。
主な使⽤例: ⼀時配列。
配列の整形
§ コンパイラが配列の形を理解するのに、プログラマの助けが必要な場合がある。
§ 最初の数字は、配列要素の最初のインデックス。
§ C/C++ では、2番めの数字は転送される配列の⻑さ。
§ Fortran では、2番めの数字は最後のインデックス。
copy(array(starting_index:ending_index))
copy(array[starting_index:length]) C/C++
Fortran
配列の整形 (続き)
多次元配列
copy(array(1:N, 1:M))
copy(array[0:N][0:M]) C/C++
Fortran
これらの例は、2次元配列をデバイスにコピーする
配列の整形 (続き)
部分配列
copy(array(i*N/4:i*N/4+N/4))
copy(array[i*N/4:N/4]) C/C++
Fortran
これらの例は、配列全体の ¼ のみデバイスにコピーする
while ( err > tol && iter < iter_max ) {
err=0.0;
#pragma acc parallel loop reduction(max:err) copyin(A[0:n*m]) copy(Anew[0:n*m])
for( int j = 1; j < n-1; j++) {
for( int i = 1; i < m-1; i++ ) {
Anew[OFFSET(j, i, m)] = 0.25 * ( A[OFFSET(j, i+1, m)] + A[OFFSET(j, i-1, m)]
+ A[OFFSET(j-1, i, m)] + A[OFFSET(j+1, i, m)]);
error = fmax( error, fabs(Anew[OFFSET(j, i, m)] - A[OFFSET(j, i , m)]));
}
}
#pragma acc parallel loop copyin(Anew[0:n*m]) copyout(A[0:n*m])
for( int j = 1; j < n-1; j++) {
for( int i = 1; i < m-1; i++ ) {
A[OFFSET(j, i, m)] = Anew[OFFSET(j, i, m)];
}
}
iter++;
}
最適化されたデータ転送
データ クローズで配列
形状を指定
“MANAGED” オプションなしでビルド
pgcc -ta=tesla -Minfo=accel laplace2d.c jacobi.c laplace2d.c:
calcNext:
47, Generating copyin(A[:m*n])
Accelerator kernel generated
Generating Tesla code
48, #pragma acc loop gang /* blockIdx.x */
Generating reduction(max:error)
50, #pragma acc loop vector(128) /* threadIdx.x */
47, Generating implicit copy(error)
Generating copy(Anew[:m*n])
50, Loop is parallelizable
swap:
62, Generating copyin(Anew[:m*n])
Generating copyout(A[:m*n])
Accelerator kernel generated
Generating Tesla code
63, #pragma acc loop gang /* blockIdx.x */
65, #pragma acc loop vector(128) /* threadIdx.x */
65, Loop is parallelizable
jacobi.c:
–ta=tesla:managed から “managed” を削除
OPENACC による ⾼速化 低速化︖
1.00X
3.23X
41.80X
0.33X
0.00X
5.00X
10.00X
15.00X
20.00X
25.00X
30.00X
35.00X
40.00X
45.00X
SERIAL MULTICORE V100 V100 (DATA CLAUSES)
Speed-Up
Speed-up
問題は何か︖
§ Magaged memory オプションなしでビルドするのに必要な情報は全て揃っているはずだが、実⾏
時間が⼤幅に増加。
§ ここでプロファイリング ツールが活躍。
アプリケーションのプロファイル (2 STEPS)
アプリケーションのプロファイル (2 STEPS)
データコピー
実⾏時間のブレークダウン
Data Copy H2D Data Copy D2H CalcNext Swap
ほとんど全ての時間が
ホスト-デバイス間の
データ転送に費やされ
ている
while ( err > tol && iter < iter_max ) {
err=0.0;
#pragma acc parallel loop reduction(max:err) copyin(A[0:n*m]) copy(Anew[0:n*m])
for( int j = 1; j < n-1; j++) {
for( int i = 1; i < m-1; i++ ) {
Anew[OFFSET(j, i, m)] = 0.25 * ( A[OFFSET(j, i+1, m)] + A[OFFSET(j, i-1, m)]
+ A[OFFSET(j-1, i, m)] + A[OFFSET(j+1, i, m)]);
error = fmax( error, fabs(Anew[OFFSET(j, i, m)] - A[OFFSET(j, i , m)]));
}
}
#pragma acc parallel loop copyin(Anew[0:n*m]) copyout(A[0:n*m])
for( int j = 1; j < n-1; j++) {
for( int i = 1; i < m-1; i++ ) {
A[OFFSET(j, i, m)] = Anew[OFFSET(j, i, m)];
}
}
iter++;
}
最適化されたデータ転送
while ループのイタレー
ションごとにデータをコ
ピーしているが、それら
を再利⽤可能︖
最適化されたデータ転送
OPENACC DATA ディレクティブ
§ data ディレクティブは、個々のループをま
たいで、データがデバイスに存在するライフ
タイムを定義する。
§ データ領域中は、デバイスがデータを所有
している。
§ data クローズは、データ領域でのデータ
転送と形状を表現する。
定義
#pragma acc data clauses
{
< Sequential and/or Parallel code >
}
!$acc data clauses
< Sequential and/or Parallel code >
!$acc end data
STRUCTURED DATA ディレクティブ
使⽤例
#pragma acc data copyin(a[0:N],b[0:N]) copyout(c[0:N])
{
#pragma acc parallel loop
for(int i = 0; i < N; i++){
c[i] = a[i] + b[i];
}
}
動作
ホスト メモリ デバイス メモリ
A B C
デバイス上に A の
メモリ領域を確保
A を CPU からデ
バイスにコピー
A
デバイス上に B の
メモリ領域を確保
B を CPU から
デバイスにコピー
B
デバイス上に C の
メモリ領域を確保
デバイス上で
ループを実⾏
C’
C をデバイスから
CPU へコピー
C’
デバイス上の
C を解放
デバイス上の
B を解放
デバイス上の
A を解放
#pragma acc data copy(A[0:n*m]) copyin(Anew[0:n*m])
while ( err > tol && iter < iter_max ) {
err=0.0;
#pragma acc parallel loop reduction(max:err) copyin(A[0:n*m]) copy(Anew[0:n*m])
for( int j = 1; j < n-1; j++) {
for( int i = 1; i < m-1; i++ ) {
Anew[OFFSET(j, i, m)] = 0.25 * ( A[OFFSET(j, i+1, m)] + A[OFFSET(j, i-1, m)]
+ A[OFFSET(j-1, i, m)] + A[OFFSET(j+1, i, m)]);
error = fmax( error, fabs(Anew[OFFSET(j, i, m)] - A[OFFSET(j, i , m)]));
}
}
#pragma acc parallel loop copyin(Anew[0:n*m]) copyout(A[0:n*m])
for( int j = 1; j < n-1; j++) {
for( int i = 1; i < m-1; i++ ) {
A[OFFSET(j, i, m)] = Anew[OFFSET(j, i, m)];
}
}
iter++;
}
最適化されたデータ転送
必要な時のみ A をコピー。
Anew の初期条件はコピーす
るが、最終的な値はしない。
コードを再度ビルド
pgcc -fast -ta=tesla -Minfo=accel laplace2d_uvm.c
main:
60, Generating copy(A[:m*n])
Generating copyin(Anew[:m*n])
64, Accelerator kernel generated
Generating Tesla code
64, Generating reduction(max:error)
65, #pragma acc loop gang /* blockIdx.x */
67, #pragma acc loop vector(128) /* threadIdx.x */
67, Loop is parallelizable
75, Accelerator kernel generated
Generating Tesla code
76, #pragma acc loop gang /* blockIdx.x */
78, #pragma acc loop vector(128) /* threadIdx.x */
78, Loop is parallelizable
データ転送はデータ領域で
のみ発生。
OPENACC による⾼速化
1.00X
3.23X
41.80X 42.99X
0.00X
5.00X
10.00X
15.00X
20.00X
25.00X
30.00X
35.00X
40.00X
45.00X
50.00X
SERIAL MULTICORE V100 V100 (DATA)
Speed-Up
Speed-up
これまでに学んだこと
§ CUDA Unified (Managed) Memory はポーティングのための強⼒なツール。
§ Managed memory を活⽤せずに GPU プログラミングを⾏う場合は、データ転送に際して配列の
形状を指定する必要がある。
§ 各ループごとにデータ転送を⾏うのは、概して⾮効率。
§ OpenACC data 領域によって、データ転送と計算を別々に管理することができる。
データの同期
update: ホストとデバイス間でデータを明⽰的に転送する
データ領域の途中でデータを同期したい場合に有効
クローズ:
self: ホスト側のデータをデバイス側のデータと⼀致させる
device: デバイス側のデータをホスト側のデータと⼀致させる
#pragma acc update self(x[0:count])
#pragma acc update device(x[0:count])
!$acc update self(x(1:end_index))
!$acc update device(x(1:end_index))
Fortran
C/C++
OPENACC UPDATE ディレクティブ
BB*
A*A
OPENACC UPDATE ディレクティブ
A
CPU Memory device Memory
#pragma acc update device(A[0:N])
B*
#pragma acc update self(B[0:N])
update ディレクティブが動作
するためには、CPU とデバイ
ス両⽅にデータが存在してい
る必要がある。
UPDATE でデータ同期
int* A=(int*) malloc(N*sizeof(int))
#pragma acc data create(A[0:N])
while( timesteps++ < numSteps )
{
#pragma acc parallel loop
for(int i = 0; i < N; i++){
a[i] *= 2;
}
if (timestep % 100 ) {
#pragma acc update self(A[0:N])
checkpointAToFile(A, N);
}
}
§ データ領域中で、ホストあるいはデバイス側のデー
タが上書きされる時がある。
§ データ領域を終了し、再度新しいデータ領域を開
始するのはコストがかかる。
§ 代わりに、ホストとデバイス側のデータが同⼀となる
よう更新。
§ 例︓ファイル I/O、通信、etc…
⾮構造 DATA ディレクティブ
⾮構造 DATA ディレクティブ
§ データのライフタイムは、必ずしもきれいに構造
化されているとは限らない。
§ Enter data ディレクティブはデバイスのメモリ
確保を処理する。
§ メモリ確保のために、create か copyin のど
ちらかを使うことができる。
§ 複数の enter data ディレクティブを挿⼊する
ことができるので、その enter data ディレク
ティブが、data 領域の開始とは限らない。
Enter Data ディレクティブ
#pragma acc enter data clauses
< Sequential and/or Parallel code >
#pragma acc exit data clauses
!$acc enter data clauses
< Sequential and/or Parallel code >
!$acc exit data clauses
⾮構造 DATA ディレクティブ
§ Exit data では、デバイスのメモリ解放を処理
する。
§ メモリ解放のために、delete か copyout のど
ちらかを使うことができる。
§ ある配列に対して、enter data の数だけ
exit data を挿⼊する。
§ これらは、別々の関数に挿⼊することができる。
Exit Data ディレクティブ
#pragma acc enter data clauses
< Sequential and/or Parallel code >
#pragma acc exit data clauses
!$acc enter data clauses
< Sequential and/or Parallel code >
!$acc exit data clauses
⾮構造 DATA クローズ
copyin ( list ) enter data に際し、デバイス上にメモリを確保し、ホストからデバイスへデータ
をコピー。
copyout ( list ) exit data に際し、デバイスからホストへデータをコピーし、デバイス上のメモリ
を解放。
create ( list ) enter data に際し、データ転送なしでデバイス上にメモリを確保。
delete ( list ) exit data に際し、データ転送なしでデバイス上のメモリを解放。
⾮構造 DATA ディレクティブ
基本的な例
#pragma acc parallel loop
for(int i = 0; i < N; i++){
c[i] = a[i] + b[i];
}
⾮構造 DATA ディレクティブ
基本的な例
#pragma acc enter data copyin(a[0:N],b[0:N]) create(c[0:N])
#pragma acc parallel loop
for(int i = 0; i < N; i++){
c[i] = a[i] + b[i];
}
#pragma acc exit data copyout(c[0:N]) delete(a,b)
⾮構造 VS. 構造
簡単なコードを例に
#pragma acc enter data copyin(a[0:N],b[0:N]) 
create(c[0:N])
#pragma acc parallel loop
for(int i = 0; i < N; i++){
c[i] = a[i] + b[i];
}
#pragma acc exit data copyout(c[0:N]) 
delete(a,b)
#pragma acc data copyin(a[0:N],b[0:N]) 
copyout(c[0:N])
{
#pragma acc parallel loop
for(int i = 0; i < N; i++){
c[i] = a[i] + b[i];
}
}
⾮構造 構造
§ 複数の開始/終了ポイントを持ち得る。
§ 異なる関数にまたがることができる。
§ 解放されるまではメモリは確保されたまま。
§ 明⽰的に開始/終了ポイントが必要。
§ 1つの関数内に収まる必要がある。
§ メモリはデータ領域中のみ確保される。
⾮構造 DATA ディレクティブ
複数の関数をまたいでの利⽤
int* allocate_array(int N){
int* ptr = (int *) malloc(N * sizeof(int));
#pragma acc enter data create(ptr[0:N])
return ptr;
}
void deallocate_array(int* ptr){
#pragma acc exit data delete(ptr)
free(ptr);
}
int main(){
int* a = allocate_array(100);
#pragma acc kernels
{
a[0] = 0;
}
deallocate_array(a);
}
§ この例では、enter data と exit data がそれぞれ
異なる関数で宣⾔されている。
§ プログラマはデバイス メモリの確保/解放をホスト メ
モリのそれと対応させることができる。
§ C++ のような、構造化スコープの設定が難しい場
合に特に有効。
C/C++ 構造体/クラス
typedef struct {
float x, y, z;
} float3;
int main(int argc, char* argv[]){
int N = 10;
float3* f3 = malloc(N * sizeof(float3));
#pragma acc enter data create(f3[0:N])
#pragma acc kernels
for(int i = 0; i < N; i++){
f3[i].x = 0.0f;
f3[i].y = 0.0f;
f3[i].z = 0.0f;
}
#pragma acc exit data delete(f3)
free(f3);
}
C 構造体
動的なメンバなしの場合
§ 動的なメンバとは、動的にメモリ確保される配
列のような、構造体内の可変サイズを持つメ
ンバのこと。
§ Float3 構造体のメンバは全て固定⻑の変数
なので、OpenACC はこの構造体をデバイス
メモリにコピーすることができる。
§ 動的にメモリが確保される配列が構造体に含
まれていたらどうなるか︖
C 構造体
動的なメンバを含む場合 typedef struct {
float *arr;
int n;
} vector;
int main(int argc, char* argv[]){
vector v;
v.n = 10;
v.arr = (float*) malloc(v.n*sizeof(float));
#pragma acc enter data copyin(v)
#pragma acc enter data create(v.arr[0:v.n])
...
#pragma acc exit data delete(v.arr)
#pragma acc exit data delete(v)
free(v.arr);
}
§ OpenACC は構造体とその動的メンバをコ
ピーするのに⼗分な情報を与えられていない。
§ まず最初に構造体をデバイス メモリにコピーし、
その後に動的メンバのメモリを確保、あるいは
コピーする。
§ メモリ解放時は、動的メンバ、構造体の順に
処理する。
§ OpenACC は動的メンバを⾃動的に構造体
にアタッチする。
おわりに
キー コンセプト
この講義で学んだこと…
§ CPU と GPU の違いと、Unified Memory。
§ OpenACC 配列の整形。
§ OpenACC Data クローズ。
§ OpenACC 構造 Data 領域。
§ OpenACC Update ディレクティブ。
§ OpenACC ⾮構造 Data ディレクティブ。

More Related Content

PDF
20190625 OpenACC 講習会 第3部
NVIDIA Japan
 
PPTX
Tensor コアを使った PyTorch の高速化
Yusuke Fujimoto
 
PPTX
競プロでGo!
鈴木 セシル
 
PDF
1070: CUDA プログラミング入門
NVIDIA Japan
 
PDF
20190625 OpenACC 講習会 第1部
NVIDIA Japan
 
PDF
Halide による画像処理プログラミング入門
Fixstars Corporation
 
PDF
遺伝的アルゴリズム (Genetic Algorithm)を始めよう!
Kazuhide Okamura
 
PDF
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
Masahito Zembutsu
 
20190625 OpenACC 講習会 第3部
NVIDIA Japan
 
Tensor コアを使った PyTorch の高速化
Yusuke Fujimoto
 
競プロでGo!
鈴木 セシル
 
1070: CUDA プログラミング入門
NVIDIA Japan
 
20190625 OpenACC 講習会 第1部
NVIDIA Japan
 
Halide による画像処理プログラミング入門
Fixstars Corporation
 
遺伝的アルゴリズム (Genetic Algorithm)を始めよう!
Kazuhide Okamura
 
Dockerの期待と現実~Docker都市伝説はなぜ生まれるのか~
Masahito Zembutsu
 

What's hot (20)

PDF
大規模グラフ解析のための乱択スケッチ技法
Takuya Akiba
 
PDF
プログラムを高速化する話Ⅱ 〜GPGPU編〜
京大 マイコンクラブ
 
PDF
(DL輪読)Variational Dropout Sparsifies Deep Neural Networks
Masahiro Suzuki
 
PDF
GPU Container as a Serviceを実現するための最新OSS徹底比較 - OpenStack最新情報セミナー 2017年7月
VirtualTech Japan Inc.
 
PDF
証明プログラミング超入門
Kyoko Kadowaki
 
PPTX
DockerコンテナでGitを使う
Kazuhiro Suga
 
PDF
HPC+AI ってよく聞くけど結局なんなの
NVIDIA Japan
 
PPTX
冬のLock free祭り safe
Kumazaki Hiroki
 
PDF
暗認本読書会10
MITSUNARI Shigeo
 
PPTX
CODE FESTIVAL 2014 本選 解説
AtCoder Inc.
 
PDF
Dpdk pmd
Masaru Oki
 
PDF
ゲーム開発者のための C++11/C++14
Ryo Suzuki
 
PDF
DQNからRainbowまで 〜深層強化学習の最新動向〜
Jun Okumura
 
PPT
Glibc malloc internal
Motohiro KOSAKI
 
PDF
Cache-Oblivious データ構造入門 @DSIRNLP#5
Takuya Akiba
 
PPTX
STARC RTL設計スタイルガイドによるVerilog HDL並列記述の補強
Kiyoshi Ogawa
 
PPTX
[DL輪読会]Set Transformer: A Framework for Attention-based Permutation-Invariant...
Deep Learning JP
 
PPTX
[DL輪読会]When Does Label Smoothing Help?
Deep Learning JP
 
PDF
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
NTT DATA Technology & Innovation
 
PDF
深層学習と確率プログラミングを融合したEdwardについて
ryosuke-kojima
 
大規模グラフ解析のための乱択スケッチ技法
Takuya Akiba
 
プログラムを高速化する話Ⅱ 〜GPGPU編〜
京大 マイコンクラブ
 
(DL輪読)Variational Dropout Sparsifies Deep Neural Networks
Masahiro Suzuki
 
GPU Container as a Serviceを実現するための最新OSS徹底比較 - OpenStack最新情報セミナー 2017年7月
VirtualTech Japan Inc.
 
証明プログラミング超入門
Kyoko Kadowaki
 
DockerコンテナでGitを使う
Kazuhiro Suga
 
HPC+AI ってよく聞くけど結局なんなの
NVIDIA Japan
 
冬のLock free祭り safe
Kumazaki Hiroki
 
暗認本読書会10
MITSUNARI Shigeo
 
CODE FESTIVAL 2014 本選 解説
AtCoder Inc.
 
Dpdk pmd
Masaru Oki
 
ゲーム開発者のための C++11/C++14
Ryo Suzuki
 
DQNからRainbowまで 〜深層強化学習の最新動向〜
Jun Okumura
 
Glibc malloc internal
Motohiro KOSAKI
 
Cache-Oblivious データ構造入門 @DSIRNLP#5
Takuya Akiba
 
STARC RTL設計スタイルガイドによるVerilog HDL並列記述の補強
Kiyoshi Ogawa
 
[DL輪読会]Set Transformer: A Framework for Attention-based Permutation-Invariant...
Deep Learning JP
 
[DL輪読会]When Does Label Smoothing Help?
Deep Learning JP
 
OpenJDKのコミッタってどんなことしたらなったの?解決してきた技術課題の事例から見えてくる必要な知識と技術(JJUG CCC 2023 Spring)
NTT DATA Technology & Innovation
 
深層学習と確率プログラミングを融合したEdwardについて
ryosuke-kojima
 
Ad

Similar to 20190625 OpenACC 講習会 第2部 (20)

KEY
NVIDIA Japan Seminar 2012
Takuro Iizuka
 
PDF
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
Computational Materials Science Initiative
 
PDF
Rにおける大規模データ解析(第10回TokyoWebMining)
Shintaro Fukushima
 
PDF
Sparkパフォーマンス検証
BrainPad Inc.
 
PPTX
CAメインフレーム システムリソース削減に貢献する製品について
Kaneko Izumi
 
PPT
Maatkit で MySQL チューニング
Kensuke Nagae
 
PDF
20181212 - PGconf.ASIA - LT
Kohei KaiGai
 
PDF
1072: アプリケーション開発を加速するCUDAライブラリ
NVIDIA Japan
 
PDF
TPC-DSから学ぶPostgreSQLの弱点と今後の展望
Kohei KaiGai
 
PDF
pgconfasia2016 lt ssd2gpu
Kohei KaiGai
 
PDF
Kai = (Dynamo + memcache API) / Erlang
Takeru INOUE
 
PPTX
機械学習 / Deep Learning 大全 (5) Tool編
Daiyu Hatakeyama
 
PDF
20170127 JAWS HPC-UG#8
Kohei KaiGai
 
PDF
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Hiraku Toyooka
 
PPT
遊休リソースを用いた 相同性検索処理の並列化とその評価
Satoshi Nagayasu
 
PDF
PF部2011年12月勉強会.androidsola
android sola
 
PDF
Kof2016 postgresql-9.6
Toshi Harada
 
KEY
Web Operations and Perl kansai.pm#14
Masahiro Nagano
 
PDF
プロとしてのOracleアーキテクチャ入門 ~番外編~ @ Developers Summit 2009
Ryota Watabe
 
PDF
Spark Analytics - スケーラブルな分散処理
Tusyoshi Matsuzaki
 
NVIDIA Japan Seminar 2012
Takuro Iizuka
 
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
Computational Materials Science Initiative
 
Rにおける大規模データ解析(第10回TokyoWebMining)
Shintaro Fukushima
 
Sparkパフォーマンス検証
BrainPad Inc.
 
CAメインフレーム システムリソース削減に貢献する製品について
Kaneko Izumi
 
Maatkit で MySQL チューニング
Kensuke Nagae
 
20181212 - PGconf.ASIA - LT
Kohei KaiGai
 
1072: アプリケーション開発を加速するCUDAライブラリ
NVIDIA Japan
 
TPC-DSから学ぶPostgreSQLの弱点と今後の展望
Kohei KaiGai
 
pgconfasia2016 lt ssd2gpu
Kohei KaiGai
 
Kai = (Dynamo + memcache API) / Erlang
Takeru INOUE
 
機械学習 / Deep Learning 大全 (5) Tool編
Daiyu Hatakeyama
 
20170127 JAWS HPC-UG#8
Kohei KaiGai
 
Linuxのプロセススケジューラ(Reading the Linux process scheduler)
Hiraku Toyooka
 
遊休リソースを用いた 相同性検索処理の並列化とその評価
Satoshi Nagayasu
 
PF部2011年12月勉強会.androidsola
android sola
 
Kof2016 postgresql-9.6
Toshi Harada
 
Web Operations and Perl kansai.pm#14
Masahiro Nagano
 
プロとしてのOracleアーキテクチャ入門 ~番外編~ @ Developers Summit 2009
Ryota Watabe
 
Spark Analytics - スケーラブルな分散処理
Tusyoshi Matsuzaki
 
Ad

More from NVIDIA Japan (20)

PDF
HPC 的に H100 は魅力的な GPU なのか?
NVIDIA Japan
 
PDF
NVIDIA cuQuantum SDK による量子回路シミュレーターの高速化
NVIDIA Japan
 
PDF
Physics-ML のためのフレームワーク NVIDIA Modulus 最新事情
NVIDIA Japan
 
PDF
20221021_JP5.0.2-Webinar-JP_Final.pdf
NVIDIA Japan
 
PDF
開発者が語る NVIDIA cuQuantum SDK
NVIDIA Japan
 
PDF
NVIDIA Modulus: Physics ML 開発のためのフレームワーク
NVIDIA Japan
 
PDF
NVIDIA HPC ソフトウエア斜め読み
NVIDIA Japan
 
PDF
Magnum IO GPUDirect Storage 最新情報
NVIDIA Japan
 
PDF
データ爆発時代のネットワークインフラ
NVIDIA Japan
 
PDF
Hopper アーキテクチャで、変わること、変わらないこと
NVIDIA Japan
 
PDF
GPU と PYTHON と、それから最近の NVIDIA
NVIDIA Japan
 
PDF
GTC November 2021 – テレコム関連アップデート サマリー
NVIDIA Japan
 
PDF
テレコムのビッグデータ解析 & AI サイバーセキュリティ
NVIDIA Japan
 
PDF
必見!絶対におすすめの通信業界セッション 5 つ ~秋の GTC 2020~
NVIDIA Japan
 
PDF
2020年10月29日 プロフェッショナルAI×Roboticsエンジニアへのロードマップ
NVIDIA Japan
 
PDF
2020年10月29日 Jetson活用によるAI教育
NVIDIA Japan
 
PDF
2020年10月29日 Jetson Nano 2GBで始めるAI x Robotics教育
NVIDIA Japan
 
PDF
COVID-19 研究・対策に活用可能な NVIDIA ソフトウェアと関連情報
NVIDIA Japan
 
PDF
Jetson Xavier NX クラウドネイティブをエッジに
NVIDIA Japan
 
PDF
GTC 2020 発表内容まとめ
NVIDIA Japan
 
HPC 的に H100 は魅力的な GPU なのか?
NVIDIA Japan
 
NVIDIA cuQuantum SDK による量子回路シミュレーターの高速化
NVIDIA Japan
 
Physics-ML のためのフレームワーク NVIDIA Modulus 最新事情
NVIDIA Japan
 
20221021_JP5.0.2-Webinar-JP_Final.pdf
NVIDIA Japan
 
開発者が語る NVIDIA cuQuantum SDK
NVIDIA Japan
 
NVIDIA Modulus: Physics ML 開発のためのフレームワーク
NVIDIA Japan
 
NVIDIA HPC ソフトウエア斜め読み
NVIDIA Japan
 
Magnum IO GPUDirect Storage 最新情報
NVIDIA Japan
 
データ爆発時代のネットワークインフラ
NVIDIA Japan
 
Hopper アーキテクチャで、変わること、変わらないこと
NVIDIA Japan
 
GPU と PYTHON と、それから最近の NVIDIA
NVIDIA Japan
 
GTC November 2021 – テレコム関連アップデート サマリー
NVIDIA Japan
 
テレコムのビッグデータ解析 & AI サイバーセキュリティ
NVIDIA Japan
 
必見!絶対におすすめの通信業界セッション 5 つ ~秋の GTC 2020~
NVIDIA Japan
 
2020年10月29日 プロフェッショナルAI×Roboticsエンジニアへのロードマップ
NVIDIA Japan
 
2020年10月29日 Jetson活用によるAI教育
NVIDIA Japan
 
2020年10月29日 Jetson Nano 2GBで始めるAI x Robotics教育
NVIDIA Japan
 
COVID-19 研究・対策に活用可能な NVIDIA ソフトウェアと関連情報
NVIDIA Japan
 
Jetson Xavier NX クラウドネイティブをエッジに
NVIDIA Japan
 
GTC 2020 発表内容まとめ
NVIDIA Japan
 

Recently uploaded (7)

PDF
20250730_QiitaBash_LT登壇資料_PDC_Kurashina.pdf
pdckurashina
 
PDF
20250729_Devin-for-Enterprise
Masaki Yamakawa
 
PDF
TaketoFujikawa_ComicComputing12th_inKumamoto
Matsushita Laboratory
 
PPTX
baserCMS『カスタムコンテンツ』徹底活用術〜あなただけの管理画面を自由自在に〜
Ryuji Egashira
 
PDF
【学会聴講報告】CVPR2025からみるVision最先端トレンド / CVPR2025 report
Sony - Neural Network Libraries
 
PDF
20250726_Devinで変えるエンプラシステム開発の未来
Masaki Yamakawa
 
PDF
MahiroYoshida_セリフに着目したキャラクタロール推定に関する基礎検討_sigcc12th2025
Matsushita Laboratory
 
20250730_QiitaBash_LT登壇資料_PDC_Kurashina.pdf
pdckurashina
 
20250729_Devin-for-Enterprise
Masaki Yamakawa
 
TaketoFujikawa_ComicComputing12th_inKumamoto
Matsushita Laboratory
 
baserCMS『カスタムコンテンツ』徹底活用術〜あなただけの管理画面を自由自在に〜
Ryuji Egashira
 
【学会聴講報告】CVPR2025からみるVision最先端トレンド / CVPR2025 report
Sony - Neural Network Libraries
 
20250726_Devinで変えるエンプラシステム開発の未来
Masaki Yamakawa
 
MahiroYoshida_セリフに着目したキャラクタロール推定に関する基礎検討_sigcc12th2025
Matsushita Laboratory
 

20190625 OpenACC 講習会 第2部

  • 1. 第2部 – OpenACC によるデータ移動の管理 Naruhiko Tan, Solution Architect, NVIDIA OPENACC 講習会
  • 3. 第2部のアウトライン カバーするトピック § CPU と GPU メモリ § CUDA Unified (Managed) Memory § OpenACC データ管理
  • 5. OPENACC による開発サイクル 分析 並列化最適化 § 分析 - コードを分析し、並列化や最適 化が必要と思われる箇所を⾒出す。 § 並列化 - 最も処理に時間がかかる箇所 からコードの並列化を⾏う。計算結果が正 しいことも確認する。 § 最適化 – 並列化によって得られた性能 から、さらなる⾼速化を図る。
  • 6. OpenACC ディレクティブ データ移動の 管理 並列実⾏の 開始 ループ マッピングの 最適化 #pragma acc data copyin(a,b) copyout(c) { ... #pragma acc parallel { #pragma acc loop gang vector for (i = 0; i < n; ++i) { c[i] = a[i] + b[i]; ... } } ... } CPU, GPU, Manycore 移植性 相互操作可能 1つのソース コード 段階的
  • 7. OpenACC ディレクティブ 第2部︓ データ移動の 管理 第1部︓ 並列実⾏の 開始 #pragma acc data copyin(a,b) copyout(c) { ... #pragma acc parallel { #pragma acc loop gang vector for (i = 0; i < n; ++i) { c[i] = a[i] + b[i]; ... } } ... } CPU, GPU, Manycore 移植性 相互操作可能 1つのソース コード 段階的 第3部︓ ループマッピン グの最適化
  • 8. while ( err > tol && iter < iter_max ) { err=0.0; #pragma acc parallel loop reduction(max:err) for( int j = 1; j < n-1; j++) { for( int i = 1; i < m-1; i++ ) { Anew[OFFSET(j, i, m)] = 0.25 * ( A[OFFSET(j, i+1, m)] + A[OFFSET(j, i-1, m)] + A[OFFSET(j-1, i, m)] + A[OFFSET(j+1, i, m)]); error = fmax( error, fabs(Anew[OFFSET(j, i, m)] - A[OFFSET(j, i , m)])); } } #pragma acc parallel loop for( int j = 1; j < n-1; j++) { for( int i = 1; i < m-1; i++ ) { A[OFFSET(j, i, m)] = Anew[OFFSET(j, i, m)]; } } iter++; } OPENACC PARALLEL LOOP による並列化 8 最初のループを並列化 max reduction を指定 2つ⽬のループを並列化 どのループを並列化するかのみを指⽰し、 どのように並列化するかの詳細は指⽰ していない。
  • 9. OPENACC による⾼速化 1.00X 3.05X 10.18X 37.14X 0.00X 5.00X 10.00X 15.00X 20.00X 25.00X 30.00X 35.00X 40.00X SERIAL MULTICORE NVIDIA TESLA K80 NVIDIA TESLA V100 Speed-Up Speed-up PGI 18.7, NVIDIA Tesla V100, Intel i9-7900X CPU @ 3.30GHz
  • 10. CPU と GPU メモリ
  • 11. CPU + GPU 構成図 § 容量は CPU メモリの⽅が⼤きく、バンド幅は GPU メ モリの⽅が広い。 § CPU と GPU のメモリはそれぞれ独⽴しており、何らか の I/O バスによって接続されている (伝統的には PCI-e が⽤いられる)。 § CPU – GPU 間で転送されるあらゆるデータは、I/O バ スを通して⾏われる。 § GPU のメモリバンド幅に⽐べて、I/O バスは遅い。 § GPU メモリ上にデータがない限り、GPU は計算を⾏う ことができない。 High Capacity Memory Shared Cache High Bandwidth Memory Shared Cache $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ IO Bus GPUCPU
  • 13. 開発者の労⼒を軽減 Without Managed Memory With Managed Memory Managed Memoryシステム メモリ GPU メモリ “Managed memory” とも呼ばれる CUDA UNIFIED MEMORY CPU と GPU のメモリが 1つの共有メモリ空間として統合
  • 14. CUDA MANAGED MEMORY § 明⽰的にホスト-デバイス (CPU-GPU) 間のデータ転送を取り扱うのは、難しい場合がある。 § CUDA Managed Memory を活⽤することにより、データ管理を PGI コンパイラに任せることができ る。 § これにより、開発者はデータ管理については最適化としてとらえて、まずは並列化に集中することが できる。 有⽤性 $ pgcc –fast –acc –ta=tesla:managed –Minfo=accel main.c $ pgfortran –fast –acc –ta=tesla:managed –Minfo=accel main.f90
  • 15. MANAGED MEMORY § ほぼ全ての場合において、⼿動でデータ転送を⾏うこと で、より良いパフォーマンスを得ることができる。 § メモリの確保/開放は、managed memory を⽤いた ⽅がより時間がかかる。 § データ転送を⾮同期で⾏うことはできない。 § 今現在、PGI コンパイラと NVIDIA GPU の組み合わせ でのみ利⽤可能。 制限事項 With Managed Memory Managed Memory
  • 17. 第1部では UNIFIED MEMORY を利⽤ Why? § PGI と NVIDIA GPU への依存を排除。 § 現状のコードでは、データは “少し遅い” タイミングで GPU に到着しているので、改善してみましょ う。 Unified Memory なしでコードを実⾏してみましょう
  • 19. 基本的なデータ管理 § ホストは CPU。 § デバイスは何らかのアクセラレータ。 § ターゲット ハードウェアがマルチ コアCPUの場合、ホ ストとデバイスは同⼀となる。つまり、メモリも同⼀と なる。 § マルチ コアのように、メモリ空間が共有されたアクセ ラレータを使う場合は、明⽰的なデータ管理の必要 はない。 ホスト - デバイス間 Host Device Host Memory Device Memory
  • 20. 基本的なデータ管理 § ターゲット ハードウェアが GPU の場合、CPU-GPU 間でのデータ転送が必要となる。 § GPU で使われる配列は、GPU 上でメモリ確保され ていなければならない。 § CPU か GPU 上のデータが更新された場合、もう⼀ ⽅のデータも更新しなければならない。 ホスト – デバイス間 High Capacity Memory Shared Cache High Bandwidth Memory Shared Cache $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ IO Bus GPUCPU
  • 21. “MANAGED” オプションなしでビルド pgcc -ta=tesla -Minfo=accel laplace2d.c jacobi.c laplace2d.c: PGC-S-0155-Compiler failed to translate accelerator region (see -Minfo messages): Could not find allocated-variable index for symbol (laplace2d.c: 47) calcNext: 47, Accelerator kernel generated Generating Tesla code 48, #pragma acc loop gang /* blockIdx.x */ Generating reduction(max:error) 50, #pragma acc loop vector(128) /* threadIdx.x */ 48, Accelerator restriction: size of the GPU copy of Anew,A is unknown 50, Loop is parallelizable PGC-F-0704-Compilation aborted due to previous errors. (laplace2d.c) PGC/x86-64 Linux 18.7-0: compilation aborted jacobi.c: –ta=tesla:managed から “managed” を削除
  • 23. DATA クローズ copy ( list ) GPU 上にメモリを確保し、データ領域に⼊る際に、ホストから GPU にデータを コピーし、データ領域から出る際に、GPU からホストにデータをコピー。 主な使⽤例: GPU へのインプットとなり、かつ上書きされ、ホストに返される 様々なデータについては、これがデフォルト。 copyin ( list ) GPU 上にメモリを確保し、データ領域に⼊る際に、ホストから GPU にデータを コピー。 主な使⽤例: あるサブルーチンに対するインプット配列とみなせる。 copyout ( list ) GPU 上にメモリを確保し、データ領域から出る際に、GPU からホストにデータを コピー。 主な使⽤例: インプット データを上書きしない計算結果。 create ( list ) GPU 上にメモリを確保するが、データ コピーは⾏わない。 主な使⽤例: ⼀時配列。
  • 24. 配列の整形 § コンパイラが配列の形を理解するのに、プログラマの助けが必要な場合がある。 § 最初の数字は、配列要素の最初のインデックス。 § C/C++ では、2番めの数字は転送される配列の⻑さ。 § Fortran では、2番めの数字は最後のインデックス。 copy(array(starting_index:ending_index)) copy(array[starting_index:length]) C/C++ Fortran
  • 25. 配列の整形 (続き) 多次元配列 copy(array(1:N, 1:M)) copy(array[0:N][0:M]) C/C++ Fortran これらの例は、2次元配列をデバイスにコピーする
  • 27. while ( err > tol && iter < iter_max ) { err=0.0; #pragma acc parallel loop reduction(max:err) copyin(A[0:n*m]) copy(Anew[0:n*m]) for( int j = 1; j < n-1; j++) { for( int i = 1; i < m-1; i++ ) { Anew[OFFSET(j, i, m)] = 0.25 * ( A[OFFSET(j, i+1, m)] + A[OFFSET(j, i-1, m)] + A[OFFSET(j-1, i, m)] + A[OFFSET(j+1, i, m)]); error = fmax( error, fabs(Anew[OFFSET(j, i, m)] - A[OFFSET(j, i , m)])); } } #pragma acc parallel loop copyin(Anew[0:n*m]) copyout(A[0:n*m]) for( int j = 1; j < n-1; j++) { for( int i = 1; i < m-1; i++ ) { A[OFFSET(j, i, m)] = Anew[OFFSET(j, i, m)]; } } iter++; } 最適化されたデータ転送 データ クローズで配列 形状を指定
  • 28. “MANAGED” オプションなしでビルド pgcc -ta=tesla -Minfo=accel laplace2d.c jacobi.c laplace2d.c: calcNext: 47, Generating copyin(A[:m*n]) Accelerator kernel generated Generating Tesla code 48, #pragma acc loop gang /* blockIdx.x */ Generating reduction(max:error) 50, #pragma acc loop vector(128) /* threadIdx.x */ 47, Generating implicit copy(error) Generating copy(Anew[:m*n]) 50, Loop is parallelizable swap: 62, Generating copyin(Anew[:m*n]) Generating copyout(A[:m*n]) Accelerator kernel generated Generating Tesla code 63, #pragma acc loop gang /* blockIdx.x */ 65, #pragma acc loop vector(128) /* threadIdx.x */ 65, Loop is parallelizable jacobi.c: –ta=tesla:managed から “managed” を削除
  • 29. OPENACC による ⾼速化 低速化︖ 1.00X 3.23X 41.80X 0.33X 0.00X 5.00X 10.00X 15.00X 20.00X 25.00X 30.00X 35.00X 40.00X 45.00X SERIAL MULTICORE V100 V100 (DATA CLAUSES) Speed-Up Speed-up
  • 30. 問題は何か︖ § Magaged memory オプションなしでビルドするのに必要な情報は全て揃っているはずだが、実⾏ 時間が⼤幅に増加。 § ここでプロファイリング ツールが活躍。
  • 33. 実⾏時間のブレークダウン Data Copy H2D Data Copy D2H CalcNext Swap ほとんど全ての時間が ホスト-デバイス間の データ転送に費やされ ている
  • 34. while ( err > tol && iter < iter_max ) { err=0.0; #pragma acc parallel loop reduction(max:err) copyin(A[0:n*m]) copy(Anew[0:n*m]) for( int j = 1; j < n-1; j++) { for( int i = 1; i < m-1; i++ ) { Anew[OFFSET(j, i, m)] = 0.25 * ( A[OFFSET(j, i+1, m)] + A[OFFSET(j, i-1, m)] + A[OFFSET(j-1, i, m)] + A[OFFSET(j+1, i, m)]); error = fmax( error, fabs(Anew[OFFSET(j, i, m)] - A[OFFSET(j, i , m)])); } } #pragma acc parallel loop copyin(Anew[0:n*m]) copyout(A[0:n*m]) for( int j = 1; j < n-1; j++) { for( int i = 1; i < m-1; i++ ) { A[OFFSET(j, i, m)] = Anew[OFFSET(j, i, m)]; } } iter++; } 最適化されたデータ転送 while ループのイタレー ションごとにデータをコ ピーしているが、それら を再利⽤可能︖
  • 36. OPENACC DATA ディレクティブ § data ディレクティブは、個々のループをま たいで、データがデバイスに存在するライフ タイムを定義する。 § データ領域中は、デバイスがデータを所有 している。 § data クローズは、データ領域でのデータ 転送と形状を表現する。 定義 #pragma acc data clauses { < Sequential and/or Parallel code > } !$acc data clauses < Sequential and/or Parallel code > !$acc end data
  • 37. STRUCTURED DATA ディレクティブ 使⽤例 #pragma acc data copyin(a[0:N],b[0:N]) copyout(c[0:N]) { #pragma acc parallel loop for(int i = 0; i < N; i++){ c[i] = a[i] + b[i]; } } 動作 ホスト メモリ デバイス メモリ A B C デバイス上に A の メモリ領域を確保 A を CPU からデ バイスにコピー A デバイス上に B の メモリ領域を確保 B を CPU から デバイスにコピー B デバイス上に C の メモリ領域を確保 デバイス上で ループを実⾏ C’ C をデバイスから CPU へコピー C’ デバイス上の C を解放 デバイス上の B を解放 デバイス上の A を解放
  • 38. #pragma acc data copy(A[0:n*m]) copyin(Anew[0:n*m]) while ( err > tol && iter < iter_max ) { err=0.0; #pragma acc parallel loop reduction(max:err) copyin(A[0:n*m]) copy(Anew[0:n*m]) for( int j = 1; j < n-1; j++) { for( int i = 1; i < m-1; i++ ) { Anew[OFFSET(j, i, m)] = 0.25 * ( A[OFFSET(j, i+1, m)] + A[OFFSET(j, i-1, m)] + A[OFFSET(j-1, i, m)] + A[OFFSET(j+1, i, m)]); error = fmax( error, fabs(Anew[OFFSET(j, i, m)] - A[OFFSET(j, i , m)])); } } #pragma acc parallel loop copyin(Anew[0:n*m]) copyout(A[0:n*m]) for( int j = 1; j < n-1; j++) { for( int i = 1; i < m-1; i++ ) { A[OFFSET(j, i, m)] = Anew[OFFSET(j, i, m)]; } } iter++; } 最適化されたデータ転送 必要な時のみ A をコピー。 Anew の初期条件はコピーす るが、最終的な値はしない。
  • 39. コードを再度ビルド pgcc -fast -ta=tesla -Minfo=accel laplace2d_uvm.c main: 60, Generating copy(A[:m*n]) Generating copyin(Anew[:m*n]) 64, Accelerator kernel generated Generating Tesla code 64, Generating reduction(max:error) 65, #pragma acc loop gang /* blockIdx.x */ 67, #pragma acc loop vector(128) /* threadIdx.x */ 67, Loop is parallelizable 75, Accelerator kernel generated Generating Tesla code 76, #pragma acc loop gang /* blockIdx.x */ 78, #pragma acc loop vector(128) /* threadIdx.x */ 78, Loop is parallelizable データ転送はデータ領域で のみ発生。
  • 41. これまでに学んだこと § CUDA Unified (Managed) Memory はポーティングのための強⼒なツール。 § Managed memory を活⽤せずに GPU プログラミングを⾏う場合は、データ転送に際して配列の 形状を指定する必要がある。 § 各ループごとにデータ転送を⾏うのは、概して⾮効率。 § OpenACC data 領域によって、データ転送と計算を別々に管理することができる。
  • 43. update: ホストとデバイス間でデータを明⽰的に転送する データ領域の途中でデータを同期したい場合に有効 クローズ: self: ホスト側のデータをデバイス側のデータと⼀致させる device: デバイス側のデータをホスト側のデータと⼀致させる #pragma acc update self(x[0:count]) #pragma acc update device(x[0:count]) !$acc update self(x(1:end_index)) !$acc update device(x(1:end_index)) Fortran C/C++ OPENACC UPDATE ディレクティブ
  • 44. BB* A*A OPENACC UPDATE ディレクティブ A CPU Memory device Memory #pragma acc update device(A[0:N]) B* #pragma acc update self(B[0:N]) update ディレクティブが動作 するためには、CPU とデバイ ス両⽅にデータが存在してい る必要がある。
  • 45. UPDATE でデータ同期 int* A=(int*) malloc(N*sizeof(int)) #pragma acc data create(A[0:N]) while( timesteps++ < numSteps ) { #pragma acc parallel loop for(int i = 0; i < N; i++){ a[i] *= 2; } if (timestep % 100 ) { #pragma acc update self(A[0:N]) checkpointAToFile(A, N); } } § データ領域中で、ホストあるいはデバイス側のデー タが上書きされる時がある。 § データ領域を終了し、再度新しいデータ領域を開 始するのはコストがかかる。 § 代わりに、ホストとデバイス側のデータが同⼀となる よう更新。 § 例︓ファイル I/O、通信、etc…
  • 47. ⾮構造 DATA ディレクティブ § データのライフタイムは、必ずしもきれいに構造 化されているとは限らない。 § Enter data ディレクティブはデバイスのメモリ 確保を処理する。 § メモリ確保のために、create か copyin のど ちらかを使うことができる。 § 複数の enter data ディレクティブを挿⼊する ことができるので、その enter data ディレク ティブが、data 領域の開始とは限らない。 Enter Data ディレクティブ #pragma acc enter data clauses < Sequential and/or Parallel code > #pragma acc exit data clauses !$acc enter data clauses < Sequential and/or Parallel code > !$acc exit data clauses
  • 48. ⾮構造 DATA ディレクティブ § Exit data では、デバイスのメモリ解放を処理 する。 § メモリ解放のために、delete か copyout のど ちらかを使うことができる。 § ある配列に対して、enter data の数だけ exit data を挿⼊する。 § これらは、別々の関数に挿⼊することができる。 Exit Data ディレクティブ #pragma acc enter data clauses < Sequential and/or Parallel code > #pragma acc exit data clauses !$acc enter data clauses < Sequential and/or Parallel code > !$acc exit data clauses
  • 49. ⾮構造 DATA クローズ copyin ( list ) enter data に際し、デバイス上にメモリを確保し、ホストからデバイスへデータ をコピー。 copyout ( list ) exit data に際し、デバイスからホストへデータをコピーし、デバイス上のメモリ を解放。 create ( list ) enter data に際し、データ転送なしでデバイス上にメモリを確保。 delete ( list ) exit data に際し、データ転送なしでデバイス上のメモリを解放。
  • 50. ⾮構造 DATA ディレクティブ 基本的な例 #pragma acc parallel loop for(int i = 0; i < N; i++){ c[i] = a[i] + b[i]; }
  • 51. ⾮構造 DATA ディレクティブ 基本的な例 #pragma acc enter data copyin(a[0:N],b[0:N]) create(c[0:N]) #pragma acc parallel loop for(int i = 0; i < N; i++){ c[i] = a[i] + b[i]; } #pragma acc exit data copyout(c[0:N]) delete(a,b)
  • 52. ⾮構造 VS. 構造 簡単なコードを例に #pragma acc enter data copyin(a[0:N],b[0:N]) create(c[0:N]) #pragma acc parallel loop for(int i = 0; i < N; i++){ c[i] = a[i] + b[i]; } #pragma acc exit data copyout(c[0:N]) delete(a,b) #pragma acc data copyin(a[0:N],b[0:N]) copyout(c[0:N]) { #pragma acc parallel loop for(int i = 0; i < N; i++){ c[i] = a[i] + b[i]; } } ⾮構造 構造 § 複数の開始/終了ポイントを持ち得る。 § 異なる関数にまたがることができる。 § 解放されるまではメモリは確保されたまま。 § 明⽰的に開始/終了ポイントが必要。 § 1つの関数内に収まる必要がある。 § メモリはデータ領域中のみ確保される。
  • 53. ⾮構造 DATA ディレクティブ 複数の関数をまたいでの利⽤ int* allocate_array(int N){ int* ptr = (int *) malloc(N * sizeof(int)); #pragma acc enter data create(ptr[0:N]) return ptr; } void deallocate_array(int* ptr){ #pragma acc exit data delete(ptr) free(ptr); } int main(){ int* a = allocate_array(100); #pragma acc kernels { a[0] = 0; } deallocate_array(a); } § この例では、enter data と exit data がそれぞれ 異なる関数で宣⾔されている。 § プログラマはデバイス メモリの確保/解放をホスト メ モリのそれと対応させることができる。 § C++ のような、構造化スコープの設定が難しい場 合に特に有効。
  • 55. typedef struct { float x, y, z; } float3; int main(int argc, char* argv[]){ int N = 10; float3* f3 = malloc(N * sizeof(float3)); #pragma acc enter data create(f3[0:N]) #pragma acc kernels for(int i = 0; i < N; i++){ f3[i].x = 0.0f; f3[i].y = 0.0f; f3[i].z = 0.0f; } #pragma acc exit data delete(f3) free(f3); } C 構造体 動的なメンバなしの場合 § 動的なメンバとは、動的にメモリ確保される配 列のような、構造体内の可変サイズを持つメ ンバのこと。 § Float3 構造体のメンバは全て固定⻑の変数 なので、OpenACC はこの構造体をデバイス メモリにコピーすることができる。 § 動的にメモリが確保される配列が構造体に含 まれていたらどうなるか︖
  • 56. C 構造体 動的なメンバを含む場合 typedef struct { float *arr; int n; } vector; int main(int argc, char* argv[]){ vector v; v.n = 10; v.arr = (float*) malloc(v.n*sizeof(float)); #pragma acc enter data copyin(v) #pragma acc enter data create(v.arr[0:v.n]) ... #pragma acc exit data delete(v.arr) #pragma acc exit data delete(v) free(v.arr); } § OpenACC は構造体とその動的メンバをコ ピーするのに⼗分な情報を与えられていない。 § まず最初に構造体をデバイス メモリにコピーし、 その後に動的メンバのメモリを確保、あるいは コピーする。 § メモリ解放時は、動的メンバ、構造体の順に 処理する。 § OpenACC は動的メンバを⾃動的に構造体 にアタッチする。
  • 58. キー コンセプト この講義で学んだこと… § CPU と GPU の違いと、Unified Memory。 § OpenACC 配列の整形。 § OpenACC Data クローズ。 § OpenACC 構造 Data 領域。 § OpenACC Update ディレクティブ。 § OpenACC ⾮構造 Data ディレクティブ。