Linux进程管理 (7)实时调度

关键词:RT、preempt_count、RT patch。html

 

除了CFS调度器以外,还包括重要的实时调度器,有两种RR和FIFO调度策略。本章只是一个简单的介绍。linux

更详细的介绍参考《Linux进程管理 (9)实时调度类分析,以及FIFO和RR对比实验》。shell

同时为了提升Linux的实时性,Linux社区还维护了realtime相关的补丁。这些补丁的介绍在《Linux实时补丁及其分析》。安全

 

1. 抢占内核

若是Linux内核不支持抢占,那么进程要么主动要求调度,如schedule()或者cond_resched();要么在系统调用、异常处理和中断处理完成返回用户空间前夕框架

 

在支持可抢占内核中,若是唤醒动做发生在系统调用或者异常处理上下文中,在下一次调用preempt_enable()是会检查是否须要抢占调度;ide

中断处理返回前夕会检查是否要抢占当前进程,注意这里是中断返回而不是不支持抢占状况的用户空间返回函数

struct thread_info成员preempt_count计数表示内核是否能够被彻底抢占,当preempt_count为0时,表示内核能够被安全抢占;大于0时则禁止抢占。工具

preempt_count是32bit,低8位用于抢占计数PREEMPT_ACTIVE表示一个很大的抢占计数,一般用于表示抢占调度。测试

内核提供preempt_disable()来关闭抢占,preempt_count会加1。preempt_enable()函数打开抢占,preempt_count减1后判断是否为0,并检查thread_info的TIF_NEED_RESCHED标志位,若是为0,则用schedule() 完成调度抢占。ui

#define preempt_disable() \
do { \ preempt_count_inc(); \----------------------------------------对当前current_thread_info()->preempt_count加1 barrier(); \ } while (0) #define preempt_count_inc() preempt_count_add(1)
#define preempt_count_add(val)    __preempt_count_add(val)
static __always_inline void __preempt_count_add(int val) { *preempt_count_ptr() += val; } 
#define preempt_enable() \ do { \ barrier(); \ if (unlikely(preempt_count_dec_and_test())) \-----------------prermpt_count减1后为0,且TIF_NEED_RESCHED被置位,则进行schedule()调度抢占。 __preempt_schedule(); \ } while (0) static __always_inline bool __preempt_count_dec_and_test(void) { return !--*preempt_count_ptr() && tif_need_resched();---------对当前preempt_count减1并判断是否为0,若是为0则检查TIF_NEED_RESCHED } static __always_inline int *preempt_count_ptr(void) { return &current_thread_info()->preempt_count; } #define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED)-----测试TIF_NEED_RESCHED是否置位 #define test_thread_flag(flag) \ test_ti_thread_flag(current_thread_info(), flag) #define __preempt_schedule() preempt_schedule() asmlinkage __visible void __sched notrace preempt_schedule(void) { if (likely(!preemptible()))-----------------------------------判断当前preempt_count是否为0,而且irq没有被禁止。 return; preempt_schedule_common();------------------------------------__schedule()调度抢占。 }
# define preemptible() (preempt_count() == 0 && !irqs_disabled()) 
 
 
static void __sched notrace preempt_schedule_common(void) { do { __preempt_count_add(PREEMPT_ACTIVE); __schedule(); __preempt_count_sub(PREEMPT_ACTIVE); /* * Check again in case we missed a preemption opportunity * between schedule and now. */ barrier(); } while (need_resched()); }

 

 

2. 内核实时进展

Linux在提升实时性方面取得一系列进展,具体以下:

主要功能 内核版本 说明
Preemption suport 2.5  
PI Mutexes N/A PI即Priority Inheritance,优先级继承的互斥体
HR Timer 2.6.24 高精度定时器
Preemptive RCU 2.6.25 可抢占RCU
IRQ Threads 2.6.30 中断线程化
Forced IRQ Threads 2.6.39 强制中断线程化
Deadline scheduler 3.14 Deadline调度器
Full Realtime Preemption support rt-patches rt.wiki.kernel.org

 

 

3. 内核延迟调试工具

内核提供了一些接口、工具,使咱们得以一窥调度延迟。经常使用的有个ftrace的调度器preemptirqoff、等,以及工具latencytop、cyclictest等。

3.1 ftrace preemptirqsoff

preemptirqsoff能够跟踪关闭中断并禁止进程抢占代码的延时,同时记录关闭的最大时长。

这些tracer能够在Kernel hacking->Tracers中打开。 

查看/sys/kernel/debug/tracing/available_tracers能够知道当前支持的tracer,里面有preemptirqsoff、preemptoff、irqsoff三种。

更详细的解释参照《Linux ftrace框架介绍及运用》。

下面是一个preemptirqsoff实例,能够看出禁止抢占、屏蔽中断的函数排列。以及最大值的进程信息和发生时的栈信息。

# tracer: preemptirqsoff # # preemptirqsoff latency trace v1.1.5 on 4.4.138-rt155-custom # -------------------------------------------------------------------- # latency: 628 us, #39/39, CPU#0 | (M:preempt VP:0, KP:0, SP:0 HP:0 #P:8) # ----------------- # | task: gnome-shell-1775 (uid:1000 nice:0 policy:0 rt_prio:0) # ----------------- # => started at: schedule # => ended at: migrate_disable # # # _--------=> CPU# # / _-------=> irqs-off # | / _------=> need-resched # || / _-----=> need-resched_lazy # ||| / _----=> hardirq/softirq # |||| / _---=> preempt-depth # ||||| / _--=> preempt-lazy-depth # |||||| / _-=> migrate-disable # ||||||| / delay # cmd pid |||||||| time   | caller # \ /      ||||||||   \    |  /            
... gnome-sh-1775    0....21.   41us!: preempt_count_sub <-_raw_spin_unlock_irq gnome-sh-1775    0....11.  627us : pin_current_cpu <-migrate_disable gnome-sh-1775    0....111  628us : preempt_count_sub <-migrate_disable gnome-sh-1775    0....111  628us : migrate_disable <-migrate_disable gnome-sh-1775    0....111  629us+: trace_preempt_on <-migrate_disable gnome-sh-1775    0....111  686us : <stack trace>
 => preempt_count_sub => migrate_disable => rt_spin_lock => add_wait_queue => __pollwait => unix_poll => sock_poll => do_sys_poll => SyS_poll => entry_SYSCALL_64_fastpath

 

 

3.2 latencytop

latencytop在内核上下文切换时记录被切换进程的内核栈,而后经过匹配内核栈函数来判断致使上下文切换的缘由。

方便判断系统出现哪方面的延迟,还能查看某个进程或者线程的延迟状况。

使用latencytop须要安装libcanberra-gtk-module,而且使能CONFIG_LATENCYTOP(经过Kernel hacking->Latency measuring infrastructure打开)。

执行sudo latencytop,获得以下结果。

整个结果分为三部分,Targets->Cause->Backtrace,分别是进程->问题点->问题点栈回溯。

相关文章
相关标签/搜索