使用gprof奇怪的分析输出
我目前正在使用gprof分析我的代码,该代码符合C99。 我的程序是递归定义的 。 我正在编译使用带有-pg标志的gcc,并启用了一些警告,并且没有优化标志。 然后我运行代码,然后执行命令:
gprof ./myProgram > outputFile.txt
不过,我对输出结果告诉我很困惑。 这是说,我花了很多时间在一个函数中,我知道这个函数我没有花太多时间。有问题的函数有一个循环,并且执行一个任务多次。 然而,这是一项小任务,并且通过将任务完成的次数从5比100增加到100,我的程序执行所花费的总时间没有发生明显变化。 然而,gprof告诉我,我已经花费了将近50%的执行时间在这个函数中。
我不知道这里的问题是什么。 有没有人遇到过这样的事情? 我能自己解决这个问题吗? 我正在使用Linux的CentOS发行版。 我曾尝试将OProfile安装为另一个配置文件,但没有对/ usr / local的写入权限,因此make install失败,因此不确定这是否只是gprof的问题
以下是输出文件的相关部分。 奇怪的输出是函数nl_jacobi_to_converge
:
从我拥有的平面轮廓
% cumulative self self total
time seconds seconds calls s/call s/call name
49.02 7.50 7.50 1562 0.00 0.01 calculate_resid_numeric_jac_diags_tc41
16.41 10.01 2.51 323878716 0.00 0.00 c
14.97 12.30 2.29 323878716 0.00 0.00 b
6.01 13.22 0.92 89 0.01 0.02 calculate_resid_tc41
5.69 14.09 0.87 10967082 0.00 0.00 rhs_function
1.11 14.26 0.17 1562 0.00 0.00 single_nl_jacobi
...
0.00 15.30 0.00 11 0.00 0.76 nl_jacobi_to_converge
从我拥有的粒度来看
index % time self children called name
0.00 8.32 11/11 nl_multigrid [3]
[5] 54.4 0.00 8.32 11 nl_jacobi_to_converge [5]
5.28 2.92 1100/1562 calculate_resid_numeric_jac_diags_tc41 [4]
0.12 0.00 1100/1562 single_nl_jacobi [17]
你是众多试图找出gprof
告诉他们的人之一,小数点后四位。 我使用随机暂停和检查堆栈。
首先, gprof
是一个“CPU分析器”。 这意味着在IO,互斥锁,分页或任何其他阻塞系统调用期间,它将被关闭,并且不会计算该时间。 你说你没有这样做,但它可能发生在一些库函数内部。 如果是这样, gprof
掩盖它。 另一方面,一个堆栈样本将显示它正在等待什么,其概率等于它正在等待的时间的一小部分。
其次,正如@凯瑟琳所说的,了解“自我时间”很重要。 如果它很高,那意味着程序计数器在该例程中占用CPU时间的很大百分比。 但是,如果它很低,那并不意味着该功能无罪。 该函数可能花费大量时间,但通过调用子函数来完成。 要看到这一点,你需要gprof
“total”列,但占总时间的百分比,而不是每次调用的绝对时间,这是它给你的。 如果你拿一个堆栈样本,那么任何例程都会以等于它花费的时间的概率出现在它上面。 更重要的是,您将确切知道为什么这段时间会花费,因为样本会告诉您发生呼叫的确切线路号码。
补充: gprof
尝试处理递归函数,但正如其作者指出的那样,它不成功。 但是,栈递归在递归方面没有问题。 如果在递归函数调用期间获取堆栈样本,该函数可能多次出现在堆栈上多次。 然而,函数的包含时间成本,或任何调用函数的代码行,只不过是它在堆栈上的时间的一小部分。 为了看到这一点,假设以恒定频率采样,总共有M个样本,并且在它们的小数F上出现了特定函数或代码行。 如果这个功能或者代码行可以不花时间,比如删除它,分支它,或者把它传递给一个无限快的处理器,那么它就没有被采样的风险。 然后,它出现的M * F样本将消失,缩短执行时间F部分。
“自我”时间实际上是在该函数的代码中花费的时间。 “累积”时间是在该函数以及函数调用的任何事物(自我加上孩子)中花费的时间。
请注意,百分比是测量时间的百分比。 一个运行很多次的函数(比如你的b
)显然会影响运行时,而不仅仅是一个只运行几次的函数(你的n1_jacobi_to_converge
)。 每次通话所花的时间( /call
)可能太小而无法报告,但总数仍可能很大,并且可能仍然表明,值得寻找方法来减少通话次数和/或提高每次调用的效率。
警告:JIT稳定之前的测量毫无意义。 而且由于JIT不确定性,特别是但不仅限于大型多线程应用程序,即使Java代码未更改,性能也可能会因运行而大幅度变化。 在测量之前进行多次测量,并进行足够的预热,甚至准备妥善检查分析器的建议,因为它们可能会引起误解。
另一个警告:检查信号量等待时间是否被测量,并确保你知道所有线程中发生了什么。 如果您不计算等待时间,您可能会错过不在您的直接调用堆栈中的性能瓶颈。
(我花了很多时间优化了Apache Xalan及其IBM内部的后代,在那里,我们也有代码生成,它有自己的不确定性,最初的性能改进很简单明显;之后它变得更加复杂具有挑战性的!)
链接地址: http://www.djcxy.com/p/7627.html上一篇: Weird profiling output using gprof
下一篇: Seeking maximum bitmap (aka bit array) performance with C/Intel assembly