Perf介紹
系統級性能優化通常包括兩個階段:性能剖析(performance profiling)和代碼優化。性能剖析的目標是尋找性能瓶頸,查找引發性能問題的原因及熱點代碼。代碼優化的目標是針對具體性能問題而優化代碼或編譯選項,以改善軟件性能。本篇主要講性能分析中常用的工具——perf。
perf是一款Linux性能分析工具。
它基於事件采樣原理,以性能事件為基礎,支持針對處理器相關性能指標與操作系統相關性能指標的性能剖析。常用於性能瓶頸的查找與熱點代碼的定位。
Linux性能計數器是一個新的基於內核的子系統,它提供一個性能分析框架,比如硬件(CPU、PMU(Performance Monitoring Unit))功能和軟件(軟件計數器、tracepoint)功能。通過perf,應用程序可以利用PMU、tracepoint和內核中的計數器來進行性能統計。它不但可以分析制定應用程序的性能問題(per thread),也可以用來分析內核的性能問題。
總之perf是一款很牛逼的綜合性分析工具,大到系統全局性性能,再小到進程線程級別,甚至到函數及匯編級別。
Perf基本原理
perf的基本原理都是對被監測對象進行采樣,最簡單的情形是根據 tick 中斷進行采樣,即在 tick 中斷內觸發采樣點,在采樣點里判斷程序當時的上下文。
事件分為以下三種:
1)Hardware Event 是由 PMU 硬件產生的事件,比如 cache 命中,當您需要了解程序對硬件特性的使用情況時,便需要對這些事件進行采樣;
2)Software Event 是內核軟件產生的事件,比如進程切換,tick 數等 ;
3)Tracepoint event 是內核中的靜態 tracepoint 所觸發的事件,這些 tracepoint 用來判斷程序運行期間內核的行為細節,比如 slab 分配器的分配次數等。
CPU周期(cpu-cycles)是默認的性能事件,所謂的CPU周期是指CPU所能識別的最小時間單元,通常為億分之幾秒,是CPU執行最簡單的指令時所需要的時間,例如讀取寄存器中的內容,也叫做clock tick。
Perf使用
Perf是一個包含23種子工具的工具集序號 | 命令 | 作用 |
1 | annotate | 解析perf record生成的perf.data文件,顯示被注釋的代碼。 |
2 | archive | 根據數據文件記錄的build-id,將所有被采樣到的elf文件打包。利用此壓縮包,可以再任何機器上分析數據文件中記錄的采樣數據。 |
3 | bench | perf中內置的benchmark,目前包括兩套針對調度器和內存管理子系統的benchmark。 |
4 | buildid-cache | 管理perf的buildid緩存,每個elf文件都有一個獨一無二的buildid。buildid被perf用來關聯性能數據與elf文件。 |
5 | buildid-list | 列出數據文件中記錄的所有buildid。 |
6 | diff | 對比兩個數據文件的差異。能夠給出每個符號(函數)在熱點分析上的具體差異。 |
7 | evlist | 列出數據文件perf.data中所有性能事件。 |
8 | inject | 該工具讀取perf record工具記錄的事件流,並將其定向到標准輸出。在被分析代碼中的任何一點,都可以向事件流中注入其它事件。 |
9 | kmem | 針對內核內存(slab)子系統進行追蹤測量的工具 |
10 | kvm | 用來追蹤測試運行在KVM虛擬機上的Guest OS。 |
11 | list | 列出當前系統支持的所有性能事件。包括硬件性能事件、軟件性能事件以及檢查點。 |
12 | lock | 分析內核中的鎖信息,包括鎖的爭用情況,等待延遲等。 |
13 | mem | 內存存取情況 |
14 | record | 收集采樣信息,並將其記錄在數據文件中。隨后可通過其它工具對數據文件進行分析。 |
15 | report | 讀取perf record創建的數據文件,並給出熱點分析結果。 |
16 | sched | 針對調度器子系統的分析工具。 |
17 | 執行perl或python寫的功能擴展腳本、生成腳本框架、讀取數據文件中的數據信息等。 | |
18 | stat | 執行某個命令,收集特定進程的性能概況,包括CPI、Cache丟失率等。 |
19 | test | perf對當前軟硬件平台進行健全性測試,可用此工具測試當前的軟硬件平台是否能支持perf的所有功能。 |
20 | timechart | 針對測試期間系統行為進行可視化的工具 |
21 | top | 類似於linux的top命令,對系統性能進行實時分析。 |
22 | trace | 關於syscall的工具。 |
23 | probe | 用於定義動態檢查點。 |
全局性概況:
perf list查看當前系統支持的性能事件;
perf bench對系統性能進行摸底;
perf test對系統進行健全性測試;
perf stat對全局性能進行統計;
全局細節:
perf top可以實時查看當前系統進程函數占用率情況;
perf probe可以自定義動態事件;
特定功能分析:
perf kmem針對slab子系統性能分析;
perf kvm針對kvm虛擬化分析;
perf lock分析鎖性能;
perf mem分析內存slab性能;
perf sched分析內核調度器性能;
perf trace記錄系統調用軌跡;
最常用功能perf record,可以系統全局,也可以具體到某個進程,更甚具體到某一進程某一事件;可宏觀,也可以很微觀。
pref record記錄信息到perf.data;
perf report生成報告;
perf diff對兩個記錄進行diff;
perf evlist列出記錄的性能事件;
perf annotate顯示perf.data函數代碼;
perf archive將相關符號打包,方便在其它機器進行分析;
perf 將perf.data輸出可讀性文本;
可視化工具perf timechart
perf timechart record記錄事件;
perf timechart生成output.svg文檔;
以下是最常用的5種
perf top 類似系統命令 查看消耗cpu比較高的內核函數或者進程
對於一個指定的性能事件(默認是CPU周期),顯示消耗最多的函數或指令。
System profiling tool.
Generates and displays a performance counter profile in real time.
perf top [-e | --event=EVENT] []
perf top主要用於實時分析各個函數在某個性能事件上的熱度,能夠快速的定位熱點函數,包括應用程序函數、
模塊函數與內核函數,甚至能夠定位到熱點指令。默認的性能事件為cpu cycles。
使用例子
1、實時顯示占用 CPU 時鍾最多的函數或者指令(可以用來查找熱點函數)
$ perf top Samples: 833 of event 'cpu-clock', Event count (approx.): 97742399 Overhead Shared Object Symbol 7.28% perf [.] 0x00000000001f78a4 4.72% [kernel] [k] vsnprintf 4.32% [kernel] [k] module_get_kallsym 3.65% [kernel] [k] _raw_spin_unlock_irqrestore ...
輸出結果中,第一行包含三個數據,
- 分別是采樣數(Samples)
- 事件類型(event)
- 事件總數量(Event count)。
比如這個例子中,perf 總共采集了 833 個 CPU 時鍾事件,而總事件數則為 97742399。
- 第一列 Overhead ,是該符號的性能事件在所有采樣中的比例,用百分比來表示。
- 第二列 Shared ,是該函數或指令所在的動態共享對象(Dynamic Shared Object),如內核、進程名、動態鏈接庫名、內核模塊名等。
- 第三列 Object ,是動態共享對象的類型。比如 [.] 表示用戶空間的可執行程序、或者動態鏈接庫,而 [k] 則表示內核空間。
- 最后一列 Symbol 是符號名,也就是函數名。當函數名未知時,用十六進制的地址來表示。
2、-g開啟調用關系分析,-p指定的進程號21515
# perf top -g -p 21515
注意:使用方向鍵切換進程,再按下回車鍵展開某個進程的調用關系。
perf list 列出perf支持的事件
Perf ist用來查看perf所支持的性能事件,有軟件的也有硬件的。
List all symbolic event types.
perf list [hw | sw | cache | tracepoint | event_glob]
性能事件的分布
hw:Hardware event,9個
sw:Software event,9個
cache:Hardware cache event,26個
tracepoint:Tracepoint event,775個
sw實際上是內核的計數器,與硬件無關。
hw和cache是CPU架構相關的,依賴於具體硬件。
tracepoint是基於內核的ftrace,主線2.6.3x以上的內核版本才支持。
指定性能事件(以它的屬性)
-e : u // userspace
-e : k // kernel
-e : h // hypervisor
-e : G // guest counting (in KVM guests)
-e : H // host counting (not in KVM guests)
使用例子
1、顯示內核和模塊中,消耗最多CPU周期的函數:
# perf top -e cycles:k
2、顯示分配高速緩存最多的函數:
# perf top -e kmem:kmem_cache_alloc
perf stat 統計profiling進程的各種信息
用於分析指定程序的性能概況。
Run a command and gather performance counter statistics.
perf stat [-e | --event=EVENT] [-a]
perf stat [-e | --event=EVENT] [-a] - []
輸出格式
# perf stat ls
輸出包括ls的執行時間,以及10個性能事件的統計。
task-clock:任務真正占用的處理器時間,單位為ms。CPUs utilized = task-clock / time elapsed,CPU的占用率。
context-switches:上下文的切換次數。
CPU-migrations:處理器遷移次數。Linux為了維持多個處理器的負載均衡,在特定條件下會將某個任務從一個CPU
遷移到另一個CPU。
page-faults:缺頁異常的次數。當應用程序請求的頁面尚未建立、請求的頁面不在內存中,或者請求的頁面雖然在內
存中,但物理地址和虛擬地址的映射關系尚未建立時,都會觸發一次缺頁異常。另外TLB不命中,頁面訪問權限不匹配
等情況也會觸發缺頁異常。
cycles:消耗的處理器周期數。如果把被ls使用的cpu cycles看成是一個處理器的
可以用cycles / task-clock算出。
stalled-cycles-frontend:略過。
stalled-cycles-backend:略過。
instructions:執行了多少條指令。IPC為平均每個cpu cycle執行了多少條指令。
branches:遇到的分支指令數。branch-misses是預測錯誤的分支指令數。
常用參數
-p:stat events on existing process id (comma separated list). 僅分析目標進程及其創建的線程。
-a:system-wide collection from all CPUs. 從所有CPU上收集性能數據。
-r:repeat command and print average + stddev (max: 100). 重復執行命令求平均。
-C:Count only on the list of CPUs provided (comma separated list), 從指定CPU上收集性能數據。
-v:be more verbose (show counter open errors, etc), 顯示更多性能數據。
-n:null run - don't start any counters,只顯示任務的執行時間 。
-x SEP:指定輸出列的分隔符。
-o file:指定輸出文件,--append指定追加模式。
--pre :執行目標程序前先執行的程序。
--post :執行目標程序后再執行的程序。
使用例子
1、執行10次程序,給出標准偏差與期望的比值:
# perf stat -r 10 ls > /dev/null
2、顯示更詳細的信息:
# perf stat -v ls > /dev/null
3、只顯示任務執行時間,不顯示性能計數器:
# perf stat -n ls > /dev/null
4、單獨給出每個CPU上的信息:
# perf stat -a -A ls > /dev/null
5、ls命令執行了多少次系統調用:
# perf stat -e syscalls:sys_enter ls
perf record profiling進程的數據,並生成 xx.data文件(默認在執行命令的路徑下)
收集采樣信息,並將其記錄在數據文件中。
隨后可以通過其它工具(perf-report)對數據文件進行分析,結果類似於perf-top的。
常用參數
-e:Select the PMU event.
-a:System-wide collection from all CPUs.
-p:Record events on existing process ID (comma separated list).
-A:Append to the output file to do incremental profiling.
-f:Overwrite existing data file.
-o:Output file name.
-g:Do call-graph (stack chain/backtrace) recording.
-C:Collect samples only on the list of CPUs provided.
使用例子
1、記錄性能事件,等待大約15秒后按 Ctrl+C 退出
# perf record -g
2、記錄nginx進程的性能數據:
# perf record -p `pgrep -d ',' nginx`
3、記錄執行ls時的性能數據:
# perf record ls -g
4、記錄執行ls時的系統調用,可以知道哪些系統調用最頻繁:
# perf record -e syscalls:sys_enter ls
perf report 讀取xx.data文件
perf record -e cpu-clock -g -p 4522
使用ctrl+c中斷perf進程,或者在程序執行結束后,會產生perf.data的文件,使用report會產生結果分析,如圖perf report
上面通過文件查看不夠直觀,還有一種火焰圖分析的方式:
工具下載:git clone https://github.com/brendangregg/FlameGraph.git
使用命令:
使用perf script工具對perf.data進行解析perf script -i perf.data &> perf.unfold
將perf.unfold中的符號進行折疊:/data/stackcollapse-perf.pl perf.unfold &> perf.folded
最后生成svg圖:/data/flamegraph.pl perf.folded > perf.svg
然后可以通過chrome或者看圖軟件打開:
Y軸表示調用棧,X軸越寬,就表示它被抽到的次數多,即執行的時間長。注意,x 軸不代表時間,而是所有的調用棧合並后,按字母順序排列的。
所以,一般我們只需要看有沒有出現 “平頂”,如果有,那么這個函數可能有性能問題。