短距離古典分子動力学計算の 高速化と大規模並列化

4,867 views

Published on

「第6回分子シミュレーションスクール」講義スライド

Published in: Education
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,867
On SlideShare
0
From Embeds
0
Number of Embeds
879
Actions
Shares
0
Downloads
35
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

短距離古典分子動力学計算の 高速化と大規模並列化

  1. 1. 1/76 短距離古典分子動力学計算の 高速化と大規模並列化 渡辺宙志 東京大学物性研究所 Outline 1.  チューニング、その前に 2.  計算機の仕組みと高速化 3.  並列化 4.  大規模計算でなにができるか 5.  まとめDec. 13, 2012「第6回分子シミュレーションスクール」@岡崎カンファレンスホール University of Tokyo
  2. 2. 2/76 チューニング、その前に University of Tokyo
  3. 3. 3/76 チューニング、その前に (1/5)A fast runner is not a good soccer player. H. Watanabe, 2012 University of Tokyo
  4. 4. 4/76 チューニング、その前に (2/5)最適化の第一法則:最適化するな最適化の第二法則(上級者限定):まだするな Michael A. Jackson, 1975 University of Tokyo
  5. 5. 5/76 チューニング、その前に (3/5)なぜ最適化するのか? プログラムの実行時間を短くするため なぜ実行時間を短くしたいのか? 計算結果を早く手に入れるため なぜ計算結果を早く手にいれたいのか? 論文を早く書くため ← ここがとりあえずのゴール 最適化、並列化をする際には、必ず「いつまでに論文執筆まで持って行くか」を意識すること。だらだらと最適化にこだわらない。 University of Tokyo
  6. 6. 6/76 チューニング、その前に (4/5)Q. 最適化、並列化でもっとも大事なことは何か?A. バグを入れないこと 通常、プログラミングにおいて最も時間のかかるプロセスは デバッグだから University of Tokyo
  7. 7. 7/76 チューニング、その前に (5/5)バグを入れない方法 いろいろあるが、特に以下の二つの方法が有効 ・単体テスト ・sort + diff デバッグ 単体テスト ・テストしようとしている部分だけを切り出す ・その部分だけでコンパイル、動作するような最低限のインターフェース ・最適化、並列化する前と後で結果が一致するかを確認する ・本番環境でテストしない sort + diff デバッグ ・print文デバッグの一種 ・出力情報を保存し、sortしてからdiffを取る ・単体テストと組み合わせて使う University of Tokyo
  8. 8. 8/76 sort + diff デバッグの例1 - 粒子対リスト作成 (1/3) ペアリストとは? ・相互作用距離(カットオフの距離)以内にある粒子対のリスト ・どの粒子同士が近いか?という情報 ・全粒子対についてチェックすると    ・高速に粒子対を作成する方法 → グリッド探索 グリッド法 ・空間をグリッドに切り、その範囲に存在する粒子を登録する 排他的グリッド(Exclusive Grid )法 非排他的グリッド(Non-Exclusive Grid )法 一つのグリッドに粒子一つ 一つのグリッドに複数粒子 ・短距離相互作用 ・長距離相互作用 ・二次元 ・三次元 ・高密度 ・低密度 University of Tokyo
  9. 9. 9/76 sort + diff デバッグの例1 - 粒子対リスト作成 (2/3) ポイント O(N^2)法は、計算時間はかかるが信頼できる O(N)法とO(N^2)法は、同じconfigurationを与えられたら、 同じペアリストを作るはず手順 初期条件を作るルーチンを作る ペアリスト作成ルーチンを作り、コンパイル、実行できるようにする (単体テスト) O(N)とO(N^2)ルーチンに初期条件を与え、作成したペアリストをダンプする ダンプ方法:作成された粒子対の、番号が若い方を左にして、一行に1ペア O(N)とO(N^2)でリストの順番が異なるはずなのでsortする $ ./on2code | sort > o2.dat $ ./on1code | sort > o1.dat diffを取る $ diff o1.dat o2.dat 結果が正しければdiffは何も出力しない いきなり本番環境に組み込んで時間発展、などとは絶対にしない University of Tokyo
  10. 10. 10/76 sort + diff デバッグの例1 - 粒子対リスト作成 (3/3) 並列版のデバッグ ペアリスト作成の並列化 ・はじっこの粒子が正しく渡されているか? ・周期境界条件は大丈夫か?手順 初期条件を作るルーチンを作る 並列版と非並列版のペアリスト作成ルーチンを作る 非並列版はそのままペアリストをダンプ 並列版は「若い番号の粒子が自分の担当の粒子」 であるときだけダンプ sort + diffで一致を確認するポイント まず、並列版と非並列版両方O(N^2)で試す →粒子の受け渡しがバグっているのか、O(N)の並列化が間違っているのか 区別するため 一度に複数の項目を同時にテストしない University of Tokyo
  11. 11. 11/76 sort + diff デバッグの例2 - 粒子情報送信 端の粒子の送り方 ナイーブな送り方 正しく情報が送られているかをチェックする →粒子の情報を送る前と、送ったあとそれぞれで 全粒子座標を出力してsort+diff通信方法を減らした送り方 (もらった粒子をさらに転送することで斜め通信をなくす) University of Tokyo
  12. 12. 12/76 チューニングをする前に ・新しい機能を追加するたびに単体テストをする・高速化をためしたら、かならず単体テストをする 単体テストとは、ミクロな情報がすべて一致するのを確認することであ り、エネルギー保存など、マクロ量のチェックは単体テストではない・時間はかかるが信用できる方法と比較する 「確実にここまでは大丈夫」という「砦」を築いて行く作業・複数の機能を一度にテストしない・特に並列プログラムはバグを入れるととても大変なので、事前に 十分なデバッグが必要 デバッグとは、入れたバグを取ることではなく、そもそもバ グを入れないことである University of Tokyo
  13. 13. 13/76 計算機の仕組み University of Tokyo
  14. 14. 14/76 計算機の仕組みと高速化 高速化とは何か? ここでは「アルゴリズムを変えずに、実装方法によって実行時間を短くする方法」と定義 → アルゴリズムレベルの最適化は終了していることを想定 遅いアルゴリズムを実装で高速化しても意味がないので、十分にアルゴリズムレベルで最適化が済んでいることを確認すること 実装レベルの高速化とは何か? 「コンパイラや計算機にやさしいコードを書く事」 ※やさしい=理解しやすい、向いている そのためには、計算機の仕組みを理解しておかなければならない University of Tokyo
  15. 15. 15/76 プログラム階層 ノード間通信(並列化) Networkメモリ転送(キャッシュ最適化) Memory Memory MemoryCPUコア(チューニング) Cache Cache CacheSIMD化、if分岐削除 CPU CPU CPU この中で最も重要なのはメモリ転送 University of Tokyo
  16. 16. 16/76 記憶階層 Register FPU Register Register L1 L2 Memory FPU Register Floating Processing Unit CPU・計算はレジスタ上で行う・レジスタにのせられた情報はFPUに渡され、レジスタにかえってくる・メモリアクセスで大事なのは、バンド幅とレイテンシLatency CPUにデータを要求されてから、レジスタに届くまでのサイクル数 ・L1キャッシュで数サイクル、L2で10 20サイクル、主記憶は 数百サイクル Bandwidth CPUにデータが届き始めてからのデータ転送速度 絶対値(GB/s)よりも、計算速度との比(B/F)の方が良く使われる University of Tokyo
  17. 17. 17/76 Byte / Flop Byte/Flop データ転送速度(Byte/s) と計算速度 (FLOPS)の比。略してB/F。 値が大きいほど、計算速度に比べたデータ転送能力が高い。 典型的には B/F = 0.1∼0.5 B/Fの意味 一つの倍精度実数(64bit)の大きさ = 8 Byte 計算するには、最低二つの倍精度実数が必要 = 16 Byte 最低でも一つの倍精度実数を書き戻す必要がある = 8 Byte. 例えば一回掛け算をして、その結果をメモリに書き戻すと、24Byteの読み書きが発生 B/F = 0.5 のマシンでは、24バイトの読み書きの間に48回計算ができる B/Fが0.5の計算機では、C = A*Bという単純な計算をくりかえすと ピーク性能の2%ほどしか出せず、ほとんど時間CPUが遊ぶ キャッシュ効率が性能に直結する University of Tokyo
  18. 18. 18/76 仮想メモリとページング (1/2)Virtual Memory 現在の一般的なOSでは、メモリをページと呼ばれる仮想記憶で管理する。 ハードディスク 仮想メモリ 物理メモリ (論理メモリ) 連続配列が、物理メモリ内 では不連続に割り当てら れてるかもしれない 一部がハードディスクにスワップさ れているかもしれない 仮想メモリを使う理由・不連続なメモリ空間を論理的には連続に見せることができる 仮想メモリなしでは、メモリに余裕があっても連続領域が取れない場合にメモリ割り当てができない・スワッピングが可能になる 記憶容量としてハードディスクも使えるため、物理メモリより広い論理 メモリ空間が取れる。 論理メモリと実メモリの対応が書いてあるのがTLB (テキスト参照) University of Tokyo
  19. 19. 19/76 仮想メモリとページング (2/2)数値計算で何が問題になるか? F90のallocateや、Cでnew、mallocされた時点では物理メモリの 割り当てがされていない場合がある real*8, allocatable :: work(:) allocate (work(10000)) この時点では予約だけされて、まだ物理アドレスが割り当てられない do i=1, 10000 work(i) = i はじめて触った時点で、アドレスがページ単位で割り当てられる end do (First touch の原則) よくある問題:最初に馬鹿でかい配列を動的に確保しているプログラムの初期化がすごく遅い 地球シミュレータからT2Kへの移植で問題になることが多い。OSがLinuxである 京でも発生する解決策: メモリを静的に確保する(?) mallocではなくcallocを使う (Fortranではどうやるのか知りません) メモリを確保した直後、ページ単位で全体を触っておく まぁ、そういうこともあると覚えておいてください University of Tokyo
  20. 20. 20/76 NUMA (1/2)NUMAとは 非対称メモリアクセス(Non-Uniform Memory Access)の略 CPUにつながっている物理メモリに近いメモリと遠いメモリの区別がある 京コンピュータはNUMAではないが、物性研System BはNUMA Fast access Memory Memory Memory CPU QPI CPU Memory Memory Memory Slow access 特にlatency University of Tokyo
  21. 21. 21/76 NUMA (2/2)数値計算で何が問題になるか?OpenMPでCPUをまたぐ並列化をする際、初期化を適当にやると作業領域がコアから遠い物理メモリに割り当てられてしまう Touch CORE CORE CORE CORE QPI CORE CORE CORE CORE OpenMPのスレッドを作る前に配列を初期化  →root プロセスの近くにメモリ割り当て その後OpenMPでスレッド並列  →遠いメモリをアクセス(遅い) 解決策: スレッドに対応する物理コアに近いところにメモリが割り当てられるように、スレッドごとに配列を用意した上、OpenMPでスレッド並列化した後にtouchとか 詳しくはNUMA最適化でググれ University of Tokyo
  22. 22. 22/76 CPU (1/2) RISCと CISC 世の中のCPUアーキテクチャは大別して RISC型とCISC型の二種類 CISC:  ・比較的複雑な命令セット  ・if分岐などに強い (Out of order 実行)  ・Intel Xeon, AMD Opteronなど。 RISC:  ・比較的単純な命令セット  ・行列演算などに強い  ・IBM Power, SPARCなど (「京」はSPARC VIIIfx) RISCでOoOだったりするので、現在はあまり意味のある区別ではない。 要するに「Intel系か、それ以外か」という区別 マルチコアとSIMD化 最近のCPUはほぼマルチコア化とSIMD化で性能をかせいでいる ・マルチコアで性能を出すには、キャッシュとメモリの構造を把握する必要あり ・京(8コア) FX10 (16コア) IBM POWER6 (32コア)、SGI Altix ICE(4コア*2) ・SIMDについては後述 University of Tokyo
  23. 23. 23/76 CPU (2/2) ゲーム機とCPU第六世代 DC SH-4PS2 MIPS (Emotion Engine), VLIWGC IBM PowerPC カスタム (Gekko)Xbox Intel Celeron (PenIII ベース)第七世代 Wii IBM PowerPC カスタム Xbox 360 IBM PowerPC カスタム PS3 IBM Cell 3.2 University of Tokyo
  24. 24. 24/76 レイテンシとパイプライン (1/3) レイテンシとは 命令が発行されてから、値が帰ってくるまでのクロック数 fadd fp2,fp0,fp1 # fp2 ← fp0 + fp1 fadd fp4,fp2,fp3 # fp4 ← fp2 + fp3 パイプライン fadd fp2,fp0,fp1 計算開始 計算中 計算中 計算中 計算中 計算中 計算終了 (fp2使用可) fadd fp4,fp2,fp3 University of Tokyo
  25. 25. 25/76 レイテンシとパイプライン (2/3) パイプラインとは 浮動小数点の加算、減算、掛け算といった計算を流れ作業で行う仕組みfadd fp2,fp0,fp1 (A)fadd fp5,fp3,fp4 (B)fadd fp8,fp3,fp7 (C) (A) 1 (A) 計算開始 (B) 1 (A) 2 (C) 1 (B) 2 (A) 3 (D) 1 (C) 2 (B) 3 (A) 4 (E) 1 (D) 2 (C) 3 (B) 4 (A) 5 (F) 1 (E) 2 (D) 3 (C) 4 (B) 5 (A) 6 (A) 計算終了 (D) 4 (C) 5 (B) 6 (B) 計算終了 時間 ここだけ見ると、6クロックかかる処理を同時に6つ処理している→ 一クロックで一回の計算ができているように見える (レイテンシの隠蔽)これを「スループット が1」と呼ぶ University of Tokyo
  26. 26. 26/76 レイテンシとパイプライン (3/3) パイプライン数 一般的にはパイプラインは2本 Load/Storeも出せる場合は、IPCは最大4 ※ パイプライン パイプライン faddd fp2,fp0,fp1 計算開始 計算開始 fmuld fp3,fp1,fp4 計算中 計算中 計算中 計算中 計算中 計算中 計算中 計算中 計算中 計算中 計算終了 (fp2使用可) 計算終了実質的に、1クロックで二つの計算が可能→ 2GHz × 2 = 4 GFLOPS University of Tokyo
  27. 27. 27/76 積和(差)命令 fmaddd, fmsubd 積和、積差 積和   X = A*B+C 積差   Y = A*B-C アセンブラでは fmaddd fp0,fp1,fp2,fp3 # fp0 ← fp1*fp2+fp3 fmsubd fp0,fp1,fp2,fp3 # fp0 ← fp1*fp2+fp3乗算一つ、加減算一つ、あわせて二つが(実質)1クロックで実行される。そのパイプラインが二つあるので、あわせて1クロックで4つの演算→ 2GHz × 4 = 8 GFLOPS アセンブリにfmaddd,fmsubdが ずらずら並んでいなければダメ University of Tokyo
  28. 28. 28/76 SIMD SIMDとは Single Instruction Multiple Data の略。通称シムド。 ベクトル命令のようなもの。 独立な同じ計算を同時に行う。 積和、積差のSIMD fmadd,s X1 = A1*B1+C1 , X2 = A2*B2+C2 を同時に実行 fmsub,s X1 = A1*B1-C1 , X2 = A2*B2-C2 を同時に実行 fmadd,sは、一つで4個の浮動小数点演算を行う。 「京」はこれが同時に二つ走る 4 * 2 * 2 GHz = 16GFlops (ピーク性能) アセンブリにfmaddd,s fmsubd,sが ずらずら並んでいなければダメ University of Tokyo
  29. 29. 29/76 パイプラインのイメージ A A +B +B A-B A*B-C A1*B1+ A2*B2+ A*B+C C1 C2 A1*B1+ A2*B2+ A-B C1 C2 A1*B1+ A2*B2+ A*B+C C1 C2 A*B-C A-B ・幅が4、長さが6のベルトコンベアがある・それぞれには、大きさ1、2、4の荷物を流せるが、同時に一つしか置けない・ピーク性能比=ベルトコンベアのカバレージ・ピーク性能を出す=なるべくおおきさ4の荷物を隙間無く流す (Intel系の命令パイプラインはやや異なる) University of Tokyo
  30. 30. 30/76 計算機の仕組みのまとめ・期待する性能がでない時、どこが問題かを調べるのに 計算機の知識が必要 (特にメモリアクセス)・積和のパイプラインを持つCPUで性能を出すためには、  独立な積和演算がたくさん必要・SIMDを持つCPUで性能を出すためには、 独立なSIMD命令がたくさん必要 → 京やFX10では、独立な積和のSIMD命令がたくさん必要 アセンブリを読みましょう 変にプロファイラと格闘するより直接的です (-S 付きでコンパイルし、 fmadd,sなどでgrep) University of Tokyo
  31. 31. 31/76 メモリアクセス最適化 University of Tokyo
  32. 32. 32/76 メモリ最適化(1/2)セル情報 相互作用粒子を探すさい、空間をセルに分割し、それぞれに登録するどの空間に粒子が存在するかを多次元配列で実装すると効率が悪い int GridParticleNumber[GridX][GridY];int GridParticleIndex[GridX][GridY][GridMax]; 一次元配列実装 O(N) Partial Sort キャッシュ効率向上 レイテンシ University of Tokyo
  33. 33. 33/76 メモリ最適化(2/2)相互作用ペアリスト短距離相互作用の場合、相互作用ペアリストを使う (Bookkeeping 法)何も考えずに実装すると・・・ メモリ空間をランダムアクセスする(キャッシュ効率低下) 二つ分の粒子の情報をレジスタに持ってくる必要がある(要求バンド幅増大) 相互作用相手でソートする相互作用粒子の一方がレジスタに載るデータの読み込みが半分になる University of Tokyo
  34. 34. 34/76 キャッシュ最適化 (1/2)空間ソート時間発展を続けると、空間的には近い粒子が、メモリ上では遠くに保存されている状態になる → ソート University of Tokyo
  35. 35. 35/76 キャッシュ最適化(2/2)空間ソートの効果 ソートあり L2 Cache L3 Cache (256 KB) (8 MB) ソートなし 粒子数 ソートなし:粒子数がキャッシュサイズをあふれる度に性能が劣化する ソートあり:性能が粒子数に依存しない University of Tokyo
  36. 36. 36/76 メモリ管理のまとめ CPUチューニングの前にメモリアクセスのチェックをとにかくキャッシュにのせる連続アクセスにする (Partial Sortが有効)メモリアクセスの最適化は、計算機を選ばないことが多い (CPUチューニングはアーキテクチャに強く依存する) 並列化の前にメモリアクセスの最適化をする・メモリアクセスの最適化をすると、データの持ち方が変わる →並列化の通信ルーチンが強く影響を受ける・逆にNUMA最適化など、並列化をにらんだデータ構造を持つ必要もある →要するになんども組み直す必要があるということ 必要なデータがほぼキャッシュに載っており、CPUの 計算待ちがほとんどになって初めてCPUチューニングへ University of Tokyo
  37. 37. 37/76 CPUチューニング University of Tokyo
  38. 38. 38/76 CPUチューニング PCで開発したコード、スパコンでの実行性能が すごく悪いんですが・・・ それ、条件分岐が原因かもしれません。開発ではIntel系のCPUを使うことが多く、スパコンは別のRISCタイプアーキテクチャを使うことが多い University of Tokyo
  39. 39. 39/76 条件分岐コスト (1/2) 条件分岐なし 条件分岐あり void voidcalcforce(void){ calcforce(void){ for(int i=0;i<N-1;i++){ for(int i=0;i<N-1;i++){ for(int j=i+1;j<N;j++){ for(int j=i+1;j<N;j++){ const double dx = q[j][X] - q[i][X]; const double dx = q[j][X] - q[i][X]; const double dy = q[j][Y] - q[i][Y]; const double dy = q[j][Y] - q[i][Y]; const double dz = q[j][Z] - q[i][Z]; const double dz = q[j][Z] - q[i][Z]; const double r2 = (dx*dx + dy*dy + dz*dz); const double r2 = (dx*dx + dy*dy + dz*dz); const double r6 = r2*r2*r2; if (r2 > CUTOFF) continue; double df = (24.0*r6-48.0)/(r6*r6*r2)*dt; const double r6 = r2*r2*r2; p[i][X] += df*dx; double df = (24.0*r6-48.0)/(r6*r6*r2)*dt; p[i][Y] += df*dy; p[i][X] += df*dx; p[i][Z] += df*dz; p[i][Y] += df*dy; p[j][X] -= df*dx; p[i][Z] += df*dz; p[j][Y] -= df*dy; p[j][X] -= df*dx; p[j][Z] -= df*dz; p[j][Y] -= df*dy; } p[j][Z] -= df*dz; } }} } } 条件分岐により、必要な計算量は80%程度に減る University of Tokyo
  40. 40. 40/76 条件分岐コスト (2/2) 条件分岐なし 経過時間[s] 条件分岐あり 条件分岐がなければIBM POWERの方がIntel Xeonより早いが 条件分岐があると、大幅に遅くなる IBM POWER、SPARC (京やFX10)は、条件分岐に弱い University of Tokyo
  41. 41. 41/76 条件分岐削除 (1/2)1.  foreach interacting particles 2.  r ← particle distance 3.  if distance > cutoff length then continue ここが重い4.  f ← calculate force (次のループが回るかわからないから) 5.  p ← update momenta 6.  next1.  foreach interacting particles 2.  r ← particle distance 3.  f ← calculate force 4.  if distance > cutoff length then f ←0 fsel 命令が使われる 5.  p ← update momenta (全てのループが確実にまわる) 6.  next 余計な計算量が増えるが、パイプラインがスムーズに流れる ために計算が早くなる(こともある) University of Tokyo
  42. 42. 42/76 条件分岐削除 (2/2) 条件分岐なし 条件分岐あり 条件分岐削除 経過時間[s] IBM POWERでの実行が大幅に高速化されたIBM POWERや、京には条件代入命令(fsel)がある fsel fp0,fp1,fp2,fp3 fp0 = (fp1 > 0)? fp2: fp3; これにより、マスク処理が可能 University of Tokyo
  43. 43. 43/76 SIMD化 (1/4) SIMD化とは何か コンパイラが出力する命令のうち、SIMD命令の割合を増やす事 スカラ命令: 一度にひとつの演算をする SIMD命令(ベクトル命令):複数の対象にたいして、同種の演算を一度に行う 実際にやること コンパイラがSIMD命令を出しやすいようにループを変形する SIMD命令が出しやすいループ:  演算に依存関係がすくないループ コンパイラがどうしてもSIMD命令を出せなかったら? 手作業によるSIMD化 ほとんどアセン (Hand-SIMDize) ブリで書くよう なものです University of Tokyo
  44. 44. 44/76 SIMD化 (2/4) ループアンローリング DO I = 1, N C[i] = A[i] + B[i] 依存関係があるのでSIMD命令が発行されない。 E[i] = C[i] + D[i] G[i] = E[i] + F[i] I[i] = G[i] + H[i] END DO ループを二倍展開し、独立な計算を作る (馬鹿SIMD化) コンパイラが A[1]+B[1] A[2]+B[2] Loop Unrolled x times C[1]+D[1] C[2]+D[2] とメッセージ出したらおそらくこれ E[1]+F[1] E[2]+F[2] 問題点: I[1]+G[1] I[2]+G[2] ・レイテンシを隠しづらい ・積和が作りにくい → 遅い University of Tokyo
  45. 45. 45/76 SIMD化 (3/4) ソフトウェアパイプライニング DO I = 1, Nループインデックス C[i] = A[i] + B[i] E[i] = C[i] + D[i] A[1]+B[1] H[i] = F[i] + G[i] C[1]+D[1] A[2]+B[2] H[i] = H[i] + I[i] END DO E[1]+F[1] C[2]+D[2] A[3]+B[3] I[1]+G[1] E[2]+F[2] C[3]+D[3] A[4]+B[4] I[2]+G[2] E[3]+F[3] C[4]+D[4] I[3]+G[3] E[4]+F[4] I[4]+G[4] 独立な計算を増やしやすい レイテンシを隠し易い 人間の手でやるのはかなり厳しい だが、FX10ではこれをやらないと速度が出ない  →いかにコンパイラに「Loop software pipelined」を出させるか University of Tokyo
  46. 46. 46/76 SIMD化 (4/4) 我々が実際にやったこと 作用反作用を使わない (二倍計算する) → FX10ではメモリへの書き戻しがボトルネックだったループを2倍展開した馬鹿SIMDループをさらに二倍アンロール (4倍展開) → レイテンシ隠蔽のため、手でソフトウェアパイプライニング局所一次元配列に座標データをコピー → 運動量の書き戻しは行わないので、局所座標の読み出しがネックに → 「グローバル、static配列でないとsoftware pipeliningできない」    というコンパイラの仕様に対応するため(もうなおったかも)除算のSIMD化 → FX10には除算のSIMD命令がない(たぶん) → 逆数近似命令(低精度)+精度補正コードを手で書いた。チューニング成果 力の計算の速度は2倍に、全体でも30%程度の速度向上 University of Tokyo
  47. 47. 47/76 CPUチューニングのまとめCPU依存のチューニングは、当然のことながらCPUに依存する→ CPUを変えるたびにチューニングしなおし→ プログラムの管理も面倒になる そこまでやる必要あるんですか? 基本的には趣味の世界です。 世の中には全部intrinsic 命令でホットスポットを書く廃人もいるにはいる University of Tokyo
  48. 48. 48/76 並列化、その前に University of Tokyo
  49. 49. 49/76 並列化、その前に (1/3)並列化とは何か? 複数のノードを使う事で、時間か空間を稼ぐ方法 時間を稼ぐ並列化 一つのコアあたりの計算量を減らすことで、計算規模をそのままに計算時間を短くする (ストロングスケーリング) 空間を稼ぐ並列化 ひとつのノードでは扱えないような大きな問題を扱いたい ひとつのコアあたりの計算量はそのままに、コア数を増やすことで サイズを大きくする(ウィークスケーリング) University of Tokyo
  50. 50. 50/76 並列化、その前に (2/3)通信時間 通信時間には、レイテンシとバンド幅が関係 レイテンシ:通信がはじまるまでの時間 バンド幅:単位時間あたりどれだけのデータを通信できるか 並列化の粒度 計算時間と通信時間の比 計算 通信 Granularity が疎 (計算ドミナント) 大規模計算向き Granularity が密(通信ドミナント) 大規模計算が難しい ストロングスケーリング(計算規模をそのままにコア数を増やす) では、粒度が密になり、レイテンシが問題となる University of Tokyo
  51. 51. 51/76 並列化、その前に (3/3)現象と計算コスト 非平衡非定常系 平衡系、非平衡定常系 タイムスケールはサイズ依存性が弱い 緩和にかかる時間が系のサイズに依存(核生成、音速、爆発) (遅い緩和を持つ現象はさらに厳しい)粒子数と扱える現象 非平衡現象 平衡状態論文としてpublishされたもの ベンチマーク (単一気泡生成) (気液相転移の臨界指数) 4.1G Particles 12M Particles 1.6M Particles 非平衡現象 今回紹介する計算 ベンチマーク (多重核生成) 38G Particles 1.4G Particles 同じ計算資源を使った場合、定常状態は非定常状態に比べてサイズが桁で落ちる大規模計算では非平衡非定常系の計算が向いている ベンチマーク > 1 3桁 > 非平衡 > 1 2桁 > 平衡状態 University of Tokyo
  52. 52. 52/76 並列化の方法 University of Tokyo
  53. 53. 53/76 並列化の方法 (1/2) 並列化をがんばる University of Tokyo
  54. 54. 54/76 並列化の方法 (2/2) ・・・これだけではあんまりなので、注意点(心構え)を二点だけ 「並列化」の限界 既存のソースコードを「並列化」して得られる性能には限りがある 本当に大規模計算を志すなら、最初から「並列コード」を書くべき 最終的には何度も書き直すことになる ベンチマークからが勝負 計算科学においては、「科学論文を書くこと」が一応のゴール大規模なベンチマークに成功しても、それだけでは論文が書けない特に、観測ルーチンの並列化や、計算条件の調査に時間がかかる あとは並列化のノウハウを少し紹介 University of Tokyo
  55. 55. 55/76 Flat MPIか、ハイブリッドか コア・CPU・ノード 複数のコアの集合→CPU ノード内はメモリ共有 複数のCPUの集合→ノード ノード間はメモリ分散 複数のノードの集合→スパコン OpenMPとMPI OpenMP 共有メモリ型並列スキーム (ノード内) ← スレッド MPI 分散メモリ型並列スキーム (ノード間) ← プロセス 一般に、Flat-MPIの方が早いが、メモリ消費も大きい 物性研 1024コア、コアあたり50万粒子 Flat-MPI: 1024 プロセス 276.5GB Hybrid: 128プロセス*8スレッド 199.1GB 全く同じ計算をしても、Flat-MPIではノードあたり600MB程度利用メモリが増加する→ 大規模計算ではMPI+OpenMPのハイブリッド並列必須 University of Tokyo
  56. 56. 56/76 ハイブリッド並列化(1/6) スレッドとプロセス タスク プロセス プロセス プロセス メモリ空間 メモリ空間 メモリ空間 スレッド スレッド スレッド スレッド スレッド プロセス:OSから見た利用単位       ひとつ以上のスレッドと、プロセスごとに固有メモリ空間を持つ。 スレッド: CPUから見た利用単位。同じプロセス中のスレッドはメモリを共有する タスク: 人間から見た利用単位。 一つ以上のプロセスが協調して一つの仕事を実行する単位。 University of Tokyo
  57. 57. 57/76 ハイブリッド並列化(2/6) スレッド並列 プロセス内で並列処理 ( ノード内並列) プロセス メモリ共有型 →排他制御が必要 メモリ空間 OpenMP、コンパイラの自動並列 スレッド スレッド 始めるのは簡単、性能を出すのは困難 スレッド スレッド プロセス並列 プロセス間で並列処理 ( ノード間並列) タスク メモリ分散型 プロセス プロセス →明示的通信が必要 MPIライブラリ メモリ空間 メモリ空間 敷居は高いが、性能予測はし易い 通信 スレッド スレッド ハイブリッド並列 スレッド スレッド プロセス並列とスレッド並列を両方やること 面倒くさい University of Tokyo
  58. 58. 58/76 ハイブリッド並列化(3/6) 一般的方法 MPI: 空間分割 OpenMP: ループ分割 DO I=1,N ここか、 DO J in Pair(I) ここにスレッド並列をかける CalcForce(I,J) ENDDO ENDDO問題点 運動量の書き戻しで同じ粒子にアクセスする可能性がある → テンポラリバッファを用意して衝突をさける → 作用反作用を使わない ペアリスト作成もスレッド並列化しなければならない 力の計算というボトルネックで、SIMD化とOpenMP化を同時に扱う必要がある University of Tokyo
  59. 59. 59/76 ハイブリッド並列化(4/6) 完全空間分割 プロセス スレッド MPI: 空間分割 OpenMP: 空間分割 MDUnit MDUnit MDUnit MDUnit MDUnitクラス:  分割された領域を担当するクラス MDManagerクラス MDUnit MDUnit MDUnit MDUnit MDUnitを束ねて、通信をするクラス DO I=1,THREAD_NUM ここにスレッド並列をかける CALL MDUnit[i]->Calculate() ENDDO MDManager MDManager MPIプロセス = MDManagerMDManagerがMDUnitを1つ担当 = Flat MPI 通信 MDManagerがMDUnitを複数担当=Hybrid MDUnit MDUnit MDUnit MDUnit MDUnit MDUnit MDUnit MDUnit University of Tokyo
  60. 60. 60/76 ハイブリッド並列化(5/6) スレッドからのMPI通信 スレッドはプロセスより「軽い」かわりに、できることも限られる例えば一般にスレッドからのMPI通信は許されて(実装されて)いない以下の4種類の実装レベルが規定されている MPI_THREAD_SINGLE MPI_THREAD_FUNNELD スレッドの通信不可 メインスレッドからなら通信可 プロセス プロセス プロセス プロセス メモリ空間 メモリ空間 メモリ空間 メモリ空間 スレッド スレッド スレッド スレッド スレッド スレッド スレッド スレッド MPI_THREAD_SERIALIZED MPI_THREAD_MULTIPLE 同時に一つまでなら通信可能 (京、物性研) どのスレッドからでも自由に通信可 プロセス プロセス プロセス プロセス メモリ空間 メモリ空間 メモリ空間 メモリ空間 スレッド 1 スレッド スレッド スレッド スレッド 2 スレッド スレッド スレッド University of Tokyo
  61. 61. 61/76 ハイブリッド並列化(6/6) 完全空間分割のメリット MDUnitクラスは、自分がスレッドであるかプロセスであるかを意識しなくてよい 二種類のロードバランスを考えなくてよい → Flat-MPIがスケールする領域であれば、ハイブリッドでもスケールする NUMA最適化を考えなくてよい(京、FX10では関係ない) 力の計算は、SIMD化のみ考えれば良い完全空間分割のデメリット 通信が面倒くさい →処理系によっては、スレッドからのMPI通信が実装されていない →マスタースレッドにまとめて通信する必要がある 観測ルーチンを組むのが面倒くさい →通信がすべて二段になっているため University of Tokyo
  62. 62. 62/76 MPIを使う際の注意点 小さいジョブが成功したのに大きなジョブが失敗・・・なぜ? MPIはリソースをかなり消費するから ノンブロッキング通信 直接通信 Process1 Process2 Buffer (heap) バッファ通信 Process1 Process2 ノンブロッキング通信はバッファを多く使うため、大きいジョブでメモリ不足に陥り易い (実はブロッキング通信を指定しても、ノンブロッキング通信が呼ばれる可能性がある) 典型的には「MPI_なんとか_MAX」が足りない、というエラーメッセージが良く出る。 対応する環境変数などを調べること。 対応策としては、通信を小分けにする、こまめにバッファをクリアするなど・・・MPIの実装はベンダーに強く依存する。あるシステムで問題なく動作したプログラムが他のところで動かない、ということはよくある University of Tokyo
  63. 63. 63/76 馬鹿パラの是非馬鹿パラとは 乱数の種やパラメータを変えたジョブを多数投入すること 自明並列(trivial parallelization)とも。 通信が発生しないため、見た目の並列化効率は100%やってはいけない馬鹿パラ 乱数の種を変えて、物理量の統計平均を稼ぐ馬鹿パラ 統計精度は、サンプル数の平方根に比例する したがって、100倍の計算資源をつぎ込んでも、 得られる精度向上は10倍程度→実質並列化効率10% 莫大なサンプル数による統計平均が必要なジョブを 超並列計算機で行う、というのは筋が悪い※ パラメータ並列も拡張アンサンブルやGAを使うなど工夫したほうが良いと思う University of Tokyo
  64. 64. 64/76 大規模計算では何ができるか 渡辺の研究紹介 University of Tokyo
  65. 65. 65/76 気液混相流の全粒子計算 気液混相流 階層的モデリング マクロな輸送現象(熱、粒子、運動量)と 相転移 気泡間相互作用 流動現象 ミクロな相転移のカップルした非平衡状態 数値計算課題として マルチスケール、マルチフィジックス 境界の移動、生成、消滅階層的モデリング スケールにより現象を分類 それぞれに支配方程式を仮定する 粒子間相互作用 ・人為的な階層定義 ・支配方程式の妥当性の検証 分子動力学法による全粒子計算 →大規模計算 Movie 全粒子計算 University of Tokyo
  66. 66. 66/76 ベンチマーク (1/3)計算の詳細 カットオフ 2.5、密度 0.5、初期条件: FCC、時間刻み: 0.001積分法:二次のシンプレクティック150ステップ後、1000ステップの計算にかかった時間を計測東京大学情報基盤センター Oakleaf (FX10) 4800ノードを使って計測(1.13ペタフロップス)並列化 Flat MPI :16プロセス/node 最大 76800プロセス Hybrid: 16 スレッド/node  最大 4800プロセス、76800スレッド University of Tokyo
  67. 67. 67/76 ベンチマーク (2/3)ウィークスケーリング(ノードあたりの計算量を固定したままノード数を増加)Flat MPIのスケーリングはほぼ完璧Hybridの速度は不安定、かつFlat MPIの二倍程度遅い University of Tokyo
  68. 68. 68/76 ベンチマーク (3/3) 4800 node 38.4G Particles 105229 MUPS (384億粒子) 1 node8M Particles22.7 MUPSMUPS: Million Updates Per Seconds ウィークスケーリング (ノードあたりの計算量を固定したままノード数を増加) 最大で4800ノード、76800プロセス、384億粒子 そろそろMUPSじゃなくてGUPSの領域 University of Tokyo
  69. 69. 69/76 急減圧シミュレーション 計算の詳細 G Liquid Temperature 初期密度と温度: T=0.9, ρ=0.7 (純液相)減圧強さ:一辺 1.025倍 (密度 0.7→0.65: 強減圧)時間刻み:0.005カットオフ:3.0 Coexistence 周期境界条件 数値積分法:二次のシンプレクティック(NVE)      二次のRESPA (NVT)緩和: 1万ステップ トータルステップ数: 70万ステップ(ISSP) 18万ステップ(FX10) Density 計算の規模 物性研: 情報基盤センター: 1024プロセス 4800プロセス (76800スレッド) 320*320*320 1440*1200*1200 物性研の64倍 22937600粒子 1449776020粒子 70万ステップに10時間 18万ステップに15時間 Hybrid実行 Flat-MPI実行 Movie University of Tokyo
  70. 70. 70/76 多重核生成からOstwald成長へ 物性研の計算結果 (2300万粒子) 初期ステージ 中間ステージ 最終ステージ 多重核生成 気泡間相互作用による「つぶしあい」 単一気泡へ収束 FX10の計算結果 (14億5千万粒子)多重核生成から気泡間相互作用フェーズへ University of Tokyo
  71. 71. 71/76 気泡の分布関数 (1/2) FX10 (L=1440) ISSP (L=320) 減圧後、一万ステップ後の気泡分布関数 (体積で規格化)→ 気泡サイズの大きい領域で統計が取れていない University of Tokyo
  72. 72. 72/76 気泡の分布関数 (2/2) ISSP (L=320) FX10 (L=1440) 減圧後、一万ステップ後の気泡分布スナップショット 初期ステージにおいても、気泡分布関数をきれいに 見るためには最低でも一億粒子は必要 University of Tokyo
  73. 73. 73/76 ロードバランス 粒子系でのロードバランス 領域分割法における計算コストは、担当領域の粒子密度に比例 初期密度:0.7 → 減圧後: 0.65 →完璧なロードバランスが達成されたら、計算コストは0.65に比例 減圧後、気相と液相に分離 計算コスト 初期温度:0.9 → 減圧後: 0.88 この温度における共存密度 気相密度: 0.0344 実際のコスト 液相密度: 0.687 理想的な場合 毎ステップバリア同期を取っているため計算速度は一番遅い領域が決める一番遅い領域は、純液相領域 (密度0.687) プロセス1 プロセス2 プロセス3 プロセス4 プロセス5 ロードバランスの悪化 0.65 / 0.687 0.95 急減圧シミュレーションにおいては、ロードインバランスは問題にならない University of Tokyo
  74. 74. 74/76 現象とスケール We are here 物理現象 Micro Macro 気泡生成 気泡流 多重気泡生成 (相転移と流動のカップリング)必要粒子数 Linear Scale 10 nm 100 nm 1 um University of Tokyo
  75. 75. 75/76 大規模計算でなにができたか ベンチマーク 最大4800ノード、76800プロセスで384億粒子の計算を実行 FX10向けのチューニングにより、ピーク性能比 17% (193TFLOPS) FlatMPIに比べてハイブリッド並列は遅く、かつ性能が安定しない しかし、ハイブリッド並列の方がメモリ消費は小さい 1ノードあたりのメモリ消費 Hybrid: 10GB/28GB急減圧による多重気泡生成過程 FlatMPI: 14GB/28GB 14億粒子による急減圧シミュレーション 大規模ハイブリッドコードが15時間完走 76800コア×15時間 = 131コア年 → これだけ長時間破綻せずに走るためには事前の綿密なデバッグが不可欠 粒子間相互作用により気泡生成 気泡間相互作用によりOstwald的成長 マルチスケールな現象の直接計算に成功 University of Tokyo
  76. 76. 76/76 全体のまとめ 高速化、並列化は好きな人がやればよいなぜなら科学とは好きなことをするものだから University of Tokyo

×