如果还没有为 synprog 收集性能数据,必须进行收集,并打开实验 test.1.er。相关说明参见为 synprog 示例收集数据。
在此示例中,可以使用 [调用者-被调用者] 标签来研究如何将函数占用的时间归为其调用者。
[调用者-被调用者] 标签分为三个窗格。中央窗格中是选定的函数。上部窗格中是选定函数的调用者,下部窗格中是选定函数调用的函数,称为被调用者。
[调用者] 窗格显示调用选定函数的两个函数:gpf_b() 和 gpf_a()。由于 gpf_work() 没有调用任何其它函数,因此 [被调用者] 窗格为空。此类函数称为“叶函数”。
检查 [调用者] 窗格中的归属用户 CPU 时间列。调用者的归属时间是指从该调用者处调用选定函数所用的时间。gpf_work() 所用时间多数是由于从 gpf_b() 进行调用所致。而极少时间是由从 gpf_a() 进行调用所致。
gpf_work() 所用时间中,从 gpf_b() 调用所用的时间几乎是从 gpf_a() 调用所用的时间的十倍,要了解其中的原因,必须检查两个调用者的源代码。
gpf_a() 成为选定函数,并移至中央窗格;该函数的调用者出现在 [调用者] 窗格中,该函数的被调用者 gpf_work() 出现在 [被调用者] 窗格中。
gpf_a() 以 1 为参数,调用 gpf_work() 十次,而 gpf_b() 以 10 为参数,只调用 gpf_work() 一次。参数从 gpf_a() 和 gpf_b() 传递到 gpf_work() 中的形式参数 amt。
现在检查 gpf_work() 的代码,以了解调用者用不同方法调用 gpf_work() 会有所不同的原因。
检查计算变量 imax 的代码行:imax 是随后的 for 循环的上限。执行 gpf_work() 所占用的时间取决于参数 amt 的平方。因此,以 10 为参数从函数进行一次调用所用的时间(400 次迭代)是以 1 为参数从函数进行十次调用所用时间(4 次迭代的 10 个实例)的十倍。
但在 gprof 中,函数占用的时间是根据调用的次数进行估算的,而不考虑函数的参数或函数可以使用的任何其它数据如何决定时间。因此对于 synprog 的分析,gprof 错误推导出从 gpf_a() 调用所需的时间是从 gpf_b() 调用所需时间的十倍。此即 gprof 谬误。
另请参见 | |
---|---|
调用者-被调用者标签 源标签 互斥、相容和归属度量 |