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

问题描述 投票:0回答:1

最近我对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,这意味着内核不会在 1 秒内调用 event_handler 超过 1s/4ms = 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

内核传递信号(不生成)进行处理的确切时间是多少?

linux kernel signals
1个回答
0
投票

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

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

应该是:

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

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

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

double delta = (double)udiff / 1000000;

将在 100 HZ 左右。

© www.soinside.com 2019 - 2024. All rights reserved.