どこが重いかを測って直す / Profiling & optimization
最適化とプロファイリング実践
Primer 01〜07 で「1フレームがどう作られるか」を追ってきました。最後は、その1フレームが遅いとき、どこが重いのかを測って直す話です。大事な原則は「推測するな、測れ」。目grep で速くしようとすると、たいてい重くないところを削って徒労に終わります。まず stat unit でフレーム時間の内訳を読み、ボトルネック(律速している場所)を特定する ── ここでこれまでの各章の知識が、直し方の判断に効いてきます。
stat unit
CPU / GPU bound
Frame budget
Unreal Insights
まず用語だけ — 読む前の30秒
フレーム時間 frame time
1枚の絵を出すのにかかる時間(ms)。60fpsなら16.7ms以内が予算。
stat unit stat unit
Frame / Game / Draw / GPU の内訳を画面に出すUEのコマンド。
ボトルネック bottleneck
一番時間のかかっている工程。ここがフレーム全体の速さを決める。
CPU / GPUバウンド bound
律速がCPU側(Game/Draw)かGPU側か。直す場所がまったく違う。
ドローコール draw call
CPUがGPUに出す「これ描いて」の命令。多いとDrawスレッドが重い。
スケーラビリティ scalability
解像度や各品質を段階的に落として軽くする仕組み。GPU側の定石。
※ 各語の詳しい定義は、ページ末尾の用語集にもあります。
§1 — What a frame is made of
1フレームは3つの工程でできている
Primer 01 で見たとおり、1フレームは大きく Game スレッド(ゲームロジック・物理・Tick)→ Draw スレッド(描画命令=ドローコールを組み立てる、レンダースレッド/RHI)→ GPU(実際にピクセルを塗る)という順で流れます。しかもこの3つはパイプラインで並行に走ります ── GPUが今フレームを塗っている間に、CPUはもう次フレームの準備を始めている。
Game (CPU)
何を描くか決める
Tick・AI・物理・アニメ・座標更新。ここが重い=ゲームロジックの問題。
Draw (CPU)
命令を組み立てる
可視判定してドローコールを積む(レンダースレッド/RHI)。ここが重い=描画物・材質が多すぎ。
GPU
実際に塗る
ピクセルを塗る・ライティング・ポスト。ここが重い=解像度/エフェクト/シェーダーの問題。
これがいちばん大事なひとこと
3工程が並行に走るので、フレーム時間 ≈ 一番長い工程の時間で決まります。短い工程はその間ただ待っている(アイドル)。だから「一番長い工程=ボトルネック」だけを短くすればfpsは上がり、それ以外を最適化してもフレーム時間は1msも縮まりません。次の §2 で、これを実際に触って確かめます。
§2 — Reading stat unit
stat unit を読む ── どこがボトルネックか
UEのコンソールで stat unit と打つと、画面右上に Frame / Game / Draw / GPU の4行が ms で出ます。読み方はシンプル ── Game・Draw・GPU のうち一番大きい数字=ボトルネックで、それが Frame の値とほぼ一致します。下のスライダーで各工程の負荷を動かして、Frame(=一番長い工程)とfps、そしてバウンド判定がどう変わるか見てください。
3工程のパイプライン(横=時間 / 白抜き=アイドル待ち)
試してみてほしいこと ── GPUバウンドの状態で Game 負荷だけを下げても、Frame は 1ms も動きません(GPUが律速のまま)。ボトルネックの GPU を下げて初めて fps が上がる。「重い所を測って、そこだけ直す」の意味はこれです。
§3 — Fixes by bottleneck
重い → こう直す(各章への地図)
ボトルネックが分かったら、その工程に効く定石を打ちます。面白いのは ── 打ち手のほとんどが、これまでの各章でもう見た話だということ。下は「どの工程が重いとき、何を、どの章の知識で直すか」の対応表です。用語をクリックする感覚で、リンクから各章に戻れます。
Draw バウンド (CPU)
症状:描画命令が多すぎる
物やマテリアルの種類が多く、ドローコールが積み上がってレンダースレッドが詰まっている状態。
インスタンシング / 統合 ── 同じメッシュはまとめて1コールに。マテリアル数を減らす。
カリング / LOD ── 視界外・小さすぎる物は描かない。
Nanite (06) はクラスタ単位でこれを自動化。
GPU バウンド
症状:ピクセルを塗るのが重い
解像度・エフェクト・シェーダー・ライティングのどれかが重い状態。GPUバウンドで一番よく効く一手は解像度を落とすこと。
解像度スケール / TSR ── 内部解像度を下げてアップスケール。
ポスト (05) の TAA/TSR がここ。
Memory / VRAM
症状:カクつく・テクスチャがぼやける
平均fpsは出ているのに時々スパイクする、遠景のテクスチャが低品質のまま ── これはVRAM不足やストリーミング待ち。テクスチャ (02) のミップ/ストリーミングプールの節が効きます。stat では stat streaming / stat RHI を見ます。スパイクそのものは フレーム構成 (09) の GC・ヒッチの節も。
§4 — Measuring in UE
UEでの計測 ── 粗く見て、細かく掘る
計測は粗い→細かいの順で掘ります。まず stat unit でCPUかGPUかを切り分け、そこから対応するツールで内訳を詰めていきます。
stat unit / stat fps
まず切り分ける
最初に打つコマンド。Frame/Game/Draw/GPU の4行で、CPU側かGPU側かを一目で判断。§2 でやったのはこれ。
stat SceneRendering / stat RHI
Draw側の内訳
ドローコール数・描画プリミティブ数・各パスの時間。Drawバウンドのとき「何が命令を増やしているか」を見る。
GPU Visualizer (ProfileGPU)
GPU側の内訳
Ctrl+Shift+, で1フレームのGPU処理を工程別に棒グラフ表示。BasePass/Lighting/ポスト等のどれが重いかが分かる。GPUバウンドの主力。
Unreal Insights
タイムラインで深掘り
全スレッドの処理をタイムラインで記録・後解析する本格ツール。スパイクの原因追跡や、フレーム間の詳細な内訳に。
これで Primer 01〜08:スレッド → テクスチャ → マテリアル → 描画パス → ポスト → Nanite → ライティング → 計測。1フレームが画面に出るまでの絵づくりと、それが遅いときの直し方の判断まで、ひととおりつながりました。描画以外(Tick・物理・GC)がフレームをどう食うかは Primer 09 へ。