Successfully reported this slideshow.

CilkPlus, TBB, OpenMP

2,980 views

Published on

  • Be the first to comment

CilkPlus, TBB, OpenMP

  1. 1. CilkPlus, TBB, OpenMP - 並列プログラミングを支える技術 - @krustf Boost.勉強会 #11 東京 2013/06/01 1
  2. 2. 自己紹介 •大学4年 •某社アルバイト •CUDA とか MPI とか並列計算とか 数値計算とか多倍長精度演算とか •C++ と Ruby etc... •Boost.Interprocess とか Boost.MPI とか Boost.Multiprecision とか 2
  3. 3. Boost.えむーぴあいから差し替えた理由 •説明の大半を MPI に費やす •説明しづらい •GPGPU 勉強会での発表だったら やってたかもしれない •色々あって水曜日に燃え尽きてました 3
  4. 4. 4 Boost の比率
  5. 5. Overview 1. 並行 (マルチスレッド) プログラム 2. 支える技術たち (一部) 3. 行列ベクトル積のサンプル 4. 各技術の比較 5. サンプル評価 (適当) 6. まとめ 5
  6. 6. 並列プログラミングについて •マルチコアの普及 •実コア1台の処理性能は上がらない •暗黙に逐次計算を前提としている •並列計算の阻害点 •並列プログラミングは基本 6
  7. 7. コスト •並列計算向けアルゴリズムを選択 •並列計算だけにかかる処理 •ロック,共有,スレッド生成... •ただし僕は詳しくはない (すみません) •今までのコードに手を加える 7
  8. 8. 並列プログラミングを支える技術 •Intel CilkPlus •Intel TBB(Threading Building Blocks) •OpenMP •C++11 Future/Promise (/Thread) 8
  9. 9. Intel CilkPlus •並列プログラミング用コンパイラ拡張 •GCC,LLVM でも使用可能 •オープンソースライセンス •GCC: GPLv3 with Runtime Library Exception •LLVM: 修正 BSD 9
  10. 10. Intel CilkPlus •cilk_spawn, cilk_sync, cilk_for •Array Notation •# pragma simd •Elemental Function 10
  11. 11. cilk_spawn, cilk_sync •fork-join 用の拡張 •cilk_spawn で関数実行を fork •cilk_sync で fork した関数を join 11 int  x  =  cilk_spawn  fib(n-­‐1); int  y  =  fib(n-­‐2); cilk_sync; return  x  +  y;
  12. 12. cilk_for •並列 for 文 •これも fork-join で動く 12 cilk_for(int  i  =  0  ;  i  <  n  ;  ++i)  {    z[i]  =  x[i]  +  y[i]; }
  13. 13. Array Notation •配列計算の拡張 •自動 SIMD 化されて計算される 13 z[0:n]  =  x[0:n]  +  y[0:n]; for  (int  i  =  0  ;  i  <  n  ;  ++i)  {    z[i]  =  x[i]  +  y[i]; }
  14. 14. # pragma simd •for に SIMD 演算を明示的に許可 14 #pragma  simd for  (int  i  =  0  ;  i  <  n  ;  ++i)  {    z[i]  =  x[i]  +  y[i]; }
  15. 15. Elemental Functions •Array Notation を用いて計算できる 関数として定義 15 template<class  T> double  fma(T  a,  T  x,  T  y)  {    return  a  *  x  +  y; } for  (int  i  =  0  ;  i  <  n  ;  ++i)    z[i]  =  fma(a,  x[i],  y[i]); __declspec(vector) template<class  T> double  fma(T  a,  T  x,  T  y)  {    return  a  *  x  +  y; } z[0:n]    =  fma(a,  x[0:n],  y[0:n]);
  16. 16. Intel TBB •C++ STL 風のアルゴリズム •オープンソースで使用可能 •GPLv2 with Runtime Exception •C++11 のラムダ式で使いやすくなった •parallel_for, parallel_reduce... 16
  17. 17. parallel_for •並列 for を実行 •C++11 のラムダ式が使える 17 tbb::parallel_for(        tbb::blocked_range<int>(0,  n,  512)    ,  [&](tbb::blocked_range<int>  const&  r)  {            for(int  i  =  r.begin()  ;  i  <  r.end()  ;  ++i)  {                z[i]  =  a  *  x[i]  +  y[i];            }        }    ); 範囲の分割幅
  18. 18. parallel_reduce •並列リダクションを実行 •C++11 のラムダ式が使える 18 tbb::parallel_reduce(        tbb::blocked_range<int>(0,  n,  512)    ,  0.0    ,  [&](tbb::blocked_range<int>  const&  r,  double  v)  -­‐>  double  {            return  std::accumulate(x  +  r.begin(),  x  +  r.end(),  v);        }    ,  [](double  x,  double  y)  {            return  x  +  y;        }    );
  19. 19. OpenMP •共有メモリ計算機用の標準化実装 •大抵 for 文の並列化に使われる •タスクの並列実行も可能 •コンパイラ指示句で設定 19
  20. 20. # omp parallel for •for 文を並列実行させる •スレッド数指定やリダクションが可能 20 #pragma  omp  parallel  for  shared(z,  x,  y) for  (int  i  =  0  ;  i  <  n  ;  ++i)  {    z[i]  =  x[i]  +  y[i]; }
  21. 21. [参考] Future/Promise •C++11 で追加された •スレッドを意識することなく並列実行 できれば実行して値を取得できる •計算できなかった場合は例外が発生 •「#9 つくば」での発表を参照 21
  22. 22. OpenMP との違い •OpenMP は指定されたスレッド数で (またはデフォルト数で) 並列計算する •HPC 分野にとっては嬉しいが... •一般的なアプリケーションは様々な マシンで動かされる •最適なスレッド数はマシンで異なる 22
  23. 23. CilkPlus, TBB •CilkPlus, TBB はワークスケジューラに よって最適な並列実行を行う •特に CilkPlus はコンパイラや実行 アプリケーションに「並列化可能」で あることをマークするキーワード 23
  24. 24. マークする理由 •コンパイラにとっては「並列化可能」 であるかを検出することは難しい •ポインタによるエイリアシング •他の箇所で更新されている... •「並列化可能」をプログラマが明示 することで最適化させやすい 24
  25. 25. サンプル •行列ベクトル積を実装 25 bi = nX j=1 aij ⇥ xj (i = 1, 2, ..., n) 図1 : 行列ベクトル積のアルゴリズム,ただし n 次正方行列の場合で, b, x はベクトル,a は行列の要素
  26. 26. 逐次計算 26 for  (int  i  =  0  ;  i  <  n  ;  ++i)  {    b[i]  =        //  bi  =  (Ai,  x)        std::inner_product(A+i*n,  A+i*n+n,  x,  0); }
  27. 27. CilkPlus 27 cilk_for  (int  i  =  0  ;  i  <  n  ;  ++i)  {    b[i]  =      __sec_reduce_add(A[i*n:n]  *  x[0:n]); } for  (int  i  =  0  ;  i  <  n  ;  ++i)  {    b[i]  =        //  bi  =  (Ai,  x)        std::inner_product(A+i*n,  A+i*n+n,  x,  0); }
  28. 28. TBB 28 tbb::parallel_for(tbb::blocked_range<int>(0,  n,  512)    ,  [&](tbb::blocked_range<int>  const&  r)  {        for(int  i  =  r.begin()  ;  i  <  r.end()  ;  ++i)  {            b[i]  =                std::inner_product(A+i*n,  A+i*n+n,  x,  0.0);        }    }); for  (int  i  =  0  ;  i  <  n  ;  ++i)  {    b[i]  =        //  bi  =  (Ai,  x)        std::inner_product(A+i*n,  A+i*n+n,  x,  0); }
  29. 29. OpenMP 29 #pragma  omp  parallel  for  shared(A,  x,  b) for(int  i  =  0  ;  i  <  n  ;  ++i)  {    b[i]  =  std::inner_product(A+i*n,  A+i*n+n,  x,  0.0); } for  (int  i  =  0  ;  i  <  n  ;  ++i)  {    b[i]  =        //  bi  =  (Ai,  x)        std::inner_product(A+i*n,  A+i*n+n,  x,  0); }
  30. 30. 性能比較 •結構適当です •1つの結果ということで •姫野ベンチマークを高速化しようと したら時間ありませんでした • CilkPlus と TBB でのチューニングがまともにできませんでした •CG 法 を使います 30
  31. 31. CG 法 •連立1次方程式の 求解を行う反復法 •ベクトル演算が 大半を占めるので 並列化しやすい 31 図2 : CG (Conjugate Gradient, 共役勾配) 法のアルゴリズム Let x0 be an initial guess. r0 = b − Ax0 p0 = r0 for k = 0, 1, ..., until ||r||2/||b||2 ≤ ε αk = (rk,rk) (pk,Apk) xk+1 = xk + αkpk rk+1 = rk − αkApk βk = (rk+1,rk+1) (rk,rk) pk+1 = rk+1 + βkpk end for
  32. 32. 解く問題 32 A = 1 1 · · · 1 1 3 · · · 3 ... ... ... ... 1 3 · · · 2n 1 x = 2 6 6 6 4 0 0 ... 0 3 7 7 7 5 , y = 2 6 6 6 4 1 1 ... 1 3 7 7 7 5 , b = Ay solve Ax = b x ⇡ y
  33. 33. 評価環境 33 OS CentOS Linux 6.3 x86_64 CPU Intel Core i7 930 CPU Memory 12 GB CPU Compiler Intel Compiler 13.0 CPU Compiler Options -O3 -march=native -fopenmp -ltbb 連立1次方程式の次元数 4096 表1 : 評価環境
  34. 34. 評価 34 Parallel Mode Time [sec] Number of Iteration GFLOPS SpeedUP Serial 16.529 1310 1.331 1.000 CilkPlus 9.539 1238 2.180 1.638 TBB 9.635 1257 2.191 1.646 OpenMP 10.667 1272 2.003 1.505 表2 : 次元数が 4096 の場合の性能評価
  35. 35. 原因とか •OpenMP が遅くなったのは多分 スレッド立ち上げのオーバヘッド •CilkPlus, TBB はワークスケジューラで タスクを投げるためその分オーバーヘ ッドは少ない •問題が大きかったら違うかも •4倍の16384元にしてみた 35
  36. 36. 評価 36 Parallel Mode Time [sec] Number of Iteration GFLOPS SpeedUP Serial 529.087 2563 1.301 1.000 CilkPlus 334.729 2556 2.050 1.576 TBB 334.144 2541 2.042 1.570 OpenMP 344.842 2551 1.986 1.527 表3 : 次元数が 16384 の場合の性能評価
  37. 37. 原因とか •性能差には大きく変化なし •問題規模が増加したことで演算性能 が全体的に極小だが低下した •OpenMP の最適化が足りないかも 37
  38. 38. ちなみに •OpenMP はスレッド数を 4 で固定 •CilkPlus, TBB はワーカ設定なし •ロードバランス等から適切なスケジュ ーリングが行われている (っぽい) 38
  39. 39. まとめ •CilkPlus か TBB を使いましょう •C++11 が使えれば Promise は有効 •この本を読むと分かりやすい 39 「構造化並列プログラミング」 マイケル・マックール/アーク・D・ロビソン/ジ ェームス・レインダース 菅原清文・エクセルソフト株式会社 訳 CUTT System : 6300 円 http://www.cutt.co.jp/book/978-4-87783-305-3.html
  40. 40. 質問 ※質問により答えられない場合があります 40

×