--- layout: default ---

用gprof来进行性能测试

"善假于物也"

Posted by Xz Yao on August 2, 2016

性能测试工具

最近在研究一些在Linux上的C/C++程序,目的是为一些现有的算法提速。主要是在做一些CV领域和压缩算法。

要想加速这些算法,首先要知道的是,这个程序每一步用了多少时间,在哪个函数上是瓶颈。那么gprof就是一个非常好用的工具了。gprof非常简单易用,值得一试。

gprof的使用过程主要有三步:编译、运行和查看(分析)。

编译

为了便于大家理解,我们首先编写一个程序:

void add()
{
        int i=1;
        int time=100000000000;
        for(i=1;i<=time;)
        {
                i=i+1;
        }
}
int main()
{
        add();
        add();
}

这个程序的含义非常简单,就是不停地做一个循环加的操作,然后做两次。

接下来我们就要编译它,常规的我们用gcc编译的命令是:

gcc test.c

即可。现在为了使用gprof,我们需要为其增加一个参数-pg,即

gcc test.c -pg

两次编译出来的结果都是a.out(当然实际上这两个文件是有差异的).为了表示区别,我们将这两个文件分别编译成a.out 和a_with_gprof.out。

运行

我们先执行a.out,等待一段时间时候结束。我们发现并没有生成什么东西。再执行a_with_gprof.out文件,我们发现执行之后,文件夹中多了gmon.out文件。这是一个二进制文件,意味着我们没办法直接打开它。

值得注意的是,如果当前文件夹下有一个gmon.out的文件,那么新生成的文件会覆盖掉原来的文件。

查看

为了查看gmon.out文件,我们需要使用gprof指令。

gprof a_with_gprof.out gmon.out

其中第一个为可执行文件的文件名,第二个为输出的gmon.out的文件。

这是我们就会看到输出的测试结果。

其中一部分是flat profile,这里显示每个函数的调用时间等信息,可以在其中看出,我们共调用了add函数2次,每次使用了4.13秒来完成。占据了几乎全部的时间(为什么这里会超过100%呢?等下再来解释)。第二个是call graph,显示的是彼此的调用关系。这张表中其实是有一系列的信息的,不过程序内为我们提供了全部的解释,这里就不做过多介绍和冗余的翻译了。

问题

为什么刚刚会超过100%呢?因为gprof只能监测到它可以监测到的部分,这意味着在我们的程序中有一些部分它是无法监测到的,例如运行在内核态的函数和没有加载-pg参数编译的第三方库。我们可以使用time命令来看一些系统调用所占的时间。 考虑到每次运行时的误差,这个结果就说得通了。

原理

这个问题的产生,和gprof的原理是分不开的。gprof的原理是在每一个函数调用时加入一个mcount的函数,mcount会在内存中保存相关的调度信息、调用次数、时间、父子函数等。因此,对于它无力解决的函数(上边提到的两种情况,它也就无能为力了。