39
C++ For Researchers 研究生のためのC++ 企画・立案 難波知宏

研究生のためのC++ no.7

Embed Size (px)

Citation preview

Page 1: 研究生のためのC++ no.7

C++ For Researchers 研究生のためのC++

企画・立案 難波知宏

Page 2: 研究生のためのC++ no.7

プログラムの高速化

第七回

2

Page 3: 研究生のためのC++ no.7

プログラム改良のステップ

3

原因の特定

高速化① 最適化

高速化② アルゴリズムの改良

高速化③ マルチスレッド

高速化④ GPUアクセラレーション

Page 4: 研究生のためのC++ no.7

ボトルネックの特定

第一節

4

Page 5: 研究生のためのC++ no.7

Visual Studioのパフォーマンスエクスプローラを使ってみよう

5

Exercise 7-1

Page 6: 研究生のためのC++ no.7

プログラムのどの部分にどれくらいの負荷がかかっているか調べること

ができるツール

6

パフォーマンスエクスプローラー

Page 7: 研究生のためのC++ no.7

7

パフォーマンスエクスプローラーの使い方

Page 8: 研究生のためのC++ no.7

8

パフォーマンス測定結果の見方

どの関数にどれくらい

の負荷がかかっている

かわかる

概要ビューで全体が わかる

Page 9: 研究生のためのC++ no.7

9

パフォーマンス測定結果の見方

プログラムのどこが

遅いかわかる

関数の詳細ビューで ボトルネックの場所が わかる

Page 10: 研究生のためのC++ no.7

最適化

第二節

10

Page 11: 研究生のためのC++ no.7

最適化

11

コンパイラで最適化(自動)

• コンパイルオプションを変えることで

コンパイラが最適化を行う

• とりあえず楽。

プログラマが最適化(手動)

• プログラマがプログラムをいじって

手動で最適化を行う

• めんどくさい。

• コンパイラオプションで最適化して、

まだ遅いときにやろう

Page 12: 研究生のためのC++ no.7

12

コンパイラによる最適化有効

ビルド構成をDebugモード

から

Releaseモードにする

Page 13: 研究生のためのC++ no.7

SIMD拡張命令セット (Single Instruction Multi Data)

一つの命令で複数のデータを扱う (float×8やdouble×4の演算を一回の命令でやる)

13

Intel SSE / AVX

1.0 2.0 3.0 4.0

2.0 4.0 6.0 8.0

+

専用レジスタ

専用レジスタ

1.0 2.0 3.0 4.0

64×4=256bit

Page 14: 研究生のためのC++ no.7

14

Intel SSE / AVXの有効化

プロジェクトのプロパティ > C/C++ > コード生成の拡張命令 セットを変更 でIntel SSE/AVXの有効化

Page 15: 研究生のためのC++ no.7

sample 7-05

#include <immintrin.h> #include <iostream> using namespace std; void main() { __m256d a = _mm256_set_pd(1.0, 2.0, 3.0, 4.0); __m256d b = _mm256_set_pd(1.0, 2.0, 3.0, 4.0); __m256d c = _mm256_add_pd(a, b); cout << c.m256d_f64[0] << endl; cout << c.m256d_f64[1] << endl; cout << c.m256d_f64[2] << endl; cout << c.m256d_f64[3] << endl; }

実行結果

8

6

4

2

15

z

Intel SSE / AVXの手動プログラミング

Page 16: 研究生のためのC++ no.7

16

ただし

Page 17: 研究生のためのC++ no.7

自動ベクトル化

最近のコンパイラは使えそうなところは自動でSIMD

命令を使う Visual C++の自動ベクトル化の説明

https://msdn.microsoft.com/ja-jp/library/hh872235.aspx

自動ベクトル化はどんな時に行われるか

http://www.isus.jp/products/c-compilers/compiler_part4/

SIMD命令をgccのオートベクタライズの最適化で使う方法

http://blog.kmckk.com/archives/4484762.html

17

Page 18: 研究生のためのC++ no.7

自動ベクトル化

最近のコンパイラは使えそうなところは自動でSIMD

命令を使う Visual C++の自動ベクトル化の説明

https://msdn.microsoft.com/ja-jp/library/hh872235.aspx

自動ベクトル化はどんな時に行われるか

http://www.isus.jp/products/c-compilers/compiler_part4/

SIMD命令をgccのオートベクタライズの最適化で使う方法

http://blog.kmckk.com/archives/4484762.html

18

基本コンパイラ任せ

で良さげ

Page 19: 研究生のためのC++ no.7

高速化のために、まずは

• 最適化オプションをつける

• 拡張命令セットを有効にする

19

ここまでのまとめ

Page 20: 研究生のためのC++ no.7

アルゴリズムの改良

第三節

20

Page 21: 研究生のためのC++ no.7

sample 7-06

static int a[length];

static int b[length];

static int c[length];

for (int i = 0; i < length; i++)

{

c[i] = a[i] + b[i];

}

sample 7-07

struct int3 { int a, b, c; };

static int3 x[length];

for (int i = 0; i < length; i++)

{

x[i].c = x[i].a + x[i].b;

}

21

アルゴリズムの改良

①キャッシュミスを減らせ

どっちのプログラムが早いだろうか

Page 22: 研究生のためのC++ no.7

sample 7-06

static int a[length];

static int b[length];

static int c[length];

for (int i = 0; i < length; i++)

{

c[i] = a[i] + b[i];

}

sample 7-07

struct int3 { int a, b, c; };

static int3 x[length];

for (int i = 0; i < length; i++)

{

x[i].c = x[i].a + x[i].b;

}

22

アルゴリズムの改良

①キャッシュミスを減らせ

答え 右

(左: 70msくらい)

(右: 50msくらい)

Page 23: 研究生のためのC++ no.7

CPU-メモリ間

23

なぜ右のプログラムの方が早いのか?

高速 低速

Page 24: 研究生のためのC++ no.7

CPU-メモリ間

24

なぜ右のプログラムの方が早いのか?

高速 低速

一回アクセスした領域

は、その周辺も含めて

キャッシュメモリに記憶

飛び飛びにアクセスすると、

キャッシュがころころ入れ替わり、

キャッシュヒット率が低下する

Page 25: 研究生のためのC++ no.7

for (int i = 0; i < 1024; i++)

{

// …

}

// …

for (int i = 0; i < 1024; i++)

{

// …

}

for (int i = 0; i < 1024; i++)

{

// …

// …

}

25

②ループを減らせ

Page 26: 研究生のためのC++ no.7

#include "Eigen¥Dense.hpp"

using namespace Eigen;

void main()

{

MatrixXd A;

}

#include "Eigen¥Sparse.hpp"

using namespace Eigen;

void main()

{

SparseMatrix<float> A;

}

26

③余計な計算を減らせ

スパース行列

Page 27: 研究生のためのC++ no.7

日頃から次に気をつけてプログラムを組む

• キャッシュヒット率が上がりやすいプログラムにする

• ループの数を減らす

• 余分な計算を減らす

27

ここまでのまとめ

Page 28: 研究生のためのC++ no.7

マルチスレッド

第四節

28

Page 29: 研究生のためのC++ no.7

マルチコアCPUだと、異なるCPUコアで同時実行ができる

マルチスレッドプログラミングの方法

• OSのマルチスレッドAPIを使う (Win32APIだとCreateThread関数)

• マルチスレッドライブラリを使う (標準ライブラリ, IntelTBB等)

• 言語拡張(OpenMP)を使う

29

マルチスレッド

複数の処理を並列に実行する

Page 30: 研究生のためのC++ no.7

#pragma omp … を既存のプログラムに挿入する形で利用

プログラムをあまり修正しなくていいので導入が簡単

コンパイルオプションでOpenMPを無効にすれば、

シングルスレッドのプログラムにすぐに直せる (もとに戻すのが簡単)

OSに依存しないので移植性が高い

30

OpenMP

マルチスレッド

Page 31: 研究生のためのC++ no.7

sample 7-01

// Calculation. float sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0; #pragma omp parallel sections { #pragma omp section { for (int i = 0; i < 2500000; i++) { sum1 += data[i]; } } #pragma omp section … } float sum = sum1 + sum2 + sum3 + sum4;

sample 7-02

// Calculation.

float sum = 0;

{

for (int i = 0; i < length; i++)

{

sum += data[i];

}

}

31

OpenMP プログラム例1 配列の総和を求める

Page 32: 研究生のためのC++ no.7

sample 7-01

// Calculation. float sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0; #pragma omp parallel sections { #pragma omp section { for (int i = 0; i < 2500000; i++) { sum1 += data[i]; } } #pragma omp section … } float sum = sum1 + sum2 + sum3 + sum4;

sample 7-02

// Calculation.

float sum = 0;

{

for (int i = 0; i < length; i++)

{

sum += data[i];

}

}

32

OpenMP プログラム例1 配列の総和を求める

配列を4等分して

それぞれ別々に総

和を計算する

素直なやり方

Page 33: 研究生のためのC++ no.7

sample 7-01 実行結果

sum is 10000000.000000. 5 ms.

sample 7-02 実行結果

sum is 10000000.000000.

13 ms.

33

OpenMP プログラム例1 配列の総和を求める

配列を4等分して

それぞれで総和を

計算する

素直なやり方

スピードUP

Page 34: 研究生のためのC++ no.7

34

OpenMPの有効化

C/C++>言語>OpenMPの

サポートを「はい」にすると

OpenMPが有効になる

Page 35: 研究生のためのC++ no.7

sample 7-09

#include <iostream> void main() { #pragma omp parallel for for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { printf("%d¥n", i); } } }

実行結果

Thread is 0 Thread is 3 Thread is 3 Thread is 3 Thread is 3 Thread is 2 Thread is 2 Thread is 2 Thread is 2 Thread is 1 Thread is 1 Thread is 1 Thread is 1 Thread is 0 Thread is 0 Thread is 0

35

OpenMP プログラム例2 for文の並列化

Page 36: 研究生のためのC++ no.7

OpenMPで行列積を高速化しよう

36

Exercise 7-2

Page 37: 研究生のためのC++ no.7

GPUアクセラレーション

第五節

37

Page 38: 研究生のためのC++ no.7

38

時間足りませんでした

Page 39: 研究生のためのC++ no.7

39

テンプレート引数で、

型、行数、列数を指定

サイズは 実数のとき固定サイズ

Xのとき可変サイズ