我使用gprof分析一个在linux上运行的程序,该程序使用一个25ms的间隔计时器(由timer_create()创建)来更新一个全局变量。信号处理程序类似于update_every_25ms(),它调用profile_dummy()来增加grobal变量:

static void update_every_25ms(int sig_nr) { profile_dummy(); }
void profile_dummy(void) { global_var++; }

计时器是通过以下方式创建的:
timer_t timer;
struct itimerspec itimer;
timer_create(CLOCK_MONOTONIC, NULL, &timer)
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_nsec = 25 * 1000 * 1000;
timer_settime(timer, 0, &itimer, NULL);

我的程序做了很多繁重的工作,但是gprof显示,当CPU使用率为100%时,update_every ms()函数花费的时间最多,而这个函数本身每次调用大约花费1.53ms!
以下是间隔为25ms时的几组gprof输出:
%time  cumulative  self     calls  self    total    name
       seconds     seconds         ms/call ms/call
3.72   116.26      7.76     22963  0.34    0.34     profile_dummy

这里的CPU使用率是60%。
为什么profile_dummy()每次调用需要0.34ms?
%time  cumulative  self     calls  self    total    name
       seconds     seconds         ms/call ms/call
9.38   38.87       38.87    25349  0.00    0.00     profile_dummy

这里的CPU使用率是100%。
38.87s/25349=1.53ms但gprof输出0.00,发生了什么?
%time  cumulative  self     calls  self    total    name
       seconds     seconds         ms/call ms/call
6.21   270.58      57.72 59105     0.00    0.00     profile_dummy

这里的CPU使用率是90%。
57.72s/59105=0.98ms,但gprof也输出0.00。
这是当我将计时器间隔更改为25s时的gprof输出:
%time  cumulative  self     calls  self    total    name
       seconds     seconds         ms/call ms/call
0.01   287.52      0.03  23        1.30    1.30     profile_dummy

函数只是增加了一个全局变量,为什么需要1.30ms?
谢谢你的回复。

最佳答案

我只是在瞎猜。
gprof每10毫秒有一个信号中断,此时它对程序计数器(pc)进行采样。
一个例程的总自时间是在该例程中着陆的样本数。
因为它还计算对例程的调用,所以它可以得到每个调用的平均自时间。
通常,当你的程序被阻塞时,比如I/O、睡眠或多任务暂停,PC机是没有意义的,所以中断被暂停。
这就是为什么gprof根本看不到I/O的原因。
但是,如果您有自己的计时器中断,则这可能只会屏蔽探查器中断,而不是挂起它,从而导致在计时器中断被解除后得到响应,这可能会优先将PC放入中断处理程序中。
但那只是猜测。
除非这纯粹是一个学术问题,否则有比gprof更好的探查器。

关于linux - gprof显示一个简单的信号处理程序占用大量CPU,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20779980/

10-11 16:24