ルーフラインモデル ─ 演算強度とボトルネックの可視化
そのカーネルが演算律速かメモリ帯域律速かを、演算強度1本の数値で見抜けます。リッジポイントと屋根の幾何から、タイリングや再利用向上で性能が伸びる理由まで原理で理解できます。
- 1.演算強度(FLOP/Byte)を横軸、到達性能(FLOP/s)を縦軸に取り、傾き=メモリ帯域の帯域ルーフと水平=ピーク演算性能の計算ルーフの最小値で性能上限を決めるのがルーフラインモデル。
- 2.2つの屋根が交わるリッジポイント(ピーク性能÷帯域)より演算強度が左ならメモリ帯域律速、右なら演算律速。最適化の方針はこの位置で分かれる。
- 3.タイリングやデータ再利用はバイト移動量を減らして演算強度を右へ動かす操作であり、帯域律速のカーネルをリッジポイント側へ押し上げて初めて演算ユニットが活きる。
同じチップで性能が10倍違う理由
同一のCPUやGPUでも、行列積は理論ピークに近い性能を出すのに、ベクトルの加算はその数分の一しか出ないことがあります。クロックもコア数も同じなのに、なぜカーネルごとに到達性能がこれほど変わるのか。その問いに1枚の図と1つの数値で答えるのが、2009年にBerkeleyのWilliamsらが提案した ルーフラインモデル(Roofline model) です。
鍵となる発想は、性能を縛る要因が大きく2つしかないと割り切ることです。1つは演算ユニットのピーク演算性能(FLOP/s)、もう1つはメモリ階層からデータを運ぶメモリ帯域(Byte/s)です。どちらが律速かは、カーネルが「1バイト運ぶごとに何回演算するか」で決まります。この比率を演算強度(arithmetic intensity, AI) と呼び、ルーフラインモデルの主役になります。
演算強度 AI = 総浮動小数点演算数 / 主記憶との総転送バイト数
(単位: FLOP/Byte)
AI が大きい : 1バイトあたり多く計算する → 演算ユニットを使い込む
AI が小さい : 少ししか計算せずすぐ次のデータを要求 → 帯域待ちになる
モデルの幾何 ─ 2つの屋根の最小値
ルーフラインモデルは、横軸に演算強度(対数)、縦軸に到達性能(対数、FLOP/s)を取った両対数グラフです。あるカーネルが出せる性能の上限は、次の単純な式で与えられます。
到達性能(AI) = min( ピーク演算性能, メモリ帯域 × AI )
└─ 計算ルーフ ─┘ └── 帯域ルーフ ──┘
- 帯域ルーフ:
メモリ帯域 × AI。両対数グラフでは傾き1の右上がり直線になり、その高さはメモリ帯域そのものが決める。AIが小さい左側で性能を抑え込む「斜めの屋根」。 - 計算ルーフ:
ピーク演算性能。AIに依存しない水平線で、右側で性能を抑え込む「平らな屋根」。
両者の min を取るので、グラフは左で斜めに立ち上がり、ある点で折れて水平になる屋根(roof)の形を描きます。この折れ点こそがモデルの心臓部です。
帯域ルーフは 性能 = 帯域 × AI です。両辺の対数を取ると log(性能) = log(帯域) + log(AI) となり、log(AI) に対して傾き1・切片 log(帯域) の直線になります。だから両対数グラフでは必ず45度(傾き1)の線です。帯域が2倍のメモリに替えると、この斜め線は傾きを保ったまま上へ平行移動します。
リッジポイント ─ 律速が切り替わる演算強度
帯域ルーフと計算ルーフが交わる点を リッジポイント(ridge point) と呼びます。メモリ帯域 × AI = ピーク演算性能 を解けば、その横位置(演算強度)が求まります。
リッジポイントの演算強度 AI_ridge = ピーク演算性能 / メモリ帯域
(FLOP/s ÷ Byte/s = FLOP/Byte)
この1点が、カーネルの運命を分けます。
- カーネルの演算強度が
AI_ridge未満(リッジポイントより左)なら、上限は帯域ルーフ上にあり メモリ帯域律速(memory-bound)。演算ユニットは遊び、性能はデータ供給速度で決まる。 - カーネルの演算強度が
AI_ridgeより大きい(右)なら、上限は計算ルーフ上にあり 演算律速(compute-bound)。帯域には余裕があり、性能はピーク演算性能で決まる。
リッジポイントが右にあるマシンほど、演算律速に到達するのが難しい、つまり「帯域に対して演算が過剰」なバランスを意味します。近年のGPUやアクセラレータはピーク演算性能が帯域より速く伸び続けたため、リッジポイントは年々右へ動いてきました(半導体の電力の壁で演算側のスケーリングが鈍る一方、帯域はさらに伸び悩んだことが背景にあります)。
| 世代の傾向 | ピーク演算性能 | メモリ帯域 | リッジポイント(FLOP/Byte) | 帰結 |
|---|---|---|---|---|
| 初期の汎用CPU | 数十 GFLOP/s | 数 GB/s | 数 前後 | 多くのカーネルが演算律速側 |
| メニーコア/初期GPU | 数 TFLOP/s | 数百 GB/s | 10 前後 | ステンシル等が帯域律速に転落 |
| 近年のGPU/アクセラレータ | 数十〜百 TFLOP/s超 | TB/s級 | 数十〜100超 | ほとんどのカーネルが帯域律速 |
数値はおおよその桁感であり、世代区分は厳密な年代ではなく傾向の分岐を示すものです。重要なのは絶対値ではなく、リッジポイントが右へ動くほど、演算ユニットを使い切るのに高い演算強度が要るという方向性です。
演算強度の見積もり方
演算強度はカーネルのコードから見積もれます。分子は総FLOP数、分母は主記憶(あるいは対象とするキャッシュ階層)と実際にやり取りするバイト数です。後者は「再利用がどれだけ効くか」で大きく変わる点が肝心です。
例: 倍精度の SAXPY y[i] = a * x[i] + y[i] (N 要素)
FLOP : 乗算1 + 加算1 = 2 FLOP/要素 → 合計 2N
バイト : x を読む(8) + y を読む(8) + y を書く(8) = 24 Byte/要素 → 合計 24N
AI = 2N / 24N ≒ 0.083 FLOP/Byte (非常に小さい=強い帯域律速)
例: 倍精度の密行列積 C = A × B (N×N)
FLOP : 2 * N^3
バイト : 素朴な実装は B を N 回読み直し、移動量が O(N^3) に膨らむ
→ AI はほぼ一定の小ささに張り付く(帯域律速)
タイリング後 : ブロックサイズ T のタイルをキャッシュに載せ再利用すると
主記憶移動量は約 O(N^3 / T) に減る
→ AI は T にほぼ比例して増える(演算律速側へ移動)
SAXPYのように各データを一度しか使わないカーネルは、演算強度が本質的に小さく、どう書いても帯域ルーフに張り付きます。一方、行列積は同じデータを何度も使う潜在的な再利用性があり、移動量を減らせば演算強度を引き上げられる。この差が最適化余地の有無を決めます。
最適化方針の導出 ─ 屋根のどこにいるか
ルーフラインモデルの実用上の価値は、測定点を屋根の上にプロットしたとき、取るべき施策が幾何学的に一意に決まることです。
| カーネルの位置 | 律速 | 効く最適化 | 効かない/無駄な最適化 |
|---|---|---|---|
| 帯域ルーフ上(左) | メモリ帯域律速 | タイリング・データ再利用でAIを右へ/データ局所性向上/不要な転送削減 | FMA活用・SIMD幅拡大など演算側の強化 |
| リッジポイント付近 | 両者が拮抗 | 両面のチューニングが効く/キャッシュ滞留量の調整 | 片側だけの強化は早期に飽和 |
| 計算ルーフ上(右) | 演算律速 | [SIMD/ベクトル化](/hardware-components/simd-vector-processing/)・FMA・命令レベル並列で実効FLOPを上げる | 帯域削減(既に余っている) |
つまり、帯域律速のカーネルにSIMD命令を足しても性能は1ミリも伸びない(屋根が斜めのまま頭を押さえている)し、逆に演算律速のカーネルでデータ転送を削っても無駄です。施策の前にまず演算強度を測り、リッジポイントの左右どちらにいるかを見るのが鉄則になります。
タイリング(ブロッキング)の本質は、データを小さなタイルに分けてキャッシュに滞留させ、主記憶へ戻る前に何度も再利用することです。FLOP数は不変のまま主記憶転送バイト数が減るので、演算強度(分子÷分母)の分母が縮み、点が右へ動きます。帯域ルーフ上にあった点がリッジポイントを越えれば、初めて演算ユニットがフル稼働します。これがタイリングで性能が跳ねる原理です。
屋根を下げる現実の天井 ─ 拡張ルーフライン
ここまでは「ピーク演算性能」と「メモリ帯域」を理想値として扱いました。現実には、それぞれの屋根がさらに低い天井で頭打ちになります。これらを追加の水平線・斜め線として描いたものが拡張ルーフラインです。
- 演算側の天井: FMA(積和)を使わない、SIMD化していない、命令レベル並列が足りない、といった理由で実効ピークが下がる。SIMDなしなら計算ルーフは数分の一に下がる。
- 帯域側の天井: 連続アクセスでない、NUMAの遠いノードを踏む、プリフェッチが効かない、といった理由で実効帯域が公称値を大きく下回り、斜めの屋根が下へ平行移動する。
階段状に積み重なる帯域の屋根(下ほど低い実効帯域)
上段: ストリーム連続アクセス・プリフェッチ良好 → 公称帯域に近い
中段: 一部ランダム・遠いNUMAノード → 実効帯域が低下
下段: 強い不規則アクセス → さらに低い屋根
測定点がどの段に乗っているかで、メモリアクセスパターン改善の余地が読める
測定点が公称の屋根よりずっと下にあるなら、屋根そのものに到達する前の問題(アクセスパターン、NUMA配置、ベクトル化漏れ)が残っているサインです。ルーフラインは「ピークまであと何倍か」だけでなく、「どの天井で詰まっているか」を切り分ける診断図として機能します。
「演算強度=総FLOP÷総転送バイト(FLOP/Byte)」「到達性能=min(ピーク演算性能, 帯域×演算強度)」「リッジポイント=ピーク演算性能÷メモリ帯域で、ここより左が帯域律速・右が演算律速」「両対数グラフで帯域ルーフは傾き1の直線、計算ルーフは水平線」の4点が核心です。さらに「タイリング/再利用は転送バイトを減らして演算強度を右へ動かす=帯域律速を緩和する」「帯域律速カーネルにSIMDやFMAを足しても効かない」という最適化の対応関係が頻出します。
まとめ
- ルーフラインモデルは到達性能を
min(ピーク演算性能, メモリ帯域 × 演算強度)で表し、両対数グラフ上では傾き1の帯域ルーフと水平の計算ルーフが作る屋根の形になる。 - 2つの屋根が交わるリッジポイントの演算強度は
ピーク演算性能 ÷ メモリ帯域。これより左はメモリ帯域律速、右は演算律速で、近年のハードはリッジポイントが右へ動き帯域律速になりやすい。 - タイリングやデータ再利用は転送バイト数を減らして演算強度を右へ動かす操作であり、帯域律速のカーネルをリッジポイント側へ押し上げて初めて演算ユニットが活きる。
- 拡張ルーフラインは、FMA・SIMDの有無やアクセスパターンによる実効ピーク・実効帯域の低下を低い屋根として描き、「どの天井で詰まっているか」を切り分ける診断図になる。
突き詰めれば、性能を決めるのはクロックでもコア数でもなく、カーネルの演算強度がリッジポイントのどちら側にあるかです。最適化とは、点を屋根に近づけ、可能なら右へ動かす作業に他なりません。
CPU/メモリ/ディスク Article
ルーフラインモデル ─ 演算強度とボトルネックの可視化を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
ルーフラインモデル
比較で見る軸
難易度: advanced / カテゴリ: CPU/メモリ/ディスク / タグ数: 5
導入後に効く点
2つの屋根が交わるリッジポイント(ピーク性能÷帯域)より演算強度が左ならメモリ帯域律速、右なら演算律速。最適化の方針はこの位置で分かれる。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- CPU/メモリ/ディスク
- タグ数
- 5
判断チェックリスト
- 自社の用途が「ルーフラインモデル / 演算強度」に近いか確認する。
- 強みである「演算強度(FLOP/Byte)を横軸、到達性能(FLOP/s)を縦軸に取り、傾き=メモリ帯域の帯域ルーフと水平=ピーク演算性能の計算ルーフの最小値で性能上限を決めるのがルーフラインモデル。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。