perf 可以对指定的进程或者事件进行采样,并且还可以用调用栈的形式,输出整个调用链上的汇总信息。

使用 perf 来查找应用程序或者内核中的热点函数,从而找出是什么函数占用CPU比较高,从而定位性能瓶颈。

使用 perf 对系统内核线程进行分析时,内核线程依然还在正常运行中,所以这种方法也被称为动态追踪技术


安装:yum install perf -y

perf常用参数:

    top:动态时实追踪显示占用CPU较高的进程

    record:由于top只能实时查看不能保存,不便于事后分析,用此参数保存追踪的内容,文件名为perf.data

    report:重放perf.data的内容

perf record常用参数:

    -p:指定追踪进程的PID

    -g:启用进程中函数的调用关系(CPU使用超过0.5%时,才会显示调用栈,可以通过man查看)

    -a:追踪所有的CPU的

    sleep N:采集多长时间的数据(如:perf record -ag sleep 10;perf report,直接采集10数据并分析)

  

第一种常见用法是 perf top,类似于 top,它能够实时显示占用 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 是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。

还是以上面的输出为例,我们可以看到,占用 CPU 时钟最多的是 perf 工具自身,不过它的比例也只有 7.28%,说明系统并没有 CPU 性能问题。


第二种常见用法,也就是 perf record 和 perf report。 

    perf top 虽然实时展示了系统的性能信息,但它的缺点是并不保存数据,也就无法用于离线或者后续的分析。

    而 perf record 则提供了保存数据的功能,保存后的数据,需要你用 perf report 解析展示。

    record会自动保存到当前目录下的perf.data文件中

$ perf record -g # 按Ctrl+C终止采样
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.452 MB perf.data (6093 samples) ]

$ perf report # 展示类似于perf top的报告

在实际使用中,我们还经常为 perf top 和 perf record 加上 -g 参数,开启调用关系的采样,方便我们根据调用链来分析性能问题。

用法示例:

    perf record -g -p <pid>  ;会自动生成perf.data文件

    perf report ;会自动分析当前目录下的perf.data文件


在工作中经常会遇到CPU使用率很高,却找不到是哪些进程的情况,一般有以下2种情况:


    • 第一个原因,进程在不停地崩溃重启,比如因为段错误、配置错误等等,这时,进程在退出后可能又被监控系统自动重启了。

    • 第二个原因,这些进程都是短时进程,也就是在其他应用内部通过 exec 调用的外面命令。这些命令一般都只运行很短的时间就会结束,你很难用 top 这种间隔时间比较长的工具发现(上面的案例,我们碰巧发现了)。

    遇到这种情况,用top命令可以看到系统CPU的使用率较高,但是在系统中所有的进程CPU使用率都比较低,此时可以尝试使用perf record -g 和perf report进行分析。

小结

    碰到常规问题无法解释的 CPU 使用率情况时,首先要想到有可能是短时应用导致的问题,比如有可能是下面这两种情况。


    • 第一,应用里直接调用了其他二进制程序,这些程序通常运行时间比较短,通过 top 等工具也不容易发现

    • 第二,应用本身在不停地崩溃重启,而启动过程的资源初始化,很可能会占用相当多的 CPU

    对于这类进程,我们可以用 pstree 或者 execsnoop 找到它们的父进程,再从父进程所在的应用入手,排查问题的根源。


问题:在使用perf report时,发现swapper占用了大量的CPU时钟,如图所示,是什么原因?

121dcefacba1b554accd0a90ef349fbd.png

其实,当你清楚了 swapper 的原理后,就很容易理解我们为什么可以忽略它了。

看到swapper,你可能首先想到的是SWAP分区。实际上, swapper 跟 SWAP 没有任何关系,它只在系统初始化时创建 init 进程,之后,它就成了一个最低优先级的空闲任务。

也就是说,当 CPU 上没有其他任务运行时,就会执行swapper 。所以,你可以称它为“空闲任务”。

回到我们的问题,在 perf report 的界面中,展开它的调用栈,你会看到, swapper 时钟事件都耗费在了 do_idle 上,也就是在执行空闲任务。