perf (Performance analysis tools for Linux),是Linux官方的性能分析器(profiling),存在于内核源码目录
tools/perf
中。可以用于分析系统调用、硬件事件、软件事件、CPU使用情况、内存使用情况、锁等信息,从而帮助定位系统性能问题。
perf原名为Linux性能计数器(Performance Counters for Linux,PCL),现名为Linux性能事件(Linux Performance Events,LPE)。它提供了一整套剖析和跟踪的工具,每个工具分别作为一个子命令,与git
类似。
通过它,应用程序可以利用 PMU(Performance Monitoring Unit,CPU上集成的性能监视单元。它可以对CPU执行的各种事件进行计数,如CPU周期、缓存命中/失误、分支预测正确/错误等)、tracepoint
和内核中的特殊计数器来进行性能统计。tracepoint
是Linux内核中的一种跟踪机制。它允许在内核源代码的关键位置插入跟踪点,当内核执行到这些位置时,会调用注册在跟踪点上的跟踪函数(勾子,hook)来进行事件跟踪或数据采集。这一特性能够被各类trace/debug工具所使用。perf将tracepoint
产生的时间记录下来,生成报告,从而了解程序的性能瓶颈在哪里。这些tracepint
的对应的sysfs
节点在/sys/kernel/debug/tracing/events
目录下。
官网文档:https://www.brendangregg.com/perf.html
源码目录:
perf [--version] [--help] [OPTIONS] COMMAND [ARGS]
# List available perf options.
--help ## 帮助
--version ## 版本
--exec-path ## 设置执行路径
--html-path ## 显示帮助文档路径
--paginate ## 显示标页数
--no-pager ## 不显示标页数
--debugfs-dir ## 设置调试目录,PERF_DEBUGFS_DIR
--buildid-dir ## 设置buildid缓存目录
--list-cmds ## 显示所有子命令
--list-opts ## 显示所有选项
--debug ## 设置调试参数
# 实践版本
[root@192 ~]# perf --version
perf version 4.18.0-348.7.1.el8_5.x86_64
# 显示子命令的帮助信息
perf list --help
Notic:不同的版本命令、选项存在差异,具体请参考man文档。
子命令 | 描述 |
---|---|
annotate | 读取pert.data (由perf record 创建) 并显示注释过的代码 |
archive | 根据数据文件中记录的buildid,将所有被采样到的DSO文件打成压缩包,供其它机器分析采样数据 |
bench | 基准测试的通用框架 |
buildid-cache | 管理perf的buildid缓存。每个ELF都有唯一的buildid表示,perf用buildid来关联符号与性能数据 |
buildid-list | 列出数据文件中记录的所有buildid |
c2c | Shared Data C2C/HITM Analyzer |
config | 读、写配置文件 |
daemon | 在后台运行录制任务 |
data | Data file related processing |
diff | 读取两个pert.data 文件并显示两份剖析信息之间的差异 |
evlist | 列出一个per.data 文件里的事件名称 |
ftrace | simple wrapper for kernel’s ftrace functionality |
inject | 过滤以加强事件流,在其中加人额外的信息 |
kallsyms | Searches running kernel for symbols |
kmem | 跟踪/测量内核内存 (slab)属性的工具 |
kvm | 跟踪/测量kvm 客户机操作系统的工具 |
list | 列出所有的符号事件类型 |
lock | 分析锁事件 |
mem | 分析内存访问 |
record | 运行一个命令,并把剖析信息记录在per.data 中 |
report | 读取per.data 并显示部析信息 |
sched | 跟踪/测量调度器属性(延时)的工具 |
script | 读取per.data 并显示跟踪输出 |
stat | 运行一个命令并收集性能计数器统计信息 |
test | 运行完整性测试,提供多个测试用例 |
timechart | 可视化某一个负载期间系统总体性能的工具 |
top | 系统剖析工具,类似于linux top |
version | 显示perf版本 |
probe | 定义新的动态跟踪点 |
trace | strace启发工具,能打印程序运行中各系统调用的耗时,如(perf trace ls) |
[root@192 perf]# cat ~/share/doc/perf-tip/tips.txt
For a higher level overview, try: perf report --sort comm,dso
Sample related events with: perf record -e '{cycles,instructions}:S'
Compare performance results with: perf diff [<old file> <new file>]
Boolean options have negative forms, e.g.: perf report --no-children
Customize output of perf script with: perf script -F event,ip,sym
Generate a script for your data: perf script -g <lang>
Save output of perf stat using: perf stat record <target workload>
Create an archive with symtabs to analyse on other machine: perf archive
Search options using a keyword: perf report -h <keyword>
Use parent filter to see specific call path: perf report -p <regex>
List events using substring match: perf list <keyword>
To see list of saved events and attributes: perf evlist -v
Use --symfs <dir> if your symbol files are in non-standard locations
To see callchains in a more compact form: perf report -g folded
Show individual samples with: perf script
Limit to show entries above 5% only: perf report --percent-limit 5
Profiling branch (mis)predictions with: perf record -b / perf report
Treat branches as callchains: perf report --branch-history
To count events in every 1000 msec: perf stat -I 1000
Print event counts in CSV format with: perf stat -x,
If you have debuginfo enabled, try: perf report -s sym,srcline
For memory address profiling, try: perf mem record / perf mem report
For tracepoint events, try: perf report -s trace_fields
To record callchains for each sample: perf record -g
To record every process run by a user: perf record -u <user>
Skip collecting build-id when recording: perf record -B
To change sampling frequency to 100 Hz: perf record -F 100
See assembly instructions with percentage: perf annotate <symbol>
If you prefer Intel style assembly, try: perf annotate -M intel
For hierarchical output, try: perf report --hierarchy
Order by the overhead of source file name and line number: perf report -s srcline
System-wide collection from all CPUs: perf record -a
Show current config key-value pairs: perf config --list
Show user configuration overrides: perf config --user --list
To add Node.js USDT(User-Level Statically Defined Tracing): perf buildid-cache --add `which node`
To report cacheline events from previous recording: perf c2c report
perf list命令用于列出系统上可用的跟踪事件,所有的符号事件类型,主要关注这三种:
Hardware Event
是由PMU硬件产生的事件,比如cache命中,分支预判等;
Software Event
是内核软件产生的事件,比如进程切换,tick 数等 ;
Tracepoint event
是内核中的静态tracepoint所触发的事件,用来判断程序运行期间内核的行为细节,比如slab分配器的分配次数,系统调用,TCP事件,文件系统IO事件,块设备事件等。
perf list
默认会输出所有支持的事件,被划分成多个类型,可能会重复。划分的类型有:
[root@192 ch]# man perf-list
Without options all known events will be listed.
To limit the list use:
1. hw or hardware to list hardware events such as cache-misses, etc.
2. sw or software to list software events such as context switches, etc.
3. cache or hwcache to list hardware cache events such as L1-dcache-loads, etc.
4. tracepoint to list all tracepoint events, alternatively use
subsys_glob:event_glob to filter by tracepoint subsystems such as sched,
block, etc.
5. pmu to print the kernel supplied PMU events.
6. sdt to list all Statically Defined Tracepoint events.
7. metric to list metrics
8. metricgroup to list metricgroups with metrics.
9. If none of the above is matched, it will apply the supplied glob to all
events, printing the ones that match.
10. As a last resort, it will do a substring search in all event names.
One or more types can be used at the same time, listing the events for the types
specified.
Support raw format:
1. --raw-dump, shows the raw-dump of all the events.
2. --raw-dump [hw|sw|cache|tracepoint|pmu|event_glob], shows the raw-dump of a
certain kind of events.
可以只显示关心的事件类型:
[root@192 ch]# perf list software
List of pre-defined events (to be used in -e):
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]
[root@192 ch]# perf list hardware
List of pre-defined events (to be used in -e):
branch-instructions OR branches [Hardware event]
branch-misses [Hardware event]
bus-cycles [Hardware event]
cache-misses [Hardware event]
cache-references [Hardware event]
cpu-cycles OR cycles [Hardware event]
instructions [Hardware event]
ref-cycles [Hardware event]
[root@192 ch]# perf list cache
list of pre-defined events (to be used in -e):
L1-dcache-load-misses [Hardware cache event]
L1-dcache-loads [Hardware cache event]
L1-dcache-stores [Hardware cache event]
L1-icache-load-misses [Hardware cache event]
LLC-load-misses [Hardware cache event]
LLC-loads [Hardware cache event]
LLC-store-misses [Hardware cache event]
LLC-stores [Hardware cache event]
branch-load-misses [Hardware cache event]
branch-loads [Hardware cache event]
dTLB-load-misses [Hardware cache event]
dTLB-loads [Hardware cache event]
dTLB-store-misses [Hardware cache event]
dTLB-stores [Hardware cache event]
iTLB-load-misses [Hardware cache event]
iTLB-loads [Hardware cache event]
node-load-misses [Hardware cache event]
node-loads [Hardware cache event]
node-store-misses [Hardware cache event]
node-stores [Hardware cache event]
事件可以通过附加一个冒号和一个或多个修饰符来过滤。如果需要限制统计的事件,可以添加以下修饰符:
u - 用户空间统计
k - 内核空间统计
h - hypervisor counting, 虚拟化统计
I - 非空闲统计
G - guest counting (in KVM guests)
H - host counting (not in KVM guests)
p - 指定精度等级,p0、p1、p2、p3
P - 使用最大检测精度
S - 读取采样值 (PERF_SAMPLE_READ)
D - pin the event to the PMU
W - group is weak and will fallback to non-group if not schedulable
e - group or event are exclusive and do not share the PMU
perf top是系统剖析工具。对于一个指定的性能事件(默认的性能事件为cpu cycles,CPU周期),显示消耗最多的函数或指令。perf top类似linux的top命令,可以排列展示当机的函数和指令消耗情况。perf top主要用于实时分析各个函数在某个性能事件上的热度,能够快速的定位热点函数,包括应用程序函数、模块函数与内核函数,甚至能够定位到热点指令。
perf top适合用于观测一直运行的服务程序或后台进程。
第一列:符号引发的性能事件的比例,默认指占用的cpu周期比例。
第二列:符号所在的DSO(Dynamic Shared Object)
,可以是应用程序、内核、动态链接库、模块。
第三列:DSO的类型。
[.] : user level 用户态空间,若自己监控的进程为用户态进程,那么这些即主要为用户态的cpu-clock占用的数值;
[k]: kernel level 内核态空间;
[g]: guest kernel level (virtualization) ;
[u]: guest os user space;
[H]: hypervisor;
第四列:符号名。有些符号不能解析为函数名,只能用地址表示。
选项有很多,仅描述常用选项,其它选项可以通过man perf-top
参考。
选项 | 描述 |
---|---|
-e |
指明要分析的性能事件 |
-p |
仅分析目标进程及其创建的线程 |
-k |
指定带符号表的内核映像所在的路径 |
-K | 不显示属于内核或模块的符号 |
-U | 不显示属于内核或模块的符号 |
-d |
界面的刷新周期,默认为2s,因为perf top默认每2s从mmap的内存区域读取一次性能数据 |
-g | 得到函数的调用关系图 |
-s,–sort | 选择排序方式,如:–sort pid |
… |
可在perf top
显示界面直接输入交互命令。
命令 | 功能 |
---|---|
h | ? | F1 | 显示帮助 |
q | ESC | 退出 |
UP/DOWN/PGUP/PGDN/SPACE | 导航 |
TAB/UNTAB | 切换事件,用于多事件会话 |
ENTER | 显示上下文菜单 |
d | 进入当前DSO,显示所有符号百分比 |
e | 扩展/收缩主调用链(需要配合-g选项使用) |
E | 扩展所有调用链(需要配合-g选项使用) |
F | 打开/关闭过滤条件(百分比大于xxx) |
H | 显示列标题 |
k | 进入内核映射,显示所有内核函数百分比 |
L | 改变百分比限制 |
m | 显示上下文菜单 |
S | 进入当前CPU套接口 |
P | Print histograms to perf.hist.N |
t | 进入当前线程 |
V | 显示详细信息(DSO names in callchains,etc) |
z | 过滤0值(实际测试中还是有0值) |
f | 启用/禁用事件 |
/ | 按符号名过滤 |
进入top界面后,按Enter查看当前DSO中各符号占比
perf stat可以快速采集各种CPU与内核事件的计数器,并在执行结束时输出统计结果,用于分析负载类型与系统性能瓶颈。
1. 支持各种事件统计,以及使用修饰符来过滤事件获取更精确的统计信息。
2. 汇总输出:汇总输出各事件的总计数器值、平均值与百分比等统计数据。
3. 多次统计:可以多次重复运行并汇总统计,方便比较不同测试情境下的系统性能差异。
4. 采样间隔设置:可以设定计数器值汇总的时间间隔,默认为整个测试周期。
7. 与其他工具配合:可以将汇总信息输出为文件,供其它工具进一步分析。
选项 | 描述 |
---|---|
-e |
指明要分析的性能事件,支持多个事件与修饰符,如:-e cycles:u,instructions:k |
-r |
重复运行n次,并多次结果的显示标准差 |
-C | 只统计特定的CPU |
-p |
只统计特定的进程 |
-t |
只统计特定的线程 |
-I |
设置间隔,单位毫秒,多久打印一次统计信息 |
record | 将统计信息存储到文件perf.data ,也可以指定输出文件名 |
report | 根据已储存的统计信息生成报告,默认输入文件为perf.data |
–interval-clear | 每次间隔刷新时,清空屏幕,有点类似top |
… |
# 将统计信息输出到perf.data
perf stat record ls
# 根据已储存的统计信息生成报告
perf stat report
统计执行5次ls
命令结果,只查看用户空间的cycles
和内核空间的instructions
,输出平均值与标准差。
perf record可以针对指定的事件、CPU、tracepoint等进行采集,采集结束后生成
perf.data
用于后续解析、报告、储存等。
1. 支持各种事件的采集以及事件过滤。
2. 采样间隔控制:可以设置采样频率。采样频率越高,获得的跟踪数据越详细,但数据文件也越大。
3. 多种输出:支持输出原始采样数据,以及经过处理的报告数据等多种格式,使报告更易于阅读。
4. 支持查看函数调用关系:可以采集函数调用关系,用于构建完整的调用链信息。
5. 与其他工具配合:输出的文件可以供perf report、perf annotate等工具进行数据分析、查看与报告生成。
7. 多次perf record之后,当前路径下会有perf.data
和perf.data.old
两个文件,分别是本次和上次的记录,这个时候我们可以通过perf diff进行对比优化的结果。
选项 | 描述 |
---|---|
-e |
指明要分析的性能事件,支持多个事件与修饰符,如:-e cycles:u,instructions:k |
-g | 捕获调用链图 |
-C | 只统计特定的CPU |
-p |
只统计特定的进程 |
-t |
只统计特定的线程 |
-F | 指定采样频率,每秒采样多少次 |
… |
# 采样频率设置为100,并显示调用链
perf record -g -F 100 ls
解析perf record产生的数据,并给出分析结果。
选项 | 描述 |
---|---|
-i |
指定要分析的输入数据文件,默认为perf.data |
-F |
指定显示的字段 |
-g | 显示调用链 |
-s |
指定排序字段 |
-T | 显示线程相关数据 |
-d |
指定要显示的dso |
–no-children | 不显示子函数的占比 |
… |
# 查看关于某个库的占用率
perf report -g -d libmy.so
# Samples:采样个数
# Event count:系统总共发生的事件数
# Children:当前函数调用的子函数数的使用率
# Self:当前函数自身的使用率。
# Command: 命令名
# Symbol:符号名,其中[.]表示用户空间函数,[k]表示内核函数
如果一个函数同时具有self与children采样结果,这说明:
- 该函数自身也参与了采样,产生了自身的采样消耗;
- 该函数还调用了其他子函数,这些子函数同样参与了采样,从而产生了children采样结果。
children采样结果是当前函数及其调用链上所有子函数产生的综合采样消耗。而self仅代表当前函数自身的采样消耗。通过观察这两个采样项之间的差异,可以分析出某个函数自身的消耗占比,以及它调用的子函数的影响。这对了解系统中各个函数的资源消耗情况与优化潜力有很大帮助。例如,如果self采样结果远大于children采样结果,说明当前函数自身消耗较大,子函数的影响较小。这提示我们优化的重点应放在改进当前函数的效率上。反之,如果children采样结果远大于self采样结果,说明当前函数主要通过调用子函数来产生资源消耗。我们应重点分析它调用的关键子函数,查找子函数中的优化点。
perf工具中的脚本处理工具。它可以读取perf工具生成的采样数据文件,并根据用户提供的脚本来处理与分析这些数据,生成定制化的报告。
perf script [<options>]
# 运行脚本进行记录,输出文件用于报告
perf script [<options>] record <script> [<record-options>] <command>
# 运行脚本进行报告
perf script [<options>] report <script> [script-args]
# 运行脚本进行实时记录与报告,不产生磁盘文件
perf script [<options>] <script> <required-script-args> [<record-options>] <command>
# 运行脚本生成与top类似的报告
perf script [<options>] <top-script> [script-args]
# 列出可用的脚本
[root@192 ~]# perf script --list
List of available trace scripts:
failed-syscalls [comm] system-wide failed syscalls
rw-by-file <comm> r/w activity for a program, by file
rw-by-pid system-wide r/w activity
rwtop [interval] system-wide r/w top
wakeup-latency system-wide min/max/avg wakeup latency
compaction-times [-h] [-u] [-p|-pv] [-t | [-m] [-fs] [-ms]] [pid|pid-range|comm-regex] display time taken by mm compaction
event_analyzing_sample analyze all perf samples
export-to-postgresql [database name] [columns] [calls] export perf data to a postgresql database
export-to-sqlite [database name] [columns] [calls] export perf data to a sqlite3 database
failed-syscalls-by-pid [comm] system-wide failed syscalls, by pid
flamegraph create flame graphs
futex-contention futext contention measurement
intel-pt-events print Intel PT Power Events and PTWRITE
mem-phys-addr resolve physical address samples
net_dropmonitor display a table of dropped frames
netdev-times [tx] [rx] [dev=] [debug] display a process of packet and processing time
powerpc-hcalls
sched-migration sched migration overview
sctop [comm] [interval] syscall top
stackcollapse produce callgraphs in short form for scripting use
syscall-counts-by-pid [comm] system-wide syscall counts, by pid
syscall-counts [comm] system-wide syscall counts
选项 | 描述 |
---|---|
-l | 列出可用的脚本 |
-s | 执行给定的分析脚本程序 |
-g, --gen-script | 生成脚本文件 |
-i, --input= | 指定输入文件 |
-d, --debug-mode | 调试模式 |
-F, --fields | 指定显示哪些字段 |
–pid= | 仅显示指定进程的事件 |
… |
# 查看ls执行调用的火焰图
[root@192 ch]# perf script record flamegraph ls
[root@192 ch]# perf script
perf 11619 4110.808946: 1 cycles:
ffffffff8100b38b __intel_pmu_enable_all.constprop.28+0x4b (/lib/modules/4.19.220-klrt/build/vmlin>
ffffffff8100b635 intel_tfa_pmu_enable_all+0x35 (/lib/modules/4.19.220-klrt/build/vmlinux)
ffffffff8100594a x86_pmu_enable+0x11a (/lib/modules/4.19.220-klrt/build/vmlinux)
ffffffff8118d537 perf_pmu_enable.part.107+0x7 (/lib/modules/4.19.220-klrt/build/vmlinux)
ffffffff8118dc7e ctx_resched+0x8e (/lib/modules/4.19.220-klrt/build/vmlinux)
ffffffff8119875c perf_event_exec+0x16c (/lib/modules/4.19.220-klrt/build/vmlinux)
ffffffff812212f1 setup_new_exec+0xd1 (/lib/modules/4.19.220-klrt/build/vmlinux)
ffffffff81279d42 load_elf_binary+0x392 (/lib/modules/4.19.220-klrt/build/vmlinux)
ffffffff8121f0fd search_binary_handler+0x7d (/lib/modules/4.19.220-klrt/build/vmlinux)
ffffffff81220ca3 __do_execve_file.isra.43+0x573 (/lib/modules/4.19.220-klrt/build/vmlinux)
ffffffff812210d9 __x64_sys_execve+0x39 (/lib/modules/4.19.220-klrt/build/vmlinux)
ffffffff810023c7 do_syscall_64+0x97 (/lib/modules/4.19.220-klrt/build/vmlinux)
ffffffff81a0007d entry_SYSCALL_64+0x6d (/lib/modules/4.19.220-klrt/build/vmlinux)
7f9be3b1c05b [unknown] ([unknown])
# ...
火焰图是一种常用于性能分析与可视化的图表。它以二维坐标轴显示采样数据,横轴表示时间,纵轴表示调用堆栈。通过火焰图可以直观地查看函数调用关系与时间轴上的资源消耗变化,发现性能瓶颈与优化点。
脚本下载地址:https://github.com/brendangregg/FlameGraph.git
生成步骤:
# 1、生成perf.data
perf record -g ls
# 2、使用perf script工具对perf.data进行解析
perf script -i perf.data &> perf.unfold
# 3、将perf.unfold中的符号进行折叠
./FlameGraph-master/stackcollapse-perf.pl perf.unfold &> perf.folded
# 4、生成svg图
./FlameGraph-master/flamegraph.pl perf.folded > perf.svg
# 脚本运行失败?直接注释97行
Can't locate open.pm in @INC (you may need to install the open module) (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5) at FlameGraph-master/flamegraph.pl line 97.
BEGIN failed--compilation aborted at FlameGraph-master/flamegraph.pl line 97
TIPS
- 火焰图就是看顶层的哪个函数占据的宽度最大。只要有
平顶
(plateaus),就表示该函数可能存在性能问题。- 火焰的每一层都会标注函数名,鼠标悬浮时会显示完整的函数名、抽样抽中的次数、占据总抽样次数的百分比。
- 在某一层点击,火焰图会水平放大,该层会占据所有宽度,显示详细信息。点击左上角
Reset Zoom
图片就会复原。- 按下
Ctrl+F
会显示一个搜索框,用户可以输入关键词或正则表达式,所有符合条件的函数名会高亮显示。