Slide 1

Slide 1 text

メモリボトルネックの概要と その影響について

Slide 2

Slide 2 text

今日話すこと ● 自己紹介 ● CPUの性能とメモリ性能の関係 ● 行列行列積に見るCPUキャッシュ最適化の例

Slide 3

Slide 3 text

今日のゴール ● 高いCPUを買っても何もしなければアプリケー ションは速くならないという実感を持つ ● キャッシュヒット率の重要性を理解する

Slide 4

Slide 4 text

大学院時代はスパコンで機械学習の訓練を高速化する研究をしていました ● 機械学習の訓練データを共有の並列ファイルシステムに置いて計算ノードからアクセスするとlatencyが高い ● 計算ノードのローカルストレージは低latencyだがコピーに時間がかるため少ない計算ノードだとペイしにくい https://dl.acm.org/doi/10.1145/3365109.3368768 というトレードオフの「いいとこどり」をする手法を提案し、Chainerで実装して訓練にかかる時間を評価

Slide 5

Slide 5 text

一方でスパコンといえば計算能力に関する研究が主流 ● スパコン分野の研究でよく出てくるネタ ○ 分散処理 ○ GPU/FPGAを使った行列計算の高速化 ○ 高速な連立一次方程式の解法 ○ 高速な固有値問題の解法 こんな感じなので、研究室内の輪講でもこれらの話題につ いて学びました。 今日はその中でも面白かった「CPU性能の評価」に関する 話をご紹介します。

Slide 6

Slide 6 text

CPUの理論性能と実効性能(1/2) ● 理論性能 ○ def; CPUのspecから求められる理論上出せる最高性能 ○ 倍精度Flop/sで表記するのが一般的 ○ 計算方法の一例 ■ clock * (FMA演算器の個数 x 2) * core数 * (最大SIMD幅 /64) ○ Intel Xeon Gold 6126 (2.6GHz/12core) の例 ■ 1 coreあたり: 2.6 GHz * (2 * 2) * (512/64) = 83.2 GFlop/s ■ 1 socketあたり: 83.2 GFLOPS/core * 12 core = 998.4 GFlop/s (ガチ勢向け)AVX使用時はクロックがベースクロックよりも下がりますが本スライドでは同じと仮定します

Slide 7

Slide 7 text

CPUの理論性能と実効性能(2/2) ● 実効性能 ○ def; 実際にapplicationを動かして計測された性能 ○ こちらも倍精度Flop/sで表現するのが一般的 ○ 計算方法の一例 ■ 2 GFlopsの計算を行うapplicationの実行に10秒 かかった ● 2 GFlops / 10 sec = 0.2 GFlop/s

Slide 8

Slide 8 text

残念なお知らせ(1/2) ● CPUの理論性能は基本的には出せない https://www.top500.org/lists/top500/2021/06/ 性能効率 (Rmax / Rpeak) [%] 82.2 % 74.0 % 75.3 %

Slide 9

Slide 9 text

残念なお知らせ(2/2) ● CPUの性能を阻害する多くのボトルネックが存 在する ○ ネットワーク latency ○ ストレージI/O latency ○ メモリI/O latency ○ 分岐予測ミス ○ パイプラインストール etc.. <- 今日はここの話をします

Slide 10

Slide 10 text

計算回数とメモリI/O回数の比率を考える(1/2) ● 計算するにはメモリからデータを読み書きしな ければならない double a = a + b; // 2回読み込み 1回書き 込み 上記のコードの場合、1回の加算に対して3回 (8 x 3 = 24 Byte) のメモリI/Oが発生している

Slide 11

Slide 11 text

計算回数とメモリI/O回数の比率を考える(2/2) ● この時 ○ メモリを24 Byte読み書きしないと1 Flop計算できな い ● 言い換えると ○ メモリを24 Byte読み書きするスピードの方が1 Flop計 算するよりも遅かったら、メモリI/Oがボトルネックに なる ○ 逆に、メモリを24 Byte読み書きするスピードの方が1 Flop計算するよりも速かったら、CPUが1 Flop計算す

Slide 12

Slide 12 text

わんこそばを食べる人とわんこそばを供給する人を考える (1/4) ● わんこそば(以下WS)で例えてみる ● WSを5杯/sec食べられる人が いるとする ● この時WS消費速度のボトルネ ックになるのは ○ WSを食べる人か? ○ WSを供給する店員か? 5杯/secでWSを食べる人 n杯/secでWSを供給する 人

Slide 13

Slide 13 text

わんこそばを食べる人とわんこそばを供給する人を考える (2/4) ● 店員がボトルネックになるケース ● 店員が3杯/secのスピードで供 給すると、3杯/secしか達成で きない ● WSを食べる人は1秒で5杯食べ る能力があるのに、1秒あたり 2杯分無駄にしてしまう 5杯/secでWSを食べる人 3杯/secでWSを供給する 人 はよ持ってこんかい!

Slide 14

Slide 14 text

わんこそばを食べる人とわんこそばを供給する人を考える (3/4) ● WSを食べる人がボトルネックになるケース ● 店員が10杯/secのスピードで 供給しても、5杯/secしか達成 できない ● 店員は1秒あたりさらに5杯供 給できるが持て余してしまう 5杯/secでWSを食べる人 10杯/secでWSを供給する 人 はよ食えや!

Slide 15

Slide 15 text

わんこそばを食べる人とわんこそばを供給する人を考える (4/4) ● WSの実効消費速度の推移をグラフにしてみる 0 1 5 WS消費速度 / WS供給速度 (WS強度) 実効WS 消費性能 WS消費速度 > WS供給速度 WS消費速度 < WS供給速度 はよWS食えやゾ ーン はよWS持ってこい ゾーン 実効WS消費性能 = min(理論WS消費速度, 理論WS供給速度 * WS強 度) 1秒間に5杯持ってき て5杯食える Higher

Slide 16

Slide 16 text

これはそのままCPUとメモリの関係になる ● CPUとメモリの関係に置き換える 0 ? 理論性能 Flops per Byte (計算 強度) 実効性能 [GFlops] CPU計算速度 > メモリI/Oバンド 幅 CPU計算速度 < メモリI/Oバンド幅 はよ計算しろやゾ ーン はよデータ持ってこい ゾーン 実効性能 = min(理論性能, 理論メモリI/O速度 * 計算強度) ここを知れば理論 性能を出すために 必要な計算強度が わかる Higher

Slide 17

Slide 17 text

Intel Xeon Gold 6126の理論性能からバランスする計算強度を計算す る ● CPU理論性能 ○ 1 coreあたり: 83.2 GFlop/s ○ 1 socketあたり: 998.4 GFlop/s ● メモリI/O理論バンド幅 ○ 2666 MHz x 8 Byte x 6 Channel = 128 GB/s ● CPU理論性能/メモリI/O理論バンド幅 ○ 998.4 GFlop/s / 128 GB/s = 7.8 [Flop/Byte] ○ ※一般的にはByte/Flopsで表現する ■ B/F比率 = 1 / 7.8 = 0.128 [Byte/Flop]

Slide 18

Slide 18 text

これはそのままCPUとメモリの関係になる ● CPUとメモリの関係に置き換える 0 998.4 Flops per Byte (計算 強度) 実効性能 [GFlops] はよ計算しろやゾ ーン はよデータ持ってこい ゾーン 実効性能 = min(理論性能, 理論メモリI/O速度 * 計算強度) 7.8 「計算強度7.8の applicationを動 かせば理論性能が 出せる」とわかっ た Higher CPU計算速度 > メモリI/Oバンド 幅 CPU計算速度 < メモリI/Oバンド幅

Slide 19

Slide 19 text

ちょっと待て、計算強度7.8だと? ● 計算強度7.8のコードを書くのはめちゃくちゃ大変 double a = a + b; // 2回読み込み 1回書き込み ● このコードだと計算強度は1 Flop / (8 * 3) Byte = 0.04167 ● 理論性能を出すために必要な計算強度の5.3%でしかなく 全然性能を出せない。 ● 計算強度7.8以上を達成するには↓みたいなコードじゃな いと無理(1回ロードしたbはレジスタに格納される想定) double a = b * … * b; // (合計125回bをかけ る)

Slide 20

Slide 20 text

どうしてこうなった? ● 現代はCPUに比べてメモリが相対的に遅い時代 https://www.extremetech.com/extreme/188776-how-l1-and-l2-cpu-caches-work-and-why- theyre-an-essential-part-of-modern-chips

Slide 21

Slide 21 text

じゃあどうする? ● 色々あります解決策 ○ 1 cycleあたりの計算量を増やしてスループットを上 げる ■ 並列化してマルチコアを活用する ■ SIMD命令を活用する ○ メモリボトルネックを真っ当に解消する ■ CPUキャッシュを使ってバンド幅を向上させる ■ いいメモリを使ってバンド幅を向上させる

Slide 22

Slide 22 text

CPUキャッシュはメモリの10倍から100倍高速 ● 例えばスパコン富岳は高バンド幅なメモリとcacheを兼ね備えている https://www.hpci- Intel Xeon Gold 6126のBF ratioは 0.128なので富岳のメモリ方がBF ratio が高い

Slide 23

Slide 23 text

簡単な実験: キャッシュヒット率を上げるとどのぐらい早くなるか(1/2) ● 正方行列 * 正方行列をnaiveに実装してみる for (i = 0; i < 1024; ++i) for (j = 0; j < 1024; ++j) for (k = 0; k < 1024; ++k) M3[i][j] += M1[i][k] * M2[k][j]; elapsed time = 6.079248 sec, 0.353248 GFLOPS https://github.com/serihiro/optimization_experiments コンパイルオプション: -O0 -std=c11 -Wall -Wextra

Slide 24

Slide 24 text

簡単な実験: キャッシュヒット率を上げるとどのぐらい早くなるか(2/2) ● 正方行列 * 正方行列をキャッシュヒット率を 高めるように実装してみる for (i = 0; i < 1024; ++i) for (k = 0; k < 1024; ++k) for (j = 0; j < 1024; ++j) M3[i][j] += M1[i][k] * M2[k elapsed time = 2.274633 sec, 0.944101 GFLOPS https://github.com/serihiro/optimization_experiments naiveに実装した時の3倍になった! for (i = 0; i < 1024; ++i) for (j = 0; j < 1024; ++j) for (k = 0; k < 1024; ++k) M3[i][j] += M1[i][k] * M2[k][j]; elapsed time = 6.079248 sec, 0.353248 GFLOPS コンパイルオプション: -O0 -std=c11 -Wall -Wextra

Slide 25

Slide 25 text

簡単な実験: (参考)手元の環境で一番はやくなったケース ● 正方行列 * 正方行列をblock化してキャッシュヒッ ト率を高めつつAVX2命令(256bit)を使用する block_size = 16; for (i = 0; i < 1024; i += block_size) { for (j = 0; j < 1024; j += block_size) { for (k = 0; k < 1024; k += block_size) { for (ii = i; ii < i + block_size; ++ii) { for (jj = j; jj < j + block_size; ++jj) { for (kk = k; kk < k + block_size; ++kk) { elapsed time = 0.172988 sec, 12.414061 GFLOPS naive実装の約35倍を達成した!(コンパイルオプションが違うので直接比較はできないけど) コンパイルオプション: -O3 -mavx2 -std=c11 -Wall -Wextra

Slide 26

Slide 26 text

まとめ ● 現代はメモリよりもCPUがはるかに高速な時代 ● 高いCPUに買い換えるだけでは性能は出ない ● CPUの性能を引き出すにはキャッシュヒット率 を高めるコードを書くなどの人手による工夫が 必要

Slide 27

Slide 27 text

併せて読みたい(CPU性能やコンピュータアーキテクチャに関する本) ● Samuel Williams, Andrew Waterman, and David Patterson. 2009. Roofline: an insightful visual performance model for multicore architectures. Commun. ACM 52, 4 (April 2009), 65–76. DOI:https://doi.org/10.1145/1498765.1498785 ● Software Engineering Advice from Building Large-Scale Distributed Systems http://static.googleusercontent.com/media/research.google.com/en/us/people/jeff/stanford-295-talk.pdf ● コンピュータアーキテクチャ技術入門 https://gihyo.jp/book/2014/978-4-7741-6426-7 ● パタヘネ5版 https://www.amazon.co.jp/dp/4822298426/ ● スーパーコンピュータ (岩波講座 計算科学 別巻) https://www.amazon.co.jp/dp/4000113070/ ● High Performance Computing: Modern Systems and Practices https://www.amazon.co.jp/dp/B077NZ4SW3/

Slide 28

Slide 28 text

appendix 1 ● 行列積の実験をしたCPUのspec ○ machdep.cpu.brand_string: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz ○ machdep.cpu.core_count: 6 ○ machdep.cpu.cache.L2_associativity: 4 ○ machdep.cpu.cache.linesize: 64 ○ machdep.cpu.cache.size: 256