10.2 使用诊断工具gprof

GNU诊断工具gprof对于测试程序的性能是非常有用的--它会记录每个函数的调用次数和函数的运行时间,以函数为单位记录。gprof工具可以非常容易的查出哪个函数消耗的运行时间最多。优化程序时应该首先关注这些函数。

我们将使用gprof工具检测一个数学程序,他计算一系列由数学上还未经证明的Collatz猜想产生的数字序列,下面的规则定义Collatz猜想的数字序列:

cxd

该数字序列从初始值Xo开始迭代,直到结果为1为止。根据该猜想,所有的数字序列最终都会终止与1。下面的程序展示了当Xo增长时的最长的数字序列。“collatz.c”源码文件包含3个函数:main,nseq和step:

include

/ Computes the length of Collatz sequences /

unsigned int

step (unsigned int x)

{

if (x % 2 == 0)

{

return (x / 2);

}

else

{

return (3 * x + 1);

}

}

unsigned int

nseq (unsigned int x0)

{

unsigned int i = 1, x;

if (x0 == 1 || x0 == 0)

return i;

x = step (x0);

while (x != 1 && x != 0)

{

x = step (x);

i++;

}

return i;

}

int

main (void)

{

unsigned int i, m = 0, im = 0;

for (i = 1; i < 500000; i++)

{

unsigned int k = nseq (i);

if (k > m)

{

m = k;

im = i;

printf ("sequence length = %u for %u\n", m, im);

}

}

return 0;

}

为了记录测试数据,程序必须使用’-pg’选项编译:

$ gcc -Wall -c -pg collatz.c

$ gcc -Wall -pg collatz.o

这会产生一个特殊的可执行文件,它包含额外的指令用于记录每个函数的执行时间。

如果程序不止一个源文件则每个源文件都需要使用’-pg’选项编译,并在链接生成最终可执行文件时也需要这个选项(就像上面的链接命令)。在链接的时候忘记使用’-pg’选项是一个常见的错误,此时不会记录任何有用信息。

可执行文件必须运行一次来产生测试数据:

$ ./a.out

(正常的程序输出显示)

当程序运行后,测试数据会写入当前目录下的’gmon.out’文件中。以可执行文件的名字作为参数运行gprof工具就可以分析这些数据:

$ gprof a.out

Flat profile:

Each sample counts as 0.01 seconds.

% cumul. self self total

Time seconds seconds calls us/call us/call name

68.59 2.14 2.14 62135400 0.03 0.03 step

31.09 3.11 0.97 499999 1.94 6.22 nseq

0.32 3.12 0.01 main

第一列数据显示程序的大多数(接近%70)时间是在运行step函数,%30的时间是在运行nseq函数。因此如果想减少程序的运行时间应该重点关注这两个函数。相对而言main函数花费的运行时间几乎可以忽略不计(少于1%)。

其他列的数据提供的信息是该函数的总调用次数和每次函数执行所花费的时间。Gprof还输出了其他的信息,但是这里没有显示。更多细节可以在Jay Fenlason和Richard Stallman编写的”GNU gprof----The GNU Profiler”手册中找到。