CPU 軟體效能分析指標解釋
Profiler 工具有很多術語和指標,這裡進行介紹、說明和總結。
Retired & Executed 指令
處理器執行的指令數量,往往會比程式流需要的指令數量要多。這是因為處理器會預測指令(分支預測等)。對於一般的指令,CPU 提交計算結果後就會 Retired(指令退役)。但是,處理器預測出來的指令不會,CPU 會保留它們。當 CPU 判斷出預測是正確的,這些被保留的指令才會像正常指令那樣執行。若 CPU 判斷出預測結果是錯誤的,CPU 會將丟掉所以預測指令的執行結果並且不會 Retired 這些指令。所以,CPU 執行的指令數量並不等於退役的指令數量。一個好的程式應該有較多的指令執行和較少的指令退役。
可以通過Linux pref工具獲得指令退役的數量:
perf stat -e instructions ./a
CPU 利用率
CPU 利用率就是 CPU 繁忙時間同佔據總執行時間的比值。
\(CPU 利用率={{CPU\_CLK\_UNHALTED.REF\_TSC(CPU繁忙週期)} \over {TSC(執行總週期)}}\)
CPU 利用率通常用來衡量程式的效能好壞的一個指標,通常情況下 CPU 的利用率越高越好。但是,有些情況下可能並不是。例如:CPU 停滯等待記憶體中的資料;在多執行緒的情況下,執行緒可能在等待一些讓其運轉必要的資源;因此,提出了 CPU 有效利用率這個指標,相較於 CPU 利用率,剔除了上述這些等待時間。
可以通過Linux pref
工具獲得 CPU 利用率:
perf stat -- a
0.634874 task-clock (msec) # 0.634 CPUs 利用率
CPI & IPC
- Cycles Per Instruction (CPI) - 平均使一條指令退役(失效)需要多少個週期。
- Instructions Per Cycle (IPC) - 平均每個週期退役(失效)的指令數。
\(IPC={{INS\_RETIRED.ANY(指令退役數)}\over{CPU\_CLK\_UNHALTED}(CPU 週期)}\)
\(CPI={1 \over {IPC}}\)
這兩個指標是分析軟體和硬體效能的常用指標。軟體工程師在優化應用程式時會關注 IPC 和 CPI。通常情況下,我們希望 CPI 越低越好 IPC 越高越好。這兩個指標我們依舊可以通過pref
perf stat -e cycles,instructions -- a
2369632 cycles
1725916 instructions
# 我們可以根據這兩個指標做除法可得
UOPs
關於UOPs的更詳細的文章
x86體系結構的微處理器將複雜的類 CISC 指令轉換為簡單的類 RISC 微操作(縮寫為 µops 或 uops)。這樣做的主要優點是可以利用 µops 可以亂序執行的。譬如說有這樣一個指令ADD EAX,[MEM]
可能會拆成兩個 µops :一個操作是將記憶體中的資料載入到暫存器中,另外一個操作是執行加法。微指令的劃分通常取決於 CPU。
除了將指令進行拆分,也可以將指令進行合併,在現代 Intel CPUs 下存在兩種融合情況:
- Microfusion——融合同種機器指令。例如:融合記憶體寫入操作和讀取修改操作。
- Macrofusion——融合不同型別機器指令。例如:解碼器可以將算術或邏輯指令與後續條件跳轉指令融合到單個計算中。
Micro-Fusion 和 Macro-Fusion 都可以節省頻寬。
通過pref
可以獲得相關的指標:
perf stat -e uops_issued.any,uops_executed.thread,uops_retired.all -- a
2856278 uops_issued.any
2720241 uops_executed.thread
2557884 uops_retired.all
有關最新 x86 體系結構指令的延遲、吞吐量、埠使用率和 UOP 數,訪問<uops.info>。
Pipeline Slot
指令流水槽(Pipeline Slot)表示處理一個uop所需的硬體資源。現代 x86 CPU 通常情況下 pipline 寬度為 4。如下圖所示,這段程式只使用了一半的 slot。從體系結構的角度來說,該程式只發揮了硬體一半的效能。
核心 & 參考週期
現在 x86 CPU 執行指令並沒有固定的頻率。它們都使用了 動態頻率縮放 技術。在 Intel 上叫 Turbo Boost ,在 AMD 上叫 Turbo Core 。它允許CPU動態地增加和減少其頻率–縮小頻率以犧牲效能為代價降低功耗,而放大頻率可以提高效能,但會犧牲功耗。
可以通過pref
工具獲取相關指標,這裡以 Skylake i7-6000為例:
perf stat -e cycles,ref-cycles ./a
43340884632 cycles # 3.97 GHz
37028245322 ref-cycles # 3.39 GHz
其中 ref-cycles 結果為 CPU 沒有進行動態頻率縮放的週期,如果我們對其進行時鐘增益縮放,就可以得到這款CPU的基礎頻率。
指標 cycles 計算的是真實 CPU 週期(也就是加入了動態頻率縮放後的週期),我們還可以計算動態頻率縮放功能的利用程度:
\(Turbo 利用率 = {{cycles} \over {ref-cycles}}\)
Cache 丟失
現代 CPU 通常具備多級快取,當 CPU 需要的資料不存在於當前快取,那麼將從其下一級快取中查詢。如下表所示,不同級別的快取訪問的週期不同。倘若最後一級 Cache (LLC)依舊沒有命中,我們需要付出很大的代價去從主存中獲取資料。快取丟失包括了指令和資料快取丟失。
記憶體層級 | 延時 |
---|---|
L1 | 4 cycles (~1ns) |
L2 | 10-25 cycles (5-10 ns) |
L3 | ~40 cycles (20 ns) |
主存 | 200+ cycles (100 ns) |
我們可以通過pref
獲取 L
perf stat -e mem_load_retired.fb_hit,mem_load_retired.l<N>_miss,mem_load_retired.l<N>_hit,mem_inst_retired.all_loads -- a
29580 mem_load_retired.fb_hit
19036 mem_load_retired.l<n>_miss # LN 快取丟失數
497204 mem_load_retired.l<n>_hit # LN 快取命中數
546230 mem_inst_retired.all_loads
預測錯誤的分支
現代處理器都會對分支進行預測,若預測正確,可以給效能帶來很大的提升,倘若預測錯誤,將會造成 10~20 時鐘週期的懲罰。我們可以通過pref
工具來檢視分支預測錯誤的數量:
perf stat -e branches,branch-misses -- a
358209 branches
14026 branch-misses # 3,92% 分支預測錯誤率