降低linux实时任务抖动&延迟

内核配置建议:

一、配置NO_HZ子系统:

内核有以下几种HZ配置供选择:

CONFIG_HZ_PERIODIC  ##周期性tick

CONFIG_NO_HZ_IDLE  ##在系统idle状态下,禁止tick

CONFIG_NO_HZ_FULL  ##在系统idle或只有一个任务在运行的状态下,禁止tick

 

默认状态下,内核的时钟tick配置为CONFIG_NO_HZ_IDLE,也就是在idle的情况下关掉时钟中断。

开启CONFIG_NO_HZ_FULL以支持全动态时钟系统,可以让单个实时任务性能更高,干扰越小。

另外NO_HZ_FULL需要和命令行参数配合使用,需要在kernel cmdline中指定要启动的CPU。

如,在一个16核CPU的系统上,通过cmdline指定nohz_full=1-15,表示所有核(除0核)使能全动态时钟tick。

 

当系统启动后,手动迁移一些对延迟不铭感的rcu后台线程:

# for i in `pgrep rcu[^c]` ; do taskset -pc 0 $i ; done

 验证系统已经使能了NO_HZ_FULL系统:(也可以使用一个死循环脚本:while :; do d=1; )

perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1 

在默认的内核配置下,应该有1秒钟1000次的时钟中断:

# perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
1000 irq_vectors:local_timer_entry

当开启动态tick后,应该只能看到一秒钟只有一次时钟中断:

# perf stat -C 1 -e irq_vectors:local_timer_entry taskset -c 1 stress -t 1 -c 1
1 irq_vectors:local_timer_entry

 

二、配置ioslated CPU:

同样在支持CPUSET的情况下,可以将系统中某些CPU孤立出来,用于单独绑定rt任务执行,这些孤立出来的CPU叫做isolated cpus,这些cpu是调度器是不可见的。

如下cmdline参数,将cpu2,5,6,7设置为隔离cpu。

isolcpus=2,5-7

三、实时任务带宽限制

默认情况下,一个rt死循环任务不会完全占满单核cpu,因为内核实现了一个带宽限制功能,内核不想让一个任务完全霸占CPU,由于RT任务的调度算法是基于优先级的,若存在一个高优先级的死循环任务,会导致其他的cfs任务永远无法执行。所以系统默认开启了带宽限制,作用为:在一个单位周期内,rt任务最多只能占用95%的cpu比例,剩余5%会留给其他的普通任务。

所以,若要想rt任务完全占满cpu,则需要调整proc接口,让rt任务可以占满整个cpu。

/proc/sys/kernel/sched_rt_period_us

/proc/sys/kernel/sched_rt_runtime_us

另外要说的是,在smp多核系统里,默认参数下,其实rt任务仍然能占用到100%,这是因为在多核下,一个rt任务用完95%的cpu后,可以向其他空闲的cpu借时间。

四、设置硬件中断亲和性

多核系统下,有中断亲和性的概念,一个外设中断触发后,由中断控制器去通知CPU,用于负载均衡。默认情况下,硬件中断的亲和性是所有CPU核。也就是可能在所有CPU上产生中断。

为了避免RT任务抖动,可以将所有的SPI中断迁移到housekeeping核心上(shared peripheral interrupt),可以通过proc接口修改,如:将6号中断只亲和到CPU1和CPU2上。

echo 6 > /proc/irq/3/smp_affinity

五、迁移工作队列

系统中有一些工作队列,可能引发在RT任务cpu上唤醒Kwokrer后台线程,导致hang_task产生,或者干扰rt任务执行。

若一个工作队列带WQ_SYSFS属性,我们可以通过修改cpu亲和性来避免特定CPU上kworker任务唤醒。

注意:内核中存在一些内置的工作队列,如system_wq,system_hi_wq等,这些预置wq都不带WQ_SYSFS属性,若要避免这些wq上的work在RT-cpu上执行,需要额外处理,内核没有提供sysfs接口。

echo 1 > /sys/bus/workqueue/devices/writeback/cpumask

 

你可能感兴趣的:(内核特性)