Linux程式優先順序的處理--Linux程式的管理與排程(二十二)
日期 | 核心版本 | 架構 | 作者 | GitHub | CSDN |
---|---|---|---|---|---|
2016-06-14 | Linux-4.6 | X86 & arm | gatieme | LinuxDeviceDrivers | Linux程式管理與排程 |
1 前景回顧
1.1 程式排程
記憶體中儲存了對每個程式的唯一描述, 並通過若干結構與其他程式連線起來.
排程器面對的情形就是這樣, 其任務是在程式之間共享CPU時間, 創造並行執行的錯覺, 該任務分為兩個不同的部分, 其中一個涉及排程策略, 另外一個涉及上下文切換.
核心必須提供一種方法, 在各個程式之間儘可能公平地共享CPU時間, 而同時又要考慮不同的任務優先順序.
排程器的一個重要目標是有效地分配 CPU 時間片,同時提供很好的使用者體驗。排程器還需要面對一些互相沖突的目標,例如既要為關鍵實時任務最小化響應時間, 又要最大限度地提高 CPU 的總體利用率.
排程器的一般原理是, 按所需分配的計算能力, 向系統中每個程式提供最大的公正性, 或者從另外一個角度上說, 他試圖確保沒有程式被虧待.
1.2 程式的分類
linux把程式區分為實時程式和非實時程式, 其中非實時程式進一步劃分為互動式程式和批處理程式
型別 | 描述 | 示例 |
---|---|---|
互動式程式(interactive process) | 此類程式經常與使用者進行互動, 因此需要花費很多時間等待鍵盤和滑鼠操作. 當接受了使用者的輸入後, 程式必須很快被喚醒, 否則使用者會感覺系統反應遲鈍 | shell, 文字編輯程式和圖形應用程式 |
批處理程式(batch process) | 此類程式不必與使用者互動, 因此經常在後臺執行. 因為這樣的程式不必很快相應, 因此常受到排程程式的怠慢 | 程式語言的編譯程式, 資料庫搜尋引擎以及科學計算 |
實時程式(real-time process) | 這些程式由很強的排程需要, 這樣的程式絕不會被低優先順序的程式阻塞. 並且他們的響應時間要儘可能的短 | 視訊音訊應用程式, 機器人控制程式以及從物理感測器上收集資料的程式 |
在linux中, 排程演算法可以明確的確認所有實時程式的身份, 但是沒辦法區分互動式程式和批處理程式, linux2.6的排程程式實現了基於程式過去行為的啟發式演算法, 以確定程式應該被當做互動式程式還是批處理程式. 當然與批處理程式相比, 排程程式有偏愛互動式程式的傾向
1.3 不同程式採用不同的排程策略
根據程式的不同分類Linux採用不同的排程策略.
對於實時程式,採用FIFO, Round Robin或者Earliest Deadline First (EDF)最早截止期限優先排程演算法|的排程策略.
對於普通程式,則需要區分互動式和批處理式的不同。傳統Linux排程器提高互動式應用的優先順序,使得它們能更快地被排程。而CFS和RSDL等新的排程器的核心思想是”完全公平”。這個設計理念不僅大大簡化了排程器的程式碼複雜度,還對各種排程需求的提供了更完美的支援.
注意Linux通過將程式和執行緒排程視為一個,同時包含二者。程式可以看做是單個執行緒,但是程式可以包含共享一定資源(程式碼和/或資料)的多個執行緒。因此程式排程也包含了執行緒排程的功能.
目前非實時程式的排程策略比較簡單, 因為實時程式值只要求儘可能快的被響應, 基於優先順序, 每個程式根據它重要程度的不同被賦予不同的優先順序,排程器在每次排程時, 總選擇優先順序最高的程式開始執行. 低優先順序不可能搶佔高優先順序, 因此FIFO或者Round Robin的排程策略即可滿足實時程式排程的需求.
但是普通程式的排程策略就比較麻煩了, 因為普通程式不能簡單的只看優先順序, 必須公平的佔有CPU, 否則很容易出現程式飢餓, 這種情況下使用者會感覺作業系統很卡, 響應總是很慢,因此在linux排程器的發展歷程中經過了多次重大變動, linux總是希望尋找一個最接近於完美的排程策略來公平快速的排程程式.
1.4 linux排程器的演變
一開始的排程器是複雜度為
然而,linux是集全球很多程式設計師的聰明才智而發展起來的超級核心,沒有最好,只有更好,在
欄位 | 版本 |
---|---|
O(n)的始排程演算法 | linux-0.11~2.4 |
O(1)排程器 | linux-2.5 |
CFS排程器 | linux-2.6~至今 |
1.5 Linux的排程器組成
2個排程器
可以用兩種方法來啟用排程
一種是直接的, 比如程式打算睡眠或出於其他原因放棄CPU
另一種是通過週期性的機制, 以固定的頻率執行, 不時的檢測是否有必要
因此當前linux的排程程式由兩個排程器組成:主排程器,週期性排程器(兩者又統稱為通用排程器(generic scheduler)或核心排程器(core scheduler))
並且每個排程器包括兩個內容:排程框架(其實質就是兩個函式框架)及排程器類
6種排程策略
linux核心目前實現了6中排程策略(即排程演算法), 用於對不同型別的程式進行排程, 或者支援某些特殊的功能
SCHED_NORMAL和SCHED_BATCH排程普通的非實時程式
SCHED_FIFO和SCHED_RR和SCHED_DEADLINE則採用不同的排程策略排程實時程式
SCHED_IDLE則在系統空閒時呼叫idle程式.
5個排程器類
而依據其排程策略的不同實現了5個排程器類, 一個排程器類可以用一種種或者多種排程策略排程某一類程式, 也可以用於特殊情況或者排程特殊功能的程式.
其所屬程式的優先順序順序為
stop_sched_class -> dl_sched_class -> rt_sched_class -> fair_sched_class -> idle_sched_class
3個排程實體
排程器不限於排程程式, 還可以排程更大的實體, 比如實現組排程.
這種一般性要求排程器不直接操作程式, 而是處理可排程實體, 因此需要一個通用的資料結構描述這個排程實體,即seched_entity結構, 其實際上就代表了一個排程物件,可以為一個程式,也可以為一個程式組.
linux中針對當前可排程的實時和非實時程式, 定義了型別為seched_entity的3個排程實體
sched_dl_entity 採用EDF演算法排程的實時排程實體
sched_rt_entity 採用Roound-Robin或者FIFO演算法排程的實時排程實體 rt_sched_class
sched_entity 採用CFS演算法排程的普通非實時程式的排程實體
排程器整體框架
每個程式都屬於某個排程器類(由欄位task_struct->sched_class標識), 由排程器類採用程式對應的排程策略排程(由task_struct->policy )進行排程, task_struct也儲存了其對應的排程實體標識
linux實現了6種排程策略, 依據其排程策略的不同實現了5個排程器類, 一個排程器類可以用一種或者多種排程策略排程某一類程式, 也可以用於特殊情況或者排程特殊功能的程式.
排程器類 | 排程策略 | 排程策略對應的排程演算法 | 排程實體 | 排程實體對應的排程物件 |
---|---|---|---|---|
stop_sched_class | 無 | 無 | 無 | 特殊情況, 發生在cpu_stop_cpu_callback 進行cpu之間任務遷移migration或者HOTPLUG_CPU的情況下關閉任務 |
dl_sched_class | SCHED_DEADLINE | Earliest-Deadline-First最早截至時間有限演算法 | sched_dl_entity | 採用DEF最早截至時間有限演算法排程實時程式 |
rt_sched_class | SCHED_RR SCHED_FIFO |
Roound-Robin時間片輪轉演算法 FIFO先進先出演算法 |
sched_rt_entity | 採用Roound-Robin或者FIFO演算法排程的實時排程實體 |
fair_sched_class | SCHED_NORMAL SCHED_BATCH |
CFS完全公平懂排程演算法 | sched_entity | 採用CFS演算法普通非實時程式 |
idle_sched_class | SCHED_IDLE | 無 | 無 | 特殊程式, 用於cpu空閒時排程空閒程式idle |
2 linux優先順序的表示
2.1 優先順序的核心表示
linux優先順序概述
在使用者空間通過nice命令設定程式的靜態優先順序, 這在內部會呼叫nice系統呼叫, 程式的nice值在-20~+19之間. 值越低優先順序越高.
setpriority系統呼叫也可以用來設定程式的優先順序. 它不僅能夠修改單個執行緒的優先順序, 還能修改程式組中所有程式的優先順序, 或者通過制定UID來修改特定使用者的所有程式的優先順序
核心使用一些簡單的數值範圍0~139表示內部優先順序, 數值越低, 優先順序越高。
從0~99的範圍專供實時程式使用, nice的值[-20,19]則對映到範圍100~139
linux2.6核心將任務優先順序進行了一個劃分, 實時優先順序範圍是0到MAX_RT_PRIO-1(即99),而普通程式的靜態優先順序範圍是從MAX_RT_PRIO到MAX_PRIO-1(即100到139).
優先順序範圍 | 描述 |
---|---|
0——99 | 實時程式 |
100——139 | 非實時程式 |
核心的優先順序表示
核心表示優先順序的所有資訊基本都放在include/linux/sched/prio.h中, 其中定義了一些表示優先順序的巨集和函式.
優先順序數值通過巨集來定義, 如下所示,
其中MAX_NICE和MIN_NICE定義了nice的最大最小值
而MAX_RT_PRIO指定了實時程式的最大優先順序, 而MAX_PRIO則是普通程式的最大優先順序數值
/* http://lxr.free-electrons.com/source/include/linux/sched/prio.h?v=4.6#L4 */
#define MAX_NICE 19
#define MIN_NICE -20
#define NICE_WIDTH (MAX_NICE - MIN_NICE + 1)
/* http://lxr.free-electrons.com/source/include/linux/sched/prio.h?v=4.6#L24 */
#define MAX_PRIO (MAX_RT_PRIO + 40)
#define DEFAULT_PRIO (MAX_RT_PRIO + 20)
巨集 | 值 | 描述 |
---|---|---|
MIN_NICE | -20 | 對應於優先順序100, 可以使用NICE_TO_PRIO和PRIO_TO_NICE轉換 |
MAX_NICE | 19 | 對應於優先順序139, 可以使用NICE_TO_PRIO和PRIO_TO_NICE轉換 |
NICE_WIDTH | 40 | nice值得範圍寬度, 即[-20, 19]共40個數字的寬度 |
MAX_RT_PRIO, MAX_USER_RT_PRIO | 100 | 實時程式的最大優先順序 |
MAX_PRIO | 140 | 普通程式的最大優先順序 |
DEFAULT_PRIO | 120 | 程式的預設優先順序, 對應於nice=0 |
MAX_DL_PRIO | 0 | 使用EDF最早截止時間優先排程演算法的實時程式最大的優先順序 |
而核心提供了一組巨集將優先順序在各種不同的表示形之間轉移
// http://lxr.free-electrons.com/source/include/linux/sched/prio.h?v=4.6#L27
/*
* Convert user-nice values [ -20 ... 0 ... 19 ]
* to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
* and back.
*/
#define NICE_TO_PRIO(nice) ((nice) + DEFAULT_PRIO)
#define PRIO_TO_NICE(prio) ((prio) - DEFAULT_PRIO)
/*
* 'User priority' is the nice value converted to something we
* can work with better when scaling various scheduler parameters,
* it's a [ 0 ... 39 ] range.
*/
#define USER_PRIO(p) ((p)-MAX_RT_PRIO)
#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio)
#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO))
還有一些nice值和rlimit值之間相互轉換的函式nice_to_rlimit和rlimit_to_nice, 這在nice系統呼叫進行檢查的時候很有用, 他們定義在include/linux/sched/prio.h, L47中, 如下所示
/*
* Convert nice value [19,-20] to rlimit style value [1,40].
*/
static inline long nice_to_rlimit(long nice)
{
return (MAX_NICE - nice + 1);
}
/*
* Convert rlimit style value [1,40] to nice value [-20, 19].
*/
static inline long rlimit_to_nice(long prio)
{
return (MAX_NICE - prio + 1);
}
DEF最早截至時間優先實時排程演算法的優先順序描述
此外新版本的核心還引入了EDF實時排程演算法, 它的優先順序比RT程式和NORMAL/BATCH程式的優先順序都要高, 關於EDF的優先順序的設定資訊都早核心標頭檔案include/linux/sched/deadline.h
因此核心將MAX_DL_PRIO設定為0, 可以參見核心檔案include/linux/sched/deadline.h
#define MAX_DL_PRIO 0
此外也提供了一些EDF優先順序處理所需的函式, 如下所示, 可以參見核心檔案include/linux/sched/deadline.h
static inline int dl_prio(int prio)
{
if (unlikely(prio < MAX_DL_PRIO))
return 1;
return 0;
}
static inline int dl_task(struct task_struct *p)
{
return dl_prio(p->prio);
}
static inline bool dl_time_before(u64 a, u64 b)
{
return (s64)(a - b) < 0;
}
2.2 程式的優先順序表示
struct task_struct
{
/* 程式優先順序
* prio: 動態優先順序,範圍為100~139,與靜態優先順序和補償(bonus)有關
* static_prio: 靜態優先順序,static_prio = 100 + nice + 20 (nice值為-20~19,所以static_prio值為100~139)
* normal_prio: 沒有受優先順序繼承影響的常規優先順序,具體見normal_prio函式,跟屬於什麼型別的程式有關
*/
int prio, static_prio, normal_prio;
/* 實時程式優先順序 */
unsigned int rt_priority;
}
動態優先順序 靜態優先順序 實時優先順序
其中task_struct採用了三個成員表示程式的優先順序:prio和normal_prio表示動態優先順序, static_prio表示程式的靜態優先順序.
為什麼表示動態優先順序需要兩個值prio和normal_prio
排程器會考慮的優先順序則儲存在prio. 由於在某些情況下核心需要暫時提高程式的優先順序, 因此需要用prio表示. 由於這些改變不是持久的, 因此靜態優先順序static_prio和普通優先順序normal_prio不受影響.
此外還用了一個欄位rt_priority儲存了實時程式的優先順序
欄位 | 描述 |
---|---|
static_prio | 用於儲存靜態優先順序, 是程式啟動時分配的優先順序, ,可以通過nice和sched_setscheduler系統呼叫來進行修改, 否則在程式執行期間會一直保持恆定 |
rt_priority | 用於儲存實時優先順序 |
normal_prio | 表示基於程式的靜態優先順序static_prio和排程策略計算出的優先順序. 因此即使普通程式和實時程式具有相同的靜態優先順序, 其普通優先順序也是不同的, 程式分叉(fork)時, 子程式會繼承父程式的普通優先順序 |
prio | 儲存程式的動態優先順序 |
實時程式的優先順序用實時優先順序rt_priority來表示
3 程式優先順序的計算
前面說了task_struct中的幾個優先順序的欄位
靜態優先順序 | 實時優先順序 | 普通優先順序 | 動態優先順序 |
---|---|---|---|
static_prio | rt_priority | normal_prio | prio |
但是這些優先順序是如何關聯的呢, 動態優先順序prio又是如何計算的呢?
3.1 normal_prio函式設定普通優先順序normal_prio
靜態優先順序static_prio(普通程式)和實時優先順序rt_priority(實時程式)是計算的起點
因此他們也是程式建立的時候設定好的, 我們通過nice修改的就是普通程式的靜態優先順序static_prio
首先通過靜態優先順序static_prio計算出普通優先順序normal_prio, 該工作可以由nromal_prio來完成, 該函式定義在kernel/sched/core.c#L861
/*
* __normal_prio - return the priority that is based on the static prio
* 普通程式(非實時程式)的普通優先順序normal_prio就是靜態優先順序static_prio
*/
static inline int __normal_prio(struct task_struct *p)
{
return p->static_prio;
}
/*
* Calculate the expected normal priority: i.e. priority
* without taking RT-inheritance into account. Might be
* boosted by interactivity modifiers. Changes upon fork,
* setprio syscalls, and whenever the interactivity
* estimator recalculates.
*/
static inline int normal_prio(struct task_struct *p)
{
int prio;
if (task_has_dl_policy(p)) /* EDF排程的實時程式 */
prio = MAX_DL_PRIO-1;
else if (task_has_rt_policy(p)) /* 普通實時程式的優先順序 */
prio = MAX_RT_PRIO-1 - p->rt_priority;
else /* 普通程式的優先順序 */
prio = __normal_prio(p);
return prio;
}
程式型別 | 排程器 | 普通優先順序normal_prio |
---|---|---|
EDF實時程式 | EDF | MAX_DL_PRIO-1 = -1 |
普通實時程式 | RT | MAX_RT_PRIO-1 - p->rt_priority = 99 - rt_priority |
普通程式 | CFS | __normal_prio(p) = static_prio |
普通優先順序normal_prio需要根據普通程式和實時程式進行不同的計算, 其中__normal_prio適用於普通程式, 直接將普通優先順序normal_prio設定為靜態優先順序static_prio. 而實時程式的普通優先順序計算依據其實時優先順序rt_priority.
3.1.1 輔助函式task_has_dl_policy和task_has_rt_policy
定義在kernel/sched/sched.h#L117 中
其本質其實就是傳入task->policy排程策略欄位看其值等於SCHED_NORMAL, SCHED_BATCH, SCHED_IDLE, SCHED_FIFO, SCHED_RR, SCHED_DEADLINE中的哪個, 從而確定其所屬的排程類, 進一步就確定了其程式型別
static inline int idle_policy(int policy)
{
return policy == SCHED_IDLE;
}
static inline int fair_policy(int policy)
{
return policy == SCHED_NORMAL || policy == SCHED_BATCH;
}
static inline int rt_policy(int policy)
{
return policy == SCHED_FIFO || policy == SCHED_RR;
}
static inline int dl_policy(int policy)
{
return policy == SCHED_DEADLINE;
}
static inline bool valid_policy(int policy)
{
return idle_policy(policy) || fair_policy(policy) ||
rt_policy(policy) || dl_policy(policy);
}
static inline int task_has_rt_policy(struct task_struct *p)
{
return rt_policy(p->policy);
}
static inline int task_has_dl_policy(struct task_struct *p)
{
return dl_policy(p->policy);
}
3.1.2 關於rt_priority數值越大, 實時程式優先順序越高的問題
我們前面提到了數值越小, 優先順序越高, 但是此處我們會發現rt_priority的值越大, 其普通優先順序越小, 從而優先順序越高.
因此網上出現了一種說法, 優先順序越高?這又是怎麼回事?難道有一種說法錯了嗎?
實際的原因是這樣的,對於一個實時程式,他有兩個引數來表明優先順序——prio 和 rt_priority,
prio才是排程所用的最終優先順序數值,這個值越小,優先順序越高;
而rt_priority 被稱作實時程式優先順序,他要經過轉化——prio=MAX_RT_PRIO - 1- p->rt_priority;
MAX_RT_PRIO = 100, ;這樣意味著rt_priority值越大,優先順序越高;
而核心提供的修改優先順序的函式,是修改rt_priority的值,所以越大,優先順序越高。
所以使用者在使用實時程式或執行緒,在修改優先順序時,就會有“優先順序值越大,優先順序越高的說法”,也是對的。
3.1.3 為什麼需要__normal_prio函式
我們肯定會奇怪, 為什麼增加了一個__normal_prio函式做了這麼簡單的工作, 這個其實是有歷史原因的: 在早期的
3.2 effective_prio函式設定動態優先順序prio
可以通過函式effective_prio用靜態優先順序static_prio計算動態優先順序prio, 即·
p->prio = effective_prio(p);
該函式定義在kernel/sched/core.c, line 861
/*
* Calculate the current priority, i.e. the priority
* taken into account by the scheduler. This value might
* be boosted by RT tasks, or might be boosted by
* interactivity modifiers. Will be RT if the task got
* RT-boosted. If not then it returns p->normal_prio.
*/
static int effective_prio(struct task_struct *p)
{
p->normal_prio = normal_prio(p);
/*
* If we are RT tasks or we were boosted to RT priority,
* keep the priority unchanged. Otherwise, update priority
* to the normal priority:
*/
if (!rt_prio(p->prio))
return p->normal_prio;
return p->prio;
}
我們會發現函式首先effective_prio設定了普通優先順序, 顯然我們用effective_prio同時設定了兩個優先順序(普通優先順序normal_prio和動態優先順序prio)
因此計算動態優先順序的流程如下
設定程式的普通優先順序(實時程式99-rt_priority, 普通程式為static_priority)
計算程式的動態優先順序(實時程式則維持動態優先順序的prio不變, 普通程式的動態優先順序即為其普通優先順序)
最後, 我們綜述一下在針對不同型別程式的計算結果
程式型別 | 實時優先順序rt_priority | 靜態優先順序static_prio | 普通優先順序normal_prio | 動態優先順序prio |
---|---|---|---|---|
EDF排程的實時程式 | rt_priority | 不使用 | MAX_DL_PRIO-1 | 維持原prio不變 |
RT演算法排程的實時程式 | rt_priority | 不使用 | MAX_RT_PRIO-1-rt_priority | 維持原prio不變 |
普通程式 | 不使用 | static_prio | static_prio | static_prio |
優先順序提高的普通程式 | 不使用 | static_prio(改變) | static_prio | 維持原prio不變 |
3.2.1 為什麼effective_prio使用優先順序數值檢測實時程式
t_prio會檢測普通優先順序是否在實時範圍內, 即是否小於MAX_RT_PRIO.參見include/linux/sched/rt.h#L6
static inline int rt_prio(int prio)
{
if (unlikely(prio < MAX_RT_PRIO))
return 1;
return 0;
}
而前面我們在normal_prio的時候, 則通過task_has_rt_policy來判斷其policy屬性來確定
policy == SCHED_FIFO || policy == SCHED_RR;
那麼為什麼effective_prio重檢測實時程式是rt_prio基於優先順序數值, 而非task_has_rt_policy或者rt_policy?
對於臨時提高至實時優先順序的非實時程式來說, 這個是必要的, 這種情況可能發生在是哦那個實時互斥量(RT-Mutex)時.
3.3 設定prio的時機
- 在新程式用wake_up_new_task喚醒時, 或者使用nice系統呼叫改變其靜態優先順序時, 則會通過effective_prio的方法設定p->prio
wake_up_new_task(), 計算此程式的優先順序和其他排程引數,將新的程式加入到程式排程佇列並設此程式為可被排程的,以後這個程式可以被程式排程模組排程執行。
- 程式建立時copy_process通過呼叫sched_fork來初始化和設定排程器的過程中會設定子程式的優先順序
3.4 nice系統呼叫的實現
nice系統呼叫是的核心實現是sys_nice, 其定義在kernel/sched/core.c#L7498,
它在通過一系列檢測後, 通過set_user_nice函式, 其定義在kernel/sched/core.c#L3497
關於其具體實現我們會在另外一篇部落格裡面詳細講
3.5 fork時優先順序的繼承
在程式分叉處子程式時, 子程式的靜態優先順序繼承自父程式. 子程式的動態優先順序p->prio則被設定為父程式的普通優先順序, 這確保了實時互斥量引起的優先順序提高不會傳遞到子程式.
可以參照sched_fork函式, 在程式複製的過程中copy_process通過呼叫sched_fork來設定子程式優先順序, 參見sched_fork函式
/*
* fork()/clone()-time setup:
*/
int sched_fork(unsigned long clone_flags, struct task_struct *p)
{
/* ...... */
/*
* Make sure we do not leak PI boosting priority to the child.
* 子程式的動態優先順序被設定為父程式普通優先順序
*/
p->prio = current->normal_prio;
/*
* Revert to default priority/policy on fork if requested.
* sched_reset_on_fork標識用於判斷是否恢復預設的優先順序或排程策略
*/
if (unlikely(p->sched_reset_on_fork)) /* 如果要恢復預設的排程策略, 即SCHED_NORMAL */
{
/* 首先是設定靜態優先順序static_prio
* 由於要恢復預設的排程策略
* 對於父程式是實時程式的情況, 靜態優先順序就設定為DEFAULT_PRIO
*
* 對於父程式是非實時程式的情況, 要保證子程式優先順序不小於DEFAULT_PRIO
* 父程式nice < 0即static_prio < 的重新設定為DEFAULT_PRIO的重新設定為DEFAULT_PRIO
* 父程式nice > 0的時候, 則什麼也沒做
* */
if (task_has_dl_policy(p) || task_has_rt_policy(p))
{
p->policy = SCHED_NORMAL; /* 普通程式排程策略 */
p->static_prio = NICE_TO_PRIO(0); /* 靜態優先順序為nice = 0 即DEFAULT_PRIO*/
p->rt_priority = 0; /* 實時優先順序為0 */
}
else if (PRIO_TO_NICE(p->static_prio) < 0) /* */
p->static_prio = NICE_TO_PRIO(0); /* */
/* 接著就通過__normal_prio設定其普通優先順序和動態優先順序
* 這裡做了一個優化, 因為用sched_reset_on_fork標識設定恢復預設排程策略後
* 建立的子程式是是SCHED_NORMAL的非實時程式
* 因此就不需要繞一大圈用effective_prio設定normal_prio和prio了
* 直接用__normal_prio設定就可 */
p->prio = p->normal_prio = __normal_prio(p); /* 設定*/
/* 設定負荷權重 */
set_load_weight(p);
/*
* We don't need the reset flag anymore after the fork. It has
* fulfilled its duty:
*/
p->sched_reset_on_fork = 0;
}
/* ...... */
}
4 總結
task_struct採用了四個成員表示程式的優先順序:prio和normal_prio表示動態優先順序, static_prio表示程式的靜態優先順序. 同時還用了rt_priority表示實時程式的優先順序
欄位 | 描述 |
---|---|
static_prio | 用於儲存靜態優先順序, 是程式啟動時分配的優先順序, ,可以通過nice和sched_setscheduler系統呼叫來進行修改, 否則在程式執行期間會一直保持恆定 |
prio | 程式的動態優先順序, 這個有顯示才是排程器重點考慮的程式優先順序 |
normal_prio | 普通程式的靜態優先順序static_prio和排程策略計算出的優先順序. 因此即使普通程式和實時程式具有相同的靜態優先順序, 其普通優先順序也是不同的, 程式分叉(fork)時, 子程式會繼承父程式的普通優先順序, 可以通過normal_prio來計算(非實時程式用static_prIo計算, 實時程式用rt_priority計算) |
rt_priority | 實時程式的靜態優先順序 |
排程器會考慮的優先順序則儲存在prio. 由於在某些情況下核心需要暫時提高程式的優先順序, 因此需要用prio表示. 由於這些改變不是持久的, 因此靜態優先順序static_prio和普通優先順序normal_prio不受影響.
此外還用了一個欄位rt_priority儲存了實時程式的優先順序靜態優先順序static_prio(普通程式)和實時優先順序rt_priority(實時程式)是計算的起點, 通過他們計算程式的普通優先順序normal_prio和動態優先順序prio.
核心通過normal_prIo函式計算普通優先順序normal_prio
通過effective_prio函式計算動態優先順序prio
參考
相關文章
- linux中設定程式排程的優先順序別Linux
- Linux排程器:程序優先順序Linux
- Linux基礎命令---升值程式優先順序niceLinux
- Linux基礎命令—修改程式優先順序reniceLinux
- Linux基礎命令---設定程式優先順序niceLinux
- Linux基礎命令---修改程式優先順序reniceLinux
- 如何使用Rust的gaffer實現優先順序的微批處理排程器 - njkRust
- Android程式優先順序Android
- linux程式排程Linux
- win10怎麼設定優先順序 win10如何設定程式程式優先順序Win10
- 程式初始(二)——程式優先順序,環境變數變數
- 2.2.5排程演算法:時間片輪轉、優先順序排程、多級反饋排程演算法
- 【pytest】fixture 與 setup, teardown 的優先順序
- Linux程式排程邏輯與原始碼分析Linux原始碼
- 運算子的優先順序
- Linux系統常見的日誌檔案及優先順序別!Linux
- win10系統如何設定工作管理員程式優先順序Win10
- CSS優先順序CSS
- [譯]HTTP/2的優先順序HTTP
- LInux實驗 : 程式排程模擬Linux
- python運算子及優先順序順序Python
- spring不同配置方式的區別與優先順序Spring
- win10如何設定優先程式_win10怎麼設定程式優先順序Win10
- Linux程式卡死,如何處理?Linux
- Linux執行時動態庫搜尋路徑優先順序Linux
- 佇列 優先順序佇列 python 程式碼實現佇列Python
- 中斷優先順序
- Yacc使用優先順序
- CSS 選擇器的優先順序CSS
- 設計中的優先順序(下)
- SAP UI configuration determination的優先順序UI
- 設計中的優先順序(上)
- 測試用例的優先順序
- (1)Linux效能調優之Linux程式管理Linux
- SpringBoot配置檔案優先順序載入順序Spring Boot
- 【分享】如何評估 bug 的優先順序
- 怎樣做好客戶的優先順序?
- Java之執行緒的優先順序Java執行緒
- SQL 優先順序join>whereSQL