pprof的原理

2013-08-09

pprof的原理

性能调优时,要分析找出哪里操作比较费时,这里pprof工具就十分重要了,它可以告诉你哪个函数被调用了多少次,帮你找到性能瓶颈。那么,pprof的原理是怎样的呢?

先从最简单的说起,关键字“取样”和“统计”。我们知道操作系统是有时钟中断的,每个进程运行一些CPU时间片,当中断到来就会切到其它进程。假设我们在每个时钟中断时对程序进行取样。具体方式是,将程序代码段的每条指令都分配一个槽,每个中断时,通过查看PC寄存器可以知道执行的哪条指令,将对应的指令槽加一。最后就可以统计,得到程序中每条指令被调用的频率。

这个是最基本的,但是有些问题。首先,指令级别的统计信息是没有太大意义的,比如说我们得到mov指令10000次,jmp指令400次是没用的,我们至少要做函数级的取样,得到函数被调用的次数。当然,只有函数信息还是不够的,比如说我们得到memset函数占整个函数调用的23%,但显然是这个库函数,我们得知道是到底是谁在调它才能找到问题。

其实,由操作系统每次中断去统计的方式,显然是不够灵活的。

不过上面已经把pprof最核心的原理说明白了,就是取样和统计。虽然存在一些问题,但是可以改进嘛。先说第二个问题, 其实可以让操作系统把计时器抽象出来,给程序发SIGALRM信号,然后由用户层去处理计时器取样,这样就灵活多了。

再看第一个问题,我们要做函数级别的信息统计并得到调用关系,其实是应该对栈帧进行取样。

假设我们在程序执行的某个时刻取样得到一个栈帧序列是ABC,可以得到的信息包括:此刻运行的函数是C,是从函数B调用到C的。当取样很多次后进行统计,就可以得到调用的信息。比如对下面这段代码的取样:

void A() {
    B();
    for (int i=0; i<3; i++)
        C();
}
void B() {
    for (int i=0; i<5; i++)
        C();
}

将得到

A
AB
ABC
ABC
ABC
ABC
ABC
AC
AC
AC

将统计结果图形化显示甚至能达到这种效果:

image

pprof