1、安装Perf性能分析工具

Perf工具是非常强大的Linux性能分析工具,可以通过该工具获得进程内的调用情况、资源消耗情况并查找分析热点函数。

所以我们使用perf工具进行性能数据的采集。

在Ubuntu上,如果不知道perf如何安装的话可以直接执行perf在命令执行报错回显里面会有建议:

root@ubuntu:~# perf

Command 'perf' not found, but can be installed with:

apt install linux-oem-5.6-tools-common # version 5.6.0-1017.17, or
apt install linux-tools-common # version 5.4.0-92.103

root@ubuntu:~#

这里他建议我们执行apt install linux-oem-5.6-tools-common或者apt install linux-tools-common进行perf的安装。那我们就先执行apt install linux-tools-common安装一下试试。

root@ubuntu:~# apt install linux-tools-common
Reading package lists... Done
Building dependency tree
Reading state information... Done
You might want to run 'apt --fix-broken install' to correct these.
The following packages have unmet dependencies:
linux-headers-5.4.0-92-generic : Depends: linux-headers-5.4.0-92 but it is not going to be installed
linux-image-generic : Depends: linux-modules-extra-5.4.0-92-generic but it is not going to be installed
E: Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution).
root@ubuntu:~#

漂亮!报错了!

不要慌,我们要学会阅读报错信息,不怕它报错,就怕它不报错。

这里的意思大概是咱们要安装的linux-tools-common需要依赖linux-headers-5.4.0-92-genericlinux-image-generic并且它还给出了建议”You might want to run ‘apt –fix-broken install’ to correct these.”。那我们就按照它说的执行apt --fix-broken install然后再执行linux-tools-common就能成功安装。然后我们执行perf -h看一下。

root@ubuntu:~# perf -h
WARNING: perf not found for kernel 5.4.0-91

You may need to install the following packages for this specific kernel:
linux-tools-5.4.0-91-generic
linux-cloud-tools-5.4.0-91-generic

You may also want to install one of the following packages to keep up to date:
linux-tools-generic
linux-cloud-tools-generic
root@ubuntu:~#

这里它又报个警告信息,这虽说是警告,但是不修复这个警告我们还是无法正常使用perf。
所以我们还需要安装linux-tools-5.4.0-91-generic和linux-tools-generic

一样的执行apt install linux-tools-5.4.0-91-genericlinux-tools-generic

⚠️:你的内核版本可能和我的不同,不要盲目复制!所以比较推荐使用apt install linux-tools-`uname -r` 进行安装。

现在我们再执行perf -h看看

root@ubuntu:~# perf -h

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
c2c Shared Data C2C/HITM Analyzer.
config Get and set variables in a configuration 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
ftrace simple wrapper for kernel's ftrace functionality
inject Filter to augment the events stream with additional information
kallsyms Searches running kernel for symbols
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.
version display the version of perf binary
probe Define new dynamic tracepoints
trace strace inspired tool

See 'perf help COMMAND' for more information on a specific command.

root@ubuntu:~#

OK,安装成功!

2、使用Perf进行性能统计

使用之前我们先了解一下Perf都能统计哪些东西的性能数据。通过上面的perf -h 发现list 参数是可以列出所有event type。(List all symbolic event types。)
那我们执行perf list会发现列出的有Hardware event、Software event、Tool event、Hardware cache event这些(大致里面就是缓存命中、cpu时间、L1缓存命中等一大堆指标)

比如说我现在需要监测resource-page-1.0.0.jar这个java服务器运行期间的CPU使用时间、上下文切换次数等信息。

同样从帮助文档中得知stat Run a command and gather performance counter statisticsstat这个参数的功能大致意思是运行命令并收集性能计数器统计信息。

我们先直接执行perf stat java -jar resource-page-1.0.0.jar,这个时候java服务器就开始运行了,然后把该java服务的测试流程走一遍,最后直接Ctrl + C结束掉当前任务。这时终端就会回显统计信息:

Performance counter stats for 'java -jar resource-page-1.0.0.jar':

15,710.07 msec task-clock # 0.263 CPUs utilized
11,808 context-switches # 0.752 K/sec
584 cpu-migrations # 0.037 K/sec
131,695 page-faults # 0.008 M/sec
40,742,785,521 cycles # 2.593 GHz
46,422,658,743 instructions # 1.14 insn per cycle
9,177,132,057 branches # 584.156 M/sec
289,552,283 branch-misses # 3.16% of all branches

59.795222167 seconds time elapsed

14.154782000 seconds user
2.164583000 seconds sys

我们会发现这种监测只是在终端回显这些数据并没有什么数据留存下来供我们生成火焰图,所以我们接下来要使用record Run a command and record its profile into perf.datarecord这个参数来把收集来的数据保存到perf.data文件中。

那首先我们先将java服务启动并获取到该服务器的pid。(我这里是2403020后续我们会用到这个pid)

root@ubuntu:~# ps -ef|grep java
root 2403020 1 0 16:25 pts/1 00:00:18 java -jar /usr/local/app/resource/resource-page-1.0.0.jar 1000
root 2406162 2354230 0 17:03 pts/1 00:00:00 grep --color=auto java
root@ubuntu:~#

然后我们使用perf record -F 50 -a -p 2403020 -g -- sleep 60来采集数据。需要等待60s。

root@ubuntu:~# perf record -F 50 -a -p 2403020 -g -- sleep 60
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.064 MB perf.data (1117 samples) ]
root@ubuntu:~#

解释一下:所有的参数和用法可以执行perf record -h查看。这里我就解释一下我上面用到几个参数:

-F 50:每秒采样50次

-a:来自系统范围所有CPU的采集

-p:记录调用栈

-p:绑定进程的PID,这样就能针对某个进程进行监控。

– sleep 60:监控持续时间60秒

3、生成火焰图

上述操作后文件夹中将会多出来一个叫perf.data的文件,但这个文件还不能直接生成火焰图,这时我们需要转换一下。

root@ubuntu:~# perf script > out.perf
root@ubuntu:~# ll
total 31596
drwxr-xr-x 3 root root 4096 Jan 7 17:43 ./
drwxr-xr-x 3 root root 4096 Dec 6 17:51 ../
drwxr-xr-x 2 root root 4096 Jan 7 04:52 logs/
-rw------- 1 root root 4054 Jan 7 16:19 nohup.out
-rw-r--r-- 1 root root 37015 Jan 7 17:43 out.perf
-rw------- 1 root root 48268 Jan 7 17:43 perf.data
-rwxr-xr-x 1 root root 32243563 Dec 13 13:10 resource-page-1.0.0.jar*
-rwxr-xr-x 1 root root 1564 Dec 6 17:53 start.sh*
root@ubuntu:~#

然后利用FlameGraph项目进行火焰图的生成:

root@ubuntu:~# git clone --depth 1 https://github.com/brendangregg/FlameGraph.git
root@ubuntu:~# FlameGraph/stackcollapse-perf.pl out.perf > out.folded
root@ubuntu:~# FlameGraph/flamegraph.pl out.folded > out.svg

🪜:如果生成火焰图的时候提示 ERROR: No stack counts found 一般有三种情况

第一种情况:监控时间太短,这种情况稍微调大sleep的时间即可。

第二种情况:程序没有在运行了,这种情况就需要排查一下被监控程序的运行情况。

第三种情况:就是我这种,我这边测试用的是一个java web程序,所以在监控期间最好是请求几次接口。

一切顺利的话当前文件夹中就会出现一个svg图片,这个图片打开就是火焰图,效果如图:

  • java程序的这个因为只有我手动调用了几次逻辑简单的接口可能火焰效果不明显[调用栈越深火焰越高,CPU耗时越长火焰越宽]