Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

C++による数値解析の並列化手法

1,506 views

Published on

C++による数値解析の並列化手法について解説したスライドです。スライドの後半では、GPGPUについて解説しています。

Published in: Education
  • Be the first to comment

C++による数値解析の並列化手法

  1. 1. 各種の並列化手法とGPGPU @dc1394 C++による数値解析の並列化手法
  2. 2. 自己紹介  Twitter: @dc1394  C++, C#, F#そしてRubyが好きです。  趣味はプログラミングではなく数値解析。  C++で量子力学の数値計算とかやってます。
  3. 3. 概要  なぜC++で数値解析と並列化のコードを書くのか  並列化の分類について  タスク並列化のパフォーマンス比較・検証  データ並列化(GPGPU)のパフォーマンス比較・検 証
  4. 4. なぜC++で数値解析のコードを書く のか  多数あるプログラム言語の中で、高性能なコンパ イラ(Intel, PGIのコンパイラ等)及び、スーパーコ ンピュータ向けのコンパイラ(IBM, Cray, Fujitsuのコ ンパイラ等)でコンパイルできる言語は、Fortran, C 及びC++だけである(ただし最近ではPythonも…)。  これらの言語の最新規格を列挙すると、  Fortran 2008 (2010年9月)  C11 (2011年12月)  C++14 (2014年12月)  これらの言語の中で、最もモダンな言語はC++で ある。
  5. 5. C++で数値解析と並列化のコードを 書くときのメリットとデメリット  メリット  FortranやC向けの、高性能かつ豊富なライブラリが使 える(LAPACKやBLAS, GSL (GNU Scitific Library), FFTW など)。  インラインアセンブラやintrinsic関数が使える(SIMDで データ並列化する際に重要、後述)。  デメリット  FortranやC向けのライブラリを使う際、C++らしく書け ない。  言語レベルで並列処理をサポートしていない。
  6. 6. 並列化の分類  命令レベル並列  並列パイプライン、スーパースカラ、アウト・オブ・ オーダー実行, etc. →CPUとコンパイラの仕事  データ並列  Single Instruction Multiple Data (SIMD)  General-purpose computing on graphics processing units (GPGPU)  タスク並列  スレッド並列  プロセス並列
  7. 7. 並列化の分類  データ並列  SIMD: インラインアセンブラ, SIMD intrinsic, Boost.SIMD(開発中), OpenMP 4.0, Cilk Plus, etc.  GPGPU: CUDA (Thrust), OpenCL (Boost.Compute), C++ AMP, DirectCompute, OpenMP 4.0, etc.  タスク並列  スレッド並列: OpenMP, Intel® Threading Building Blocks (Intel® TBB), Cilk Plus, Parallel Patterns Library (Microsoft PPL)  プロセス並列: Message Passing Interface (MPI) (Boost.MPI)
  8. 8. スレッド並列とプロセス並列 タスク並列
  9. 9. スレッド並列とプロセス並列  スレッド並列:1つのプロセスの中でスレッドを複 数個生成させ、各スレッドに異なるCPUコアを割り 当てて並列処理を行う方法(共有メモリ型並列計 算機専用)。  プロセス並列:複数のプロセスを起動して、各プ ロセスに異なるCPUコアを割り当てて並列処理を 行う方法(分散メモリ型並列計算機向け、共有メ モリ型並列計算機でも動作)。
  10. 10. ハイブリッド並列  スーパーコンピュータでは、プロセス並列(MPI)と、 スレッド並列(OpenMP)の両方を駆使したハイブ リッド並列化の利用が普通である。  ノード間をMPIでプロセス並列化し、複数のCPUと CPUコアがあるノード内をOpenMPでスレッド並列 化するケースが一般的である。
  11. 11. 参考スライド  C++における並列化については、yohhey様が書か れた以下のスライドが非常に参考になります。  「新しい並列for文のご提案」 ( http://www.slideshare.net/yohhoy/boostjp14- parfor-20140301-31781446 )
  12. 12. 並列化の一般論 1. まず最初に、シリアルコード(並列化しないコー ド)で、バグのないプログラムを作成する(最初 からパラレルコード(並列化コード)を書こうとす るのは無謀である)。 2. シリアルコードでプログラムの無駄をなくし、 チューニングする。 3. プロファイラ等で、プログラムの各計算部分の実 行時間の測定を行い、ホットスポットを見つける。
  13. 13. 並列化の一般論 4. ホットスポットの部分で、かつ並列化できる部分 を並列化する。ただし、プログラムの改変は一度 に一部分ごとに行い、その都度シリアルコードと 結果を比較する。パラレルコードのデバッグは、 シリアルコードと比較し、難しい。従って、ステッ プバイステップを心がける。 5. パラレルコードが完成したと思ったら、並列数や 問題サイズを変えて、結果を慎重にチェックする。 6. 並列数に対する計算時間を測定し、並列効率比 をプロットする。
  14. 14. 数値積分の並列化  以下の定積分を、Simpsonの公式によって数値積 分する。  この定積分は、解析的に積分した結果が厳密に1 となるため、数値積分の結果と容易に比較できる。  この数値積分のプログラムを、C++11非同期処 理, OpenMP, TBB, Cilk Plus, PPL及びMPIによって並 列化し、シリアルコードと比較した場合の並列効 率比や誤差を調べる。
  15. 15. Simpsonの公式とは  関数f(x)を、微小区間[xj, xj+2]において、2次関数 P(x)で近似する(上図参照)。  このとき、  である(ただし、xj+2 - xj+1 = xj+1 - xj = Δh) 左図は、 http://www.yamamo10.jp/y amamoto/lecture/2007/5E_ comp_app/test_4/html/nod e2.html より引用 ΔhΔh
  16. 16. Simpsonの公式とは  ここで、区間[a, b]にわたっての関数f(x)の積分は、 上式を足し合わせればよい。ただし、 j = 0, 2, 4,…, N-2と足し合わせる。 ΔhΔh
  17. 17. 並列化無しのコード
  18. 18. C++11非同期処理の特徴、メリット、 デメリット  特徴:C++11標準の機能。  メリット  移植性に比較的優れる(C++11対応のコンパイラが あればOK)。  デメリット  各スレッドに対する計算範囲を、自分でコーディング する必要がある。  コードが複雑になり、可読性が落ちる。
  19. 19. C++11非同期処理で並列化したコー ド
  20. 20. OpenMPの特徴、メリット、デメリット  特徴:並列コンピューティング用のFortran, C/C++言 語拡張。  メリット  最も移植性に優れる。  比較的可読性に優れる。  デメリット  C++例外の扱いが面倒(OpenMPスレッドからC++例外が 投げられた際、例外がcatchされず、実行時クラッシュなど が起こる)。  上記の問題に対処しようとすると、コードが複雑になり、可 読性が低くなる。
  21. 21. OpenMPで並列化したコード
  22. 22. TBBの特徴、メリット、デメリット  特徴:Intelが公開している、マルチスレッド対応の C++テンプレートライブラリ。ICCに付属のものと オープンソース版とがある。  メリット  移植性に優れる(GCC, Clang, MSVC, ICC,…等の普 通のコンパイラ上なら動く)。  デメリット  若干コードが複雑になり、可読性が落ちる。
  23. 23. TBBで並列化したコードその1
  24. 24. TBBで並列化したコードその2
  25. 25. Cilk Plusの特徴、メリット、デメリット  特徴:Intelによる並列コンピューティング用の C/C++言語拡張。  メリット  可読性に優れる。  デメリット  対応しているコンパイラが少ない(ICC及びGCC 5.1以 上のみ)。  Clangは、Cilk Plus/LLVMというプロジェクトで対応。
  26. 26. Cilk Plusで並列化したコード
  27. 27. PPLの特徴、メリット、デメリット  特徴:Microsoft製の、並列プログラミングをサポー トするライブラリ。  メリット  比較的可読性に優れる。  デメリット  対応しているコンパイラがMSVC(VC10以降)のみ。  他の方法と比べて、誤差が大きく、またパフォーマン スが低い(後述)。
  28. 28. PPLで並列化したコード
  29. 29. MPIの特徴、メリット、デメリット  特徴:Fortran, C/C++で、並列コンピューティングを利 用するための標準化された規格である。  メリット  分散メモリ型並列計算機においては、この方法が必須。  移植性に優れる。  デメリット  各プロセスに対する計算範囲を、自分でコーディングする 必要がある。  コードが極めて複雑になり、可読性が大きく落ちる。  並列化数を、実行時にコマンドラインオプションから明示 的に指定する必要がある。  デバッグが極めて困難。
  30. 30. MPIで並列化したコード
  31. 31. MPIで並列化したコード(続き)
  32. 32. タスク並列のパフォーマンスの検証  それぞれの方法において、並列化のパフォーマン スを測定し、結果を次ページの表1にまとめた(区 間[1, 4]を10億個の区間に分割、ループ5億回)。  計測環境:  CPU: Intel Core i7-3930K (Sandy Bridge-E, Hyper Threading ON (6C12T), SpeedStep OFF, Turbo Boost OFF)  コンパイラ: Intel® Parallel Studio XE 2016 for C++ on Visual C++ 2015 (x64ビルド)  MPIの実装: Microsoft MPI v7  OS: Microsoft Windows 8.1 (64bit)
  33. 33. タスク並列のパフォーマンスの検証 計算時間 (ミリ秒) 並列効率比 (倍) 積分結果 並列化なしに 対する誤差 誤差の標準偏 差 並列化 なし 1019.3 1 0.999999999999949 0 0 C++11 非同期 172.9 5.90 0.999999999999999 5.0E-14 0 OpenMP 180.1 5.66 0.999999999999999 5.0E-14 0 TBB1 172.2 5.92 0.999999999999998 4.9E-14 2.2E-15 TBB2 170.0 6.00 1.000000000000000 5.1E-14 0 Cilk Plus 178.4 5.71 1.000000000000000 5.1E-14 4.7E-16 PPL 397.2 2.57 1.000000000000020 7.1E-14 9.4E-15 MPI 171.1 5.96 0.999999999999999 5.0E-14 0 表1 各方法で並列化した場合のパフォーマンスの比較(5回の平均)
  34. 34. 結局、どれを使うべきか  計算機が普通のPCなら、TBBかCilk Plusを使うこと を推奨する。  あくまで移植性を重視するなら、OpenMPが唯一 の選択肢となる。  個人でPCクラスタを組んでいたり、スーパーコン ピュータへの移植を考えるなら、MPI単独か、 OpenMPとMPIのハイブリッド並列が選択肢になる。  個人的な疑問:TBBやCilk Plusと、MPIのハイブリッド並列は可能なのだろうか?
  35. 35. ソースコードへのリンク  これらのプログラム(simpson, simpsonmpi)のソー スコードは、GitHub上で公開しています。  https://github.com/dc1394/simpson  https://github.com/dc1394/simpsonmpi  ライセンスは2条項BSDライセンスとします。
  36. 36. SIMDとGPGPU データ並列
  37. 37. SIMDとは  SIMD(Single Instruction Multiple Dataの略)とは、コ ンピュータで並列処理を行なうための設計様式の 一つで、一つの命令を同時に複数のデータに適 用し、並列に処理する方式。  cf. フリンの分類, SISD, MISD, MIMD  そのような処理方式をベクトル演算、ベクトル処 理などと呼ぶことがあり、この方式による並列化 のことをベクトル化などという。
  38. 38. ベクトル化の注意  2016年現在のコンパイラは非常に優秀であり、単 にコンパイラオプションでSSE/AVX命令を使うよう に指示するだけで、コンパイラが自動的にベクト ル化を行ってくれる。  インラインアセンブラ, SIMD intrinsic, Boost.SIMDな どによる手動のベクトル化は、コンパイラの自動 ベクトル化に、パフォーマンスで及ばない場合が あり、注意が必要。  コンパイラを「負かせる」には、極めて慎重なプロ グラミングが必要である。
  39. 39. SSE2命令(SIMD intrinsic)を使って memcpyを自作したコード
  40. 40. GPGPUとは  GPGPU(General-purpose computing on graphics processing unitsの略)とは、GPUの演算資源を画像 処理以外の目的に応用する技術のこと(なお、 GPGPUはSIMDの一つに分類される)。  GPUはもともと画像処理を専門とする演算装置で あり、非常に多数のデータを並列処理することが できる。従ってCPUと比較すると、GPUは並列的な 演算が得意である。  そのため、プログラムの並列演算部分をGPUで計 算させることで、プログラムの高速化が望める。
  41. 41. CUDAとは  CUDA(Compute Unified Device Architectureの略)と は、NVIDIAが提供するGPU向けのC/C++言語の 統合開発環境であり、コンパイラ(nvcc)やライブラ リなどから構成されている。  CUDAはGPGPU技術の先駆けである(CUDA 1.0の 提供開始は2007年7月)。  このため、先発技術であるCUDAは、教育・研究機 関での採用事例が多いほか、機械学習などの分 野で産業界でも採用への取り組みが進んでいる。
  42. 42. CUDAのメリット、デメリット  メリット  CUDA 7.0から、C++11規格のサポートが強化され、 デバイスコード(CPUで動かすコード)におけるラムダ 式の利用などが可能となっている。  Thrustと呼ばれる、(C++のSTLによく似た)GPU用の並 列アルゴリズムライブラリが提供されている。  カーネルコード(GPUで動かすコード)が普通にコンパ イルできる。  デメリット  NVIDIAのGPU専用である。
  43. 43. OpenCLとは  OpenCL(Open Computing Languageの略)は、 OpenCL C言語による、マルチコアCPUやGPUなど による異種混在の計算資源を利用した並列コン ピューティングのためのクロスプラットフォームな フレームワークである。  マルチコアCPUやGPU以外にも、FPGAやXeon Phi などをサポートしている。
  44. 44. OpenCLのメリット、デメリット  メリット  少なくとも、NVIDIA, AMD及びIntelのGPUで動作する。  デバイスコードでは、C++11が使用可能。  Boost.Compute(Boost 1.61.0以降に含まれる)と呼ばれる、 OpenCLのC++ラッパーが存在し、カーネルコードを簡潔 に記述できる。  デメリット  オンラインコンパイルでは、カーネルコードが実行時に ロードされコンパイルされるため、デバッグが困難になり、 初回起動時に時間がかかる(Boost.Computeはこちらしか 対応していない)。  オフラインコンパイル(通常のコンパイル)では移植性が 落ちる。
  45. 45. 分子動力学のGPGPUによる並列化  シンプソンの公式による数値積分を、GPGPUで並 列化すると、CPUより遅かったという現象に直面し た(調査中)ため、簡単な分子動力学(Molecular Dynamics, MD)のコードをGPGPUで並列化するこ とにした。  分子動力学については、拙著のスライド(以下 URL)を参照のこと。  http://www.slideshare.net/dc1394/4-52829134
  46. 46. GPGPUのパフォーマンス検証  LJポテンシャルの下で相互作用する、2048個のアル ゴン原子を100ステップ計算した場合の、並列化無し、 CPUをTBB(6コア12スレッド)で並列化した場合、 CUDA及びOpenCLで並列化した場合の計算時間を測 定し、結果を次ページの表1にまとめた。  計測環境:  GPU: NVIDIA GeForce GTX 970 (Maxwell)  GeForce Driverバージョン: 353.90  CUDAコンパイラ: nvcc 7.5.17  OpenCLバージョン: OpenCL 1.2 CUDA  OpenCLのCPU側のコンパイラや、OSについては、タス ク並列のパフォーマンス比較の記載と同じ。
  47. 47. GPGPUのパフォーマンス検証  CUDA及びOpenCLで並列化した場合は、並列化無し の場合に対してそれぞれ29.1倍、28.3倍程度速く、 CPUをTBB(6コア12スレッド)で並列化した場合に対し ても、それぞれ6.2倍、6.0倍程度速い。  CUDAとOpenCLでは、CUDAの方が若干速かった。 計算時間(秒) 並列効率比(倍) TBBに対する並列効率 比(倍) 並列化無し 1307.9 1 0.21 TBB 279.0 4.69 1 CUDA 45.0 29.06 6.20 OpenCL 46.2 28.31 6.04 表1 GPGPUのパフォーマンスの比較(5回の平均)
  48. 48. GPGPUの問題  デバッグが困難。  基本的に、GPUで倍精度演算を行うためには、高 価なGPGPU専用カードが必要(e.g. NVIDIA Tesla, AMD FirePro, Intel Xeon Phi)。  デバイス(CPU)とホスト(GPU)間のデータ転送が 頻繁に行われると、それがボトルネックになり得る ので、慎重にプログラミングする必要がある。
  49. 49. ソースコードへのリンク  これらのプログラム(LJ_Argon_MD_CUDA, LJ_Argon_MD_OpenCL)のソースコードは、GitHub 上で公開しています。  https://github.com/dc1394/LJ_Argon_MD_CUDA  https://github.com/dc1394/LJ_Argon_MD_OpenC L  ライセンスは2条項BSDライセンスとします。
  50. 50. まとめ  並列化の分類について説明した。  タスク並列について、種々の方法について説明し、 それらの方法のパフォーマンスを比較・検証した。  手動ベクトル化の注意点について説明した。  GPGPUについて、CUDAとOpenCLについて説明し、 これらのパフォーマンスを比較・検証した。

×