HPC アプリケーションの OOP を用いた パフォーマンスチューニング

57
東東東東 東東東 東東東東東東東 東東 東東 * 東東東 東東 東東 東 HPC 東東東東東東東東東 OOP 東東東東 東東東東東東東東東東東東東

description

HPC アプリケーションの OOP を用いた パフォーマンスチューニング. 東京大学 大学院 創造情報学専攻 穂積 俊平 *  伊尾木 将之 千葉 滋. HPC の現状. C 言語や Fortran によって記述されている 実行性能が重要 手続きライブラリが広く利用されている 関数単位での変更のみ可能. HPC の近年の傾向. 実行環境に合わせたチューニングが必要 実行環境のハードウェアが多様化. GPU. コンピュータ クラスタ. マルチ CPU. HPC の近年の傾向. 実行環境に合わせたチューニングが必要 実行環境のハードウェアが多様化. GPU. - PowerPoint PPT Presentation

Transcript of HPC アプリケーションの OOP を用いた パフォーマンスチューニング

Page 1: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

東京大学 大学院創造情報学専攻

穂積 俊平 *  伊尾木 将之 千葉 滋

HPC アプリケーションのOOP を用いた

パフォーマンスチューニング

Page 2: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

2

HPC の現状•C 言語や Fortran によって記述されている- 実行性能が重要

•手続きライブラリが広く利用されている- 関数単位での変更のみ可能

Page 3: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

3

HPC の近年の傾向•実行環境に合わせたチューニングが必要- 実行環境のハードウェアが多様化

コンピュータクラスタ

マルチ CPUGPU

Page 4: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

4

HPC の近年の傾向•実行環境に合わせたチューニングが必要- 実行環境のハードウェアが多様化

コンピュータクラスタ

マルチ CPUGPU

Page 5: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

5

HPC の問題点•粒度の細かいチューニングができない- 手続きライブラリはブラックボックスであり、関数

より粒度の細かい変更が不可能。

入力 出力

メモリ管理

データ転送

Page 6: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

6

HPC の問題点•粒度の細かいチューニングができない- 手続きライブラリはブラックボックスであり、関数

より粒度の細かい変更が不可能。

入力 出力

メモリ管理

データ転送

処理 ( 関心事 )ごとに実装を決めたい!

Page 7: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

7

例:行列積

A

L

MB

M

N

C

L

N

C コードfor (int i = 0; i < L; i++) {

for (int j = 0; j < N; j++) {

for (int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k] * B[k * N +

j];

}}}

①②

Page 8: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

8

例:行列積

A

L

MB

M

N

C

L

N

C コードfor (int i = 0; i < L; i++) {

for (int j = 0; j < N; j++) {

for (int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k] * B[k * N +

j];

}}}

j

i

•素直な2重ループ• i と j を入れ替えた2重ループ•GPU で並列実行•MPI で並列実行

Page 9: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

9

例:行列積

A

L

MB

M

N

C

L

N

C コードfor (int i = 0; i < L; i++) {

for (int j = 0; j < N; j++) {

for (int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k] * B[k * N +

j];

}}}

k

k

•素直なループ•展開したループ

Page 10: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

10

例:行列積

C コードfor (int i = 0; i < L; i++) {

for (int j = 0; j < N; j++) {

for (int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k] * B[k * N +

j];

}}}③

A

L

M

M

1次元配列

・・・

•1次元配列•2次元配列•シェアードメモリ•疎行列•対角行列

Page 11: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

11

C 言語での実装•保守性のスケーラビリティが得られない- 関数ポインタ- ifdef

Page 12: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

12

オブジェクト指向を用いたチューニング

•ユーザによる設定が可能な形で機能提供ができる

Matmul matmul = new Matmul();

matmul.setTraverse (new Traverse());

matmul.setReduction(new Reduction());

Mat A = new SingleArray(), B = ・・・ , C = ・・・ ;

matmul.calc(A, B, C);

Javaコード

Page 13: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

13

オブジェクト指向を用いたチューニング

•ユーザによる設定が可能な形で機能提供ができる

Matmul matmul = new Matmul();

matmul.setTraverse (new ParallelOnGPU());

matmul.setReduction(new Reduction());

Mat A = new SingleArray(), B = ・・・ , C = ・・・ ;

matmul.calc(A, B, C);

Javaコード

Page 14: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

14

オートチューニングへの応用•実装の切り替えが容易

List<Traverse> traverses;

traverses.add(new Traverse());

traverses.add(new ParallelOnGPU());

:

for(Traverse tra : traverses) {

matmul.setTraverse(tra);

matmul.calc(A, B, C);

}

Javaコード

Cのたどり方の実装を変更して実行

Page 15: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

15

HPC アプリケーションの特徴•カーネルコードが計算時間の大半を占める

各種設定

カーネルコード

実行時間実行過程

Page 16: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

16

WootinJ•OOP と実行性能を両立する機構- カーネルコードを強力に JIT コンパイルする- ユーザに最適化の条件を満たしているかを提示

実行時コンパイラ

Javaバイトコード

機械語

最適化

コンパイル時チェッカー

Javaソースコード

警告!

Page 17: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

17

通常の JIT との違い•OOP と実行性能を両立する機構- カーネルコードを強力に JIT コンパイルする

Java バイトコード 機械語

最適化

•静的型•動的型

一部をインライン化•オブジェクト•メソッド

Page 18: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

18

通常の JIT との違い•OOP と実行性能を両立する機構- カーネルコードを強力に JIT コンパイルする

Java バイトコード 機械語

最適化

•静的型•動的型•strictfinal

全てをインライン化•オブジェクト•メソッド

Page 19: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

19

WootinJ•OOP と実行性能を両立する機構- カーネルコードを強力に JIT コンパイルする- ユーザに最適化の条件を満たしているかを提示

•strictFinal : 静的に型が一意に決定できる型- プリミティブな型- strictFinal の配列- 自分と親クラスのフィールドが strictFinal であ

り、 final な型

Page 20: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

20

WootinJ•OOP と実行性能を両立する機構- カーネルコードを強力に JIT コンパイルする- ユーザに最適化の条件を満たしているかを提示

Javaソースコード

strictFinal ?

警告!!

Page 21: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

21

WootinJ•OOP と実行性能を両立する機構- カーネルコードを強力に JIT コンパイルする

class Calc { void run(A a){ a.hoge();  }}

static void main(String[] args) { CUDARunner.invoke( new Calc(), “run”, new A() );}

最適化

実行

Java コードJava

バイトコード

Java抽象構文木

CUDAコード

機械語

メソッド情報

ユーザが指定したメソッド

Page 22: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

22

WootinJ•OOP と実行性能を両立する機構- カーネルコードを強力に JIT コンパイルする

class Calc { void run(A a){ a.hoge();  }}

static void main(String[] args) { CUDARunner.invoke( new Calc(), “run”, new A() );}

Java コード

メソッド情報

ユーザが指定したメソッド

メソッドのレシーバ、実引数の型は変換時に一意に決定できる

メソッドのレシーバ、実引数は自由に OOP の抽象化を利用できる

Page 23: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

23

実験•目的- WootinJ の実行性能の測定

•実験環境- Tsubame2.0 : 東工大のスパコン

•プログラム- 行列積

Page 24: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

24

実験結果

• 変換によるオーバーヘッドの分だけ WootinJ の方が遅かったが、 OOP の抽象化による差は見られなかった。

Page 25: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

25

関連研究•Firepile [Nathaniel Nystrom ら・ 2011]- Scala から OpenCL への実行時変換器。動的束縛は

Switch 文を用いて表現

•Aparapi- Java から OpenCL への実行時変換器。オブジェクト

の利用はできない

Page 26: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

26

まとめと今後の課題•まとめ- オブジェクト指向を利用する事で、実行環境に合わ

せたパフォーマンスチューニングができる事を述べた。

- オブジェクト指向と実行性能を両立する機構としてWootinJ を開発した。

•今後の課題- WootinJ を利用したフレームワークの作成- C++ との比較

Page 27: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

36

C の要素のたどり方for (int i = 0; i < L; i++) {

for (int j = 0; j < N; j++) {

for (int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k]*B[k * N +

j];

}

}

}

GPU を利用した並列実行dim3 grid(N/BS, L/BS),

block(BS,BS);

traverse<<<grid, block>>>(A, B, C);

_global_ void traverse(float *

A ・・ ){

int i = BS*blockIdx.y +

threadIdx.y;

int j = BS*blockIdx.x +

threadIdx.x;

          :

}

i と j を入れ替えた2重ループ

for (int i = 0; i < L; i++) {

for (int j = 0; j < N; j++) {

         :

}

}

素直な2重ループ

for (int i = 0; i < L; i++) {

for (int j = 0; j < N; j++) {

         :

}

}

Page 28: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

37

C の1要素の求め方

for (int k = 0; k < M; k++) {

C[i*N + j] += A[i*M + k]*B[k*N +

j];

}

素直なループ

for (int i = 0; i < L; i++) {

for (int j = 0; j < N; j++) {

for (int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k]*B[k * N +

j];

}

}

}

for (int k = 0; k < M; k+=2) {

C[i*N + j] += A[i*M + k] * B[k*N + j];

C[i*N + j] += A[i*M + k + 1] * B[(k+1)*N +

j];

}

展開したループ

Page 29: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

38

行列の表現方法•言語上の確保の仕方の違い- 1次元配列- 2次元配列

•ハードウェア的な違い- シェアードメモリの利用

•行列の種類による違い- 疎行列- 対角行列

Page 30: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

39

オブジェクト指向を用いたチューニング

•ユーザによる設定が可能な形で機能提供ができる

Matmul matmul = new Matmul();

matmul.iterate = new LoopOnCPU();

matmul.reduction = new Reduction();

Matrix A = new SingleArray(),

B = ・・・ , C = ・・・ ;

matmul.calc(A, B, C);

Javaコード

Page 31: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

40

オブジェクト指向を用いたチューニング

•ユーザによる設定が可能な形で機能提供ができる

Matmul matmul = new Matmul();

matmul.iterate = new LoopOnCPU();

matmul.reduction = new

UnrollingReduction();

Matrix A = new SingleArray(),

B = ・・・ , C = ・・・ ;

matmul.calc(A, B, C);

Javaコード

Page 32: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

41

実行環境に合わせたチューニング

•ユーザによる設定ができる形で機能提供すべき- C 言語や Fortran では難しい

•手続きライブラリはブラックボックス- ブラックボックス内の実装の変更が困難

入力 出力

複数の処理( 関心事 ) が含まれる

メモリ管理

データ転送

Page 33: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

42

•複数の関心事に分割できる

行列積に含まれる関心事

C コードfor (int i = 0; i < L; i++) {

for (int j = 0; j < N; j++) {

for (int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k] * B[k * N +

j];

}}}A

L

MB

M

N

C

L

N

j

i

Page 34: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

43

•複数の関心事に分割できる

行列積に含まれる関心事

C コードfor (int i = 0; i < L; i++) {

for (int j = 0; j < N; j++) {

for (int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k] * B[k * N +

j];

}}}A

L

MB

M

N

C

L

N

k

k

Page 35: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

44

•複数の関心事に分割できる

行列積に含まれる関心事

C コードfor (int i = 0; i < L; i++) {

for (int j = 0; j < N; j++) {

for (int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k] * B[k * N +

j];

}}}A

L

M

M

1次元配列

・・・

Page 36: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

45

オブジェクト指向を用いたチューニング

•ユーザによる設定が可能な形で機能提供ができる

Matmul matmul = new Matmul();

matmul.setTraverse(Traverse.factory(“simpleLoop”

));

matmul.setReduction(Reduction.factory(“unrolling

”));

Matrix A = new SingleArray(), B = ・・・ , C

= ・・・ ;

matmul.calc(A, B, C);

Javaコード

Page 37: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

46

オブジェクト指向を用いたチューニング

•ユーザによる設定が可能な形で機能提供ができる

void calc(Mat A, Mat B, Mat C) { tra.calc(A, B, C, red);}

Matmulvoid calc(Mat A, Mat B, Mat C, Reduction red) { for(int i = 0; i < C.getRows(); i++) { for(int j = 0; j < C.getCols(); j++) { red.calc(A, B, C);}}}

Traverse

void calc(Mat A, Mat B, Mat C){ for(int k = 0; k < A.getCols(); k++) { C[i*C.getCols()+j] += A[i*A.getCols()+k] * B[k*B.getCols()+j];}}

Reduction

void calc(Mat A, Mat B, Mat C, Reduction red) {for(int j = 0; j < C.getCols(); j++) { for(int i = 0; i < C.getRows(); i++) { red.calc(A, B, C);}}}

ReverseTraverse

Page 38: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

47

オブジェクト指向を用いたチューニング

•ユーザによる設定が可能な形で機能提供ができる

void calc(Mat A, Mat B, Mat C) { tra.calc(A, B, C, red);}

Matmul

void calc(Mat A, Mat B, Mat C, Reduction red) { for(int i = 0; i < C.getRows(); i++) { for(int j = 0; j < C.getCols(); j++) { red.calc(A, B, C);}}}

Traverse

void calc(Mat A, Mat B, Mat C, Reduction red) {for(int j = 0; j < C.getCols(); j++) { for(int i = 0; i < C.getRows(); i++) { red.calc(A, B, C);}}}

ReverseTraverse

Page 39: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

48

近年の傾向•実行環境に合わせたチューニングが必要- ハードウェアが複雑化している• GPU

• コンピュータ・クラスタ• マルチコア CPU

GPU

Page 40: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

49

関数による分離

C コードvoid matmul(float *A, float *B, float *C) {

traverse(A, B, C);

}

void traverse(float *A, float *B, float *C) {

for(int i = 0; i < L; i++) {

for(int j = 0; j < N; j++) {

reduction(A, B, C, i, j);

}}}

void reduction(float *A, float *B, float *C, int i, int

j) {

for(int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k] * B[k * N + j];

}}

Page 41: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

50

手続きライブラリの限界•粒度の細かいチューニングができない- 手続きライブラリはブラックボックスであり、関数

より粒度の細かい変更が不可能。

入力 出力

メモリ管理

データ転送

他の実装へ変更

Page 42: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

51

オブジェクト指向を用いたチューニング

•ユーザによる設定が可能な形で機能提供ができる

class Matmul { Traverse traverse; Reduction reduction;

void calc(Matrix A, Matrix B, Matrix C) { traverse.calc(A, B, C, reduction); }}

Javaコード

Page 43: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

52

オブジェクト指向を用いたチューニング

•ユーザによる設定が可能な形で機能提供ができる

class SimpleDoubleLoop implements Traverse { void calc(Matrix A, Matrix B, Matrix C, Reduction red) { for(int i = 0; i < C.getRows(); i++) { for(int j = 0; j < C.getColumns(); j++) { reduction.calc(A, B, C); } } }}

Javaコード

Page 44: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

53

オブジェクト指向を用いたチューニング

•ユーザによる設定が可能な形で機能提供ができる

class SimpleLoop implements Reduction { void calc(Matrix A, Matrix B, Matrix C){ for(int k = 0; k < A.getColumns(); k++) { C[i*C.getColumns()+j] += A[i*A.getColumns()+k] * B[k*B.getColumns()+j]; } }}

Javaコード

Page 45: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

54

オブジェクト指向を用いたチューニング

•ユーザによる設定が可能な形で機能提供ができる

void calc(Matrix A, Matrix B, Matrix C) { traverse.calc(A, B, C, reduction);}

Matmul

void calc(Matrix A, Matrix B, Matrix C, Reduction red) { for(int i = 0; i < C.getRows(); i++) { for(int j = 0; j < C.getColumns(); j++) { reduction.calc(A, B, C);}}}

Traverse

void calc(Matrix A, Matrix B, Matrix C){ for(int k = 0; k < A.getColumns(); k++) { C[i*C.getColumns()+j] += A[i*A.getColumns()+k] * B[k*B.getColumns()+j];}}

Reduction

Page 46: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

55

関数ポインタによる変更C コード

int (*traP)(float *A, float *B, float *C) = &traverse;

int (*redP)(float *A, float *B, float *C, int i, int j) = &reduction;

void matmul(float *A, float *B, float *C) {

(traP)(A, B, C);

}

void traverse(float *A, float *B, float *C) {

for(int i = 0; i < L; i++) {

for(int j = 0; j < N; j++) {

(redP)(A, B, C, i, j);

}}}

void reduction(float *A, float *B, float *C, int i, int j) {

for(int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k] * B[k * N + j];

}}

void traverse(float *A, float *B, float *C) {

for(int i = 0; i < L; i++) {

for(int j = 0; j < N; j++) {

(redP)(A, B, C, i, j);

}}}

void reverseTraverse(float *A, float *B, float

*C) {

for(int i = 0; i < L; i++) {

for(int j = 0; j < N; j++) {

(redP)(A, B, C, i, j);

}}}

Page 47: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

56

関数による分離

C コードvoid matmul(float *A, float *B, float *C) {

traverse(A, B, C);

}

void traverse(float *A, float *B, float *C) {

for(int i = 0; i < L; i++) {

for(int j = 0; j < N; j++) {

reduction(A, B, C, i, j);

}}}

void reduction(float *A, float *B, float *C, int i, int

j) {

for(int k = 0; k < M; k++) {

C[i * N + j] += A[i * M + k] * B[k * N + j];

}}

Page 48: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

57

手続きライブラリの利用•実行環境に合ったライブラリを利用する事で、アプリケーションのチューニングができる。

• GotoBLAS

• cublas

• ・・・・

線形代数ライブラリCPU

GPU

Page 49: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

58

関数ポインタによる変更int (*traP)(float *A, float *B, float *C);

int (*redP)(float *A, float *B, float *C, int i, int j);

void matmul(float *A, float *B, float *C) {

(traP)(A, B, C);

}

void traverse(float *A, float *B, float *C) {

for(int i = 0; i < L; i++) {

for(int j = 0; j < N; j++) {

(redP)(A, B, C, i, j);

}}}

void reverseTraverse(float *A, float *B, float

*C) {

for(int j = 0; j < N; j++) {

for(int i = 0; i < L; i++) {

(redP)(A, B, C, i, j);

}}}

Page 50: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

59

C 言語による実装の限界•関数ポインタ- 安全でない

•フラグによる制御- ライブラリ作成者がすべての状況を想定できない

Page 51: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

60

オブジェクト指向を用いたチューニング

•安全に実装の変更が可能

void calc(Mat A, Mat B, Mat C) { tra.calc(A, B, C, red);}

Matmul

void calc(Mat A, Mat B, Mat C, Reduction red) { for(int i = 0; i < C.getRows(); i++) { for(int j = 0; j < C.getCols(); j++) { red.calc(A, B, C);}}}

Traverse

void calc(Mat A, Mat B, Mat C, Reduction red) {for(int j = 0; j < C.getCols(); j++) { for(int i = 0; i < C.getRows(); i++) { red.calc(A, B, C);}}}

ReverseTraverse

Page 52: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

61

モジュラリティと実行性能•WootinJ が生成するコードには Java の抽象化が含まれていない

Java

• 動的束縛

• オブジェクト

どうする??

CUDA

• switch 文?

• 構造体?

Java のサブセットを提供

Page 53: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

62

• 動的メソッド呼び出しの除去

実行時情報を利用した最適化

A

+hoge()

class Calc { void run(A a){ a.hoge();  }}

static void main(String[] args) { CUDARunner.invoke( new Calc(), “run”, new B() );}

Java コード

実行時情報 void run(A a) { B_hoge();}

void B_hoge() { :}

静的呼び出しに変換

B

+hoge()

Page 54: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

63

• オブジェクトの除去

実行時情報を利用した最適化

A

int x;int y;

class Calc { void run(A a){ int sum = a.x + a.y  }}

static void main(String[] args) { CUDARunner.invoke( new Calc(), “run”, new A() );}

Java コード

実行時情報

void run(int a_x, int a_y) { int sum = a_x + a_y;}

プリミティブな値の利用に変換

Page 55: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

64

•Java バイトコードから CUDA C への実行時変換器- 実行時情報を利用し、抽象化のオーバーヘッドを除去

WootinJ

class Calc { void run(A a){ a.hoge();  }}

static void main(String[] args) { CUDARunner.invoke( new Calc(), “run”, new A() );} 最適化

実行

Java コードJava

バイトコード

Java抽象構文木

CUDAコード

機械語

メソッド情報

Page 56: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

65

WootinJ•OOP と実行性能を両立する機構- カーネルコードをアグレッシブに JIT コンパイルする- コンパイル時に条件 (strictFinal) を満たしているか確認

OOP の抽象化が含まれないコード

以下が含まれない•動的束縛•オブジェクト

Page 57: HPC アプリケーションの OOP を用いた パフォーマンスチューニング

66

実験結果• 変換によるオーバーヘッドの分だけ WootinJ の方が

遅かったが、 OOP の抽象化による差は見られなかった。