← SEARCHABLE ARCHIVE
Assembly · 2026-08-15

如何測量 x86-64 效能最佳化?

以 profiler 與 benchmark 驗證 uop、相依性、快取與分支預測

INTERACTIVE READING MODE →

如何測量 x86-64 效能最佳化?

本文章以教學為目的。 效能會隨 microarchitecture、電力與溫度、記憶體階層、OS、輸入而變化,不要把固定 cycle 數當成普遍規則。

指令少不保證更快。一條指令可能拆成多個 uop,獨立指令可以重疊執行,而一次 cache miss 或長 dependency 就可能主宰整個迴圈。最佳化是量測瓶頸、建立因果假設,再用受控實驗嘗試反證的過程。

latency 與 throughput

latency 是結果可供相依指令使用前的延遲;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-endinstruction cache、decode、uop cache
Executionport、latency、dependency、divider
Memorycache/DRAM/TLB、store forwarding
Controlbranch misprediction、indirect target
Systempage fault、scheduler、lock、I/O

原始碼行數、指令數、binary bytes、jmp 數都只是線索,不是時間證明。先以 wall time 與 profiler 確認 hot path。

locality 與分支分布

連續陣列有利 cache line 與 prefetch。大結構只讀一個 field 或 pointer chasing 會浪費頻寬、限制 memory-level parallelism。AoS 改 SoA、縮小 working set 可能比 ASM 更有效。

幾乎永遠往同方向的分支很好預測。亂序輸入可能讓 cmov 或 mask 有利,但也可能執行兩邊工作、增加 dependency。與產品分布不同的隨機 benchmark 會誤導。

benchmark 契約

記錄假設、輸入大小與分布、避免 dead-code elimination、是否包含 setup、cold/warm cache、反覆是否獨立。再記錄 CPU、microcode、compiler/options、target ISA、LTO/PGO、seed、affinity、電源、溫度、重複次數、結果分布、OS 負載。看多次獨立 run,而非單一最好值。

rdtsc 不是自動的函式計時器;out-of-order、serialization、migration、invariant TSC 都必須處理。先使用可信 benchmark framework 與 monotonic clock。

profiler、counter 與 compiler

sampling profiler 找到時間位置;hardware counter 幫助檢查 cycles、branch、cache/TLB 假設。但 event 意義依 CPU 而異,也有 multiplexing、skid、speculation。IPC 一個數字不能判定好壞。

最佳化順序:建立正確的 C/C++ 基準與測試、查看 Release output、改善 algorithm/data layout、考慮 PGO/target/intrinsic,最後才在狹窄 hot loop 實驗 ASM。獨立 ASM 函式可能失去 inlining 與跨函式最佳化。

速度比較前必須測試 0、1、vector 邊界、大輸入、overflow、alignment、alias/overlap、FP 特殊值、feature fallback、sanitizer 與 unwind。

總結

x86-64 效能由 latency、throughput、uop、執行資源、dependency、cache/TLB、branch 預測與系統雜訊共同決定。以 profiler 找 hot path,用明確假設的 benchmark 驗證,只在效益與維護條件可重現的狹窄區域保留 handwritten ASM。

官方資料