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,分別是進程->問題點->問題點棧回溯。

相關文章
相關標籤/搜索