在Linux-5.8.18中运行cyclictest时,是什么导致额外的计时器中断
我在Linux-5.8.18 X86_64上运行CyclcTest,与我自己编写的类似代码相比,我发现CyclcTest有些奇怪 奇怪的是,在运行CycleCTest时会触发很多额外的计时器中断,我通过使用ftrace得出如下结论:在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
#!/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,¶m);
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,¶m);
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