簡(jiǎn)介
perf是linux上的性能分析工具,perf可以對(duì)event進(jìn)行統(tǒng)計(jì)得到event的發(fā)生次數(shù),或者對(duì)event進(jìn)行采樣,得到每次event發(fā)生時(shí)的相關(guān)數(shù)據(jù)(cpu、進(jìn)程id、運(yùn)行棧等),利用這些數(shù)據(jù)來對(duì)程序性能進(jìn)行分析。
perf可以統(tǒng)計(jì)或采樣的event有很多,如果我們要分析cpu,那么我們可以使用cpu-cycles、cpu-clock來衡量占用cpu的程序的分布情況,還可以通過cache-misses、page-faults、branch-misses等event來分析造成cpu占用高的底層原因,確定原因后方便優(yōu)化。
如果我們要分析內(nèi)存、io、網(wǎng)絡(luò)等,也可以通過其他event來進(jìn)行分析,perf可以使用的event非常多,如果要使用perf來分析問題,就需要了解問題相關(guān)的event有哪些,作用是什么,這是使用perf的一個(gè)門檻。
perf工作大致可以分成三種模式:
-
counter 計(jì)數(shù)模式,記錄perf執(zhí)行過程中,統(tǒng)計(jì)的目標(biāo)程序或者整個(gè)系統(tǒng)范圍內(nèi),event的出現(xiàn)次數(shù)。
-
sampling 采樣模式,按照指定頻率去采樣event,記錄每次采樣時(shí),采樣事件輸出的信息(cpu、進(jìn)程id、運(yùn)行棧等)。這種方式由于每次都記錄信息,所以額外的資源消耗是比較大的,需要權(quán)衡一下采樣頻率。同時(shí)產(chǎn)生的數(shù)據(jù)量也容易很大,可能需要大量的硬盤空間。
-
bpf 可以對(duì)對(duì)應(yīng)的event執(zhí)行用戶自己設(shè)計(jì)的代碼,也就是說記錄的信息、執(zhí)行的操作可以由用戶定制
perf可以使用的event非常多,上圖是Brendan Gregg的文章中找到的一張圖,畫出了perf可以使用的event的結(jié)構(gòu)圖,大致可以分為以下幾類:
-
Hardware Events: CPU的PMU(performance monitoring unit)觸發(fā)的事件,也叫performance monitoring counters (PMCs),例如cpu-cycles、cache miss
-
Software Events: 一些比較底層的軟件event,例如缺頁、timer(定時(shí))
-
Kernel Tracepoint Events: 內(nèi)核中的tracepoint
-
User Statically-Defined Tracing (USDT): 用戶態(tài)的tracepoint
-
Dynamic Tracing: 動(dòng)態(tài)設(shè)置的event,例如使用內(nèi)核的kprobe,可以在大部分函數(shù)動(dòng)態(tài)增加event
-
Timed Profiling: 定時(shí)event
安裝
x86安裝
sudo apt install linux-tools-common
sudo apt install linux-tools-generic
sudo apt install linux-tools-5.4.0-137-generic
交叉編譯
由于我們經(jīng)常是在自己編譯的內(nèi)核上進(jìn)行開發(fā)工作,進(jìn)入linux內(nèi)核源碼目錄linux/tools/perf。
? tools git:(firefly) ? make CROSS_COMPILE=/home/zhongyi/code/rk3399_linux_release_v2.5.1_20210301/prebuilts/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- ARCH=arm WERROR=0 perf V=1
可能在編譯的時(shí)候,有報(bào)錯(cuò)大概是由于平臺(tái)問題,數(shù)據(jù)類型不匹配,導(dǎo)致所有的warning都被當(dāng)作error對(duì)待:出現(xiàn)這問題的原因是-Werror這個(gè)gcc編譯選項(xiàng)。只要在makefile中找到包含這個(gè)-Werror選項(xiàng)的句子,將-Werror刪除,或是注釋掉就行了
編譯完成后將會(huì)在當(dāng)前目錄下生成perf可執(zhí)行文件,拷貝到設(shè)備上即可運(yùn)行。
root@firefly:~/mnt# ./perf --help
usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS]
The most commonly used perf commands are:
annotate Read perf.data (created by perf record) and display annotated code
archive Create archive with object files with build-ids found in perf.data file
bench General framework for benchmark suites
buildid-cache Manage build-id cache.
buildid-list List the buildids in a perf.data file
data Data file related processing
diff Read perf.data files and display the differential profile
evlist List the event names in a perf.data file
inject Filter to augment the events stream with additional information
kmem Tool to trace/measure kernel memory properties
kvm Tool to trace/measure kvm guest os
list List all symbolic event types
lock Analyze lock events
mem Profile memory accesses
record Run a command and record its profile into perf.data
report Read perf.data (created by perf record) and display the profile
sched Tool to trace/measure scheduler properties (latencies)
script Read perf.data (created by perf record) and display trace output
stat Run a command and gather performance counter statistics
test Runs sanity tests.
timechart Tool to visualize total system behavior during a workload
top System profiling tool.
trace strace inspired tool
See 'perf help COMMAND' for more information on a specific command.
需要C/C++ Linux服務(wù)器架構(gòu)師學(xué)習(xí)資料加qun579733396獲取(資料包括C/C++,Linux,golang技術(shù),Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協(xié)程,DPDK,ffmpeg等),免費(fèi)分享
使用方法
總覽
上圖整理了perf的子命令之間的關(guān)系,常用的有:
-
perf record —— 采樣,生成perf.data二進(jìn)制文件
-
perf annotate/perf report/perf script —— 分析perf.data文件,annotate可以查看代碼,report可以統(tǒng)計(jì)分析,script是直接轉(zhuǎn)化成文本格式
-
perf stat —— counter,統(tǒng)計(jì)event的出現(xiàn)次數(shù)
-
perf top —— 整個(gè)系統(tǒng)的分析,類似于top命令,但可以具體到函數(shù),可以指定event
下面我們介紹一些常用的使用方法。
help
perf --help之后可以看到perf的一級(jí)命令。
root@firefly:~/mnt# ./perf --help
usage: perf [--version] [--help] [OPTIONS] COMMAND [ARGS]
The most commonly used perf commands are:
annotate Read perf.data (created by perf record) and display annotated code
archive Create archive with object files with build-ids found in perf.data file
bench General framework for benchmark suites
buildid-cache Manage build-id cache.
buildid-list List the buildids in a perf.data file
data Data file related processing
diff Read perf.data files and display the differential profile
evlist List the event names in a perf.data file
inject Filter to augment the events stream with additional information
kmem Tool to trace/measure kernel memory properties
kvm Tool to trace/measure kvm guest os
list List all symbolic event types
lock Analyze lock events
mem Profile memory accesses
record Run a command and record its profile into perf.data
report Read perf.data (created by perf record) and display the profile
sched Tool to trace/measure scheduler properties (latencies)
script Read perf.data (created by perf record) and display trace output
stat Run a command and gather performance counter statistics
test Runs sanity tests.
timechart Tool to visualize total system behavior during a workload
top System profiling tool.
trace strace inspired tool
See 'perf help COMMAND' for more information on a specific command.
perf command --help 可以看到二級(jí)命令的幫助命令。
root@firefly:~/mnt# ./perf stat -h
Usage: perf stat [<options>] [<command>]
-a, --all-cpus system-wide collection from all CPUs
-A, --no-aggr disable CPU count aggregation
-B, --big-num print large numbers with thousands' separators
-C, --cpu <cpu> list of cpus to monitor in system-wide
-c, --scale scale/normalize counters
-D, --delay <n> ms to wait before starting measurement after program s
-d, --detailed detailed run - start a lot of events
-e, --event <event> event selector. use 'perf list' to list available even
-G, --cgroup <name> monitor event in cgroup name only
-g, --group put the counters into a counter group
-I, --interval-print <n>
print counts at regular interval in ms (>= 10)
-i, --no-inherit child tasks do not inherit counters
-n, --null null run - dont start any counters
-o, --output <file> output file name
-p, --pid <pid> stat events on existing process id
-r, --repeat <n> repeat command and print average + stddev (max: 100, f
-S, --sync call sync() before starting a run
-t, --tid <tid> stat events on existing thread id
-T, --transaction hardware transaction statistics
下面對(duì)一級(jí)命令作一個(gè)解釋
序號(hào) |
命令 |
作用 |
---|---|---|
1 |
annotate |
解析perf record生成的perf.data文件,顯示被注釋的代碼。 |
2 |
archive |
根據(jù)數(shù)據(jù)文件記錄的build-id,將所有被采樣到的elf文件打包。利用此壓縮包,可以再任何機(jī)器上分析數(shù)據(jù)文件中記錄的采樣數(shù)據(jù)。 |
3 |
bench |
perf中內(nèi)置的benchmark,目前包括兩套針對(duì)調(diào)度器和內(nèi)存管理子系統(tǒng)的benchmark。 |
4 |
buildid-cache |
管理perf的buildid緩存,每個(gè)elf文件都有一個(gè)獨(dú)一無二的buildid。buildid被perf用來關(guān)聯(lián)性能數(shù)據(jù)與elf文件。 |
5 |
buildid-list |
列出數(shù)據(jù)文件中記錄的所有buildid。 |
6 |
diff |
對(duì)比兩個(gè)數(shù)據(jù)文件的差異。能夠給出每個(gè)符號(hào)(函數(shù))在熱點(diǎn)分析上的具體差異。 |
7 |
evlist |
列出數(shù)據(jù)文件perf.data中所有性能事件。 |
8 |
inject |
該工具讀取perf record工具記錄的事件流,并將其定向到標(biāo)準(zhǔn)輸出。在被分析代碼中的任何一點(diǎn),都可以向事件流中注入其它事件。 |
9 |
kmem |
針對(duì)內(nèi)核內(nèi)存(slab)子系統(tǒng)進(jìn)行追蹤測(cè)量的工具 |
10 |
kvm |
用來追蹤測(cè)試運(yùn)行在KVM虛擬機(jī)上的Guest OS。 |
11 |
list |
列出當(dāng)前系統(tǒng)支持的所有性能事件。包括硬件性能事件、軟件性能事件以及檢查點(diǎn)。 |
12 |
lock |
分析內(nèi)核中的鎖信息,包括鎖的爭(zhēng)用情況,等待延遲等。 |
13 |
mem |
內(nèi)存存取情況 |
14 |
record |
收集采樣信息,并將其記錄在數(shù)據(jù)文件中。隨后可通過其它工具對(duì)數(shù)據(jù)文件進(jìn)行分析。 |
15 |
report |
讀取perf record創(chuàng)建的數(shù)據(jù)文件,并給出熱點(diǎn)分析結(jié)果。 |
16 |
sched |
針對(duì)調(diào)度器子系統(tǒng)的分析工具。 |
17 |
script |
執(zhí)行perl或python寫的功能擴(kuò)展腳本、生成腳本框架、讀取數(shù)據(jù)文件中的數(shù)據(jù)信息等。 |
18 |
stat |
執(zhí)行某個(gè)命令,收集特定進(jìn)程的性能概況,包括CPI、Cache丟失率等。 |
19 |
test |
perf對(duì)當(dāng)前軟硬件平臺(tái)進(jìn)行健全性測(cè)試,可用此工具測(cè)試當(dāng)前的軟硬件平臺(tái)是否能支持perf的所有功能。 |
20 |
timechart |
針對(duì)測(cè)試期間系統(tǒng)行為進(jìn)行可視化的工具 |
21 |
top |
類似于linux的top命令,對(duì)系統(tǒng)性能進(jìn)行實(shí)時(shí)分析。 |
22 |
trace |
關(guān)于syscall的工具。 |
23 |
probe |
用于定義動(dòng)態(tài)檢查點(diǎn)。 |
全局性概況:
perf list查看當(dāng)前系統(tǒng)支持的性能事件; perf bench對(duì)系統(tǒng)性能進(jìn)行摸底; perf test對(duì)系統(tǒng)進(jìn)行健全性測(cè)試; perf stat對(duì)全局性能進(jìn)行統(tǒng)計(jì);
全局細(xì)節(jié):
perf top可以實(shí)時(shí)查看當(dāng)前系統(tǒng)進(jìn)程函數(shù)占用率情況; perf probe可以自定義動(dòng)態(tài)事件;
特定功能分析:
perf kmem針對(duì)slab子系統(tǒng)性能分析; perf kvm針對(duì)kvm虛擬化分析; perf lock分析鎖性能; perf mem分析內(nèi)存slab性能; perf sched分析內(nèi)核調(diào)度器性能; perf trace記錄系統(tǒng)調(diào)用軌跡;
最常用功能perf record,可以系統(tǒng)全局,也可以具體到某個(gè)進(jìn)程,更甚具體到某一進(jìn)程某一事件;可宏觀,也可以很微觀。
pref record記錄信息到perf.data; perf report生成報(bào)告; perf diff對(duì)兩個(gè)記錄進(jìn)行diff; perf evlist列出記錄的性能事件; perf annotate顯示perf.data函數(shù)代碼; perf archive將相關(guān)符號(hào)打包,方便在其它機(jī)器進(jìn)行分析; perf script將perf.data輸出可讀性文本;
可視化工具perf timechart
perf timechart record記錄事件; perf timechart生成output.svg文檔;
list
使用perf之前肯定要知道perf能監(jiān)控哪些性能指標(biāo)吧?那么就要使用perf list進(jìn)行查看,通常使用的指標(biāo)是cpu-clock/task-clock等,具體要根據(jù)需要來判斷。
root@firefly:~/mnt# perf list
List of pre-defined events (to be used in -e):
rNNN [Raw hardware event descrip
cpu/t1=v1[,t2=v2,t3 ...]/modifier [Raw hardware event descrip
(see 'man perf-list' on how to encode it)
mem:<addr>[/len][:access] [Hardware breakpoint]
android_fs:android_fs_dataread_end [Tracepoint event]
android_fs:android_fs_dataread_start [Tracepoint event]
android_fs:android_fs_datawrite_end [Tracepoint event]
android_fs:android_fs_datawrite_start [Tracepoint event]
asoc:snd_soc_bias_level_done [Tracepoint event]
asoc:snd_soc_bias_level_start [Tracepoint event]
asoc:snd_soc_dapm_connected [Tracepoint event]
asoc:snd_soc_dapm_done [Tracepoint event]
asoc:snd_soc_dapm_path [Tracepoint event]
asoc:snd_soc_dapm_start [Tracepoint event]
asoc:snd_soc_dapm_walk_done [Tracepoint event]
asoc:snd_soc_dapm_widget_event_done [Tracepoint event]
asoc:snd_soc_dapm_widget_event_start [Tracepoint event]
asoc:snd_soc_dapm_widget_power [Tracepoint event]
asoc:snd_soc_jack_irq [Tracepoint event]
asoc:snd_soc_jack_notify [Tracepoint event]
asoc:snd_soc_jack_report [Tracepoint event]
block:block_bio_backmerge [Tracepoint event]
block:block_bio_bounce [Tracepoint event]
block:block_bio_complete [Tracepoint event]
block:block_bio_frontmerge [Tracepoint event]
block:block_bio_queue [Tracepoint event]
block:block_bio_remap [Tracepoint event]
block:block_dirty_buffer [Tracepoint event]
block:block_getrq [Tracepoint event]
......
具體監(jiān)控哪個(gè)變量的話,譬如使用后面的perf report工具,則加**-e 監(jiān)控指標(biāo)**,如監(jiān)控運(yùn)行l(wèi)s命令時(shí)的cpu時(shí)鐘占用:
perf report -e cpu-clock ls
event
不同內(nèi)核版本列出的結(jié)果不一樣多。不過基本是夠用的,但是無論多少,我們可以基本將其分為三類
-
一些事件只是單純的內(nèi)核計(jì)數(shù)器,這種情況下,他們被稱為software events。例如,上下文切換。
-
事件的另一個(gè)來源是處理器本身及其性能監(jiān)控單元(Performance Monitoring Unit,PMU)。它提供了一個(gè)事件列表來衡量微架構(gòu)事件,如周期數(shù)、指令異常、L1緩存未命中等。這些事件被稱為PMU硬件事件( PMU hardware events)或簡(jiǎn)稱為硬件事件(hardware events)。這些事件因每種處理器類型和型號(hào)而異。 perf_events接口還提供了一小組常見的硬件事件名字對(duì)象。在每個(gè)處理器上,這些事件被映射到CPU提供的實(shí)際事件上,只有映射成立即實(shí)際事件存在時(shí),這些事件才能被使用。這些事件也被稱為硬件事件(hardware events)和硬件緩存事件( hardware cache events)。
-
還有一些 tracepoint events 是依賴于ftrace架構(gòu)實(shí)現(xiàn)的,這些只有在2.6.3x以上的內(nèi)核才可以使用。
一個(gè)事件可以有子事件(或 unit masks)。在某些處理器上,對(duì)于某些事件,可以將 unit masks組合 使用并測(cè)量任一子事件發(fā)生的時(shí)間。
/sys/kernel/debug/tracing/available_events,可查看當(dāng)前系統(tǒng)的所有tracepoint分成了幾大類:
ext4:文件系統(tǒng)的tracepoint events,如果是其它文件系統(tǒng),比如XFS,也有對(duì)應(yīng)的tracepoint event;
jbd2 :文件日志的tracepoint events;
skb: 內(nèi)存的tracepoint events;
net,napi,sock,udp:網(wǎng)絡(luò)的tracepoint events;
scsi, block, writeback:磁盤IO
kmem:內(nèi)存
sched: 調(diào)度
syscalls: 系統(tǒng)調(diào)用
屬性
用戶如果想要使用高精度采樣,需要在指定性能事件時(shí),在事件名后添加后綴:p或:pp。Perf在采樣精度上定義了4個(gè)級(jí)別,如下所示。
0 :無精度保證
1 :采樣指令與觸發(fā)性能事件的指令之間的偏差為常數(shù)(:p)
2 :需要盡量保證采樣指令與觸發(fā)性能事件的指令之間的偏差為0(:pp)
3 :保證采樣指令與觸發(fā)性能事件的指令之間的偏差必須為0(:ppp)
目前的X86處理器,包括Intel處理器與AMD處理器均僅能實(shí)現(xiàn)前 3 個(gè)精度級(jí)別。
除了精度級(jí)別以外,性能事件還具有其它幾個(gè)屬性,均可以通過event:X的方式予以指定。
u 僅統(tǒng)計(jì)用戶空間程序觸發(fā)的性能事件
k 僅統(tǒng)計(jì)內(nèi)核觸發(fā)的性能事件
h 僅統(tǒng)計(jì)Hypervisor觸發(fā)的性能事件
G 在KVM虛擬機(jī)中,僅統(tǒng)計(jì)Guest系統(tǒng)觸發(fā)的性能事件
H 僅統(tǒng)計(jì) Host 系統(tǒng)觸發(fā)的性能事件
p 精度級(jí)別
stat
perf stat 分析系統(tǒng)/進(jìn)程的整體性能概況。
命令解析
-a, --all-cpus 采集所有CPU的信息
-A, --no-aggr 不要在system-wide(-a)模式下匯集所有CPU的計(jì)數(shù)信息
-B, --big-num 保留三位小數(shù)
-C, --cpu <cpu> 指定某個(gè)cpu
-D, --delay <n> 在測(cè)試程序開始后,在測(cè)量前等等 n ms
-d, --detailed 打印更詳細(xì)的統(tǒng)計(jì)數(shù)據(jù),最多可以指定3次
-d: detailed events, L1 and LLC data cache
-d -d: more detailed events, dTLB and iTLB events
-d -d -d: very detailed events, adding prefetch events
-e, --event <event> 事件選擇。可以參考perf list。
-G, --cgroup <name> 僅在name為cgroup時(shí)有效。
-g, --group 將計(jì)數(shù)器放到一個(gè)計(jì)數(shù)組中
-I, --interval-print <n> 每n毫秒打印計(jì)數(shù)增量(最小值:10ms).在某些情況下,開銷可能很高,例如小于100毫秒的間隔。
-i, --no-inherit 禁止子任務(wù)繼承父任務(wù)的性能計(jì)數(shù)器。
-M, --metrics <metric/metric group list> 監(jiān)視指定的 metrics 或 metric groups,以逗號(hào)分隔。
-n, --null 僅輸出目標(biāo)程序的執(zhí)行時(shí)間,而不開啟任何性能計(jì)數(shù)器。
-o, --output <file> 輸出文件的名字
-p, --pid <pid> 指定待分析的進(jìn)程id
-r, --repeat <n> 重復(fù)執(zhí)行 n 次目標(biāo)程序,并給出性能指標(biāo)在n 次執(zhí)行中的變化范圍。
-S, --sync 在開始前調(diào)用sync()
-t, --tid <tid> 指定待分析的線程id
-T, --transaction 如果支持,打印事務(wù)執(zhí)行的統(tǒng)計(jì)數(shù)據(jù)。
-v, --verbose 顯示詳細(xì)信息
-x, --field-separator <separator> 使用CSV樣式的輸出打印計(jì)數(shù),以便直接導(dǎo)入表格。列由SEP中指定的字符串分隔。
舉例
ubuntu# perf stat -B dd if=/dev/zero of=/dev/null count=1000000
1000000+0 records in
1000000+0 records out
512000000 bytes (512 MB, 488 MiB) copied, 0.868718 s, 589 MB/s
Performance counter stats for 'dd if=/dev/zero of=/dev/null count=1000000':
869.31 msec task-clock # 0.999 CPUs utilized
2 context-switches # 0.002 K/sec
0 cpu-migrations # 0.000 K/sec
71 page-faults # 0.082 K/sec
<not supported> cycles
<not supported> instructions
<not supported> branches
<not supported> branch-misses
0.870022180 seconds time elapsed
0.450870000 seconds user
0.418950000 seconds sys
如果沒有指定那個(gè)事件,perf stat將收集上面列出的常見事件。比如,上下文切換,CPU遷移次數(shù),缺頁故障等。
-
task‐clock:事件表示目標(biāo)任務(wù)真正占用處理器的時(shí)間,單位是毫秒。也稱任務(wù)執(zhí)行時(shí)間。CPUs utilized = task-clock / time elapsed,CPU的占用率。
-
context-switches:程序在運(yùn)行過程中上下文的切換次數(shù)。
-
CPU-migrations:程序在運(yùn)行過程中發(fā)生的處理器遷移次數(shù)。Linux為了維持多個(gè)處理器的負(fù)載均衡,在特定條件下會(huì)將某個(gè)任務(wù)從一個(gè)CPU遷移到另一個(gè)CPU。
-
CPU遷移和上下文切換:發(fā)生上下文切換不一定會(huì)發(fā)生CPU遷移,而發(fā)生CPU遷移時(shí)肯定會(huì)發(fā)生上下文切換。發(fā)生上下文切換有可能只是把上下文從當(dāng)前CPU中換出,下一次調(diào)度器還是將進(jìn)程安排在這個(gè)CPU上執(zhí)行。
-
page-faults:缺頁異常的次數(shù)。當(dāng)應(yīng)用程序請(qǐng)求的頁面尚未建立、請(qǐng)求的頁面不在內(nèi)存中,或者請(qǐng)求的頁面雖然在內(nèi)存中,但物理地址和虛擬地址的映射關(guān)系尚未建立時(shí),都會(huì)觸發(fā)一次缺頁異常。另外TLB不命中,頁面訪問權(quán)限不匹配等情況也會(huì)觸發(fā)缺頁異常。
-
cycles:消耗的處理器周期數(shù)。如果把被ls使用的cpu cycles看成是一個(gè)處理器的,那么它的主頻為2.486GHz??梢杂胏ycles / task-clock算出。
-
stalled-cycles-frontend:指令讀取或解碼的質(zhì)量步驟,未能按理想狀態(tài)發(fā)揮并行左右,發(fā)生停滯的時(shí)鐘周期。
-
stalled-cycles-backend:指令執(zhí)行步驟,發(fā)生停滯的時(shí)鐘周期。
-
instructions:執(zhí)行了多少條指令。IPC為平均每個(gè)cpu cycle執(zhí)行了多少條指令。
-
branches:遇到的分支指令數(shù)。branch-misses是預(yù)測(cè)錯(cuò)誤的分支指令數(shù)。
-
branch‐misses:是預(yù)測(cè)錯(cuò)誤的分支指令數(shù)。
-
XXX seconds time elapsed:系程序持續(xù)時(shí)間
每次運(yùn)行性能工具時(shí),可以測(cè)量一個(gè)或多個(gè)事件。事件使用其符號(hào)名稱,后跟可選的單元掩碼和修飾符來指定。事件名稱、單元掩碼和修飾符不區(qū)分大小寫。
perf stat -e cpu-clock dd if=/dev/zero of=/dev/null count=100000
默認(rèn)情況下,會(huì)在用戶和內(nèi)核級(jí)別測(cè)量事件。如果僅在用戶級(jí)別進(jìn)行測(cè)量,需要傳遞一個(gè)修飾符:
perf stat -e cpu-clock:u dd if=/dev/zero of=/dev/null count=100000
如果即在用戶態(tài)測(cè)量,又在內(nèi)核態(tài)測(cè)量,則可以同時(shí)傳遞uk參數(shù)
perf stat -e cpu-clock:uk dd if=/dev/zero of=/dev/null count=100000
ls命令執(zhí)行了多少次系統(tǒng)調(diào)用
perf stat -e syscalls:sys_enter_exit ls
只顯示任務(wù)執(zhí)行時(shí)間,不顯示性能計(jì)數(shù)器
perf stat -n ls > /dev/null
record
記錄一段時(shí)間內(nèi)系統(tǒng)/進(jìn)程的性能時(shí)間。
命令解析
-a, --all-cpus system-wide collection from all CPUs
-b, --branch-any sample any taken branches
-B, --no-buildid do not collect buildids in perf.data
-c, --count <n> 事件的采樣周期
-C, --cpu <cpu> 只采集指定CPU數(shù)據(jù)
-d, --data 記錄采樣地址
-D, --delay <n> 在測(cè)試程序開始后,在測(cè)量前等等 n ms
-F 指定采樣頻率
-e, --event <event> 選擇性能事件
-F, --freq <freq or 'max'> 指定頻率
-g 記錄函數(shù)間的調(diào)用關(guān)系
-G, --cgroup <name> 僅僅監(jiān)視指定的cgroup name
-I, --intr-regs[=<any register>] 每n毫秒打印計(jì)數(shù)增量(最小值:10ms).在某些情況下,開銷可能很高,例如小于100毫秒的間隔。
-i, --no-inherit 禁止子任務(wù)繼承父任務(wù)的性能計(jì)數(shù)器。
-j, --branch-filter <branch filter mask> 啟用分支堆棧采樣。每個(gè)樣本捕獲一系列連續(xù)的采樣分支。
-k, --clockid <clockid> 設(shè)置用于perf_event_type中各種時(shí)間字段的時(shí)鐘id記錄。請(qǐng)參見clock_gettime()。
-m, --mmap-pages <pages[,pages]> mmap數(shù)據(jù)頁面和輔助區(qū)域跟蹤mmap頁面的數(shù)量
-N, --no-buildid-cache 不要更新buildid緩存
-n, --no-samples 不要采樣
-o, --output <file> 指定輸出文件,默認(rèn)為perf.data
-P, --period 采樣周期
-p, --pid <pid> 指定進(jìn)程id
-q, --quiet 不打印任何信息
-R, --raw-samples 從所有打開的計(jì)數(shù)器收集原始樣本記錄
-r, --realtime <n> 以 SCHED_FIFO 優(yōu)先級(jí)實(shí)時(shí)收集數(shù)據(jù)
-S, --snapshot[=<opts>] 快照模式
-s, --stat 記錄每個(gè)線程的事件計(jì)數(shù),使用perf report -T 查看可選值
-t, --tid <tid> 在現(xiàn)有線程ID上記錄事件(逗號(hào)分隔列表)
-T, --timestamp 記錄采樣時(shí)間戳。使用 perf report -D查看更詳細(xì)信息
-u, --uid <user> 指定用戶id
-W, --weight 啟用加權(quán)采樣
舉例
記錄執(zhí)行l(wèi)s時(shí)的性能數(shù)據(jù)
perf record ls -g
記錄執(zhí)行l(wèi)s時(shí)的系統(tǒng)調(diào)用,可以知道哪些系統(tǒng)調(diào)用最頻繁
perf record -e syscalls:sys_enter ls
report
讀取perf record生成的數(shù)據(jù)文件,并顯示分析數(shù)據(jù)。
-p<regex>:用指定正則表達(dá)式過濾調(diào)用函數(shù)
-e <event>:指定性能事件(可以是多個(gè),用,分隔列表)
-p <pid>:指定待分析進(jìn)程的 pid(可以是多個(gè),用,分隔列表)
-t <tid>:指定待分析線程的 tid(可以是多個(gè),用,分隔列表)
-u <uid>:指定收集的用戶數(shù)據(jù),uid為名稱或數(shù)字
-a:從所有 CPU 收集系統(tǒng)數(shù)據(jù)
-C <cpu-list>:只統(tǒng)計(jì)指定 CPU 列表的數(shù)據(jù),如:0,1,3或1-2
-r <RT priority>:perf 程序以SCHED_FIFO實(shí)時(shí)優(yōu)先級(jí)RT priority運(yùn)行這里填入的數(shù)值越大,進(jìn)程優(yōu)先級(jí)越高(即 nice 值越?。?-c <count>: 事件每發(fā)生 count 次采一次樣
-F <n>:每秒采樣 n 次
-o <output.data>:指定輸出文件output.data,默認(rèn)輸出到perf.data
-i:輸入的數(shù)據(jù)文件
-v:顯示每個(gè)符號(hào)的地址
-d <dos>:只顯示指定dos的符號(hào)
-S:只考慮指定符號(hào)
-U:只顯示已解析的符號(hào)
-g[type,min,order]:顯示調(diào)用關(guān)系,具體等同于perf top命令中的-g
-c:只顯示指定cpu采樣信息
-M:以指定匯編指令風(fēng)格顯示
–source:以匯編和source的形式進(jìn)行顯示
舉例
記錄執(zhí)行l(wèi)s時(shí)的性能數(shù)據(jù)
perf record ls -g
顯示
perf report -i perf.data
overhead:cpu-clock占用百分比
command:當(dāng)前執(zhí)行的命令
shared object :依賴的共享庫
symbol:當(dāng)前占用比下對(duì)應(yīng)的符號(hào)
[.]代表該調(diào)用屬于用戶態(tài),若自己監(jiān)控的進(jìn)程為用戶態(tài)進(jìn)程,那么這些即主要為用戶態(tài)的cpu-clock占用的數(shù)值,[k]代表屬于內(nèi)核態(tài)的調(diào)用。 也許有的人會(huì)奇怪為什么自己完全是一個(gè)用戶態(tài)的程序?yàn)槭裁催€會(huì)統(tǒng)計(jì)到內(nèi)核態(tài)的指標(biāo)? 一是用戶態(tài)程序運(yùn)行時(shí)會(huì)受到內(nèi)核態(tài)的影響,若內(nèi)核態(tài)對(duì)用戶態(tài)影響較大,統(tǒng)計(jì)內(nèi)核態(tài)信息可以了解到是內(nèi)核中的哪些行為導(dǎo)致對(duì)用戶態(tài)產(chǎn)生影響;二則是有些用戶態(tài)程序也需要依賴內(nèi)核的某些操作,譬如I/O操作
annotate
perf annotate提供指令級(jí)別的record文件定位。使用調(diào)試信息-g編譯的文件能夠顯示匯編和本身源碼信息。
但要注意, annotate命令并不能夠解析內(nèi)核image中的符號(hào),必須要傳遞未壓縮的內(nèi)核image給annotate才能正常的解析內(nèi)核符號(hào),比如:
perf annotate -k /tmp/vmlinux -d symbol
命令解析
-i:輸入文件名
-d:只考慮這些DSO中的符號(hào)
-f:強(qiáng)制讀取
-D:轉(zhuǎn)儲(chǔ)ASCII中的原始跟蹤
-k:vmlinux路徑名
-m:加載模塊符號(hào)表.僅與-k和一起使用
-l:打印匹配到的源代碼行
-P:顯示完整路徑名
-M 指定反匯編程序樣式
-stdio:使用stdio接口
-gtk:使用GTK接口
舉例
main.c內(nèi)容如下:
#include <stdio.h>
#include <time.h>
void func_a() {
unsigned int num = 1;
int i;
for (i = 0;i < 10000000; i++) {
num *= 2;
num = 1;
}
}
void func_b() {
unsigned int num = 1;
int i;
for (i = 0;i < 10000000; i++) {
num <<= 1;
num = 1;
}
}
int main() {
func_a();
func_b();
return 0;
}
編譯命令:
gcc -g -O0 main.c #-g是debug信息,保留符號(hào)表等;-O0表示不進(jìn)行優(yōu)化處理
統(tǒng)計(jì)命令:
perf record -a -g ./a.out
perf report查看結(jié)果:
Samples: 73 of event 'cpu-clock', Event count (approx.): 18250000
Children Self Command Shared Object Symbol
+ 97.26% 0.00% a.out a.out [.] main
+ 97.26% 0.00% a.out libc-2.19.so [.] __libc_start_main
+ 49.32% 49.32% a.out a.out [.] func_a
+ 47.95% 47.95% a.out a.out [.] func_b
+ 1.37% 1.37% perf [kernel.kallsyms] [k] finish_task_switch
+ 1.37% 0.00% a.out ld-2.19.so [.] dl_main
perf annotate查看結(jié)果:
func_a /home/goodboy/tmp/a.out
│ void func_a() {
│ push %rbp
│ mov %rsp,%rbp
│ unsigned int num = 1;
│ movl $0x1,-0x8(%rbp)
│ int i;
│ for (i = 0;i < 10000000; i++) {
│ movl $0x0,-0x4(%rbp)
│ ↓ jmp 22
│ num *= 2;
11.11 │14:┌─→shll -0x8(%rbp)
│ │ num = 1;
│ │ movl $0x1,-0x8(%rbp)
│ │#include <stdio.h>
│ │#include <time.h>
│ │void func_a() {
│ │ unsigned int num = 1;
│ │ int i;
│ │ for (i = 0;i < 10000000; i++) {
5.56 │ │ addl $0x1,-0x4(%rbp)
33.33 │22:│ cmpl $0x98967f,-0x4(%rbp)
50.00 │ └──jle 14
│ num *= 2;
│ num = 1;
│ }
│ }
│ pop %rbp
│ ← retq
top
實(shí)時(shí)顯示系統(tǒng)/進(jìn)程的性能統(tǒng)計(jì)信息
命令解析
-e:指定性能事件
-a:顯示在所有CPU上的性能統(tǒng)計(jì)信息
-d:界面的刷新周期,默認(rèn)為2s。
-C:顯示在指定CPU上的性能統(tǒng)計(jì)信息
-p:指定進(jìn)程PID
-t:指定線程TID
-K:隱藏內(nèi)核統(tǒng)計(jì)信息
-k:帶符號(hào)表的內(nèi)核映像所在的路徑。
-U:隱藏用戶空間的統(tǒng)計(jì)信息
-s:指定待解析的符號(hào)信息
-g:得到函數(shù)的調(diào)用關(guān)系圖。
‘‐G’ or‘‐‐call‐graph’ <output_type,min_percent,call_order>
graph: 使用調(diào)用樹,將每條調(diào)用路徑進(jìn)一步折疊。這種顯示方式更加直觀。
每條調(diào)用路徑的采樣率為絕對(duì)值。也就是該條路徑占整個(gè)采樣域的比率。
fractal
默認(rèn)選項(xiàng)。類似與 graph,但是每條路徑前的采樣率為相對(duì)值。
flat
不折疊各條調(diào)用
選項(xiàng) call_order 用以設(shè)定調(diào)用圖譜的顯示順序,該選項(xiàng)有 2個(gè)取值,分別是
callee 與caller。
將該選項(xiàng)設(shè)為callee 時(shí),perf按照被調(diào)用的順序顯示調(diào)用圖譜,上層函數(shù)被下層函數(shù)所調(diào)用。
該選項(xiàng)被設(shè)為caller 時(shí),按照調(diào)用順序顯示調(diào)用圖譜,即上層函數(shù)調(diào)用了下層函數(shù)路徑,也不顯示每條調(diào)用路徑的采樣率
舉例
顯示分配高速緩存最多的函數(shù)
perf top -e kmem:kmem_cache_alloc
顯示內(nèi)核和模塊中,消耗最多CPU周期的函數(shù)
perf top -e cycles:k
第一列:符號(hào)引發(fā)的性能事件的比例,默認(rèn)指占用的cpu周期比例。
第二列:符號(hào)所在的DSO(Dynamic Shared Object),可以是應(yīng)用程序、內(nèi)核、動(dòng)態(tài)鏈接庫、模塊。
第三列:DSO的類型。[.]表示此符號(hào)屬于用戶態(tài)的ELF文件,包括可執(zhí)行文件與動(dòng)態(tài)鏈接庫)。[k]表述此符號(hào)屬于內(nèi)核或模塊。
第四列:符號(hào)名。有些符號(hào)不能解析為函數(shù)名,只能用地址表示。
bench
perf bench作為benchmark工具的通用框架,包含sched/mem/numa/futex等子系統(tǒng),all可以指定所有。
perf bench可用于評(píng)估系統(tǒng)sched/mem等特定性能。
命令解析
-f, --format <default|simple> 選擇輸出格式,simple模式下只顯示測(cè)量時(shí)間
-r, --repeat <n> 指定重復(fù)運(yùn)行的次數(shù)
子系統(tǒng)包括
sched:調(diào)度器和IPC機(jī)制。包含messaging和pipe兩個(gè)功能。
mem:內(nèi)存存取性能。包含memcpy和memset兩個(gè)功能。
numa:NUMA架構(gòu)的調(diào)度和內(nèi)存處理性能。包含mem功能。
futex:futex壓力測(cè)試。包含hash/wake/wake-parallel/requeue/lock-pi功能。
all:所有bench測(cè)試的集合
舉例
sched messaging評(píng)估進(jìn)程調(diào)度和核間通信,sched message 是從經(jīng)典的測(cè)試程序 hackbench 移植而來,用來衡量調(diào)度器的性能,overhead 以及可擴(kuò)展性。
該 benchmark 啟動(dòng) N 個(gè) reader/sender 進(jìn)程或線程對(duì),通過 IPC(socket 或者 pipe) 進(jìn)行并發(fā)的讀寫。一般人們將 N 不斷加大來衡量調(diào)度器的可擴(kuò)展性。
sched message 的用法及用途和 hackbench 一樣,可以通過修改參數(shù)進(jìn)行不同目的測(cè)試:
-g, --group <n> Specify number of groups
-l, --nr_loops <n> Specify the number of loops to run (default: 100)
-p, --pipe Use pipe() instead of socketpair()
-t, --thread Be multi thread instead of multi process
ubuntu# perf bench sched all
# Running sched/messaging benchmark...
# 20 sender and receiver processes per group
# 10 groups == 400 processes run
Total time: 0.077 [sec]
# Running sched/pipe benchmark...
# Executed 1000000 pipe operations between two processes
Total time: 27.550 [sec]
27.550083 usecs/op
36297 ops/sec
使用pipe()和socketpair()對(duì)測(cè)試影響:
ubuntu# perf bench sched messaging
# Running 'sched/messaging' benchmark:
# 20 sender and receiver processes per group
# 10 groups == 400 processes run
Total time: 0.071 [sec]
ubuntu# perf bench sched messaging -p
# Running 'sched/messaging' benchmark:
# 20 sender and receiver processes per group
# 10 groups == 400 processes run
Total time: 0.069 [sec]
ubuntu#
可見socketpair()性能要明顯低于pipe()。
使用perf分析完整例子
下面我們舉一個(gè)具體的例子來看下perf的使用方法。
//t1.c
void longa()
{
int i,j;
for(i = 0; i < 1000000; i++)
j=i; //am I silly or crazy? I feel boring and desperate.
}
void foo2()
{
int i;
for(i=0 ; i < 10; i++)
longa();
}
void foo1()
{
int i;
for(i = 0; i< 100; i++)
longa();
}
int main(void)
{
while(1)
{
foo1();
foo2();
}
}
總攬全局
先用 perf stat 查看下程序整體性能情況,該工具主要是從全局上監(jiān)控,可以看到程序?qū)е滦阅芷款i主要是什么原因。perf stat通過概括精簡(jiǎn)的方式提供被調(diào)試程序運(yùn)行的整體情況和匯總數(shù)據(jù)。
ubuntu# perf stat ./perf_test
^C./perf_test: Interrupt
Performance counter stats for './perf_test':
8,659.24 msec task-clock # 1.000 CPUs utilized
21 context-switches # 0.002 K/sec
0 cpu-migrations # 0.000 K/sec
43 page-faults # 0.005 K/sec
<not supported> cycles
<not supported> instructions
<not supported> branches
<not supported> branch-misses
8.660065455 seconds time elapsed
8.659661000 seconds user
0.000000000 seconds sys
task-clock :指程序運(yùn)行期間占用了8,659.24 msec的任務(wù)時(shí)鐘周期,該值高,說明程序的多數(shù)時(shí)間花費(fèi)在 CPU 計(jì)算上而非 IO。
context-switches :表示程序運(yùn)行期間進(jìn)行了21次上下文切換。記錄了程序運(yùn)行過程中發(fā)生了多少次進(jìn)程切換。
page-faults :是指程序發(fā)生了 43次缺頁錯(cuò)誤。
通過perf stat獲得了程序性能瓶頸類型后,已經(jīng)知道哪個(gè)進(jìn)程需要優(yōu)化,若不知道則需要使用perf top進(jìn)行進(jìn)一步監(jiān)控。
精準(zhǔn)導(dǎo)航
下一步就是對(duì)該進(jìn)程進(jìn)行細(xì)粒度的分析,分析在長(zhǎng)長(zhǎng)的程序代碼中究竟是哪幾段代碼、哪幾個(gè)函數(shù)需要修改呢?
perf record -e cpu-clock -g ./perf_test
-g選項(xiàng)是告訴perf record額外記錄函數(shù)的調(diào)用關(guān)系,-e cpu-clock 指perf record監(jiān)控的指標(biāo)為cpu周期,程序運(yùn)行完之后,perf record會(huì)生成一個(gè)名為perf.data的文件。
可視化分析
前面通過perf record工具獲得了某一進(jìn)程的指標(biāo)監(jiān)控?cái)?shù)據(jù)perf.data,下面就需要使用perf report工具查看該文件。
perf report -i perf.data
Self:是最后一列的符號(hào)(可以理解為函數(shù))本身所占比例。
Children :是這個(gè)符號(hào)調(diào)用的其他符號(hào)(可以理解為子函數(shù),包括直接和間接調(diào)用)占用的比例之和。
[.]:代表該調(diào)用屬于用戶態(tài),若自己監(jiān)控的進(jìn)程為用戶態(tài)進(jìn)程,那么這些即主要為用戶態(tài)的cpu-clock占用的數(shù)值,[k]代表屬于內(nèi)核態(tài)的調(diào)用。
我們可以看到longa符號(hào)占用了perf_test程序的99%的CPU資源。
通過方向鍵和回車,可以看到函數(shù)的調(diào)用關(guān)系,同時(shí)以匯編代碼的形式展示資源的消耗情況。
?
addl $0x1,-0x8(%rbp)
cmpl $0xf423f,-0x8(%rbp)
這兩句匯編代碼,先將0x8(%rbp)加一,然后和一個(gè)常數(shù)進(jìn)行比較,占據(jù)了63.5%的資源。
查看源代碼可以發(fā)現(xiàn)做了一次1000000次的for循環(huán)。接著以同樣的方法, 可以發(fā)現(xiàn)foo1() 也是一個(gè)潛在的調(diào)優(yōu)對(duì)象,為什么要調(diào)用 100 次那個(gè)無聊的 longa() 函數(shù)呢。
火焰圖
on-cpu火焰圖可以用于分析cpu是被哪些線程、哪些函數(shù)占用的,可以方便的找到熱點(diǎn)代碼便于后續(xù)分析優(yōu)化。下面我們介紹下火焰圖的生成和使用方法。
使用方法
-
準(zhǔn)備FlameGraph工具。
git clone https://github.com/brendangregg/FlameGraph.git
-
用perf record采集CPU信息。
perf record -e cpu-clock -g ./perf_test
Ctrl+c結(jié)束執(zhí)行后,在當(dāng)前目錄下會(huì)生成采樣數(shù)據(jù)perf.data。
-
用perf script工具對(duì)perf.data進(jìn)行解析。
perf script -i perf.data &> perf.unfold
-
將perf.unfold中的符號(hào)進(jìn)行折疊。
./stackcollapse-perf.pl perf.unfold &> perf.folded
-
最后生成svg圖。
./flamegraph.pl perf.folded > perf.svg
perf.svg 用瀏覽器就可以打開
火焰圖解讀
y 軸表示調(diào)用棧,每一層都是一個(gè)函數(shù)。調(diào)用棧越深,火焰就越高,頂部就是正在執(zhí)行的函數(shù),下方都是它的父函數(shù)。
x 軸表示抽樣數(shù),如果一個(gè)函數(shù)在 x 軸占據(jù)的寬度越寬,就表示它被抽到的次數(shù)多,即執(zhí)行的時(shí)間長(zhǎng)。注意,x 軸不代表時(shí)間,而是所有的調(diào)用棧合并后,按字母順序排列的。
火焰圖就是看頂層的哪個(gè)函數(shù)占據(jù)的寬度最大。只要有"平頂"(plateaus),就表示該函數(shù)可能存在性能問題。比如圖中的longa()函數(shù)正是問題所在點(diǎn)。
顏色沒有特殊含義,因?yàn)榛鹧鎴D表示的是 CPU 的繁忙程度,所以一般選擇暖色調(diào)。
互動(dòng)
火焰圖是SVG 圖片,可以與用戶互動(dòng)。
-
火焰的每一層都會(huì)標(biāo)注函數(shù)名,鼠標(biāo)懸浮時(shí)會(huì)顯示完整的函數(shù)名、抽樣抽中的次數(shù)、占據(jù)總抽樣次數(shù)的百分比。下面是一個(gè)例子。
-
在某一層點(diǎn)擊,火焰圖會(huì)水平放大,該層會(huì)占據(jù)所有寬度,顯示詳細(xì)信息。
-
按下 Ctrl + F 會(huì)顯示一個(gè)搜索框,用戶可以輸入關(guān)鍵詞或正則表達(dá)式,所有符合條件的函數(shù)名會(huì)高亮顯示。
其他
還有幾個(gè)火焰圖,就不介紹了,可以去看brendang regg的網(wǎng)站,簡(jiǎn)單說一下:
off-cpu相關(guān):
-
off-cpu flame graphs —— 與on-cpu互補(bǔ),on-cpu只能看到運(yùn)行情況,但如果某個(gè)請(qǐng)求運(yùn)行慢,可能是被阻塞導(dǎo)致,那么就需要分析阻塞點(diǎn)在代碼的哪個(gè)位置,off-cpu就是畫出每個(gè)阻塞點(diǎn)的阻塞時(shí)間,用于分析這個(gè)問題。
-
Wakeup flame graphs —— off-cpu的進(jìn)一步,off-cpu畫出了阻塞點(diǎn),但不知道阻塞是被誰喚醒的,wakeup通過分析喚醒阻塞點(diǎn)的線程棧,就可以知道是在哪里進(jìn)行的喚醒,從而分析喚醒慢的原因。
-
Chain graphs —— off-cpu和wakeup火焰圖畫出了阻塞點(diǎn)、喚醒點(diǎn),但兩者之間的關(guān)系并沒有,也就是不知道喚醒點(diǎn)是喚醒哪個(gè)阻塞點(diǎn),chain graph就是解決這個(gè)問題
其他
-
Hot/Cold Flame Graphs —— 就是講on-cpu與off-cpu結(jié)合,在一張圖上顯示,這樣可以清晰的看到on和off各自的比例
-
Differential Flame Graphs —— 對(duì)比兩個(gè)數(shù)據(jù),畫出來的圖上顯示變化情況,也就是相對(duì)之前的數(shù)據(jù),每個(gè)部分占用是變高還是變低文章來源:http://www.zghlxwxcb.cn/news/detail-794788.html
總結(jié)
使用perf+FlameGraph可以清晰的了解程序on-cpu運(yùn)行時(shí)間占比,可以高效的了解程序性能,這種方法對(duì)我們了解程序運(yùn)行過程具有重要指導(dǎo)作用。要善于使用工具幫助我們分析復(fù)雜問題。文章來源地址http://www.zghlxwxcb.cn/news/detail-794788.html
到了這里,關(guān)于Linux性能分析工具perf和火焰圖使用方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!