导入
使用 gprof 进行代码性能分析
了解另一个在 C 语言中可用的工具 gprof,它帮助我们分析程序的执行时间。
性能分析(Profiling)是指收集程序执行过程中各项统计信息,以识别性能瓶颈并提升程序效率的过程。
如何使用 GNU 性能分析工具
UNIX 系统中有一个名为 gprof 的实用工具,可以帮助我们确定程序中哪些部分消耗了最多的执行时间。
基本步骤如下:
- 使用
-pg编译器标志编译程序,启用性能分析功能。 - 运行程序一次,生成性能分析数据文件。
- 执行
gprof命令来分析收集到的数据。
以下是一个进行数值计算的示例程序,我们希望对其进行性能分析:
1#include <stdio.h> 2#include <math.h> 3 4#define MAXLOOP 1e7 5 6double myFun1(double x) { 7 double a = sin(x); 8 return a; 9} 10 11double myFun2(double x) { 12 double a = pow(x, 3); 13 return a; 14} 15 16double myFun3(double x) { 17 double a = sqrt(x); 18 return a; 19} 20 21int main(int argc, char *argv[]) { 22 int i; 23 double x; 24 double xsum = 0.0; 25 for (i = 1; i < MAXLOOP; i++) { 26 x = myFun1(i) + myFun2(i) + myFun3(i); 27 xsum += x; 28 } 29 printf("xsum = %.6f\n", xsum); 30 return 0; 31}
我们可以使用命令行中的 time 命令查看该程序的执行耗时:
1$ gcc -o go go.c -lm 2$ time ./go 3xsum = 2499999499999934350004060160.000000 4 5real 0m1.576s 6user 0m1.572s 7sys 0m0.000s
为了对程序进行性能分析,我们需要重新编译程序以支持性能分析(使用 -pg 标志),运行一次程序生成数据,然后使用 gprof 查看分析结果:
1$ gcc -o go go.c -lm -pg 2$ ./go 3xsum = 2499999499999934350004060160.000000 4$ gprof go -p 5Flat profile: 6 7Each sample counts as 0.01 seconds. 8 % cumulative self self total 9 time seconds seconds calls ns/call ns/call name 10 40.35 0.12 0.12 9999999 12.11 12.11 myFun3 11 40.35 0.24 0.12 main 12 13.45 0.28 0.04 9999999 4.04 4.04 myFun2 13 3.36 0.29 0.01 9999999 1.01 1.01 myFun1 14 3.36 0.30 0.01 frame_dummy 15 16 % the percentage of the total running time of the 17time program used by this function. 18 19cumulative a running sum of the number of seconds accounted 20 seconds for by this function and those listed above it. 21 22 self the number of seconds accounted for by this 23seconds function alone. This is the major sort for this 24 listing. 25 26calls the number of times this function was invoked, if 27 this function is profiled, else blank. 28 29 self the average number of milliseconds spent in this 30ms/call function per call, if this function is profiled, 31 else blank. 32 33 total the average number of milliseconds spent in this 34ms/call function and its descendents per call, if this 35 function is profiled, else blank. 36 37name the name of the function. This is the minor sort 38 for this listing. The index shows the location of 39 the function in the gprof listing. If the index is 40 in parenthesis it shows where it would appear in 41 the gprof listing if it were to be printed.
gprof 输出的最开始部分提供了关键信息:程序有 40.35% 的时间花费在 myFun3 函数上,而 myFun2 和 myFun1 分别只占 13.45% 和 3.36%。显然,下一步应尝试优化 myFun3 函数的性能。
动手实践
请尝试使用 -pg 标志编译(gcc -o go go.c -lm -pg),运行程序(./go),再运行 GNU 性能分析器(gprof go -p)来分析以下代码。
No configuration found for ID: d3dbd6d7bafd23586ce4f09f87ccc2846f36b0d0fd626a247812448427193e14
尽管有这些工具可用,但在 C 语言中仍有一些编程方法会始终拖慢程序性能。我们将在下一课中讨论这些问题。