研究生のためのc++ no.7
TRANSCRIPT
![Page 1: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/1.jpg)
C++ For Researchers 研究生のためのC++
企画・立案 難波知宏
![Page 2: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/2.jpg)
プログラムの高速化
第七回
2
![Page 3: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/3.jpg)
プログラム改良のステップ
3
原因の特定
高速化① 最適化
高速化② アルゴリズムの改良
高速化③ マルチスレッド
高速化④ GPUアクセラレーション
![Page 4: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/4.jpg)
ボトルネックの特定
第一節
4
![Page 5: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/5.jpg)
Visual Studioのパフォーマンスエクスプローラを使ってみよう
5
Exercise 7-1
![Page 6: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/6.jpg)
プログラムのどの部分にどれくらいの負荷がかかっているか調べること
ができるツール
6
パフォーマンスエクスプローラー
![Page 7: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/7.jpg)
7
パフォーマンスエクスプローラーの使い方
![Page 8: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/8.jpg)
8
パフォーマンス測定結果の見方
どの関数にどれくらい
の負荷がかかっている
かわかる
概要ビューで全体が わかる
![Page 9: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/9.jpg)
9
パフォーマンス測定結果の見方
プログラムのどこが
遅いかわかる
関数の詳細ビューで ボトルネックの場所が わかる
![Page 10: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/10.jpg)
最適化
第二節
10
![Page 11: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/11.jpg)
最適化
11
コンパイラで最適化(自動)
• コンパイルオプションを変えることで
コンパイラが最適化を行う
• とりあえず楽。
プログラマが最適化(手動)
• プログラマがプログラムをいじって
手動で最適化を行う
• めんどくさい。
• コンパイラオプションで最適化して、
まだ遅いときにやろう
![Page 12: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/12.jpg)
12
コンパイラによる最適化有効
ビルド構成をDebugモード
から
Releaseモードにする
![Page 13: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/13.jpg)
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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/14.jpg)
14
Intel SSE / AVXの有効化
プロジェクトのプロパティ > C/C++ > コード生成の拡張命令 セットを変更 でIntel SSE/AVXの有効化
![Page 15: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/15.jpg)
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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/16.jpg)
16
ただし
![Page 17: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/17.jpg)
自動ベクトル化
最近のコンパイラは使えそうなところは自動で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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/18.jpg)
自動ベクトル化
最近のコンパイラは使えそうなところは自動で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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/19.jpg)
高速化のために、まずは
• 最適化オプションをつける
• 拡張命令セットを有効にする
19
ここまでのまとめ
![Page 20: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/20.jpg)
アルゴリズムの改良
第三節
20
![Page 21: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/21.jpg)
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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/22.jpg)
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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/23.jpg)
CPU-メモリ間
23
なぜ右のプログラムの方が早いのか?
高速 低速
![Page 24: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/24.jpg)
CPU-メモリ間
24
なぜ右のプログラムの方が早いのか?
高速 低速
一回アクセスした領域
は、その周辺も含めて
キャッシュメモリに記憶
飛び飛びにアクセスすると、
キャッシュがころころ入れ替わり、
キャッシュヒット率が低下する
![Page 25: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/25.jpg)
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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/26.jpg)
#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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/27.jpg)
日頃から次に気をつけてプログラムを組む
• キャッシュヒット率が上がりやすいプログラムにする
• ループの数を減らす
• 余分な計算を減らす
27
ここまでのまとめ
![Page 28: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/28.jpg)
マルチスレッド
第四節
28
![Page 29: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/29.jpg)
マルチコアCPUだと、異なるCPUコアで同時実行ができる
マルチスレッドプログラミングの方法
• OSのマルチスレッドAPIを使う (Win32APIだとCreateThread関数)
• マルチスレッドライブラリを使う (標準ライブラリ, IntelTBB等)
• 言語拡張(OpenMP)を使う
29
マルチスレッド
複数の処理を並列に実行する
![Page 30: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/30.jpg)
#pragma omp … を既存のプログラムに挿入する形で利用
↓
プログラムをあまり修正しなくていいので導入が簡単
コンパイルオプションでOpenMPを無効にすれば、
シングルスレッドのプログラムにすぐに直せる (もとに戻すのが簡単)
OSに依存しないので移植性が高い
30
OpenMP
マルチスレッド
![Page 31: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/31.jpg)
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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/32.jpg)
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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/33.jpg)
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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/34.jpg)
34
OpenMPの有効化
C/C++>言語>OpenMPの
サポートを「はい」にすると
OpenMPが有効になる
![Page 35: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/35.jpg)
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](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/36.jpg)
OpenMPで行列積を高速化しよう
36
Exercise 7-2
![Page 37: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/37.jpg)
GPUアクセラレーション
第五節
37
![Page 38: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/38.jpg)
38
時間足りませんでした
![Page 39: 研究生のためのC++ no.7](https://reader034.vdocuments.pub/reader034/viewer/2022042503/58d00bbb1a28abad3e8b530b/html5/thumbnails/39.jpg)
39
テンプレート引数で、
型、行数、列数を指定
サイズは 実数のとき固定サイズ
Xのとき可変サイズ