OPENACCの現状 Akira Naruse NVIDAI Developer Technologies アプリをGPUで加速する方法 Application CUDA 主要処理をCUDAで記述 高い自由度 OpenACC Library 既存コードにディレクティブを挿入 簡単に加速 GPU対応ライブラリにチェンジ 簡単に開始 OPENACC GPU CPU 簡単: 既存のコードに コンパイラへのヒントを追加 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 強力: そこそこの労力で、コンパイラが ヒントの 追加 既存のC/Fortranコード コードを自動で並列化 オープン: 複数コンパイラベンダが、 複数アクセラレータをサポート NVIDIA, AMD, Intel(予定) 実行モデル アプリケーション・コード GPU $acc parallel 計算の 重い部分 CPU $acc end parallel 並列部分は GPUコードを生成 逐次部分は CPUコードを生成 SAXPY (Y=A*X+Y, C/C++) 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]; } 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(N, 3.0, x, y); ... SAXPY (Y=A*X+Y, FORTRAN) OpenMP OpenACC subroutine saxpy(n, a, X, Y) real :: a, X(:), Y(:) integer :: n, i subroutine saxpy(n, a, X, Y) real :: a, Y(:), 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 !$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) ... ... call saxpy(N, 3.0, x, y) ... OPENMPとの併用 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); ... 簡単にコンパイル OpenMP / OpenACC void saxpy(int n, float a, float *x, float *restrict y) $ pgcc -Minfo -acc saxpy.c { saxpy: #pragma acc parallel copy(y[:n]) copyin(x[:n]) 16, Generating present_or_copy(y[:n]) #pragma omp parallel for Generating for present_or_copyin(x[:n]) (int i = 0; i < n; ++i) Generatingy[i] Tesla += code a*x[i]; 19, Loop is } parallelizable Accelerator kernel generated 19, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */ ... saxpy(N, 3.0, x, y); ... 簡単に実行 OpenMP / OpenACC void saxpy(int n, float a, float *x, float *restrict y) { $ pgcc -Minfo -acc saxpy.c $ nvprof ./a.out #pragma acc kernels copy(y[:n]) copyin(x[:n]) saxpy: ==10302== NVPROF is profiling process 10302, command: ./a.out #pragma omp parallel for 16, Generating present_or_copy(y[:n]) ==10302== Profiling application: ./a.out for present_or_copyin(x[:n]) (int i = 0; i < n; ++i) Generating ==10302== Profiling result: += code a*x[i]; Generatingy[i] Tesla Time(%) Time Calls Avg Min Max Name } parallelizable 19, Loop is 62.95% 3.0358ms 2 1.5179ms 1.5172ms 1.5186ms [CUDA memcpy HtoD] Accelerator kernel generated 31.48% 1.5181ms 1 1.5181ms 1.5181ms 1.5181ms [CUDA memcpy DtoH] ... 19, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */ 5.56% 268.31us 1 268.31us 268.31us 268.31us saxpy_19_gpu saxpy(N, 3.0, x, y); ... 簡単に高速 Automotive Financial Life Science Real-Time Object Detection Valuation of Stock Portfolios using Monte Carlo Interaction of Solvents and Biomolecules Global Manufacturer of Navigation Systems Global Technology Consulting Company University of Texas at San Antonio 40時間で5倍 4時間で2倍 8時間で5倍 コンパイラとツール 2013年10月~ コンパイラ デバッグツール 2013年12月~ 2014年1月~ OpenACC 2.0対応 2015年(予定) SPEC ACCEL 15本のOpenACCベンチマーク www.spec.org/accel 気象・天候・海洋モデル 気候(C) NCAR-CISL, ORNL / CESM • • CAM-SE (HOMME) LANL / POP MPAS-O NASA / GEOS-5 NOAA-GFDL / CFSv2 • NOAA-GFDL / MOM6 UKMO / HadGEM3 • • UM GungHo NEMO MPI-M / MPI-ESM • ECHAM6 ICON-ATM MPIOM ICON-OCE 天候(W) UKMO / UM GungHo ECMWF / IFS PantaRhei DWD / GME ICON NOAA-NCEP / GFS NIM? EC, CMC / GEM USNRL / NAVGEM NOAA-ESRL / FIM NIM DWD, MPI-M / ICON NOAA-ESRL / NIM NCAR / MPAS-A 海洋(O) LANL / POP MPAS-O NOAA-GFDL / MOM6 CNRS, STFC/ NEMO USNRL / HYCOM MIT / MITgcm LANL / MPAS-O MPI-M / ICON-OCE Rutgers-UCLA / ROMS UNC-ND / ADCIRC NCAR-M3 / WRF MPAS-A or NIM USNRL / COAMPS DWD, MCH / COSMO GPU Development (8) CAM-SE, GEOS-5, NEMO, WRF, COSMO, NIM, FIM, GRAPES NCAR-M3 / WRF MPAS-A or NIM MFR / AROME GPU Evaluation (15) MFR, ICHEC / HARMONIE POP, ICON, NICAM, OLAM, GungHo, PantaRhei, ASUCA, DWD, MCH / COSMO HARMONIE, COAMPS, HYCOM, MITgcm, ROMS, ADCIRC, • HIRLAM + ALADIN UniMiami / OLAM DYNAMICO, MOM6 JAMSTEC-JMA / ASUCA GPU Not Started (7) CAS-CMA / GRAPES MPAS-A, MPAS-O, GFS, GEM, NAVGEM, AROME, ICON-OCE UniMiami / OLAM Indicates Next-Gen Model • RIKEN, UniTokyo / NICAM IPSL / DYNAMICO OPENACCへの移行 Model Focus GPU Approach Collaboration NCAR / WRF NWP/Climate-R (1) OpenACC, (2) CUDA (1) NCAR-MMM, (2) SSEC UW-M DWD / COSMO NWP/Climate-R CUDA+OpenACC CSCS, MeteoSwiss (MCH) ORNL / CAM-SE Climate-G CUDA-F OpenACC ORNL, Cray NCAR / CAM-SE Climate- G CUDA,CUDA-F,OpenACC NCAR-CISL NOAA / NIM&FIM NWP/Climate-G F2C-ACC,OpenACC NOAA-ESRL, PGI NASA / GEOS-5 Climate-G CUDA-F OpenACC NASA, PGI CNRS / NEMO Ocean GCM OpenACC STFC UKMO / GungHo NWP/Climate-G OpenACC STFC, UKMO in future? USNRL / HYCOM Ocean GCM OpenACC US Naval Research Lab RIKEN / NICAM Climate-G OpenACC RIKEN, UniTokyo UNC / ADCIRC Storm Surge OpenACC (AmgX?) LSU LONI NOAA / MOM6 Ocean GCM OpenACC NOAA-GFDL NASA / FV-Core Atmospheric GCM OpenACC NASA, NOAA-GFDL Other Evaluations: US – COAMPS, MPAS, ROMS, OLAM; Europe – ICON, IFS, HARMONIE; DYNAMICO Asia-Pacific – ASUCA (JP), GRAPES (CN) OPENACCでどこまで出来るの? 例: JACOBI ITERATION A(i,j+1) 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-1,j) A(i,j) A(i+1,j) A(i,j-1) 並列領域 (KERNELS CONSTRUCT) 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]; } } } Parallels と Kernels — 並列領域を指示 Parallels — 並列実行スタート Kernels — 複数のカーネル 並列領域 (KERNELS CONSTRUCT) 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]); } } Parallels と Kernels — 並列領域を指示 Parallels — 並列走行の開始 Kernels $ pgcc -Minfo=acc -acc jacobi.c — 複数のGPUカーネル #pragma acc kernels jacobi: for (int j = 1; j < N-1; j++) { 60, Loop carried scalar dependence for 'error' at line 64 for (int i = 1; i < M-1; i++) { ... = Anew[j][i]; A[j][i] } Accelerator scalar kernel generated } 61, Loop carried scalar dependence for 'error' at line 64 } ... Accelerator scalar kernel generated リダクション (REDUCTION CLAUSE) while ( error > tol ) { error = 0.0; #pragma acc kernels #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]); } } #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]; } } } 演算の種類 + 和 * 積 Max 最大 Min 最小 | ビット和 & ビット積 ^ XOR || 論理和 && 論理積 リダクション (REDUCTION CLAUSE) while ( error > tol ) { error = 0.0; 演算の種類 + #pragma acc kernels #pragma acc loop reduction(max:error) * for (int j = 1; j < N-1; j++) { #pragma acc loop reduction(max:error) Max $ pgccfor -Minfo=acc jacobi.c (int i = 1;-acc i < M-1; i++) { Min jacobi: Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; 59, Generating present_or_copyout(Anew[1:4094][1:4094])| error = max(error, abs(Anew[j][i] - A[j][i]); Generating present_or_copyin(A[:][:]) } & Generating Tesla code } 61, Loop is parallelizable ^ 和 積 最大 最小 ビット和 ビット積 XOR #pragma acc kernels 63, Loop is parallelizable for (int j = 1; j < N-1; j++) { || 論理和 Accelerator generated for (int i = 1; i kernel < M-1; i++) { A[j][i] = Anew[j][i]; 61, #pragma acc loop gang /* blockIdx.y */ && 論理積 } 63, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */ } } Max reduction generated for error データ転送方法 (DATA CLAUSE) while ( error > tol ) { error = 0.0; #pragma acc kernels #pragma acc loop reduction(max:error) for (int j = 1; j < N-1; j++) { #pragma acc loop reduction(max:error) $ pgccfor -Minfo=acc jacobi.c (int i = 1;-acc i < M-1; i++) { jacobi: Anew[j][i] = (A[j][i+1] + A[j][i-1] + A[j-1][i] + A[j+1][i]) * 0.25; 59, Generating present_or_copyout(Anew[1:4094][1:4094]) error = max(error, abs(Anew[j][i] - A[j][i]); Generating present_or_copyin(A[:][:]) } Generating Tesla code } 61, Loop is parallelizable #pragma acc kernels 63, Loop is parallelizable for (int j = 1; j < N-1; j++) { Accelerator generated for (int i = 1; i kernel < M-1; i++) { A[j][i] = Anew[j][i]; 61, #pragma acc loop gang /* blockIdx.y */ } 63, #pragma acc loop gang, vector(128) /* blockIdx.x threadIdx.x */ } } Max reduction generated for error データ転送方法 (DATA CLAUSE) while ( error > tol ) { error = 0.0; #pragma acc kernels \ pcopyout(Anew[1:N-2][1:M-2]) pcopyin(A[0:N][0:M]) #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]); } } #pragma acc kernels \ pcopyout(A[1:N-2][1:M-2]) pcopyin(Anew[1:N-2][1:M-2]) for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } copyin (HostGPU) copyout (HostGPU) copy create present pcopyin pcopyout pcopy pcreate データ転送方法 (DATA CLAUSE) 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]); } } #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]; } } copyin (HostGPU) copyout (HostGPU) copy create present pcopyin pcopyout pcopy pcreate データ転送がボトルネック (NVVP) 稼働率:低い 1 cycle GPU kernel GPU kernel 過剰なデータ転送 GPU Host while ( error > tol ) { error = 0.0; #pragma acc kernels \ pcopy(Anew[:][:]) \ pcopyin(A[:][:]) { } #pragma acc kernels \ pcopy(A[:][:]) \ pcopyin(Anew[:][:]) { } } copyin copyout copyin copyout #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]); } } for (int j = 1; j < N-1; j++) { for (int i = 1; i < M-1; i++) { A[j][i] = Anew[j][i]; } } データ領域 (DATA CONSTRUCT) #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]); } } #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]; } } } copyin (CPUGPU) copyout (CPUGPU) copy create present pcopyin pcopyout pcopy pcreate 適正なデータ転送 GPU Host #pragma acc data \ pcopy(A) create(Anew) while ( error > tol ) { error = 0.0; copyin #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]); } } } #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]; } } } } copyout データ転送の削減 (NVVP) 稼働率:高い 1 cycle 2つの処理 CPU Memory データ転送 GPU Memory PCI 計算オフロード 計算オフロード、データ転送、両方を考慮する必要がある カーネルチューニング カーネルチューニング (LOOP CONSTRUCT) #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]); } } ... } カーネルチューニング (LOOP CONSTRUCT) #pragma acc data pcopy(A) create(Anew) while ( error > tol ) { error = 0.0; Gang Worker #pragma acc kernels pcopy(Anew[:][:]) pcopyin(A[:][:]) Vector … SIMD幅 #pragma acc loop reduction(max:error) for (int j = 1; j < N-1; j++) { Independent $ pgcc -Minfo=acc -acc jacobi.c #pragma acc loop reduction(max:error) jacobi: Collapse for (int i = 1; i < M-1; i++) { 59, Generating present_or_copyout(Anew[1:4094][1:4094]) Anew[j][i] = (A[j][i+1] + A[j][i-1] + Seq + A[j+1][i]) * 0.25; GeneratingA[j-1][i] present_or_copyin(A[:][:]) error = max(error, abs(Anew[j][i] - A[j][i]); 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 カーネルチューニング (LOOP CONSTRUCT) #pragma acc data pcopy(A) create(Anew) while ( error > tol ) { error = 0.0; } Gang Worker #pragma acc kernels pcopy(Anew[:][:]) pcopyin(A[:][:]) #pragma acc loop reduction(max:error) gang vector(1) for (int j = 1; j < N-1; j++) { #pragma acc loop reduction(max:error) 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]); } } Vector … SIMD幅 ... Tile Collapse Independent Seq Cache 実行条件設定 (VECTOR CLAUSE) #pragma acc loop gang vector(4) for (j = 0; j < 16; j++) { #pragma accloop gang vector(16) for (i = 0; i < 16; i++) { ... #pragma acc loop gang vector(8) for (j = 1; j < 16; j++) { #pragma accloop gang vector(8) for (i = 0; i < 16; i++) { ... i i 4 x 16 8x8 8x8 8x8 8x8 4 x 16 j 4 x 16 j カーネルチューニング (LOOP CONSTRUCT) #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]); } } ... } Gang Worker Vector … SIMD幅 Collapse Independent Seq Cache Tile ... カーネルチューニング (LOOP CONSTRUCT) #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]; #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]); } } ... } Gang Worker Vector … SIMD幅 Collapse Independent Seq Cache Tile ... カーネルチューニング (LOOP CONSTRUCT) #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], ... ); } } } Gang Worker Vector … SIMD幅 Collapse Independent Seq Cache Tile ... MPIとは簡単に併用できるの? MPI並列 (HALO EXCHANGE) A(i,j+1) A(i-1,j) A(i,j) A(i+1,j) A(i,j-1) ブロック分割 各プロセスは1ブロック担当 境界部(halo)のデータ交換 MPI JACOBI ITERATION #pragma acc data pcopy(A) create(Anew) while ( error > tol ) { #pragma acc kernels pcopy(Anew) pcopyin(A) calc_new_A( Anew, A, ... ); #pragma acc kernels pcopy(A) pcopyin(Anew) update_A( A, Anew ); } MPI JACOBI ITERATION GPU #pragma acc data pcopy(A) create(Anew) while ( error > tol ) { pack_data_at_boundary( send_buf, A, ... ); exchange_data_by_MPI( recv_buf, send_buf, ... ); unpack_data_to_halo( A, recv_buf, ... ); #pragma acc kernels pcopy(Anew) pcopyin(A) calc_new_A( Anew, A, ... ); #pragma acc kernels pcopy(A) pcopyin(Anew) update_A( A, Anew ); } 1.送信データ の梱包 MPI 2.データの交換 GPU 3.受信データ の開梱 MPI JACOBI ITERATION #pragma acc data pcopy(A) create(Anew) while ( error > tol ) { #pragma acc kernels pcopyin(A) pcopyout(send_buf) pack_data_at_boundary( send_buf, A, ... ); exchange_data_by_MPI( recv_buf, send_buf, ... ); #pragma acc kernels pcopy(A) pcopyin(recv_buf) unpack_data_to_halo( A, recv_buf, ... ); #pragma acc kernels pcopy(Anew) pcopyin(A) calc_new_A( Anew, A, ... ); #pragma acc kernels pcopy(A) pcopyin(Anew) update_A( A, Anew ); } GPU 1. GPU上でデータを 送信バッファに梱包 し、Hostに転送 MPI 2. 隣接プロセスと データ交換 GPU 3. GPUに転送、 GPU上で受信バッ ファのデータを開梱 MPI JACOBI ITERATION (NVVP) 1 cycle Pack MPI Upck データ梱包 MPI データ開梱 オーバーラップ (ASYNC/WAIT CLAUSE) while ( error > tol ) { #pragma acc kernels pcopyin(A) pcopyout(send_buf) pack_data_at_boundary( send_buf, A, ... ); exchange_data_by_MPI( recv_buf, send_buf, ... ); #pragma acc kernels pcopy(A) pcopyin(recv_buf) unpack_data_to_halo( A, recv_buf, ... ); #pragma acc kernels pcopy(Anew) pcopyin(A) calc_new_A( Anew, A, ... ); #pragma acc kernels pcopy(A) pcopyin(Anew) update_A( A, Anew ); } オーバーラップ (ASYNC/WAIT CLAUSE) while ( error > tol ) { #pragma acc kernels pcopyin(A) pcopyout(send_buf) pack_data_at_boundary( send_buf, A, ... ); #pragma acc kernels pcopy(Anew) pcopyin(A) calc_new_A_inside( Anew, A, ... ); 内部 exchange_data_by_MPI( recv_buf, send_buf, ... ); #pragma acc kernels pcopy(A) pcopyin(recv_buf) unpack_data_to_halo( A, recv_buf, ... ); #pragma acc kernels pcopy(Anew) pcopyin(A) calc_new_A_at_boundary( Anew, A, ... ); #pragma acc kernels pcopy(A) pcopyin(Anew) update_A( A, Anew ); } 境界部 オーバーラップ (ASYNC/WAIT CLAUSE) while ( error > tol ) { #pragma acc kernels pcopyin(A) pcopyout(send_buf) async(2) pack_data_at_boundary( send_buf, A, ... ); #pragma acc kernels pcopy(Anew) pcopyin(A) async(1) calc_new_A_inside( Anew, A, ... ); #pragma acc wait(2) exchange_data_by_MPI( recv_buf, send_buf, ... ); #pragma acc kernels pcopy(A) pcopyin(recv_buf) async(2) unpack_data_to_halo( A, recv_buf, ... ); #pragma acc kernels pcopy(Anew) pcopyin(A) async(2) calc_new_A_at_boundary( Anew, A, ... ); #pragma acc kernels pcopy(A) pcopyin(Anew) wait(1,2) update_A( A, Anew ); } オーバーラップ(NVVP) 1 cycle Pack MPI Upck OPENACCって、 実際に使われているの? NICAM 気象・気候モデル by 理研AICS/東大 — 膨大なコード (数十万行) — ホットスポットがない (パレートの法則) 特性の異なる2種類の処理 — 力学系 … メモリバンド幅ネック — 物理系 … 演算ネック NICAM: 力学系(NICAM-DC) Tsubame 2.5 (GPU:K20X) OpenACCによるGPU化 — 主要サブルーチンは、全てGPU上 で動作(50以上) — MPI対応済み — 2週間 良好なスケーラビリティ — Tsubame 2.5, 最大2560 GPUs Performance (GFLOPS) 1.E+05 K computer (*) weak scaling Tsubame 2.5 (CPU:WSM) 1.E+04 1.E+03 1.E+02 — Scaling factor: 0.8 1.E+01 1.E+00 Weak scaling 1.E+01 1.E+02 1.E+03 Number of CPUs or GPUs 1.E+04 NICAM: 力学系(NICAM-DC) Measured Performance (GFLOPS) 1.E+05 Tsubame 2.5 (GPU:K20X) K computer 1.E+04 Tsubame 2.5 (CPU:WSM) 1.E+03 1.E+02 1.E+01 1.E+02 1.E+03 1.E+04 1.E+05 Aggregate Peak Memory Bandwidth (GB/s) 1.E+06 NICAM: 物理系(SCALE-LES) Atmospheric radiation transfer Speedup vs. CPU 1-core — 物理系の中で、最も重い計算 — OpenACCによるGPU対応、完了 160 140 120 100 80 60 40 20 0 151 76.0 37.8 1.00 1.99 3.88 8.51 1 core 2 core 4 core 10 core Xeon E5-2690v2(3.0GHz,10-core) 1 GPU 2 GPUs 4 GPUs Tesla K40 (*) PCIデータ転送時間込み, グリッドサイズ:1256x32x32 SEISM3D 地震シミュレーション by 東大地震研(古村教授) 主要サブルーチンのGPU対応が完了 — メモリバンド幅ネック、 3次元モデル(2次元分割)、隣接プロセス間通信 GPUの実行時間内訳 SEISM3D (480x480x1024, 1K steps) 600 Time (sec) 500 3.4x speedup (アプリ全体) 605 459 400 140 Others (CPU, MPI and so on) 120 [CUDA memcpy DtoH] 100 300 80 200 60 [CUDA memcpy HtoD] (other subroutines) update_vel_pml 100 134 0 update_vel 40 update_stress_pml update_stress 20 K: 8x SPARC64 VIIIfx CPU: 8x Xeon E5-2690v2 GPU: 8x Tesla K40 diff3d_* 0 GPU: 8x Tesla K40 SEISM3D Tesla K40 SX9 FX10 K Xeon E5-2* v2 (IVB) Xeon E5-4* (SDB) Xeon X7* (NHL EX) 性能 (M grids/sec) 10,000 1,000 100 100 1,000 トータルピークメモリバンド幅 (GB/s) 10,000 FFR/BCM 次世代CFD by 理研AICS/北大(坪倉准教授) MUSCL_bench: — MUSCLスキームに基づくFlux計算 (とても複雑な計算) — CFD計算の主要部分 (60-70%) Speedup vs. 1 CPU core — OpenACCによるGPU対応、完了 35 30 25 20 15 10 5 0 33.21 1.00 1.93 1 core 2 core 4.55 5 core Xeon E5-2690v2(3.0GHz,10-core) 8.30 10 core 1 GPU Tesla K40 (*) PCIデータ転送時間込み、サイズ:80x32x32x32 まとめ OpenACCの現状を紹介 簡単: 既存コードへのディレクティブ追加 強力: 少ない労力でGPU利用可能 オープン: 採用事例の増加 CUDA 6の強化ポイント Akira Naruse NVIDAI Developer Technologies CUDA 6 ユニファイド・メモリ XTライブラリ ドロップイン・ライブラリ GPUDirect RDMA 開発ツール ユニファイドメモリ 開発者から見えるメモリモデル ユニファイドメモリ Now ホストメモリ GPUメモリ 煩雑なメモリマネジメント CPUコード void sortfile(FILE *fp, int N) { char *data; data = (char *)malloc(N); fread(data, 1, N, fp); qsort(data, N, 1, compare); use_data(data); free(data); } GPUコード void sortfile(FILE *fp, int N) { char *data char *d_data; data = (char *)malloc(N); cudaMalloc(&d_data, N); fread(data, 1, N, fp); cudaMemcpy(d_data, data, N, ..); qsort<<<...>>>(d_data,N,1,compare); cudaDeviceSynchronize(); cudaMemcpy(data, d_data, N, ..); use_data(data); cudaFree(d_data); free(data); } メモリマネジメントを簡素化 CPUコード void sortfile(FILE *fp, int N) { char *data; } ユニファイドメモリ(CUDA6) void sortfile(FILE *fp, int N) { char *data data = (char *)malloc(N); cudaMallocManaged(&d_data, N); fread(data, 1, N, fp); fread(data, 1, N, fp); qsort(data, N, 1, compare); qsort<<<...>>>(d_data,N,1,compare); cudaDeviceSynchronize(); use_data(data); use_data(data); free(data); cudaFree(data); } メモリマネジメントの統合(将来) CPUコード void sortfile(FILE *fp, int N) { char *data; } 将来? void sortfile(FILE *fp, int N) { char *data data = (char *)malloc(N); data = (char *)malloc(N); fread(data, 1, N, fp); fread(data, 1, N, fp); qsort(data, N, 1, compare); qsort<<<...>>>(d_data,N,1,compare); cudaDeviceSynchronize(); use_data(data); use_data(data); free(data); free(data); } DEEP COPY CPU Memory struct dataElem { int prop1; int prop2; char *text; }; dataElem prop1 prop2 *text “Hello World” GPU Memory DEEP COPY コピーが 2回必要 CPU Memory struct dataElem { int prop1; int prop2; char *text; }; dataElem prop1 prop2 “Hello World” *text dataElem prop1 prop2 *text “Hello World” GPU Memory DEEP COPY 実際は 3回必要 void launch(dataElem *elem) { dataElem *g_elem; char *g_text; CPU Memory int textlen = strlen(elem->text); cudaMalloc(&g_elem, sizeof(dataElem)); cudaMalloc(&g_text, textlen); cudaMemcpy(g_elem, elem, sizeof(dataElem)); cudaMemcpy(g_text, elem->text, textlen); cudaMemcpy(&(g_elem->text), &g_text, sizeof(g_text)); kernel<<< ... >>>(g_elem); } dataElem prop1 prop2 “Hello World” *text dataElem prop1 prop2 *text “Hello World” GPU Memory DEEP COPY (ユニファイドメモリ) void launch(dataElem *elem) { kernel<<< ... >>>(elem); } CPU Memory Unified Memory dataElem prop1 prop2 *text “Hello World” GPU Memory 連結リスト CPU Memory key key key key data data data data next next next next GPU Memory 連結リスト 毎回、全部転送 — PCIのバンド幅ネック CPU Memory 最初は全部転送、以降は 更新箇所だけ転送 — とても複雑な処理 key key key key data data data data next next next next 全部を 転送? CPUメモリにデータを配置、 GPUはPCI経由のアクセス — PCI経由、遅い GPU Memory 連結リスト (ユニファイドメモリ) CPUからもGPUからもリスト 操作が可能 — 挿入、削除 CPU Memory リスト更新後に、CPUメモリと GPUメモリ間の明示的な同 期は不要 CPUとGPUから同時アクセスはNG 、排他制御必要 通常のメモ リアクセス Unified Memory key key key key data data data data next next next next 通常のメモリ アクセス GPU Memory ロードマップ CUDA 6:簡単に利用 Next:最適化 Pascal 単一のポインタ Memcpy記述不要 ホスト側プログラムと データ構造を共有 プリフェッチ データ移動ヒント システムアロケータの統合 OSサポートの追加 スタックメモリの統合 メモリコヒーレンシを HWでアクセラレート XTライブラリ XTライブラリ cuBLAS-XT and cuFFT-XT 明示的なデータ転送の指示は不要 — 必要なGPUメモリはライブラリが確保 マルチGPUに自動対応 — マルチGPU向けのコード記述は不要 GPUメモリ容量を超えるサイズに対応 (out-of-core) — カーネル実行とデータ転送をオーバーラップ(BLAS level 3) CUBLAS 行列積コード cuBLAS cublasHandle_t handle; cublasCreate(&handle); cudaMalloc(&d_A, ..); cudaMalloc(&d_B, ..); cudaMalloc(&d_C, ..); cudaSetMatrix(.., d_A, .., A, ..); cudaSetMatrix(.., d_B, .., B, ..); cublasDgemm(handle, .., d_A, .., d_B, .., d_C, ..); cudaGetMatrix(.., d_C, .., C, ..); cudaFree(d_A); cudaFree(d_B); cudaFree(d_C); cublasDestroy(handle); CUBLAS CUBLAS-XT 行列積コード cuBLAS cublasHandle_t handle; cublasCreate(&handle); cudaMalloc(&d_A, ..); cudaMalloc(&d_B, ..); cudaMalloc(&d_C, ..); cudaSetMatrix(.., d_A, .., A, ..); cudaSetMatrix(.., d_B, .., B, ..); cublasDgemm(handle, .., d_A, .., d_B, .., d_C, ..); cudaGetMatrix(.., d_C, .., C, ..); cudaFree(d_A); cudaFree(d_B); cudaFree(d_C); cublasDestroy(handle); cuBLAS-XT cublasXtHandle_t handle; cublasXtCreate(&handle); cublasXtDgemm(handle, .., A, .., B, .., C, ..); cublasXtDestroy(handle); CUBLAS-XT API 使用GPU — cublasXtDeviceSelect() GPU数、使用GPU IDs ブロッキングサイズ — cublasXtSetBlockDim() ブロッキングサイズの設定 — cublasXtGetBloskDim() (現設定の取得) CPU・GPUハイブリッド実行 — cublasXtSetCpuRoutine() CPU版BLASの設定 — cublasXtSetCpuRatio() CPU比率の設定 Pinnedメモリ — cublasXtSetPinningMemMode() Pinnedメモリの設定 — cublasXtGetPinningMemMode() (現設定の取得) CUBLAS-XT 全てのBLAS level 3 ルーチンをサポート 行列サイズがGPUメモリ容量超でもOK (out-of-core) cuBLAS ZGEMM Performance on 2 GPUs 2500 GFLOPS 2000 1 K20c 1500 2 K20c 1000 500 In-core 0 0 4096 8192 Out-of-core 12288 16384 20480 Matrix Size (NxN) 24576 28672 CUBLAS-XT (NVVP) ドロップイン・ライブラリ ドロップイン・ライブラリ 標準ライブラリAPIでのGPU利用を可能に NVBLAS — BLAS level 3関数呼び出しを、自動的にcuBLASに置き換え — cuBLAS利用のためのソース変更は不要 CPU dgemm(.., A, .., B, .., C, ..); 使い方 — NVBLASを入れて再コンパイル — Linuxは、LD_PRELOAD設定で使用可能 (最コンパイル不要) ドロップイン・ライブラリ 標準ライブラリAPIでのGPU利用を可能に NVBLAS — BLAS level 3関数呼び出しを、自動的にcuBLASに置き換え — cuBLAS利用のためのソース変更は不要 CPU dgemm(.., A, .., B, .., C, ..); NVBLAS dgemm(.., A, .., B, .., C, ..); 使い方 — NVBLASを入れて再コンパイル — Linuxは、LD_PRELOAD設定で使用可能 (最コンパイル不要) NVBLAS (LINUX) 設定ファイル (nvblas.conf) NVBLAS_LOGFILE nvblas.log NVBLAS_CPU_BLAS_LIB libmkl_intel_lp64.so \ libmkl_core.so \ libmkl_intel_thread.so NVBLAS_GPU_LIST 0 NVBLAS_TILE_DIM 2048 # ALL, ALL0 NVBLAS_AUTOPIN_MEM_ENABLED $ LD_PRELOAD=/usr/local/cuda-6.0/lib64/libnvblas.so ./a.out NVBLAS BLAS level 3使用のアプリに適用可能 — Octave, Scilab, など. 3000 R言語での行列乗算 fp64 GFlops/s 2500 2000 1500 nvBLAS, 4x K20X GPUs 1000 MKL, 6-core Xeon E5-2667 CPU 500 0 0 5000 10000 15000 20000 25000 matrix dimension 30000 35000 NVBLASデモ CUDA 6 ユニファイド・メモリ XTライブラリ ドロップイン・ライブラリ GPUDirect RDMA 開発ツール CUDA 6 並列コンピューティング を簡単に CUDA Registered Developer Program developer.nvidia.com/cuda-toolkit CUDA 6.5 RC 64-bit ARMマシン Microsoft Visual Studio 2013 (VC12) cuFFT callbacks cuSPARSE (BSR格納形式) CUDA占有率計算API CUDA FORTRAN デバッグ機能 アプリケーションリプレイモード (Visual Profile and nvprof) Nvprune ユーティリティ (objectサイズ削減)
© Copyright 2024 Paperzz