在Linux-5.8.18中运行cyclictest时,是什么导致额外的计时器中断

在Linux-5.8.18中运行cyclictest时,是什么导致额外的计时器中断,linux,performance-testing,Linux,Performance Testing,我在Linux-5.8.18 X86_64上运行CyclcTest,与我自己编写的类似代码相比,我发现CyclcTest有些奇怪 奇怪的是,在运行CycleCTest时会触发很多额外的计时器中断,我通过使用ftrace得出如下结论: #!/bin/bash target=$1 delay=$2 echo f > /sys/devices/virtual/workqueue/cpumask sysctl -w vm.stat_interval=120 sysctl -w kernel.sc

我在Linux-5.8.18 X86_64上运行CyclcTest,与我自己编写的类似代码相比,我发现CyclcTest有些奇怪

奇怪的是,在运行CycleCTest时会触发很多额外的计时器中断,我通过使用ftrace得出如下结论:

#!/bin/bash
target=$1
delay=$2

echo f > /sys/devices/virtual/workqueue/cpumask
sysctl -w vm.stat_interval=120
sysctl -w kernel.sched_rt_runtime_us=-1

pushd /sys/kernel/debug/tracing/
echo 0 > tracing_on
echo function > current_tracer
echo > set_ftrace_filter
echo __sysvec_apic_timer_interrupt >> set_ftrace_filter # 5.8.18
echo 1 > tracing_on
##~/test/process/load $target 1 99 100 $delay
echo "Sleeping $delay seconds"
sleep $delay

echo 0 > tracing_on
cat per_cpu/cpu${target}/trace > ~/trace_cpu${target}
popd

我用下面的内核命令行隔离了CPU 6和7进行测试

irqaffinity=0-5 isolcpus=nohz,domain,6-7 nowatchdog intel_idle.max_cstate=0 rcu_nocbs=6-7 rcu_nocb_poll=0-5 audit=0 selinux=0 nmi_watchdog=0 mce=ignore_ce transparent_hugepage=never clocksource=tsc tsc=reliable skew_tick=1 intel_iommu=on intel_pstate=disable nosoftlockup nohz_full=6-7 idle=halt

然后我以
taskset-c7chrt-f99运行cyclictest。/cyclictest-q-s-t1-m-p99-i100-a6-7-d10m
我可以像这样运行上面的脚本“capt.sh 6 5”,它将在CPU6中收集ftrace 5秒钟。
然后我检查了trace_cpu6的输出文件,以检查计时器中断之间的间隔,我会发现类似的内容

<idle>-0       [006] d.h1 68077.196942: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
cyclictest-12923   [006] d.h1 68077.196966: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
==============================
--------
<idle>-0       [006] d.h1 68077.546239: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
<idle>-0       [006] d.h1 68077.546274: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
==============================
--------
<idle>-0       [006] d.h1 68077.864248: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
cyclictest-12923   [006] d.h1 68077.864265: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
==============================
--------
<idle>-0       [006] d.h1 68079.618839: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
<idle>-0       [006] d.h1 68079.618868: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
==============================
--------
<idle>-0       [006] d.h1 68080.218837: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
<idle>-0       [006] d.h1 68080.218878: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
==============================
--------
<idle>-0       [006] d.h1 68080.975849: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
<idle>-0       [006] d.h2 68080.975870: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
==============================
--------
<idle>-0       [006] d.h1 68082.106053: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
cyclictest-12923   [006] d.h1 68082.106071: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
==============================
--------
<idle>-0       [006] d.h1 68082.117046: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
<idle>-0       [006] d.h1 68082.117071: __sysvec_apic_timer_interrupt <-asm_call_irq_on_stack
==============================
当cyclictest在CPU 6上运行时,除rt_sigtimedwait外,没有其他系统调用。
在这种情况下,是什么导致调用额外的计时器中断

为了与cyclictest进行比较,我编写了一个简单的代码来调用sigtimedwait()以在循环中延迟100us,就像cyclictest一样

#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <sched.h>

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/sysinfo.h>
#include <time.h>

void catcher( int sig )
{
    printf( "Signal catcher called for signal %d\n", sig );
}

int main( int argc, char *argv[] ) {

    int result = 0;
    struct sigaction sigact;
    sigset_t waitset;
    siginfo_t info;
    struct timespec timeout;
    int  loops, delay_us;
    struct sched_param param;
    int ret = 0, cpu;
    int sched_method;
    int sched_priority;
    cpu_set_t mask;
    unsigned long i;
    struct timeval tv1, tv2;

    if (argc != 6) {
        fprintf(stderr,"usage:./test cpu sched_method sched_priority sleep_interval_in_us delay_in_sec\n");
        return -1;
    }

    cpu = atoi(argv[1]);
    CPU_ZERO(&mask);
    CPU_SET(cpu,&mask);

    printf("XXXXX Running this loop one CPU with scheduler and priority\n");

    loops = atoi(argv[5]);
    if (loops < 0) {
        loops = 1;
    }

    delay_us = atoi(argv[4]);

    sched_method = atoi(argv[2]);
    sched_priority = atoi(argv[3]);
    if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
        printf("warning: could not set CPU affinity, continuing...\n");
    }

    if (sched_method > 2 || sched_method < 0) {
        fprintf(stderr,"sched_method scope [0,2]\n");
        return -2;
    }
    if (sched_priority > 99 || sched_priority < 1) {
        fprintf(stderr,"sched_priority scope [1,99]\n");
        return -3;
    }

    if (sched_method == 1 || sched_method == 2) {
        param.sched_priority = sched_priority;
        ret = sched_setscheduler(getpid(),sched_method,&param);
        if (ret) {
            fprintf(stderr,"set scheduler to %d %d failed \n", sched_method, sched_priority);
            return -4;
        }
    }

    int scheduler = sched_getscheduler(getpid());

    fprintf(stderr,"the scheduler of PID(%d) is %d, priority (%d),BEGIN time is :%ld\n",
            getpid(),scheduler,sched_priority,time(NULL));

    sigemptyset( &sigact.sa_mask );
    sigact.sa_flags = 0;
    sigact.sa_handler = catcher;
    sigaction( SIGALRM, &sigact, NULL );

    sigemptyset( &waitset );
    sigaddset( &waitset, SIGALRM );

    sigprocmask( SIG_BLOCK, &waitset, NULL );

    loops = (loops * 1000000) / delay_us;

    for (i = 0; i <= loops; i ++) {
        timeout.tv_sec = 0;     /* Number of seconds to wait */
        timeout.tv_nsec = delay_us * 1000;  /* Number of nanoseconds to wait */

        gettimeofday(&tv1, NULL);
        result = sigtimedwait( &waitset, &info, &timeout );
        gettimeofday(&tv2, NULL);
    }

    return( result );
}

and running it as ./a.out 6 0 99 100 2000, means running it in CPU 6 with priority of 99 in
SCHED_FIFO, with 100usec as sleep, and totally run it for 2000 seconds.
所以主要的问题是为什么在CycleCTest运行时会有额外的计时器中断,而我自己的代码没有额外的中断

#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <sched.h>

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/sysinfo.h>
#include <time.h>

void catcher( int sig )
{
    printf( "Signal catcher called for signal %d\n", sig );
}

int main( int argc, char *argv[] ) {

    int result = 0;
    struct sigaction sigact;
    sigset_t waitset;
    siginfo_t info;
    struct timespec timeout;
    int  loops, delay_us;
    struct sched_param param;
    int ret = 0, cpu;
    int sched_method;
    int sched_priority;
    cpu_set_t mask;
    unsigned long i;
    struct timeval tv1, tv2;

    if (argc != 6) {
        fprintf(stderr,"usage:./test cpu sched_method sched_priority sleep_interval_in_us delay_in_sec\n");
        return -1;
    }

    cpu = atoi(argv[1]);
    CPU_ZERO(&mask);
    CPU_SET(cpu,&mask);

    printf("XXXXX Running this loop one CPU with scheduler and priority\n");

    loops = atoi(argv[5]);
    if (loops < 0) {
        loops = 1;
    }

    delay_us = atoi(argv[4]);

    sched_method = atoi(argv[2]);
    sched_priority = atoi(argv[3]);
    if (sched_setaffinity(0, sizeof(mask), &mask) == -1) {
        printf("warning: could not set CPU affinity, continuing...\n");
    }

    if (sched_method > 2 || sched_method < 0) {
        fprintf(stderr,"sched_method scope [0,2]\n");
        return -2;
    }
    if (sched_priority > 99 || sched_priority < 1) {
        fprintf(stderr,"sched_priority scope [1,99]\n");
        return -3;
    }

    if (sched_method == 1 || sched_method == 2) {
        param.sched_priority = sched_priority;
        ret = sched_setscheduler(getpid(),sched_method,&param);
        if (ret) {
            fprintf(stderr,"set scheduler to %d %d failed \n", sched_method, sched_priority);
            return -4;
        }
    }

    int scheduler = sched_getscheduler(getpid());

    fprintf(stderr,"the scheduler of PID(%d) is %d, priority (%d),BEGIN time is :%ld\n",
            getpid(),scheduler,sched_priority,time(NULL));

    sigemptyset( &sigact.sa_mask );
    sigact.sa_flags = 0;
    sigact.sa_handler = catcher;
    sigaction( SIGALRM, &sigact, NULL );

    sigemptyset( &waitset );
    sigaddset( &waitset, SIGALRM );

    sigprocmask( SIG_BLOCK, &waitset, NULL );

    loops = (loops * 1000000) / delay_us;

    for (i = 0; i <= loops; i ++) {
        timeout.tv_sec = 0;     /* Number of seconds to wait */
        timeout.tv_nsec = delay_us * 1000;  /* Number of nanoseconds to wait */

        gettimeofday(&tv1, NULL);
        result = sigtimedwait( &waitset, &info, &timeout );
        gettimeofday(&tv2, NULL);
    }

    return( result );
}

and running it as ./a.out 6 0 99 100 2000, means running it in CPU 6 with priority of 99 in
SCHED_FIFO, with 100usec as sleep, and totally run it for 2000 seconds.
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
100.00    0.925396          52     17548     17548 rt_sigtimedwait
------ ----------- ----------- --------- --------- ----------------
100.00    0.925396                 17548     17548 total