性能工具perf的用法以及如何绘制性能火焰图

perf简介

Perf是内置于Linux内核源码树中的性能剖析(profiling)工具。其基于事件采样原理,以性能事件为基础,常用于性能瓶颈的查找与热点代码的定位。

性能调优工具如 perf,Oprofile 等的基本原理都是对被监测对象进行采样,最简单的情形是根据 tick 中断进行采样,即在 tick 中断内触发采样点,在采样点里判断程序当时的上下文。假如一个程序 90% 的时间都花费在函数 foo() 上,那么 90% 的采样点都应该落在函数 foo的上下文中。只要采样频率足够高,采样时间足够长,那么以上推论就比较可靠。因此,通过 tick 触发采样,我们便可以了解程序中哪些地方最耗时间,从而重点分析。

稍微扩展一下思路,就可以发现改变采样的触发条件使得我们可以获得不同的统计数据:

  • 以时间点 ( 如 tick) 作为事件触发采样便可以获知程序运行时间的分布。
  • 以 cache miss 事件触发采样便可以知道 cache miss 的分布,即 cache 失效经常发生在哪些程序代码中
  • 等等其他事件

当然,perf使用更多是CPU的PMU计数器,PMU计数器是大部分CPU都有的功能,它们可以用来统计比如L1 Cache失效的次数,分支预测失败的次数等。PMU可以在这些计数器的计数超过一个特定的值的时候产生一个中断,这个中断,我们可以用和时钟一样的方法,来抽样判断系统中哪个函数发生了最多的Cache失效,分支预测失效等。

perf 用法

本文示例代码:

//
// Created by wilcohuang on 2018/11/19.
//

#include 

using namespace std;

#define NUM 500000

void init(int *int_array) {
    for (int i = 0; i < NUM; i++) {
        int_array[i] = i;
    }
}

void accu(int *int_array, long &sum) {
    for (int i = 0; i < NUM; i++) {
        sum += int_array[i];
        usleep(3);
    }
}

int main() {
    int int_array[NUM];
    init(int_array);
    long sum = 0;
    accu(int_array, sum);
}

说明

perf的使用可以分为两种方式:

  1. 直接使用perf启动服务
  2. 挂接到已启动的进程
    第一种方式不需要root权限,第二种方式需要root权限

perf top

用于查看cpu的主要性能消耗点

跟踪一个名为main的进程:

perf top -e cycles -p `pgrep main`

输入如下:
性能工具perf的用法以及如何绘制性能火焰图_第1张图片

perf record

同样是分析诊断进程:

perf record -e cpu-clock -g ./run
或者
perf record -e cpu-clock -g -p 4522

使用ctrl+c中断perf进程,或者在程序执行结束后,会产生perf.data的文件,使用
perf report
会产生结果分析,如图
性能工具perf的用法以及如何绘制性能火焰图_第2张图片

火焰图

上面通过文件查看不够直观,还有一种火焰图分析的方式:
工具下载:
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或者看图软件打开:
性能工具perf的用法以及如何绘制性能火焰图_第3张图片

Y轴表示调用栈,X轴越宽,就表示它被抽到的次数多,即执行的时间长。注意,x 轴不代表时间,而是所有的调用栈合并后,按字母顺序排列的。

所以,一般我们只需要看有没有出现 “平顶”,如果有,那么这个函数可能有性能问题。

perf diff

优化程序性能后,我们自然要看下效果:
perf diff perf.data perf.data.before

我们干掉了上文中的usleep(3);这句代码,然后diff结果输出如下:
性能工具perf的用法以及如何绘制性能火焰图_第4张图片

init、accu函数的时间占比已经将为了0

权限问题

perf如果不是root,你可以做什么取决于sysctl设置。kernel.perf_event_paranoid

cat /proc/sys/kernel/perf_event_paranoid

kernel.perf_event_paranoid= 2:您无法进行任何测量。该perf实用程序可能仍然是有用的分析现有的记录用perf ls,perf report,perf timechart或perf trace。
kernel.perf_event_paranoid= 1:您可以使用perf stator 跟踪命令perf record,并获取内核分析数据。
kernel.perf_event_paranoid= 0:您可以使用perf stat或跟踪命令perf record,并获取CPU事件数据。
kernel.perf_event_paranoid= -1:您获得了对内核跟踪点的原始访问权限(具体来说,您可以mmap创建文件perf_event_open,我不知道其含义是什么)。

参考

更全的perf参考:

  • 系统级性能分析工具perf的介绍与使用
  • Linux性能调优工具perf的使用

本文参考:

  • 如何读懂火焰图?
  • Linux性能分析工具与图形化方法
  • Linux性能调优工具perf的使用
  • 在Linux下做性能分析3:perf

你可能感兴趣的:(性能分析)