190 likes | 313 Views
C ++ テンプレート機能による 数値計算プログラミングのための 並列クラスライブラリ. 佐藤 この研究は、新情報処理開発機構(RWCP)の時にやったもの (1998 年ごろ). C++. オブジェクトを定義するために class を導入。データ型に対し、その操作を定義するメンバー関数を宣言できる。ちなみに C の構造体である struct は、全メンバーが公開( public )な class と同値。
E N D
C++テンプレート機能による数値計算プログラミングのための並列クラスライブラリC++テンプレート機能による数値計算プログラミングのための並列クラスライブラリ 佐藤 この研究は、新情報処理開発機構(RWCP)の時にやったもの(1998年ごろ)
C++ • オブジェクトを定義するためにclassを導入。データ型に対し、その操作を定義するメンバー関数を宣言できる。ちなみにCの構造体であるstructは、全メンバーが公開(public)なclassと同値。 • クラス定義において、継承(inheritance)関係を定義でき、メンバーの可視性を制御できる。2つ以上のベースクラスも持つことができる。(Multiple inheritance) • クラス定義においては、クラスを生成する構築子(constructor)と消滅子(destructor)を宣言でき、クラスが生成・消滅するときに呼び出される。 • new / delete 演算子 • 仮想メンバー関数 (virtual function) • オブジェクトに対し、演算子をできる(operator overloading) • 多義関数名、int foo(int x)とint foo(double)は違う関数となる。ただし、「暗黙の型変換」が行われるので注意。 • defaultの引数が使える。 • 引数のReference渡しが使える。 • Template機能。Genericなプログラミングができる。
数値計算とオブジェクト指向言語 • これまでの数値計算プログラミングにはFORTRANが主に使われてきた • なぜ、C++か? • 多くのオブジェクト指向言語の中で、最も実用的 • 多くのプラットフォームで商用のコンパイラが利用可能 • 高性能なプログラムが可能 →データ型はコンパイル時にチェックされる • 演算子のoverloading • テンプレート機能 • 豊富なコンテナークラス(STL) ? • 数値計算分野では、数学的な記述が好まれる • MV++, IML++ (テネシ大、NIST)
OBP(Object-oriented building Blocks for Parallel programming) Library • 目標:並列数値計算で、有用なオブジェクト部品を提供する • 並列処理の詳細をオブジェクトの中に隠蔽する(通信など) • 逐次と親和性のよいプログラミングができる • SPMD(Single Program/Multiple Data)モデル、データ並列 • 並列アレイライブラリ • FORTRANのArray Expressionを提供 • Template Closureにより、配列の演算の一時変数を削除 • 並列行列ベクトルライブラリ • 逐次と並列で、同じアルゴリズムテンプレートを使えるように設計 pArray A(n,n),B(n,n),C(n,n) A = B + C; for(i=0; i<n; i++) for(j=0; j<n; j++) A[i][j] = B[i][j]+C[i][j];
C++による数値計算プログラミング • 演算オペレータのoverloading • 行列やベクトルなどの数学的な実体について演算子を定義し、自然な記述ができる • クラステンプレートによるパラメータ化クラスの定義 • コンテーナクラス - 他のデータを格納するデータ型 • 例: vector <double> • 関数テンプレートによる汎用(generic)なアルゴリズムの定義 • データに一定の操作や演算が定義されれば、polymorphicなアルゴリズムの記述ができる。 • クラスの継承、仮想関数 • モデリングなどに有用
逐次行列ベクトルクラス • 数値計算のための部品 • ベクトル Vector • 代入、加算、減算、定数倍、内積を定義 • 行列 Matrix • ベクトルとの積を定義 • 密行列、バンド行列 band_matrix, 疎行列CRS_matrix • 前処理 Preconditioner • solveのメソッドを定義 • 行列クラスごとに定義 • band_DiagPreconditioner, band_ICPreconditioner, • CRS_DiagPrecondtioner, CRS_ICPrecondtioner • 対角でスケーリング(DiagPrecondtioner), • 不完全コレスキー分解(ICPrecondtioer)
C++関数テンプレートによる汎用アルゴリズムライブラリC++関数テンプレートによる汎用アルゴリズムライブラリ • 反復解法のためのgenericなアルゴリズムライブラリ • 行列ベクトルのデータの格納の形式によらない • 例:IML++, MV++ 行列ベクトルクラス アルゴリズムテンプレート ベクトルvector 反復解法CG LU分解 密行列Matrix 固有値計算 疎行列CRS_Matrix こちらは並列クラス でもよい(OPB Lib) (並列) 数値計算プログラム
例:反復解法のテンプレートアルゴリズム 共役勾配法(CG法)のテンプレート // CG interation for(l=0; l<itr; l++){ Q = A*P; w2 = dot(P,Q); alpha = w1 / w2; X += alpha*P; R += -alpha*Q; res2 = dot(R,R); // convergence test if((res2/b2) <= eps){ rc = 0; break; } Q = M.solve(R); w2 = dot(R,Q); beta = w2 / w1; w1 = w2; P = Q + beta*P; } eps = res2/b2; itr = l; return rc; } template<class Matrix, class Vector, class Preconditioner> int CG(Matrix& A, Vector& B, Vector& X,Preconditioner& M, int& itr, double& eps) { typedef Matrix::value_type T; int n = A.size(); int l, rc=1; // working vector Vector R(n), P(n), Q(n); T w1, w2, b2, res2, alpha, beta; Q = A*X; R = B-Q; P = M.solve(R); w1 = dot(R,P); b2 = dot(B,B);
C++関数テンプレートによる汎用アルゴリズムライブラリC++関数テンプレートによる汎用アルゴリズムライブラリ • 行列クラス、ベクトルクラスを与える • CRS_DiagPreConditionerを用いる場合 #include "Vector.h" // ベクトルクラ #include "CRSMatrix.h” // 疎行列クラス #include "cg.h" // CGアルゴリズム vector<double> X(N),B(N); CRSMatrix<double> A(ファイル名); // 例えば、ファイルから読み込み生成 .... CRSDiagPreconditioner<double> D(A); // 前処理DiagPreconditionerを作成 // ICCG法を用いる場合には、CRSICPreconditionerを使う。 int rc = CG(A, B, X, D, itr, eps); // テンプレートの呼出
KAI C++コンパイラ g++/gccコンパイラ 用いた機能 N=100 N=1000 N=100 N=1000 no template (C) 0.19(1.00) 2.3(1.00) 0.23(1.00) 2.1(1.00) 2.5(1.08) 3.0(1.42) C++ template 0.20(1.05) 0.25(1.09) 0.36(1.89) 4.1(1.78) 0.54(2.35) 5.1(2.48) + op. overloading 逐次クラスライブラリの性能 CG法テンプレートライブありの性能(繰り返し1回あたりの実行時間(ミリ秒) • データは、5点差分による対称行列 • 括弧内はCコードとの性能比 • SUN SS20は、モデル71、SuperSparc 75 MHz、メモリ32MB • コンパイルのオプションは、KAI C++では+K3 -fast -O4、g++では-O3を用いた • 行列クラスはCRSフォーマットの疎行列、Preconditionerは、対角スケーリングで前処理するものを用いた
実験結果 • Operator overloadingを用いると一時変数のためのオーバーヘッドが大きい。 • 1回の反復に7回のベクトルオブジェクトの生成とコピー • in-placeの演算子(メソッド)を用いる • a+=c*b → Vectaxpy(a,b,c) • その他の解決方法 • template closure [松田ら], Expression Template[Velhusizen] • valarray • テンプレートを用いたオーバヘッドは、10%ぐらい
並列行列ベクトルクラス • 演算子、メソッドは各プロセッサで同時に呼び出されることを仮定(SPMD) • 逐次と同じ、テンプレートアルゴリズムがそのまま適用できる • 並列ベクトル pvector • 並列行列クラス • 分割方法に対応(現在は1次元分割のみ) • 行分割 ColPartitioned • ColPartitionedMatrix • ColPartitionedCRSMatrix • ColPartitionedBandMatrix • 列分割 RowPartitioned • RowPartitionedMatrix • RowPartionedCRSMatrix • ColPartitionedBandMatrix PE1 PE3 PE2 PE4 PE1 PE2 PE3 PE4
逐次クラスから並列クラスへの拡張 • 逐次のクラスをベースに並列クラスを構成 • スカラの値は書くプロセッサで、同じ値になるように構成 • 例:ベクトルの内積 • 並列ベクトルクラス template <class T> class pVector { int _size; // ベクトルの全体のサイズ int _base; // ローカルベクトルの最初の要素のインデックス Vector<T> _local; // このプロセッサにあるローカルベクトル public: int size() const { return _size; } ... };
逐次クラスから並列クラスへの拡張 • 分割用のコンテナクラスを作って、行列クラスごとの分割行列を生成 • コンストラクタは、分割クラスごとに定義しなくてはならない • 操作ごとに同期を行う • クラスに特化したメソッドが定義できる • バンド行列では、隣接通信だけですむ。 template <class Matrix,class T> class RowPartitionedMat { int _row_size;// 次元サイズ int _col_size; int _row_base; // ローカル行列の最初の列 Matrix _local;// ローカル行列 public: .... // 行列ベクトル積のin-place演算 void MulVect(const Vector<T>& x, pVector<T>& y) { _local.MulVect(X,Y.local_vect());} ... }; template<class T> class RowPartitionedMatrix : RowPartionedMat<Matrix<T>,T> >{ public: RowPartitionedMatrix(...); // コンストラクタ ... };
用いた機能 逐次 4 proc. 8 proc. 16 proc. Op overloading 35.55(1.0) 10.65(3.3) 7.98(4.5) 7.63(4.6) 6.74(3.7) In-place op 24.89(1.0) 7.96(3.1) 6.53(3.8) 24.89(1.0) 3.54(7.0) 2.64(9.4) + comm. opt 6.06(4.1) 並列クラスライブラリの性能 SR2201での並列版のCG法テンプレートライブラリの性能 (繰り返し1回あたりの実行時間(ミリ秒)) • テストデータは5点差分、次元数は10000 • 通信レイヤは、MPI • コンパイラとオプション: g++ -O3 • 括弧内は対逐次性能比。 • + comm. Opt は、隣接のみの転送に行列ベクトル積を最適化
まとめ • 逐次と同じアルゴリズムテンプレートを適用できる並列ベクトルクラスライブラリを試作 • C++テンプレート機能を用いたgenericなプログラミング • アルゴリズムとデータ構造を分離→並列にも適用可 • 欠点:デバックが面倒、ソースの共有 • operator overloadingによる記述 • 数学的な記述が使える、数値計算には有用 • 欠点:一時変数による性能低下→将来は、コンパイラ等で改善? • 実験的なライブラリやプロトタイピングには十分有用な手段 • OBP Lib:並列処理のための(便利な)部品を提供
オブジェクト指向設計 Object oriented designの一般的な注意 • 保守性:後から、見たとき、あるいはデバック中にも容易に理解できるようなプログラムを作ること。他の人が見たときにわかりやすいこと(可読性)も重要である。 • 拡張性:プログラムの機能を加えるときに、なるべくほかのコードを変更せずに機能を加えることができることが望ましい。 • 再利用性:ほかのプログラムに転用できるような部品として設計しておけば、プログラムの価値は高まる。 • 効率:そして、プログラムは速くなくてはならない。
オブジェクト指向設計の基本ルール(のいくつか)オブジェクト指向設計の基本ルール(のいくつか) • 参考文献 • Effective C++ 、スコット・マイヤーズ’(岩谷宏 訳)、ソフトバンク ISBN4-89052-401-0 • オブジェクト指向開発の落とし穴 、B.F.ウェブスター(細井拓史 訳)、トッパン ISBN4-931356-25-7 • publicな継承が” is a”関係であることをしっかり理解する • 層化によって”has a”関係や”is implemented in terms of”関係を表現する(項目40) • Privateな継承は、正しくつかう(項目41)
C++プログラミングの一般的な注意 • "better C"として使う場合は問題はないが、… • 細かい単位のオブジェクト化を避けること。 • 仮想関数のオーバーヘッドで遅くなる • 最適化もできなくなる • 行列演算ぐらいはOKか。ただし、安直につくると一時変数がたくさん現れるので、遅くなる。そのためにはExpression Templateなどを使う必要がある。 • operator overloadingは、慎重に使うこと • プログラムが何をしているのかが、わからなくなる。違う言語のようなもの。 • 書いているときには気持ちいいが、後でメンテナンスできなくなる • 利用のためのコンセプト、規範を明確にしておく必要がある。