福井技術者の集い その6 発表資料スライド

50
C++による数値解析の並列化手法 @dc1394 福井技術者の集い その6 発表資料ス ライド

Upload: dc1394

Post on 13-Jan-2017

248 views

Category:

Education


1 download

TRANSCRIPT

Page 1: 福井技術者の集い その6 発表資料スライド

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

@dc1394

福井技術者の集いその6発表資料スライド

Page 2: 福井技術者の集い その6 発表資料スライド

自己紹介

Twitter: @dc1394

C++, C#, F#そしてRubyが好きです。

趣味はプログラミングではなく数値解析。

C++で量子力学の数値計算とかやってます。

Page 3: 福井技術者の集い その6 発表資料スライド

概要

なぜC++で数値解析と並列化のコードを書くのか

並列化の分類について

タスク並列化のパフォーマンス比較・検証

データ並列化(GPGPU)のパフォーマンス比較・検証

Page 4: 福井技術者の集い その6 発表資料スライド

なぜC++で数値解析のコードを書くのか

多数あるプログラム言語の中で、高性能なコンパイラ(Intel, PGIのコンパイラ等)及び、スーパーコンピュータ向けのコンパイラ(IBM, Cray, Fujitsuのコンパイラ等)でコンパイルできる言語は、Fortran, C及びC++だけである(ただし最近ではPythonも…)。

これらの言語の最新規格を列挙すると、 Fortran 2008 (2010年9月)

C11 (2011年12月)

C++14 (2014年12月)

これらの言語の中で、最もモダンな言語はC++である。

Page 5: 福井技術者の集い その6 発表資料スライド

C++で数値解析と並列化のコードを書くときのメリットとデメリット

メリット FortranやC向けの、高性能かつ豊富なライブラリが使える(LAPACKやBLAS, GSL (GNU Scitific Library), FFTWなど)。

インラインアセンブラやintrinsic関数が使える(SIMDでデータ並列化する際に重要、後述)。

デメリット FortranやC向けのライブラリを使う際、C++らしく書けない。

言語レベルで並列処理をサポートしていない。

Page 6: 福井技術者の集い その6 発表資料スライド

並列化の分類

命令レベル並列

並列パイプライン、スーパースカラ、アウト・オブ・オーダー実行, etc. →CPUとコンパイラの仕事

データ並列

Single Instruction Multiple Data (SIMD)

General-purpose computing on graphics processing

units (GPGPU)

タスク並列

スレッド並列

プロセス並列

Page 7: 福井技術者の集い その6 発表資料スライド

並列化の分類

データ並列

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)

Page 8: 福井技術者の集い その6 発表資料スライド

スレッド並列とプロセス並列

タスク並列

Page 9: 福井技術者の集い その6 発表資料スライド

スレッド並列とプロセス並列

スレッド並列:1つのプロセスの中でスレッドを複数個生成させ、各スレッドに異なるCPUコアを割り

当てて並列処理を行う方法(共有メモリ型並列計算機専用)。

プロセス並列:複数のプロセスを起動して、各プロセスに異なるCPUコアを割り当てて並列処理を

行う方法(分散メモリ型並列計算機向け、共有メモリ型並列計算機でも動作)。

Page 10: 福井技術者の集い その6 発表資料スライド

ハイブリッド並列

スーパーコンピュータでは、プロセス並列(MPI)と、スレッド並列(OpenMP)の両方を駆使したハイブリッド並列化の利用が普通である。

ノード間をMPIでプロセス並列化し、複数のCPUとCPUコアがあるノード内をOpenMPでスレッド並列化するケースが一般的である。

Page 11: 福井技術者の集い その6 発表資料スライド

参考スライド

C++における並列化については、yohhey様が書かれた以下のスライドが非常に参考になります。

「新しい並列for文のご提案」( http://www.slideshare.net/yohhoy/boostjp14-

parfor-20140301-31781446 )

Page 12: 福井技術者の集い その6 発表資料スライド

並列化の一般論

1. まず最初に、シリアルコード(並列化しないコード)で、バグのないプログラムを作成する(最初からパラレルコード(並列化コード)を書こうとするのは無謀である)。

2. シリアルコードでプログラムの無駄をなくし、チューニングする。

3. プロファイラ等で、プログラムの各計算部分の実行時間の測定を行い、ホットスポットを見つける。

Page 13: 福井技術者の集い その6 発表資料スライド

並列化の一般論

4. ホットスポットの部分で、かつ並列化できる部分を並列化する。ただし、プログラムの改変は一度に一部分ごとに行い、その都度シリアルコードと結果を比較する。パラレルコードのデバッグは、シリアルコードと比較し、難しい。従って、ステップバイステップを心がける。

5. パラレルコードが完成したと思ったら、並列数や問題サイズを変えて、結果を慎重にチェックする。

6. 並列数に対する計算時間を測定し、並列効率比をプロットする。

Page 14: 福井技術者の集い その6 発表資料スライド

数値積分の並列化

以下の定積分を、Simpsonの公式によって数値積分する。

この定積分は、解析的に積分した結果が厳密に1となるため、数値積分の結果と容易に比較できる。

この数値積分のプログラムを、C++11非同期処理, OpenMP, TBB, Cilk Plus, PPL及びMPIによって並列化し、シリアルコードと比較した場合の並列効率比や誤差を調べる。

Page 15: 福井技術者の集い その6 発表資料スライド

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

Page 16: 福井技術者の集い その6 発表資料スライド

Simpsonの公式とは

ここで、区間[a, b]にわたっての関数f(x)の積分は、上式を足し合わせればよい。ただし、 j = 0, 2,

4,…, N-2と足し合わせる。

ΔhΔh

Page 17: 福井技術者の集い その6 発表資料スライド

並列化無しのコード

Page 18: 福井技術者の集い その6 発表資料スライド

C++11非同期処理の特徴、メリット、デメリット

特徴:C++11標準の機能。

メリット

移植性に比較的優れる(C++11対応のコンパイラがあればOK)。

デメリット

各スレッドに対する計算範囲を、自分でコーディングする必要がある。

コードが複雑になり、可読性が落ちる。

Page 19: 福井技術者の集い その6 発表資料スライド

C++11非同期処理で並列化したコード

Page 20: 福井技術者の集い その6 発表資料スライド

OpenMPの特徴、メリット、デメリット

特徴:並列コンピューティング用のFortran, C/C++言語拡張。

メリット最も移植性に優れる。

比較的可読性に優れる。

デメリット C++例外の扱いが面倒(OpenMPスレッドからC++例外が投げられた際、例外がcatchされず、実行時クラッシュなどが起こる)。

上記の問題に対処しようとすると、コードが複雑になり、可読性が低くなる。

Page 21: 福井技術者の集い その6 発表資料スライド

OpenMPで並列化したコード

Page 22: 福井技術者の集い その6 発表資料スライド

TBBの特徴、メリット、デメリット

特徴:Intelが公開している、マルチスレッド対応のC++テンプレートライブラリ。ICCに付属のものとオープンソース版とがある。

メリット

移植性に優れる(GCC, Clang, MSVC, ICC,…等の普通のコンパイラ上なら動く)。

デメリット

若干コードが複雑になり、可読性が落ちる。

Page 23: 福井技術者の集い その6 発表資料スライド

TBBで並列化したコードその1

Page 24: 福井技術者の集い その6 発表資料スライド

TBBで並列化したコードその2

Page 25: 福井技術者の集い その6 発表資料スライド

Cilk Plusの特徴、メリット、デメリット

特徴:Intelによる並列コンピューティング用のC/C++言語拡張。

メリット

可読性に優れる。

デメリット

対応しているコンパイラが少ない(ICC及びGCC 5.1以上のみ)。

Clangは、Cilk Plus/LLVMというプロジェクトで対応。

Page 26: 福井技術者の集い その6 発表資料スライド

Cilk Plusで並列化したコード

Page 27: 福井技術者の集い その6 発表資料スライド

PPLの特徴、メリット、デメリット

特徴:Microsoft製の、並列プログラミングをサポートするライブラリ。

メリット

比較的可読性に優れる。

デメリット

対応しているコンパイラがMSVC(VC10以降)のみ。

他の方法と比べて、誤差が大きく、またパフォーマンスが低い(後述)。

Page 28: 福井技術者の集い その6 発表資料スライド

PPLで並列化したコード

Page 29: 福井技術者の集い その6 発表資料スライド

MPIの特徴、メリット、デメリット

特徴:Fortran, C/C++で、並列コンピューティングを利用するための標準化された規格である。

メリット分散メモリ型並列計算機においては、この方法が必須。

移植性に優れる。

デメリット

各プロセスに対する計算範囲を、自分でコーディングする必要がある。

コードが極めて複雑になり、可読性が大きく落ちる。

並列化数を、実行時にコマンドラインオプションから明示的に指定する必要がある。

デバッグが極めて困難。

Page 30: 福井技術者の集い その6 発表資料スライド

MPIで並列化したコード

Page 31: 福井技術者の集い その6 発表資料スライド

MPIで並列化したコード(続き)

Page 32: 福井技術者の集い その6 発表資料スライド

タスク並列のパフォーマンスの検証

それぞれの方法において、並列化のパフォーマンスを測定し、結果を次ページの表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)

Page 33: 福井技術者の集い その6 発表資料スライド

タスク並列のパフォーマンスの検証

計算時間(ミリ秒)

並列効率比(倍)

積分結果 並列化なしに対する誤差

誤差の標準偏差

並列化なし

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回の平均)

Page 34: 福井技術者の集い その6 発表資料スライド

結局、どれを使うべきか

計算機が普通のPCなら、TBBかCilk Plusを使うことを推奨する。

あくまで移植性を重視するなら、OpenMPが唯一の選択肢となる。

個人でPCクラスタを組んでいたり、スーパーコンピュータへの移植を考えるなら、MPI単独か、OpenMPとMPIのハイブリッド並列が選択肢になる。

個人的な疑問:TBBやCilk Plusと、MPIのハイブリッド並列は可能なのだろうか?

Page 35: 福井技術者の集い その6 発表資料スライド

ソースコードへのリンク

これらのプログラム(simpson, simpsonmpi)のソースコードは、GitHub上で公開しています。

https://github.com/dc1394/simpson

https://github.com/dc1394/simpsonmpi

ライセンスは2条項BSDライセンスとします。

Page 36: 福井技術者の集い その6 発表資料スライド

SIMDとGPGPU

データ並列

Page 37: 福井技術者の集い その6 発表資料スライド

SIMDとは

SIMD(Single Instruction Multiple Dataの略)とは、コ

ンピュータで並列処理を行なうための設計様式の一つで、一つの命令を同時に複数のデータに適用し、並列に処理する方式。

cf. フリンの分類, SISD, MISD, MIMD

そのような処理方式をベクトル演算、ベクトル処理などと呼ぶことがあり、この方式による並列化のことをベクトル化などという。

Page 38: 福井技術者の集い その6 発表資料スライド

ベクトル化の注意

2016年現在のコンパイラは非常に優秀であり、単にコンパイラオプションでSSE/AVX命令を使うように指示するだけで、コンパイラが自動的にベクトル化を行ってくれる。

インラインアセンブラ, SIMD intrinsic, Boost.SIMDなどによる手動のベクトル化は、コンパイラの自動ベクトル化に、パフォーマンスで及ばない場合があり、注意が必要。

コンパイラを「負かせる」には、極めて慎重なプログラミングが必要である。

Page 39: 福井技術者の集い その6 発表資料スライド

SSE2命令(SIMD intrinsic)を使ってmemcpyを自作したコード

Page 40: 福井技術者の集い その6 発表資料スライド

GPGPUとは

GPGPU(General-purpose computing on graphics processing unitsの略)とは、GPUの演算資源を画像処理以外の目的に応用する技術のこと(なお、GPGPUはSIMDの一つに分類される)。

GPUはもともと画像処理を専門とする演算装置であり、非常に多数のデータを並列処理することができる。従ってCPUと比較すると、GPUは並列的な演算が得意である。

そのため、プログラムの並列演算部分をGPUで計算させることで、プログラムの高速化が望める。

Page 41: 福井技術者の集い その6 発表資料スライド

CUDAとは

CUDA(Compute Unified Device Architectureの略)とは、NVIDIAが提供するGPU向けのC/C++言語の統合開発環境であり、コンパイラ(nvcc)やライブラリなどから構成されている。

CUDAはGPGPU技術の先駆けである(CUDA 1.0の提供開始は2007年7月)。

このため、先発技術であるCUDAは、教育・研究機

関での採用事例が多いほか、機械学習などの分野で産業界でも採用への取り組みが進んでいる。

Page 42: 福井技術者の集い その6 発表資料スライド

CUDAのメリット、デメリット

メリット

CUDA 7.0から、C++11規格のサポートが強化され、デバイスコード(CPUで動かすコード)におけるラムダ式の利用などが可能となっている。

Thrustと呼ばれる、(C++のSTLによく似た)GPU用の並列アルゴリズムライブラリが提供されている。

カーネルコード(GPUで動かすコード)が普通にコンパイルできる。

デメリット

NVIDIAのGPU専用である。

Page 43: 福井技術者の集い その6 発表資料スライド

OpenCLとは

OpenCL(Open Computing Languageの略)は、OpenCL C言語による、マルチコアCPUやGPUなど

による異種混在の計算資源を利用した並列コンピューティングのためのクロスプラットフォームなフレームワークである。

マルチコアCPUやGPU以外にも、FPGAやXeon Phi

などをサポートしている。

Page 44: 福井技術者の集い その6 発表資料スライド

OpenCLのメリット、デメリット

メリット少なくとも、NVIDIA, AMD及びIntelのGPUで動作する。

デバイスコードでは、C++11が使用可能。

Boost.Compute(Boost 1.61.0以降に含まれる)と呼ばれる、OpenCLのC++ラッパーが存在し、カーネルコードを簡潔に記述できる。

デメリット

オンラインコンパイルでは、カーネルコードが実行時にロードされコンパイルされるため、デバッグが困難になり、初回起動時に時間がかかる(Boost.Computeはこちらしか対応していない)。

オフラインコンパイル(通常のコンパイル)では移植性が落ちる。

Page 45: 福井技術者の集い その6 発表資料スライド

分子動力学のGPGPUによる並列化

シンプソンの公式による数値積分を、GPGPUで並列化すると、CPUより遅かったという現象に直面した(調査中)ため、簡単な分子動力学(Molecular

Dynamics, MD)のコードをGPGPUで並列化することにした。

分子動力学については、拙著のスライド(以下URL)を参照のこと。

http://www.slideshare.net/dc1394/4-52829134

Page 46: 福井技術者の集い その6 発表資料スライド

GPGPUのパフォーマンス検証

LJポテンシャルの下で相互作用する、2048個のアルゴン原子を100ステップ計算した場合の、並列化無し、CPUをTBB(6コア12スレッド)で並列化した場合、CUDA及びOpenCLで並列化した場合の計算時間を測定し、結果を次ページの表1にまとめた。

計測環境:

GPU: NVIDIA GeForce GTX 970 (Maxwell)

GeForce Driverバージョン: 368.69

CUDAコンパイラ: nvcc 7.5.17

OpenCLバージョン: OpenCL 1.2 CUDA

OpenCLのCPU側のコンパイラや、OS, CPU等については、タスク並列のパフォーマンス比較の記載と同じ。

Page 47: 福井技術者の集い その6 発表資料スライド

GPGPUのパフォーマンス検証

CUDA及びOpenCLで並列化した場合は、並列化無しの場合に対してそれぞれ29.1倍、28.3倍程度速く、CPUをTBB(6コア12スレッド)で並列化した場合に対しても、それぞれ6.2倍、6倍程度速い。

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回の平均)

Page 48: 福井技術者の集い その6 発表資料スライド

GPGPUの問題

デバッグが困難。

基本的に、GPUで倍精度演算を行うためには、高価なGPGPU専用カードが必要(e.g. NVIDIA Tesla,

AMD FirePro, Intel Xeon Phi)。

デバイス(CPU)とホスト(GPU)間のデータ転送が

頻繁に行われると、それがボトルネックになり得るので、慎重にプログラミングする必要がある。

Page 49: 福井技術者の集い その6 発表資料スライド

ソースコードへのリンク

これらのプログラム(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ライセンスとします。

Page 50: 福井技術者の集い その6 発表資料スライド

まとめ

並列化の分類について説明した。

タスク並列について、種々の方法について説明し、それらの方法のパフォーマンスを比較・検証した。

手動ベクトル化の注意点について説明した。

GPGPUについて、CUDAとOpenCLについて説明し、これらのパフォーマンスを比較・検証した。