最近我对linux内核处理信号的方式很困惑。
我知道当一个进程从内核返回(准备在用户模式下运行)时,内核调用用户注册的信号处理程序。最常见的情况是系统调用或内核调度任务。所以我写了一个程序,这是cpu绑定没有太多的系统调用。我在一台负载很低的机器上运行这个程序。
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#define USECREQ 10
#define LOOPS 1000
void event_handler(int signum)
{
static unsigned long cnt = 0;
static struct timeval tsFirst;
if (cnt == 0)
{
gettimeofday(&tsFirst, 0);
}
cnt++;
if (cnt >= LOOPS)
{
struct timeval tsNow;
struct timeval diff;
setitimer(ITIMER_REAL, NULL, NULL);
gettimeofday(&tsNow, 0);
timersub(&tsNow, &tsFirst, &diff);
unsigned long long udiff = (diff.tv_sec * 1000000) + diff.tv_usec;
double delta = (double)(udiff / cnt) / 1000000;
int hz = (unsigned)(1.0 / delta);
printf("kernel timer interrupt frequency is approx. %d Hz", hz);
if (hz >= (int)(1.0 / ((double)(USECREQ) / 1000000)))
{
printf(" or higher");
}
printf("\n");
exit(0);
}
}
int main(int argc, char **argv)
{
struct sigaction sa;
struct itimerval timer;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = &event_handler;
sigaction(SIGALRM, &sa, NULL);
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = USECREQ;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = USECREQ;
setitimer(ITIMER_REAL, &timer, NULL);
while (1) ;
}
由于机器的负载相当低(24核,没有其他任务),我认为没有太多的调度事件。
我认为唯一的内核到/从用户模式切换是时钟中断,大约是4 ms或10 ms,这意味着内核不会在1秒内调用event_handler超过1 s/4 ms = 250次。但令人惊讶的是,产量约为100000,它只需要约。这是否意味着大约有111111个内核调度事件?
// output
[root@my-centos ~]# time ./a.out
kernel timer interrupt frequency is approx. 111111 Hz or higher
real 0m0.011s
user 0m0.009s
sys 0m0.001s
时间内核传递信号(而不是生成)来处理的确切时间是多少?
1条答案
按热度按时间gupuwyp21#
首先,这一行是错误的,因为你在除法运算之后类型转换为double(这将是int)
它应该是:
我非常确定变量'delta'的值将非常接近USECREQ/1000000,这意味着大约。0.000010秒。“但是……这条线也是错的。通过将'delta'除以cnt,您持有 AVG。进程收到的所有SIGALRM的TIME(以秒为单位),但需要累计时间。
要知道在第二行中传递了多少个中断,应该是:
大约100 HZ。