x86-64の性能最適化をどう測るか
uop、依存関係、キャッシュ、分岐予測をプロファイルとベンチマークで検証する
x86-64の性能最適化をどう測るか
本記事は講義を目的としています。 性能はmicroarchitecture、電力・温度、memory hierarchy、OS、入力で変わるため、固定cycle数を普遍的規則として暗記しないでください。
命令数が少なくても速いとは限らない。一命令が複数uopになり、独立命令は重なって実行される一方、cache missや長いdependency一つが全体を支配できる。最適化は瓶頸を測定し、原因仮説を作り、制御した実験で反証する過程である。
latencyとthroughput
latencyは結果をdependent命令が使えるまで、throughputは独立演算を開始できる頻度である。
; dependency chain
add rax, rbx
add rax, rcx
add rax, rdx
; independent
add r8, rbx
add r9, rcx
add r10, rdx
同じ三つのaddでもcritical pathが違う。benchmarkがどちらを測るか明示する。
複数層の瓶頸
| 層 | 例 |
|---|---|
| Front-end | instruction cache、decode、uop cache |
| Execution | port、latency、dependency、divider |
| Memory | cache/DRAM/TLB、store forwarding |
| Control | branch misprediction、indirect target |
| System | page fault、scheduler、lock、I/O |
source行数、命令数、binary byte、jmp数は仮説の手掛かりであって時間の証明ではない。まずwall timeとprofilerでhot pathを確認する。
data localityとbranch分布
連続arrayはcache lineとprefetchに向く。大きな構造体の一fieldだけ読む、pointer chasingを行うと帯域やmemory-level parallelismを失う。AoS→SoAやworking set削減がASMより大きな効果を持つことがある。
分岐がほぼ一方向なら予測しやすい。乱れた入力ではcmovやmaskが有利な場合もあるが、両経路の処理とdependencyを増やす。製品と異なるランダム入力のmicrobenchmarkを信じすぎない。
benchmark契約
仮説、入力size/分布、dead-code elimination防止、setupを含むか、cold/warm cache、反復独立性を明記する。CPU、microcode、compiler/options、ISA、LTO/PGO、seed、affinity、電源、温度、反復数、分布、OS負荷を記録する。一回のbest値より独立runの分布を見る。
rdtscは自動的な関数timerではない。out-of-order、serialization、migration、invariant TSCを扱う必要がある。まず信頼できるframeworkとmonotonic clockを使う。
profilerとcounter
sampling profilerは時間の場所を示し、hardware counterはcycle、branch、cache/TLBなど原因仮説を助ける。ただしevent意味はCPUごとに異なり、multiplexing、skid、speculationがある。IPC一つで良否を決めない。
compilerを基準線にする
- 明確なC/C++基準実装とtest
- Release出力確認
- algorithm/data layout改善
- target option、PGO、intrinsic
- narrow hot loopだけASM実験
- 同じ契約で正確性と速度を比較
別ASM関数はinliningや全体最適化を失うことがある。0、1、vector境界、大入力、overflow、alignment、alias、FP特殊値、feature fallback、sanitizer/unwindを速度比較前に通す。
採用条件
end-to-end影響、対応CPU全体の利益、dispatch/fallback、compiler更新後の再検証、debug/sanitizer/mitigation、team保守性を含める。compilerやintrinsicが同等なら透明な実装の方が長期的に優れる。
まとめ
x86-64性能はlatency、throughput、uop、resource、dependency、cache/TLB、branch予測、system noiseの組合せである。profileでhot pathを見つけ、明確な仮説をbenchmarkで検証し、利益と保守条件を再現できる狭い場所だけにhandwritten ASMを残す。