天天看點

【原創】(六)Linux程序排程-實時排程器

<code>Read the fucking source code!</code> --By 魯迅

<code>A picture is worth a thousand words.</code> --By 高爾基

說明:

Kernel版本:4.14

ARM64處理器,Contex-A53,雙核

使用工具:Source Insight 3.5, Visio

在Linux核心中,實時程序總是比普通程序的優先級要高,實時程序的排程是由<code>Real Time Scheduler(RT排程器)</code>來管理,而普通程序由<code>CFS排程器</code>來管理。

實時程序支援的排程政策為:<code>SCHED_FIFO</code>和<code>SCHED_RR</code>。

前邊的系列文章都是針對<code>CFS排程器</code>來分析的,包括了<code>CPU負載</code>、<code>組排程</code>、<code>Bandwidth控制</code>等,本文的<code>RT排程器</code>也會從這些角度來分析,如果看過之前的系列文章,那麼這篇文章了解起來就會更容易點了。

前戲不多,直奔主題。

有必要把關鍵的結構體羅列一下了:

<code>struct rq</code>:運作隊列,每個CPU都對應一個;

<code>struct rt_rq</code>:實時運作隊列,用于管理實時任務的排程實體;

<code>struct sched_rt_entity</code>:實時排程實體,用于參與排程,功能與<code>struct sched_entity</code>類似;

<code>struct task_group</code>:組排程結構體;

<code>struct rt_bandwidth</code>:帶寬控制結構體;

老規矩,先上張圖,捋捋這些結構之間的關系吧:

【原創】(六)Linux程式排程-實時排程器

從圖中的結構組織關系看,與<code>CFS排程器</code>基本一緻,差別在與<code>CFS排程器</code>是通過紅黑樹來組織排程實體,而<code>RT排程器</code>使用的是優先級隊列來組織實時排程實體;

<code>rt_rq</code>運作隊列,維護了100個優先級的隊列(連結清單),優先級0-99,從高到底;

排程器管理的對象是排程實體,任務<code>task_struct</code>和任務組<code>task_group</code>都是通過内嵌排程實體的資料結構,來最終參與排程管理的;

<code>task_group</code>任務組排程,自身為每個CPU維護<code>rt_rq</code>,用于存放自己的子任務或者子任務組,子任務組又能往下級聯,是以可以構造成樹;

上述結構體中,<code>struct rq</code>和<code>struct task_group</code>,在前文中都分析過。

下邊針對RT運作隊列相關的關鍵結構體,簡單注釋下吧:

運作時的統計資料更新,是在<code>update_curr_rt</code>函數中完成的:

【原創】(六)Linux程式排程-實時排程器

<code>update_curr_rt</code>函數功能,主要包括兩部分:

運作時間的統計更新處理;

如果運作時間超出了配置設定時間,進行時間均衡處理,并且判斷是否需要進行限流,進行了限流則需要将RT隊列出隊,并重新進行排程;

為了更直覺的了解,下邊還是來兩張圖檔說明一下:

<code>sched_rt_avg_update</code>更新示意如下:

【原創】(六)Linux程式排程-實時排程器

<code>rq-&gt;age_stamp</code>:在CPU啟動後運作隊列首次運作時設定起始時間,後續周期性進行更新;

<code>rt_avg</code>:累計的RT平均運作時間,每0.5秒減半處理,用于計算CFS負載減去RT在CFS負載平衡中使用的時間百分比;

<code>RT排程器</code>與<code>CFS排程器</code>的組排程基本類似,<code>CFS排程器</code>的組排程請參考<code>(四)Linux程序排程-組排程及帶寬控制</code>。

看一下<code>RT排程器</code>組排程的組織關系圖吧:

【原創】(六)Linux程式排程-實時排程器

系統為每個CPU都配置設定了RT運作隊列,以及RT排程實體,任務組通過它包含的RT排程實體來參與排程;

任務組<code>task_group</code>的RT隊列,用于存放歸屬于該組的任務或子任務組,進而形成級聯的結構;

看一下實際的組織示意圖:

【原創】(六)Linux程式排程-實時排程器

請先參考<code>(四)Linux程序排程-組排程及帶寬控制</code>。

<code>RT排程器</code>在帶寬控制中,排程時間周期設定的為1s,運作時間設定為0.95s:

這兩個值可以在使用者态通過<code>/sys/fs/cgroup/cpu/rt_runtime_us</code>和<code>/sys/fs/cgroup/cpu/rt_period_us</code>來進行設定。

看看函數調用流程:

【原創】(六)Linux程式排程-實時排程器

<code>init_rt_bandwidth</code>函數在建立配置設定RT任務組的時候調用,完成的工作是将<code>rt_bandwidth</code>結構體的相關字段進行初始化:設定好時間周期<code>rt_period</code>和運作時間限制<code>rt_runtime</code>,都設定成預設值;

可以從使用者态通過操作<code>/sys/fs/cgroup/cpu</code>下對應的節點進行設定<code>rt_period</code>和<code>rt_runtime</code>,最終調用的函數是<code>tg_set_rt_bandwidth</code>,在該函數中會從下往上的周遊任務組進行設定時間周期和限制的運作時間;

在<code>enqueue_rt_entity</code>将RT排程實體入列時,最終觸發<code>start_rt_bandwidth</code>函數執行,當高精度定時器到期時調用<code>do_sched_rt_period_timer</code>函數;

<code>do_sched_rt_period_timer</code>函數,會去判斷該RT運作隊列的累計運作時間<code>rt_time</code>與設定的限制運作時間<code>rt_runtime</code>之間的大小關系,以确定是否限流的操作。在這個函數中,如果已經進行了限流操作,會調用<code>balance_time</code>來在多個CPU之間進行時間均衡處理,簡單點說,就是從其他CPU的rt_rq隊列中勻出一部分時間增加到目前CPU的rt_rq隊列中,也就是将目前rt_rt運作隊列的限制運作時間<code>rt_runtime</code>增加一部分,其他CPU的rt_rq運作隊列限制運作時間減少一部分。

來一張效果示意圖:

【原創】(六)Linux程式排程-實時排程器

來一張前文的圖:

【原創】(六)Linux程式排程-實時排程器

看一下RT排程器執行個體的代碼:

<code>pick_next_task_rt</code>函數是排程器用于選擇下一個執行任務。流程如下:

【原創】(六)Linux程式排程-實時排程器

與<code>CFS排程器</code>不同,<code>RT排程器</code>會在多個CPU組成的<code>domain</code>中,對任務進行<code>pull/push</code>處理,也就是說,如果目前CPU的運作隊列中任務優先級都不高,那麼會考慮去其他CPU運作隊列中找一個更高優先級的任務來執行,以確定按照優先級處理,此外目前CPU也會把任務推送到其他更低優先級的CPU運作隊列上。

<code>_pick_next_task_rt</code>的處理邏輯比較簡單,如果實時排程實體是<code>task</code>,則直接查找優先級隊列的位圖中,找到優先級最高的任務,而如果實時排程實體是<code>task_group</code>,則還需要繼續往下進行周遊查找;

關于任務的<code>pull/push</code>,linux提供了<code>struct plist</code>,基于優先級的雙連結清單,其中任務的組織關系如下圖:

【原創】(六)Linux程式排程-實時排程器

<code>pull_rt_task</code>的大概示意圖如下:

【原創】(六)Linux程式排程-實時排程器

目前CPU上的優先級任務不高,從另一個CPU的<code>pushable_tasks</code>連結清單中找優先級更高的任務來執行;

當RT任務進行出隊入隊時,通過<code>enqueue_task_rt/dequeue_task_rt</code>兩個接口來完成,調用流程如下:

【原創】(六)Linux程式排程-實時排程器

<code>enqueue_task_rt</code>和<code>dequeue_task_rt</code>都會調用<code>dequeue_rt_stack</code>接口,當請求的rt_se對應的是任務組時,會從頂部到請求的rt_se将排程實體出列;

任務添加到rt運作隊列時,如果存在多個任務可以配置設定給多個CPU,設定overload,用于任務的遷移;

有點累了,收工了。

【原創】(六)Linux程式排程-實時排程器

作者:LoyenWang

出處:https://www.cnblogs.com/LoyenWang/

公衆号:<b>LoyenWang</b>

版權:本文版權歸作者和部落格園共有

轉載:歡迎轉載,但未經作者同意,必須保留此段聲明;必須在文章中給出原文連接配接;否則必究法律責任

下一篇: C# 9.0 新特性

繼續閱讀