性能分析利器之perf淺析

源:http://walkerdu.com/2018/09/13/perf-event/

作為服務器後臺開發,不僅僅要寫業務邏輯,後臺意味著高併發,穩定性,當你寫了很多邏輯,發現性能有問題的時候,也要學會性能分析,進行性能優化, 也許你會接觸很多性能分析工具:valgrind,gperftools,gprof, oprofile, 有時間慢慢一一介紹,在學習perf的過程中,也學習和加深了很多之前的知識,本文拋磚引玉,希望能幫助大家瞭解一些性能分析更深的一些東西。

1. perf簡介

perf是一款linux內置的性能分析工具,隨著內核發佈,也被稱為perf_events, perf tools, PCL(Performance Counters for Linux), 發佈於Linux kernel version 2.6.31, perf是怎麼工作的呢?perf如何使用?本文是來介紹一下。

perf官方wiki的介紹是:Linux profiling with performance counters

Perf可以解決高級性能和故障排除,它可以分析(當然目前我也只是用來進行cpu性能分析):

  • 為什麼內核消耗CPU高, 代碼的位置在哪裡?
  • 什麼代碼引起了CPU 2級cache未命中?
  • CPU是否消耗在內存I/O上?
  • 哪些代碼分配內存,分配了多少?
  • 什麼觸發了TCP重傳?
  • 某個內核函數是否正在被調用,調用頻率多少?
  • 線程釋放CPU的原因?

2. perf的event

它可以利用CPU performance counters(性能計數器),tracepoints, kprobes和uprobes來進行應用程序的性能分析。perf使用這些linux內核提供的tracing特性進行事件的採集和分析,perf使用的event主要有以下幾種:

  • Hardware Events: CPU中的寄存器含有performance counters(性能計數器),用來統計 Hardware event,例如 cpu-cycles、instructions executed 、cache-misses、branch mispredicted等。這些event構成了應用程序profiling的基礎。
  • Software Events: 基於內核計數器的低優先級events, 例如, CPU migrations(處理器遷移次數), minor faults(soft page faults), major faults(hard page faults).
  • Tracepoints: 是散落在內核源代碼中的一些 hook,用來調用probe函數,開啟後,它們便可以在特定的代碼被運行到時被觸發,這一特性可以被各種 trace/debug 工具所使用。Perf 就是該特性的用戶之一。假如您想知道在應用程序運行期間,內核內存管理模塊的行為,便可以利用潛伏在 slab 分配器中的 tracepoint。當內核運行到這些 tracepoint 時,便會通知 perf。
  • Dynamic Tracing: probe函數(探針or探測函數),kprobe(kernel probe)內核態探針,用來創建和管理內核代碼中的探測點。Uprobes,user-probe,用戶態探針,用來對用戶態應用程序進行探測點的創建和管理,關於kprobe和uprobe可參考對應的內核文檔
  • perf使用的event來源,如下圖:來源:brendangregg
性能分析利器之perf淺析

3. 安裝

兩種安裝方式

  • 通過包管理進行安裝,perf工具在 linux-tools-common工具包裡,通過包管理軟件安裝的時候還需要依賴linux-tools-kernelversion包
  • 源碼編譯:找到對應內核版本的源碼包,在tools/perf目錄下進行編譯

4. 背景

要想使用perf來分析應用程序,需要了解一些基礎概念,例如符號表, frame pointer等信息

4.1 符號表

應用程序的符號表,用來將邏輯地址翻譯成對應的函數和變量名,這樣才能被程序員閱讀和分析,沒有符號表,profile的結果都是一些16進制的邏輯地址:

如下是perf report分析sshd進程的堆棧調用情況(來自brendangregg):


性能分析利器之perf淺析


對於通過軟件包安裝的程序,通常都會有dubug package(-dbgsym)即帶有符號表信息的程序,如果是源碼安裝的就需要編譯時開啟debug選項。

通過使用openssh-server-dbgsym and libc6-dbgsym,sshd的perf report分析結果如下:

性能分析利器之perf淺析

4.2 棧回溯(棧展開)

我們經常在編譯的時候會開啟frame pointers優化選項,即優化掉函數棧幀rbp,省略掉frame pointer是編譯器一個很爛的優化,它會破壞debug, 更爛的是省略frame pointer一般是編譯器默認的優化選項。

沒有frame pointer會使perf 無法獲取完整的調用棧,如下示例:

性能分析利器之perf淺析

例如上面代碼正常不開啟優化的編譯,進行profile是可以看到call graph的,如下:

性能分析利器之perf淺析

如果編譯時開啟-fomit-frame-pointer(這裡因為測試代碼簡單,直接開優化的話就優化沒了),就無法獲取到call graph

性能分析利器之perf淺析

有三種方法可以修復這個問題,這裡不做展開,這些stack walking techniques後面可以寫一篇單獨的文章:

  • using dwarf data to unwind the stack, 實際上很多profile工具:gperftools, valgrind都是依賴於libunwind,通過dwarf來進行stack trace的
  • using last branch record (LBR) if available (a processor feature)
  • returning the frame pointers

5. 使用

perf提供了一系列的命令來分析程序,如下:

sub command功能說明

annotate 讀取perf.data(由perf record生成)顯示註釋信息,如果被分析的進程含義debug符號信息,則會顯示彙編和對應的源碼,否則只顯示彙編代碼

archive 根據perf.data(由perf record生成)文件中的build-id將相關的目標文件打包,方便在其他機器分析

bench perf提供的基準套件的通用框架,可以對當前系統的調度,IPC,內存訪問進行性能評估

buildid-cache 管理build-id,管理對於的bin文件

buildid-list 列出perf.data中的所以buildids

data 把perf.data文件轉換成其他格式diff讀取多個perf.data文件,並給出差異分析

evlist 列出perf.data中採集的事件列表

kmem 分析內核內存的使用kvm分析

kvm 虛擬機上的guest os

list 列出當前系統支持的所有事件名,可分為三類:硬件事件、軟件事件,檢查點

lock 分析內核中的鎖信息,包括鎖的爭用情況,等待延遲等

record 對程序運行過程中的事件進行分析和記錄,並寫入perf.data

report 讀取perf.data(由perf record生成) 並顯示分析結果

sched 針對調度器子系統的分析工具。

script 讀取perf.data(由perf record生成),生成trace記錄,供其他分析工具使用

stat 對程序運行過程中的性能計數器進行統計

test perf對當前軟硬件平臺進行健全性測試,可用此工具測試當前的軟硬件平臺是否能支持perf的所有功能。

timechart 對record結果進行可視化分析輸出,record命令需要加上timechart記錄

top 對系統的性能進行分析,類型top命令,當然可以對單個進程進行分析

probe 用於定義動態檢查點。

trace 類似於strace,跟蹤目標的系統調用,但開銷比strace小

perf的使用大體可以有三種方式:

  • Counting:統計的方式,統計事件發生的次數,這種方式不生成perf.data文件,例如perf stat, perf top
  • Sampling:採樣的方式,採樣事件,並寫入到內核buffer中,並異步寫入perf.data文件中,perf.data文件可以被perf report或者perf>
  • bpf programs on events(https://www.ibm.com/developerworks/cn/linux/l-lo-eBPF-history/index.html)

5.1. perf list

perf list命令可以列出當前perf可用的事件:

cpu-cycles OR cycles [Hardware event]
instructions [Hardware event]
cache-references [Hardware event]
cache-misses [Hardware event]
branch-instructions OR branches [Hardware event]
branch-misses [Hardware event]
bus-cycles [Hardware event]
stalled-cycles-frontend OR idle-cycles-frontend [Hardware event]
stalled-cycles-backend OR idle-cycles-backend [Hardware event]
ref-cycles [Hardware event]
alignment-faults [Software event]
bpf-output [Software event]
context-switches OR cs [Software event]
cpu-clock [Software event]
cpu-migrations OR migrations [Software event]
dummy [Software event]
emulation-faults [Software event]
major-faults [Software event]
minor-faults [Software event]
page-faults OR faults [Software event]
task-clock [Software event]
msr/tsc/ [Kernel PMU event]
rNNN [Raw hardware event descriptor]
cpu/t1=v1[,t2=v2,t3 ...]/modifier [Raw hardware event descriptor]
(see 'man perf-list' on how to encode it)
mem:<addr>[/len][:access] [Hardware breakpoint]
/<addr>

這些事件可以分為三類(在文章開始介紹perf工作原理的時候也說了):Hardware Event, Software event, Tracepoint event.

每個具體事件的含義在perf_event_open的man page中有說明:

  • cpu-cycles:統計cpu週期數,cpu週期:指一條指令的操作時間。
  • instructions: 機器指令數目
  • cache-references: cache命中次數
  • cache-misses: cache失效次數
  • branch-instructions: 分支預測成功次數
  • branch-misses: 分支預測失敗次數
  • alignment-faults: 統計內存對齊錯誤發生的次數, 當訪問的非對齊的內存地址時,內核會進行處理,已保存不會發生問題,但會降低性能
  • context-switches: 上下文切換次數,
  • cpu-clock: cpu clock的統計,每個cpu都有一個高精度定時器
  • task-clock :cpu clock中有task運行的統計
  • cpu-migrations:進程運行過程中從一個cpu遷移到另一cpu的次數
  • page-faults: 頁錯誤的統計
  • major-faults:頁錯誤,內存頁已經被swap到硬盤上,需要I/O換回
  • minor-faults :頁錯誤,內存頁在物理內存中,只是沒有和邏輯頁進行映射

5.2. perf stat

perf stat可以對程序運行過程中的性能計數器(包括Hardware,software counters)進行統計,分析程序的整體消耗情況:

$perf stat ls
Performance counter stats for 'ls':
2.164836 task-clock (msec) # 0.808 CPUs utilized
51 context-switches # 0.024 M/sec
4 cpu-migrations # 0.002 M/sec
333 page-faults # 0.154 M/sec
5506056 # 2.543 GHz
0 stalled-cycles-frontend # 0.00% frontend cycles idle
0 stalled-cycles-backend # 0.00% backend cycles idle
6100570 instructions # 1.11 insns per cycle
1298744 branches # 599.927 M/sec
18509 branch-misses # 1.43% of all branches
0.002679758 seconds time elapsed

具體各個字段的含義在perf list中已經列出了,這裡分析一下重要的數據:

  • task-clock (msec): cpu處理task所消耗的時間,單位ms,0.808 CPUs utilized的表示cpu使用率為80.8% = 2.164836 / 2.679758. 該值越高代表程序是CPU bound而非IO bound 類型。
  • instructions:執行的指令條數, insns per cycle: 即IPC,每個cpu週期執行的指令條數,1.11 = 6100570(instructions) / 5506056(cycles),IPC比上面的CPU使用率更能說明CPU的使用情況,關於IPC有一篇brendangregg的文章,很好的說明CPU使用率不是一個很好的性能分析指標
  • stalled-cycles-frontend和stalled-cycles-backend表示CPU停滯統計,具體可參考

perf stat可以加上-e選項來設置自己關心的事件統計,具體參數可以通過上面的perf list來查看

5.3. perf top

perf top類似系統的命令top,可以實時的查看當前系統各個進程的各個函數的性能計數分析:$sudo perf top

性能分析利器之perf淺析

perf top的和perf record的功能參數差不多,我們可以加上-e:來統計特定的event,-g: 開啟call-graph, -p:分析特定的進程

平常我們用的更多的是perf record,因為它可以將profiler的結果輸出到文件,然後通過perf report來進行分析,或者通過可視化工具進行分析和輸出。所以下面著重介紹perf record

5.4. perf record

perf reord可以運行一個命令,但更多的是對已運行的進程進行性能分析,並將分析結果輸出到perf.data(默認該文件名)中。不會像perf top一樣實時輸出分析結果。輸出perf.data可以通過perf report進行分析,或者通過perf>

$perf record -g -F 99 ./a.out
$perf report
性能分析利器之perf淺析

perf record幾個總要參數說明一下:

  • -F: 事件採樣的頻率, 單位HZ, 更高的頻率會獲得更細的統計,但會帶來更多的開銷
  • -g: 進行堆棧追蹤,生成調用關係圖,等價於–call-graph, 默認情況下,-g等同於–call-graph fp,即通過frame pointer來進行堆棧追蹤。 如果frame pointer被優化掉的話,可以通過dwarf, lbr進行堆棧追蹤
  • sleep: 採樣的時間

5.5. perf可視化分析

perf 提供了內置的可視化分析工具 perf timechart,例如:

$perf timechart record ./a.out
$perf timechart
性能分析利器之perf淺析

perf timechart輸出的是進程運行過程中系統調度的情況,無法對程序的具體代碼段進行性能分析,但可以看出總結運行情況:running,idle,I/O等,

Brendangregg寫了兩款對perf採樣結果進行可視化分析的開源工具:Flame Graphs和HeatMap. FlameGraphs即所謂的火焰圖,是大家使用比較多的工具,能清晰的展示程序各個函數的性能消耗。HeatMap可以從採樣數據中的延遲數據來進行消耗展示。

下面是對之前實例代碼的採樣數據perf.data進行FlameGraphs的繪製:

$perf/>
性能分析利器之perf淺析

perf_flamegraph.png

6. 參考

Perf官方wiki

https://perf.wiki.kernel.org/index.php/Main_Page

Perf 維基百科

https://en.wikipedia.org/wiki/Perf_(Linux)

Perf – Linux下的系統性能調優工具,第 1 部分

https://www.ibm.com/developerworks/cn/linux/l-cn-perf1/index.html

Linux 效能分析工具: Perf

http://wiki.csie.ncku.edu.tw/embedded/perf-tutorial

Linux內核調試技術——kprobe使用與實現

https://blog.csdn.net/luckyapple1028/article/details/52972315

內核uprobes使用介紹

https://blog.csdn.net/badu_123/article/details/8302642

perf Examples

http://www.brendangregg.com/perf.html

火焰圖的使用

http://www.brendangregg.com/flamegraphs.html

https://github.com/brendangregg/FlameGraph

頁錯誤

https://yq.aliyun.com/articles/55820

http://cwndmiao.github.io/programming%20tools/2013/11/26/Dwarf/


分享到:


相關文章: