コードのチューニング

Similar documents
演習1: 演習準備

NUMAの構成

Microsoft PowerPoint - OpenMP入門.pptx

OpenMPプログラミング

openmp1_Yaguchi_version_170530

Microsoft Word - openmp-txt.doc

(Microsoft PowerPoint \215u\213`4\201i\221\272\210\344\201j.pptx)

OpenMP¤òÍѤ¤¤¿ÊÂÎó·×»»¡Ê£±¡Ë

Microsoft PowerPoint - 阪大CMSI pptx

OpenMP¤òÍѤ¤¤¿ÊÂÎó·×»»¡Ê£±¡Ë

enshu5_4.key

02_C-C++_osx.indd

AICS 村井均 RIKEN AICS HPC Summer School /6/2013 1

Microsoft PowerPoint - 演習1:並列化と評価.pptx

OpenMP (1) 1, 12 1 UNIX (FUJITSU GP7000F model 900), 13 1 (COMPAQ GS320) FUJITSU VPP5000/64 1 (a) (b) 1: ( 1(a))

PowerPoint プレゼンテーション

2. OpenMP OpenMP OpenMP OpenMP #pragma#pragma omp #pragma omp parallel #pragma omp single #pragma omp master #pragma omp for #pragma omp critica

Microsoft PowerPoint - 阪大CMSI pptx

01_OpenMP_osx.indd

<4D F736F F F696E74202D D F95C097F D834F E F93FC96E5284D F96E291E85F8DE391E52E >

内容 イントロダクション スカラチューニング OpenMPによる並列化 最近のHPC分野の動向 まとめ

コードのチューニング

Microsoft Word - 計算科学演習第1回3.doc

並列プログラミング入門(OpenMP編)

Microsoft Word - appli_SMASH_tutorial_2.docx

OpenMP¤òÍѤ¤¤¿ÊÂÎó·×»»¡Ê£²¡Ë

enshu5_6.key

I I / 47

生物情報実験法 (オンライン, 4/20)

並列計算導入.pptx

Microsoft PowerPoint - sales2.ppt

Microsoft PowerPoint - 03_What is OpenMP 4.0 other_Jan18

コードのチューニング

演習準備

演習1

03_Fortran_osx.indd

Microsoft PowerPoint - compsys2-06.ppt

Microsoft PowerPoint - KHPCSS pptx

目次 LS-DYNA 利用の手引き 1 1. はじめに 利用できるバージョン 概要 1 2. TSUBAME での利用方法 使用可能な LS-DYNA の実行 4 (1) TSUBAMEにログイン 4 (2) バージョンの切り替え 4 (3) インタラ

研究背景 大規模な演算を行うためには 分散メモリ型システムの利用が必須 Message Passing Interface MPI 並列プログラムの大半はMPIを利用 様々な実装 OpenMPI, MPICH, MVAPICH, MPI.NET プログラミングコストが高いため 生産性が悪い 新しい並

Microsoft PowerPoint - 計算機言語 第7回.ppt

memo

Microsoft Word ●IntelクアッドコアCPUでのベンチマーク_吉岡_ _更新__ doc

Microsoft PowerPoint - uv2000parallel.pptx

スライド 1

The 3 key challenges in programming for MC

OpenMP の概要

OpenACCによる並列化

LS-DYNA 利用の手引 第 1 版 東京工業大学学術国際情報センター 2017 年 9 月 25 日

appli_HPhi_install

OpenMPプログラミング

ÊÂÎó·×»»¤È¤Ï/OpenMP¤Î½éÊâ¡Ê£±¡Ë

Microsoft PowerPoint - 講義:コミュニケータ.pptx

Fortran 勉強会 第 5 回 辻野智紀

スライド 1

情報処理概論(第二日目)

プログラミング基礎

2. OpenMP におけるキーワード一覧 OpenMP の全体像を理解するために 指示文 指示節 実行時ライブラリ関数 環境変数にそれぞれどうようなものがあるのかを最初に示します 各詳細については第 4 章以降で説明します 2.1 OpenMP の指示文 OpenMPの指示文は プログラム内で並列

HPC143

インテル(R) Visual Fortran コンパイラ 10.0

Microsoft PowerPoint _MPI-01.pptx

C 言語の式と文 C 言語の文 ( 関数の呼び出し ) printf("hello, n"); 式 a a+4 a++ a = 7 関数名関数の引数セミコロン 3 < a "hello" printf("hello") 関数の引数は () で囲み, 中に式を書く. 文 ( 式文 ) は

$ cmake --version $ make --version $ gcc --version 環境が無いあるいはバージョンが古い場合は yum などを用いて導入 最新化を行う 4. 圧縮ファイルを解凍する $ tar xzvf gromacs tar.gz 5. cmake を用

about MPI

講習No.1

SGI AltixUV1000 並列化プログラミング講習会

概要 プログラミング論 変数のスコープ, 記憶クラス. メモリ動的確保. 変数のスコープ 重要. おそらく簡単. 記憶クラス 自動変数 (auto) と静的変数 (static). スコープほどではないが重要.

ガイダンス

OpenMP 3.0 C/C++ 構文の概要

スライド 0

Microsoft PowerPoint - 演習2:MPI初歩.pptx

NUMAの構成

Microsoft PowerPoint ppt

ERDAS IMAGINE における処理速度の向上 株式会社ベストシステムズ PASCO CORPORATION 2015

Microsoft PowerPoint - 先端GPGPUシミュレーション工学特論(web).pptx

Java知識テスト問題

JavaプログラミングⅠ

POSIXスレッド

Microsoft PowerPoint - 高速化WS富山.pptx

演習2

PowerPoint プレゼンテーション

Microsoft PowerPoint ppt

8 / 0 1 i++ i 1 i-- i C !!! C 2

スーパーコンピューティングニュース特集号 原稿

Microsoft PowerPoint - 09.pptx

PowerPoint プレゼンテーション

2012年度HPCサマーセミナー_多田野.pptx

Hphi実行環境導入マニュアル_v1.1.1

Microsoft PowerPoint - 講義:片方向通信.pptx

π-VizStudio User Manual

JavaプログラミングⅠ

解答編 第 7 章実数型の計算と標準数学関数 演習問題 7.1 文法事項 1 ) 暗黙の型変換とは何か答えなさい 代入演算子 (=) や算術演算子 (+,-,*,/,%) では 2 つの演算項のデータ型が揃っている事が必要です 2 つの演算項のデータ型が異なる場合 可能ならば 演算項のデータ型を変換

C C UNIX C ( ) 4 1 HTML 1

PowerPoint プレゼンテーション

Microsoft Word - appli_OpenMX_install.docx

1. TSUBAME2.0 通常実行まで 1.1. 環境設定 (MPI ライブラリ & コンパイラ ) 最新の Open MPI と Intel コンパイラを使用するため,${HOME}/.bashrc 等で環境変数 ( パス等 ) を設定します. ~ 設定例 ~ export SELECT_MPI

演習準備 2014 年 3 月 5 日神戸大学大学院システム情報学研究科森下浩二 1 RIKEN AICS HPC Spring School /3/5

第8回講義(2016年12月6日)

Microsoft Word - ユーザ向け利用の手引き_v0.3.doc

サイバーメディアセンター 大規模計算機システムの利用

Transcription:

OpenMP による並列化実装 八木学 ( 理化学研究所計算科学研究センター ) KOBE HPC Spring School 2019 2019 年 3 月 14 日

スレッド並列とプロセス並列 スレッド並列 OpenMP 自動並列化 プロセス並列 MPI プロセス プロセス プロセス スレッドスレッドスレッドスレッド メモリ メモリ プロセス間通信 Private Private Private Private プロセス プロセス Global メモリ空間 メモリ メモリ

並列計算について CPU を N 個使って並列計算した時 計算速度が N 倍になるのが理想だが - 並列化率の問題 ( アムダールの法則 ) - 通信時間ボトルネック 京のような大型計算機を有効利用するためには 如何に計算速度を N 倍に近づけられるかが重要

アムダールの法則 プログラムの並列化できる割合を P とし プロセッサ数を n とすると 並列計算した時の性能向上率は 1 で与えられる 1 P + P n 9 割並列化できるが 1 割逐次処理が残ってしまうような場合 どれだけプロセッサを投入しても計算速度は 10 倍以上にはならない

OpenMP とは 共有メモリ型計算機用の並列計算 API ノード内の並列 ( ノード間は不可 ) ユーザーが明示的に並列のための指示を与える コンパイラの自動並列とは異なる 標準化された規格であり 広く使われている 指示行の挿入で並列化できるため 比較的手軽

OpenMP によるスレッド並列 Fork-Join モデル スレッド 0 Fork スレッド 0 スレッド 1 スレッド 2 スレッド 3 並列リージョン Join スレッド 0... 非並列!$omp parallel... 並列リージョン!$omp end parallel... 非並列 Fork Join... 非並列 #pragma omp parallel {... 並列リージョン Join... 非並列処理 Fork

スレッド数の指定 シェルの環境変数で与える ( 推奨 ) export OMP_NUM_THREADS=16 (bash の場合 ) setenv OMP_NUM_THREADS 16 (tcsh の場合 ) プログラム内部で設定することも可能 #include <omp.h> omp_set_num_threads(16);

スレッド数の指定 シェルの環境変数で与える ( 推奨 ) export OMP_NUM_THREADS=16 (bash の場合 ) setenv OMP_NUM_THREADS 16 (tcsh の場合 ) プログラム内部で設定することも可能!$use omp_lib call omp_set_num_threads(16)

コンパイル コンパイルオプションで OpenMP を有効にする gcc -fopenmp test.f90 icc -qopenmp test.f90 オプションを指定しない場合は OpenMP の指示行は無視される #pragma omp parallel for for (i=0; i<100; i++) { a[i] = b[i] + c; 指示行は Fortran の場合!$OMP から始まる 行頭の! は通常はコメントを意味する C の場合は #pragma omp という形になるが オプションを入れない場合 通常処理されない

コンパイル コンパイルオプションで OpenMP を有効にする gfortran -fopenmp test.f90 ifort -qopenmp test.f90 オプションを指定しない場合は OpenMP の指示行は無視される!$OMP PARALLEL DO do i = 1, 100 a(i) = b(i) + c enddo!$omp END PARALLEL DO 指示行は Fortran の場合!$OMP から始まる 行頭の! は通常はコメントを意味する C の場合は #pragma omp という形になるが オプションを入れない場合 通常処理されない

OpenMP の基本関数 OpenMP モジュール / ヘッダをロード [C] #include <omp.h> [F] use omp_lib *OpenMP 関連の関数を使用するためのおまじない!$ use omp_lib integer :: myid, nthreads nthreads = omp_get_num_threads() myid = omp_get_thread_num() #include <omp.h> int myid, nthreads; nthreads = omp_get_num_threads(); myid = omp_get_thread_num();

OpenMP の基本関数 最大スレッド数取得 (Integer) [C][F] nthreads = omp_get_num_threads() 自スレッド番号取得 (Integer) [C][F] myid = omp_get_thread_num()!$ use omp_lib integer :: myid, nthreads nthreads = omp_get_num_threads() myid = omp_get_thread_num() #include <omp.h> int myid, nthreads; nthreads = omp_get_num_threads(); myid = omp_get_thread_num();

OpenMP の基本関数 時間を測る ( 倍精度型 ) [F][C] time = omp_get_wtime()!$ use omp_lib real(8) :: dts, dte dts = omp_get_wtime() 処理 dte = omp_get_wtime() print *, dte-dts #include <omp.h> double dts; double dte; dts = omp_get_wtime(); 処理 dte = omp_get_wtime(); なお OpenMP モジュール ( ヘッダ ) のロードを忘れると これらの関数を使用できずコンパイルエラーになる

Working Sharing 構文 〇複数のスレッドで分担して実行する部分を指定〇並列リージョン内で記述する #pragma omp parallel { の括弧範囲内 指示文の基本形式は [C] #pragma omp xxx [F]!$omp xxx ~!$omp end xxx for 構文, do 構文ループを分割し各スレッドで実行 section 構文各セクションを各スレッドで実行 single 構文 1 スレッドのみ実行 master 構文マスタースレッドのみ実行

並列リージョンを指定 #pragma omp parallel { #pragma omp for for (i=0; i<100; i++) { a[i] = i #pragma omp single {... #pragma omp for for (...)... スレッドの起動 ~ 終結 [C] #pragma omp parallel { 括弧 { 内が複数スレッドで処理される 複数スレッドで処理 ( 並列リージョン )

for 構文 #pragma omp parallel { #pragma omp for for (i=0; i<100; i++) { a[i] = i #pragma omp single { output(a); #pragma omp for for (i=0; i<100; i++) { b[i] = i for ループをスレッドで分割し 並列処理を行う [C] #pragma omp for for ループの前に指示行 #pragma omp for を入れる #pragma omp parallel でスレッドを生成しただけでは 全てのスレッドが全ループを計算してしまう #pragma omp for を入れることでループ自体が分割され 各スレッドに処理が割り当てられる

1 スレッドのみで処理 #pragma omp parallel { #pragma omp for for (i=0; i<100; i++) { a[i] = i; #pragma omp single { output(a); #pragma omp for for (i=0; i<100; i++) { b[i] = i; [C] #pragma omp single { 逐次処理やデータの出力のような処理が入る場合 全スレッドで行う必要はなく 1 スレッドのみで処理を行えばよい #pragma omp single { を用いることで { 内の記述は 1 スレッドのみで処理される

並列リージョンを指定!$omp parallel!$omp do do i = 1, 100 a(i) = i enddo!$omp end do!$omp single call output(a)!$omp end single!$omp do do i = 1, 100 b(i) = i enddo!$omp end do!$omp end parallel スレッドの起動 [F]!$omp parallel スレッドの終結 [F]!$omp end parallel 複数スレッドで処理 ( 並列リージョン )

do 構文!$omp parallel!$omp do do i = 1, 100 a(i) = i enddo!$omp end do!$omp single call output(a)!$omp end single!$omp do do i = 1, 100 b(i) = i enddo!$omp end do!$omp end parallel do ループをスレッドで分割し 並列処理を行う [F]!$omp do ~!$omp end do do の直前に指示行!$omp do を入れる enddo の直後に指示行!$omp end do を入れる!$omp parallel でスレッドを生成しただけでは 全てのスレッドが全ループを計算してしまう!$omp do を入れることでループ自体が分割され 各スレッドに処理が割り当てられる

1 スレッドのみで処理!$omp parallel!$omp do do i = 1, 100 a(i) = i enddo!$omp end do!$omp single call output(a)!$omp end single!$omp do do i = 1, 100 b(i) = i enddo!$omp end do!$omp end parallel [F]!$omp single ~!$omp end single 逐次処理やデータの出力のような処理が入る場合 全スレッドで行う必要はなく 1 スレッドのみで処理を行えばよい!$omp single を用いることで { 内の記述は 1 スレッドのみで処理される

OpenMP によるスレッド並列 #pragma omp parallel { for (i=0; i<100; i++) { a[i] = i; スレッドを生成しただけでは 全スレッドが全ての処理を行ってしまい負荷分散にならない スレッド 0 for (i=0; i<100; i++) スレッド 1 for (i=0; i<100; i++) スレッド 2 for (i=0; i<100; i++) スレッド 3 for (i=0; i<100; i++)

OpenMP によるスレッド並列 #pragma omp parallel { #pragma omp for for (i=0; i<100; i++) { a[i] = i; ワークシェアリング構文を入れることにより 処理が分割され 正しく並列処理される #pragma omp for!$omp do はループを自動的にスレッド数で均等に分割する スレッド 0 for (i=0; i<25; i++) スレッド 1 for (i=25; i<50; i++) スレッド 2 for (i=50; i<75; i++) スレッド 3 for (i=75; i<100; i++)

OpenMP の基本命令 スレッド生成とループ並列を 1 行で記述 [C 言語 ] #pragma omp parallel { #pragma omp for #pragma omp parallel for と書ける #pragma omp parallel { #pragma omp for for (i=0; i<100; i++) { a[i] = i; #pragma omp parallel for for (i=0; i<100; i++) { a[i] = i;

OpenMP の基本命令 スレッド生成とループ並列を 1 行で記述 [Fortran]!$omp parallel!$omp do!$omp parallel do と書ける!$omp parallel!$omp do do i = 1, 100 a(i) = i enddo!$omp end do!$omp end parallel!$omp parallel do do i = 1, 100 a(i) = i enddo!$omp end parallel do

プライベート変数について OpenMP において変数は基本的には共有 (shared) であり どのスレッドからもアクセス可能である プライベート変数に指定した変数は各スレッドごとに値を保有し 他のスレッドからアクセスされない 並列化したループ演算の内部にある一時変数などは プライベート変数に指定する必要がある 例外的に [C]#pragma omp for [F]!$omp parallel do の直後のループ変数はプライベート変数になる

プライベート変数について プライベート変数を指定 [C] #pragma omp parallel for private(a, b,...) [C] #pragma omp for private(a, b,...) #pragma omp parallel { #pragma omp for private(j, k) for (i=0; i<nx; i++) { for (j=0; j<ny; j++) { for (k=0; k<nz; k++) { f[i][j][k] = (double)(i * j * k); ループ変数の扱いに関して 並列化したループ変数は自動的に private 変数になる しかし多重ループの場合 内側のループに関しては共有変数のままである 左の例の場合 i は自動的に private になるため必要ないが j, k については private 宣言が必要となる

プライベート変数について プライベート変数を指定 [F]!$omp parallel private(a, b,...) [F]!$omp do private(a, b,...)!$omp parallel!$omp do private(j, k) do i = 1, nx do j = 1, ny do k = 1, nz f(k, j, i) = dble(i * j * k) enddo enddo enddo!$omp end do!$omp end parallel ループ変数の扱いに関して 並列化したループ変数は自動的に private 変数になる しかし多重ループの場合 内側のループに関しては共有変数のままである 左の例の場合 i は自動的に private になるため必要ないが j, k については private 宣言が必要となる

プライベート変数について 起こりがちなミス #pragma omp for for (i=0; i<100; i++) { tmp = myfunc(i); a[i] = tmp; tmp を上書きしてしまい 正しい結果にならない #pragma omp for private(tmp) for (i=0; i<100; i++) { tmp = myfunc(i); a[i] = tmp; private 宣言を入れる 並列化したループ内で値を設定 更新する場合は要注意 private にすべきではないか確認する必要あり

プライベート変数について スレッド 0 スレッド 1 共有変数 tmp に 0 を代入 tmp = 0 共有変数 tmp は 25 を代入 tmp = 25 a[0] には 25 が代入される a[0] = tmp private 宣言なし #pragma omp for for (i=0; i<100; i++) { tmp = myfunc(i); a[i] = tmp; a[25] = tmp 処理順

プライベート変数について スレッド 0 スレッド 1 スレッド 0 のプライベート変数 tmp に 0 を代入 スレッド 1 のプライベート変数 tmp に 25 を代入 a[0] には 0 が代入される tmp = 0 a[0] = tmp tmp = 25 private 宣言あり #pragma omp for private(tmp) for (i=0; i<100; i++) { tmp = myfunc(i); a[i] = tmp; a[25] = tmp 処理順

多重ループに関して 良くない例 for (i=0; i<nx; i++) { for (j=0; j<ny; j++) { #pragma omp parallel for private(i, j, k) for (k=0; k<nz; k++) { f[i][j][k] = (double)(i * j * k); 改善案 #pragma omp parallel { for (i=0; i<nx; i++) { for (j=0; j<ny; j++) { #pragma omp for private(i, j, k) for (k=0; k<nz; k++) { f[i][j][k] = (double)(i * j * k); OpenMP を用いた並列化では 内側ループ 外側ループのどちらを並列化しても動作はするが 内側ループを並列化すると毎回スレッドの生成を行うため遅くなる ( 上記の例では nx * ny 回のスレッド生成 ) なお 並列化するループを変えたり ループの計算順序を変更する可能性があるため private 宣言にはループ変数も書いた方が無難

共有変数について 共有 (shared) 変数を指定 [C] #pragma omp parallel shared(a, b,...) [C] #pragma omp for shared(a, b,...) [F]!$omp parallel shared(a, b,...) [F]!$omp do shared(a, b,...) 指定しなければ基本的に共有変数であるため 省略可能

スレッドの同期 nowait を明示しない限り ワークシェアリング構文の終わりに自動的に同期処理が発生 スレッドの同期待ちをしない [C] #pragma omp for nowait [F]!$omp do ~!$omp end do nowait スレッドの同期をとる [C] #pragma omp barrier [F]!$omp barrier

注意点等 自動並列化と違い 並列化できるかどうかの判断はプログラマが行う 依存関係などにより並列化できないループであっても 明示してしまえば並列化されてしまう スレッド内でのグローバル変数 プライベート変数を間違えると Run ごとに結果が変わってしまう 数回実行し 結果が変わらないことを確認 OpenMP は手軽だが デバッグには注意が必要

演習問題 2-1 OpenMPを用いて次のコードを完成させよ Fortran: 2019spring/code/f90/openmp/1d_adv_omp.f90 C 言語 : 2019spring/code/c/openmp/1d_adv_omp.c * 演習 1にて使用したコードを用いても良い 移流が出来たら流体にも挑戦! 1d_fluid_rk : 1 次元流体 2d_fluid : 2 次元流体

補足 : マシン上の操作 コンパイル ジョブの投入 (C 言語 ) > icc -qopenmp 1d_adv_omp.c > qsub run.sh #!/bin/bash #PBS -q S #PBS -l select=1:ncpus=8 #PBS -N OpenMP #PBS -o output #PBS -j oe source /etc/profile.d/modules.sh module load intel export OMP_NUM_THREADS=8 export KMP_AFFINITY=disabled cd ${PBS_O_WORKDIR dplace -x2./a.out 使用ノード数 CPU 数ジョブ名標準出力の出力先ファイル Intelコンパイラ環境のロードスレッド数を指定実行 run.sh

補足 : マシン上の操作 コンパイル ジョブの投入 (Fortran) > ifort -qopenmp 1d_adv_omp.f90 > qsub run.sh #!/bin/bash #PBS -q S #PBS -l select=1:ncpus=8 #PBS -N OpenMP #PBS -o output #PBS -j oe source /etc/profile.d/modules.sh module load intel export OMP_NUM_THREADS=8 export KMP_AFFINITY=disabled cd ${PBS_O_WORKDIR dplace -x2./a.out 使用ノード数 CPU 数ジョブ名標準出力の出力先ファイル Intelコンパイラ環境のロードスレッド数を指定実行 run.sh

演習問題 2-1 解答例 Fortran: 2019spring/code/f90/openmp/sample/1d_adv_omp_sample.f90 2019spring/code/f90/openmp/sample/1d_fluid_rk_omp_sample.f90 2019spring/code/f90/openmp/sample/2d_fluid_omp_sample.f90 C 言語 : 2019spring/code/c/openmp/sample/1d_adv_omp_sample.c 2019spring/code/c/openmp/sample/1d_fluid_rk_omp_sample.c 2019spring/code/c/openmp/sample/2d_fluid_omp_sample.c

演習問題 2-2 OpenMP を用いて並列化したプログラムを スレッド数を変えて実行し処理時間を計測せよ スレッド数の指定方法 : スクリプト run.sh の export OMP_NUM_THREADS=xx の数値を変更 処理時間の計測 dts = omp_get_wtime() 処理 dte = omp_get_wtime() print *, dte-dts