CPU绑定进程如何在内核模式和用户模式之间切换



最近我很困惑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核,没有其他任务),我认为没有太多的调度事件。

我认为唯一的内核到/从用户模式切换是时钟中断,这大约是4ms或10ms,这意味着内核不会调用event_handler超过1s/4ms = 250次在1秒内。但令人惊讶的是,输出大约是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

时间内核传递信号(而不是生成)到底是什么?

首先,这一行是错误的,因为您在除法操作(将在int中)之后将类型转换为double

double delta = (double)(udiff / cnt) / 1000000;

应该是:

double delta = ((double)udiff / cnt) / 1000000;

我很确定变量'delta'的值将非常接近USECREQ/1000000,这意味着大约。0.000010秒。BUT这一行也是错误的。通过将'delta'除以nt,您将持有AVG。TIME(以秒为单位)进程接收到的所有SIGALRM,但您需要累积时间。

要知道在第二行中传递了多少个中断,应该:

double delta = (double)udiff / 1000000;

大约100hz。

最新更新