09.代码剖析
对于比较大的程序,可以借助一些工具来首先把需要优化的点清理出来。接下来我们来看看在程序执行过程中获取数据并进行分析的工具:代码剖析程序。
测试程序:
#include <stdio.h>
#define T 100000
void call_one()
{
int count = T * 1000;
while(count--);
}
void call_two()
{
int count = T * 50;
while(count--);
}
void call_three()
{
int count = T * 20;
while(count--);
}
int main(void)
{
int time = 10;
while(time--)
{
call_one();
call_two();
call_three();
}
return 0;
}
编译的时候加入-pg选项:
deng@itcast:~/tmp$ gcc -pg test.c -o test
执行完成后,在当前文件中生成了一个gmon.out文件。
deng@itcast:~/tmp$ ./test
deng@itcast:~/tmp$ ls
gmon.out test test.c
deng@itcast:~/tmp$
使用gprof剖析主程序:
deng@itcast:~/tmp$ gprof test
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
95.64 1.61 1.61 10 160.68 160.68 call_one
3.63 1.67 0.06 10 6.10 6.10 call_two
2.42 1.71 0.04 10 4.07 4.07 call_three
其中主要的信息有两个,一个是每个函数执行的时间占程序总时间的百分比,另外一个就是函数被调用的次数。通过这些信息,可以优化核心程序的实现方式来提高效率。
当然这个剖析程序由于它自身特性有一些限制,比较适用于运行时间比较长的程序,因为统计的时间是基于间隔计数这种机制,所以还需要考虑函数执行的相对时间,如果程序执行时间过短,那得到的信息是没有任何参考意义的。
将上诉程序时间缩短:
#include <stdio.h>
#define T 100
void call_one()
{
int count = T * 1000;
while(count--);
}
void call_two()
{
int count = T * 50;
while(count--);
}
void call_three()
{
int count = T * 20;
while(count--);
}
int main(void)
{
int time = 10;
while(time--)
{
call_one();
call_two();
call_three();
}
return 0;
}
剖析结果如下:
deng@itcast:~/tmp$ gcc -pg test.c -o test
deng@itcast:~/tmp$ ./test
deng@itcast:~/tmp$ gprof test
Flat profile:
Each sample counts as 0.01 seconds.
no time accumulated
% cumulative self self total
time seconds seconds calls Ts/call Ts/call name
0.00 0.00 0.00 10 0.00 0.00 call_one
0.00 0.00 0.00 10 0.00 0.00 call_three
0.00 0.00 0.00 10 0.00 0.00 call_two
因此该剖析程序对于越复杂、执行时间越长的函数也适用。
那么是不是每个函数执行的绝对时间越长,剖析显示的时间就真的越长呢?可以再看如下的例子
#include <stdio.h>
#define T 100
void call_one()
{
int count = T * 1000;
while(count--);
}
void call_two()
{
int count = T * 100000;
while(count--);
}
void call_three()
{
int count = T * 20;
while(count--);
}
int main(void)
{
int time = 10;
while(time--)
{
call_one();
call_two();
call_three();
}
return 0;
}
剖析结果如下:
deng@itcast:~/tmp$ gcc -pg test.c -o test
deng@itcast:~/tmp$ ./test
deng@itcast:~/tmp$ gprof test
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
101.69 0.15 0.15 10 15.25 15.25 call_two
0.00 0.15 0.00 10 0.00 0.00 call_one
0.00 0.15 0.00 10 0.00 0.00 call_three
总结:
在使用gprof工具的时候,对于一个函数进行gprof方式的剖析,实质上的时间是指除去库函数调用和系统调用之外,纯碎应用部分开发的实际代码运行的时间,也就是说time一项描述的时间值不包括库函数printf、系统调用system等运行的时间。这些实用库函数的程序虽然运行的时候将比最初的程序实用更多的时间,但是对于剖析函数来说并没有影响。 |