实时linux:禁用本地定时器中断

时间:2017-09-06 14:15:30

标签: timer linux-kernel real-time scheduler interrupt

TL; DR :使用linux内核实时与NO_HZ_FULL我需要隔离一个进程以获得确定性结果但是/ proc / interrupts告诉我仍然存在本地定时器中断(以及其他)。如何禁用它?

长版:

我想确保我的程序没有被中断,所以我尝试使用实时的Linux内核。 我使用的是arch linux的实时版本(AUR上的linux-rt),我修改了内核的配置,选择了以下选项:

CONFIG_NO_HZ_FULL=y
CONFIG_NO_HZ_FULL_ALL=y
CONFIG_RCU_NOCB_CPU=y
CONFIG_RCU_NOCB_CPU_ALL=y

然后我重新启动计算机以使用以下选项在这个实时内核上启动:

nmi_watchdog=0
rcu_nocbs=1
nohz_full=1
isolcpus=1

我还在BIOS中禁用了以下选项:

C state
intel speed step
turbo mode
VTx
VTd
hyperthreading

我的CPU(i7-6700 3.40GHz)有4个内核(8个具有超线程技术的逻辑CPU) 我可以在/ proc / interrupts文件中看到CPU0,CPU1,CPU2,CPU3。

CPU1被isolcpus内核参数隔离,我想在此CPU上禁用本地定时器中断。 我虽然实时内核有CONFIG_NO_HZ_FULL和CPU隔离(isolcpus)就足够了,我试着通过运行这些命令来检查:

cat /proc/interrupts | grep LOC > ~/tmp/log/overload_cpu1
taskset -c 1 ./overload
cat /proc/interrupts | grep LOC >> ~/tmp/log/overload_cpu1

重载过程是:

***overload.c:***
int main()
{
  for(int i=0;i<100;++i)
    for(int j=0;j<100000000;++j);
}

文件overload_cpu1包含结果:

LOC:     234328        488      12091      11299   Local timer interrupts
LOC:     239072        651      12215      11323   Local timer interrupts

含义651-488 = 163来自本地定时器的中断,而不是0 ......

为了比较我做同样的实验,但是我更改了我的进程overload运行的核心(我一直在看CPU1上的中断):

taskset -c 0 :   8 interrupts
taskset -c 1 : 163 interrupts
taskset -c 2 :   7 interrupts
taskset -c 3 :   8 interrupts

我的一个问题是为什么没有0中断?当我的进程在CPU1上运行时,为什么中断的数量会更大? (我的意思是我虽然NO_HZ_FULL会阻止中断,如果我的进程是独自的:&#34; CONFIG_NO_HZ_FULL = y Kconfig选项会导致内核避免 使用单个可运行任务向CPU发送调度时钟中断&#34;(https://www.kernel.org/doc/Documentation/timers/NO_HZ.txt

可能有一个解释是在CPU1上运行其他进程。 我使用ps命令检查:

CLS CPUID RTPRIO PRI  NI CMD                           PID
TS      1      -  19   0 [cpuhp/1]                      18
FF      1     99 139   - [migration/1]                  20
TS      1      -  19   0 [rcuc/1]                       21
FF      1      1  41   - [ktimersoftd/1]                22
TS      1      -  19   0 [ksoftirqd/1]                  23
TS      1      -  19   0 [kworker/1:0]                  24
TS      1      -  39 -20 [kworker/1:0H]                 25
FF      1      1  41   - [posixcputmr/1]                28
TS      1      -  19   0 [kworker/1:1]                 247
TS      1      -  39 -20 [kworker/1:1H]                501

如您所见,CPU1上有线程。 是否可以禁用这些过程?我想这是因为如果不是这样的话,NO_HZ_FULL永远不会正常工作?

TS类的任务不会打扰我,因为他们在SCHED_FIFO中没有优先权,我可以将此策略设置为我的程序。 类FF和优先级小于99的任务也是如此。

但是,您可以看到SCHED_FIFO中的migration / 1和优先级99。 也许这些过程在运行时会导致中断。这解释了我在CPU0,CPU2和CPU3上的进程(分别为8,7和8个中断)时的几个中断,但它也意味着这些进程不经常运行然后没有解释为什么当我有很多中断时进程在CPU1上运行(163次中断)。

我也做同样的实验,但是我的重载过程的SCHED_FIFO得到了:

taskset -c 0 : 1
taskset -c 1 : 4063
taskset -c 2 : 1
taskset -c 3 : 0

在此配置中,如果我的进程在CPU1上使用SCHED_FIFO策略而在其他CPU上使用较少,则会有更多中断。你知道为什么吗?

1 个答案:

答案 0 :(得分:1)

问题在于,一个全不滴答的CPU(也称为自适应滴答,配置有nohz_full=)仍然会收到滴答声。

最值得注意的是,调度程序需要在隔离的完整无滴答CPU上安装一个计时器,以便每秒大约更新一次状态。

这是已记录的限制(截至2019年):

  

某些流程处理操作仍然需要偶尔       计划时钟滴答声。这些操作包括计算CPU       负载,保持预定平均值,计算CFS实体vruntime,       计算avenrun并执行负载平衡。他们是       当前由调度时钟滴答声每秒容纳       或者。正在进行的工作将消除这些需求       不频繁的计划时钟滴答声。

(来源:Documentation/timers/NO_HZ.txt,请参见2013年以来的LWN文章(Nearly) full tickless operation in 3.10,出于某些背景)

一种更精确的方法来测量本地计时器中断(/proc/interrupts中的LOC行)是使用perf。例如:

$ perf stat -a -A -e irq_vectors:local_timer_entry ./my_binary

my_binary的线程固定在隔离的CPU上,这些线程不停地使用CPU而无需调用系统调用-持续2分钟。

还有其他本地计时器滴答声的来源(当只有1个可运行任务时)。

例如,VM统计信息的收集-默认情况下,它们每秒钟收集一次。因此,我可以通过设置较高的值来减少LOC中断,例如:

# sysctl vm.stat_interval=60

另一个来源是定期检查不同CPU上的TSC是否不漂移-您可以使用以下内核选项禁用它们:

tsc=reliable

(仅在您真的知道您的TSC不会漂移时才应用此选项。)

您可能会通过使用ftrace(在测试二进制文件运行时)记录跟踪来找到其他来源。

由于它出现在注释中:是的,SMI对内核是完全透明的。它不会显示为NMI。您只能间接检测SMI。