Más contenido relacionado
Similar a x64 のスカラー,SIMD 演算性能を測ってみた v0.1 @ C++ MIX #10 (20)
x64 のスカラー,SIMD 演算性能を測ってみた v0.1 @ C++ MIX #10
- 2. 改版履歴
2024/4/19 初版
2024/4/21はぇ~@haxe さまのご指摘を受けて以下を追記修正
x64 数値演算の拡張命令の AVX-512 に半精度浮動小数点を追加
valarray の性能問題の推定原因,積和演算命令への変換,floatの逆数命令への変換を追記修正
2
- 3. 背 景
DAW (Digital Audio Workstation: 楽曲作成ソフト) 向けのエフェクタープラグインを開発
• 立体音響用プラグイン等のバイナリ,ソースを無償で公開
• DAW はディジタル信号処理の実験プラットフォームとして最適
プラグイン信号処理部の実体はリアルタイムの数値計算
• 処理時間に上限
• CPU 負荷は最大 1%−数% 程度
構想段階で,実現可能性をどう判断する?
• 作ってみなければ判らない,出たとこ勝負ではリスクが高い
• 経験値から感覚論で判断?
• 感覚論であっても CPU の演算性能に関する基本的なデータが必要
3
- 4. 評価の目的と適用性
評価の目的
• Visual C++ による x64 スカラー,ベクトル数値演算命令のスループットを評価
• 演算命令の直接記述やアセンブリ言語は使用しない
評価の適用性
• スループットはループ処理による繰り返し演算やベクトル演算の性能指標
• 単発の演算ではレイテンシが重要な性能指標となるが,今回は評価しない
• スループット性能は,繰り返し回数やベクトルの次数による影響を強く受ける
• コンパイラによって変換された機械語ルーチンの構造はこれらに依存
• Visual C++ の Vup,他のコンパイラ,他の CPU,GPU では全く異なる結果となる可能性は十分にある
4
- 5. x64 数値演算の拡張命令
拡張命令 機能概要 VC++ オプション
SSE2 128 bit 長 16 本の XMM レジスタ による浮動小数点のスカラー,ベクトル演算 (SIMD),整数のベクトル演算
32 bit 単精度浮動小数点の四則,平方根,逆数,平方根の逆数演算命令
64 bit 倍精度浮動小数点の四則,平方根演算命令
8, 16, 32, 64 bit 整数の加算,減算命令,16, 32 bit 整数の乗算命令
default
AVX2 256 bit 長 16 本の YMM レジスタによる浮動小数点のスカラー,ベクトル演算 (SIMD),整数のベクトル演算
3-4 オペランドの新命令形式によるレジスタ割り当ての効率化
32 bit 単精度浮動小数点の四則,平方根,逆数,平方根の逆数,積和演算命令
64 bit 倍精度浮動小数点の四則,平方根,積和演算命令
8, 16, 32, 64 bit 整数の加算,減算命令,16, 32 bit 整数の乗算命令
/arch:AVX2
AVX-512 512 bit 長 32 本 の ZMM レジスタ による浮動小数点のスカラー,ベクトル演算 (SIMD),整数のベクトル演算
16 bit 半精度浮動小数点の四則,平方根,積和,複素積,複素積和演算命令
32 bit 単精度浮動小数点の四則,平方根,逆数,平方根の逆数,積和演算命令
64 bit 倍精度浮動小数点の四則,平方根,積和演算命令
8, 16, 32, 64 bit 整数の加算,減算命令,16, 32, 64 bit 整数の乗算命令
/arch:AVX512
AMX 512 bit 長ベクトル演算レジスタによる 8 bit 整数,16 bit 半精度浮動小数点行列の積演算
行列の最大サイズは 1K Byte,整数で 16 行 64 列,浮動小数点で 16 行 32 列
演算結果は 32 bit 整数か 32 bit 単精度浮動小数点行列
未サポート
5
Note: Visual C++ オプションは最低要件を示す (機能制限では無い).デフォルトの SSE2 では,SSE4.1 や AVX-512 の命令 (pmulld, vpmullq) と,
スカラー演算命令の双方に変換され,実行時に cpuid に基づいて選択される.
- 6. Visual C++ におけるベクトル演算
Visual C++ コンパイラの自動ベクトル化機能
• ループ処理における最適化機能の一つ
• x64 ベクトル演算命令へ変換される場合がある
C++ 標準ライブラリの valarray
• 明示的にベクトル演算を記述
• x64 ベクトル演算命令へ変換される場合がある
Visual C++ 独自機能の組み込み (intrinsics) 関数
• x64 ベクトル演算命令を直接記述
• 今回は対象としない
6
- 7. ループ処理の最適化
演算性能はコンパイラによる最適化に強く依存
Visual C++ の最適化 /O2 は以下を含む
ループ展開 (Loop unrolling)
• for 文,while 文による演算のループを,スカラー演算命令を羅列したループに変換
• Visual C++ でループ展開される条件は不明
自動ベクトル化 (Automatic vectorization)
• for 文,while 文による演算のループを,ベクトル演算命令を羅列したループに変換
• Visual C++ で自動ベクトル化される条件は不明確
• 自動ベクトル化レポート出力オプション
[構成プロパティ]>[C/C++]>[コマンドライン]>[追加のオプション] に /Qvec-report:2 を追加
• 自動ベクトル化の抑止
ループ記述の前に #pragma loop (no_vector) を挿入
7
- 8. ループ展開の例
5 回ループ展開された加算命令の例
2, 4, 5, 10 回のループ展開を確認
8
$LL43@main:
; 108 : for (int j = 0; j < len; j++)
; 109 : *c32_p++ = *a32_p++ + *b32_p++;
mov eax, DWORD PTR [r10]
lea r10, QWORD PTR [rcx+20] r10 update
add eax, DWORD PTR [r9] スカラー加算
lea r9, QWORD PTR [rdx+20] r9 update
mov DWORD PTR [r11], eax
lea r11, QWORD PTR [r8+20] r11 update
mov eax, DWORD PTR [rcx+4]
add eax, DWORD PTR [rdx+4] スカラー加算
mov DWORD PTR [r8+4], eax
mov eax, DWORD PTR [rdx+8]
add eax, DWORD PTR [rcx+8] スカラー加算
mov DWORD PTR [r8+8], eax
mov eax, DWORD PTR [rcx+12]
add eax, DWORD PTR [rdx+12] スカラー加算
mov DWORD PTR [r8+12], eax
mov eax, DWORD PTR [rdx+16]
mov rdx, r9 rdx update
add eax, DWORD PTR [rcx+16] スカラー加算
mov rcx, r10 rcx update
mov DWORD PTR [r8+16], eax
mov r8, r11 r8 update
sub rbx, 1 loop カウンタ更新
jne SHORT $LL43@main
- 9. エラーメッセージから推定した
自動ベクトル化の条件
対象は for 文, while 文によるループ (do 文は対象外)
for (int i; i < 1000; i++)
ループ変数はローカル変数のみ; ループ終了条件はループ開始時から不変; ループ変数更新は +1 のみ
{
NG: 依存関係のあるループ計算
NG: if, switch, break, continue 文等の条件分岐
OK: 浮動小数点の四則演算,sqrt (),整数の加減乗算,math 関数 (演算速度は不変),inline 関数
NG: その他の関数
NG: bit 長が異なる変数への代入
NG: 32, 64bit 以外の構造体メンバへの参照
NG: 連続しない配列要素の参照
NG: 可変回数のシフト演算
} 等々謎
9
- 10. 評価方法
評価環境
• Core i7 8565U 1.8GHz (8th Gen.)
• Visual C++ v143
評価対象
• int16 (short), int32 (int), int64 (long long), float, double の四則,平方根演算
• ループ展開無し,有りにおけるスカラー演算
• 自動ベクトル化,valarray によるベクトル演算 (SSE2, AVX2)
評価指標
• 各演算を 1,000M 回繰り返し,経過時間を計測
• 1 回あたりの平均演算時間を CPU クロック数に換算し,スループットとする
10
- 11. スカラー演算のスループット
11
add sub mul div add sub mul div
ループ展開なし ループ展開
int16 1.15 1.16 1.28 4.25 0.48 0.47 0.58 3.22
int32 1.18 1.18 1.18 4.21 0.47 0.46 0.47 3.00
int64 1.18 1.17 1.18 12.19 0.48 0.69 0.48 10.99
float 1.15 1.15 1.15 1.23 0.53 0.51 0.53 1.23
double 1.19 1.16 1.17 1.70 0.51 0.52 0.51 1.69
0.00
0.50
1.00
1.50
2.00
2.50
3.00
3.50
4.00
4.50
5.00
int16 int32 int64 float double
12.19 10.99
Throughput
[clocks]
- 12. 整数ベクトル演算のスループット
12
add sub mul add sub mul add sub mul add sub mul add sub mul
[参考] ループ展開 自動ベクトル化 SSE2 自動ベクトル化 AVX2 valarray SSE2 valarray AVX2
int16 0.48 0.47 0.58 0.08 0.07 0.10 0.07 0.06 0.07 0.28 0.21 0.20 0.20 0.19 0.19
int32 0.47 0.46 0.47 0.15 0.14 0.19 0.10 0.09 0.09 0.35 0.35 0.35 0.30 0.29 0.30
int64 0.48 0.69 0.48 0.29 0.27 0.28 0.24 1.03 1.00 1.58 1.59
0.00
0.10
0.20
0.30
0.40
0.50
0.60
0.70
0.80
int16 int32 int64
Throughput
[clocks]
1.03
1.00
1.58
1.59
valarray の int64 のスループットは非実用的
- 13. 浮動小数点ベクトル演算の
スループット
13
add sub mul div sqrt add sub mul div sqrt add sub mul div sqrt add sub mul div sqrt add sub mul div sqrt
[参考] ループ展開 自動ベクトル化 SSE2 自動ベクトル化 AVX2 valarray SSE2 valarray AVX2
float 0.53 0.51 0.53 1.23 1.23 0.18 0.18 0.18 0.31 0.31 0.18 0.18 0.17 0.27 0.31 0.37 0.34 0.35 0.48 0.49 0.32 0.28 0.28 0.45 0.51
double 0.51 0.52 0.51 1.69 2.52 0.28 0.27 0.28 0.81 1.22 0.20 0.20 0.19 0.82 1.23 1.73 1.74 1.71 2.20 2.63 0.86 0.87 0.87 1.47 1.90
0.00
0.50
1.00
1.50
2.00
2.50
3.00
float double
Throughput
[clocks]
valarray の double のスループットは非実用的
- 14. [参考] 初等関数のスループット
14
exp (x) log (x) sin (x) cos (x) tan (x) asin (x) acos (x) atan (x) pow (x, y) pow (x, 2.0)
float 6.91 7.87 11.79 12.26 12.55 13.05 17.41 9.85 62.12 24.12
double 8.53 9.74 12.83 12.87 17.69 17.68 18.14 15.34 76.21 50.29
0.00
10.00
20.00
30.00
40.00
50.00
60.00
70.00
80.00
float double
Throughput
[clocks]
- 15. 結 果
スカラー演算のスループット
加減乗算のスループットは語長に係わらず整数,浮動小数点で有意差は無い
除算のスループットは,浮動小数点の方が高い
ループ展開と比較した,整数ベクトル演算のスループット (自動ベクトル化)
SSE2 の int32 は,加減算で約 3 倍,乗算で約 2 倍に性能向上
AVX2 の int32 は 4 −5 倍に性能向上
ループ展開と比較した,浮動小数点ベクトル演算のスループット (自動ベクトル化)
SSE2 の float は,加減乗算で約 3 倍,除算平方根で約 4 倍に性能向上
SSE2 の double は約 2 倍の性能向上
AVX2 の double は,加減乗算で約 3 倍の性能向上 (float と同等)
その他
valarray は int64, double の演算性能に問題あり,また自動ベクトル化より性能が低い
int16 のスカラー乗算,除算は 32bit 命令に変換されている
コンパイラは float の 逆数,平方根の逆数演算命令,AVX2 の積和演算命令への変換はしない
15
2024/4/21 追記
valarray の性能問題は,四則演算
結果を一時変数に記憶し,= で変数
に代入しているためと推定される
AVX2 の積和演算命令は
/fp:contract か /fp:fast を指定すれ
ば変換される
AVX-512 で追加された float の逆数
命令 (VRCP14PS) への変換はされる
- 16. おわりに
スループットをどう使う?
• 例えば,サンプリングレートが 48KHz のデータを,クロック速度が 1.8GHz の CPU でリアルタイム処理
• CPU 負荷を 1% 以下とすると 1 サンプル処理のクロック数の上限は 1.8GHz / 48KHz / 100 = 375 clocks
• 次数 67 の FIR フィルタは積和演算が 67 回となるから 67 clocks 程度必要か
• 5 フィルタは行けるな,という感覚論
x64 ベクトル演算は,使える局面を選ぶが,性能向上に確実に寄与する
• Visual C++ はループ展開や自動ベクトル化の条件をドキュメント化して欲しい
valarray はベクトル演算を簡潔に記述できる利点がある
• Visual C++ は valarray の性能を,自動ベクトル化と比較して遜色ないレベルにして欲しい
今回のスループット評価のソースコード
16
- 17. 参考資料
Intel CPU 技術資料
Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined
Volumes: 1, 2A, 2B, 2C, 2D, 3A, 3B, 3C, 3D, and 4.
Intel® 64 and IA-32 Architectures Optimization Reference Manual Volume 1.
x86, x84 CPU 命令セット一覧
x86, x64 CPU 命令のレイテンシ,スループット一覧
CPU の拡張機能サポート状況表示ツール Coreinfo
17