1. 排程政策
//https://android.googlesource.com/kernel/common/+/refs/heads/android-4.14/include/uapi/linux/sched.h
.......
/*
* Scheduling policies
*/
#define SCHED_NORMAL 0
#define SCHED_FIFO 1
#define SCHED_RR 2
#define SCHED_BATCH 3
/* SCHED_ISO: reserved but not implemented yet */
#define SCHED_IDLE 5
#define SCHED_DEADLINE 6
/*
0: 預設的排程政策,針對的是普通程序。
1:針對實時程序的先進先出排程。适合對時間性要求比較高但每次運作時間比較短的程序。
2:針對的是實時程序的時間片輪轉排程。适合每次運作時間比較長得程序。
3:針對批處理程序的排程,适合那些非互動性且對cpu使用密集的程序。
SCHED_ISO:是核心的一個預留字段,目前還沒有使用
5:适用于SCHED_DEADLINE優先級較低的背景程序。
6:SCHED_DEADLINED在規定的期限内cpu必須要花指定的時間在本程序上。
SCHED_NORMAL和SCHED_BATCH排程普通的非實時程序,
SCHED_FIFO和SCHED_RR和SCHED_DEADLINE則采用不同的排程政策排程實時程序,
SCHED_IDLE則在系統空閑時調用idle程序.
*/
可以通過chrt檢視程序的排程政策和優先級
pencil: $ chrt -p 551
pid 551's current scheduling policy: SCHED_BATCH
pid 551's current scheduling priority: 0 #實時優先級,普通程序為0
pencil: $ chrt -p 511
pid 511's current scheduling policy: SCHED_FIFO
pid 511's current scheduling priority: 15 #實時程序優先級 1(優先級最低)~99(優先級最高)
2. 核心優先級表示
2.1 概述
- 核心使用0~139表示内部優先級,
的數值越低, 優先級越高(注意:這裡指的是task_struct.prio
,還有其他優先級表示,注意區分)task_struct.prio
- 實時優先級範圍是 0 - MAX_RT_PRIO-1(即0 ~ 99)
- 普通程序的靜态優先級範圍是從 MAX_RT_PRIO - MAX_PRIO-1(即100~139),nice的值[-20,19]的映射的範圍就是對應優先級的100 - 139,
優先級範圍 | 描述 |
---|---|
0——99 | 實時程序 |
100——139 | 非實時程序 |
貼下這部分的代碼,核心裡面有詳盡的注釋
https://elixir.bootlin.com/linux/v5.1.5/source/include/linux/sched/prio.h
#define MAX_NICE 19
#define MIN_NICE -20
#define NICE_WIDTH (MAX_NICE - MIN_NICE + 1)
/*
* Priority of a process goes from 0..MAX_PRIO-1, valid RT
* priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH
* tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority
* values are inverted: lower p->prio value means higher priority.
* 這部分能看到SCHED_NORMAL/SCHED_BATCH的優先級在MAX_RT_PRIO..MAX_PRIO-1(100 ~ 139),
* 即普通非實時程序。而p->prio越小優先級越高
* The MAX_USER_RT_PRIO value allows the actual maximum
* RT priority to be separate from the value exported to
* user-space. This allows kernel threads to set their
* priority to a value higher than any user task. Note:
* MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO.
*/
#define MAX_USER_RT_PRIO 100
#define MAX_RT_PRIO MAX_USER_RT_PRIO
#define MAX_PRIO (MAX_RT_PRIO + NICE_WIDTH)
#define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2)
/*
* Convert user-nice values [ -20 ... 0 ... 19 ]
* to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
* and back.
看到NICE值對應的是MAX_RT_PRIO..MAX_PRIO-1
[ -20 ... 0 ... 19 ] ~ [ MAX_RT_PRIO..MAX_PRIO-1 ]
*/
#define NICE_TO_PRIO(nice) ((nice) + DEFAULT_PRIO)
#define PRIO_TO_NICE(prio) ((prio) - DEFAULT_PRIO)
2.2 核心優先級表示
在核心task_struct中有四個字段表示優先級,分别是:static_prio,rt_priority,normal_prio,prio,這四種優先級需要注意 rt_priority 不是越小優先級越高,而是越大優先級越高,見下文
靜态優先級 | 實時優先級 | 普通優先級 | 動态優先級 |
---|---|---|---|
static_prio | rt_priority | normal_prio | prio |
https://elixir.bootlin.com/linux/v5.1.5/source/include/linux/sched.h#L585
struct task_struct {
............
int recent_used_cpu;
int wake_cpu;
#endif
int on_rq;
/* prio: 動态優先級, 範圍為100~139,與靜态優先級和補償(bonus)有關*/
int prio;
/* static_prio: 靜态優先級
* static_prio = NICE_TO_PRIO(nice) = (nice) + DEFAULT_PRIO = (nice) + (MAX_RT_PRIO + NICE_WIDTH / 2)
* 即:static_prio = 100 + nice + 20
* nice值為-20~19,是以static_prio值為100~139
*/
int static_prio;
/* normal_prio: 動态優先級 */
int normal_prio;
/* 實時程序優先級 1 ~ 99*/
unsigned int rt_priority;
const struct sched_class *sched_class;
............
-
prio
動态優先級
(1)值越小,程序優先級越高
(2)prio值為 -1 ~139
(3)排程器排程采用該優先級排程。該優先級會根據是否為實時程序采用下面的三個優先級來計算
-
static_prio
靜态優先級
(1)值越小,程序優先級越高
(2)static_prio值為100~139,static_prio = nice + MAX_RT_PRIO + NICE_WIDTH / 2
(3)預設值是 120
(4)使用者空間可以通過nice()或者setpriority對該值進行修改。通過getpriority可以擷取該值。
(5)新建立的程序會繼承父程序的static priority。
-
normal_prio
動态優先級,
(1)值越小,程序優先級越高
(2)normal_prio值為 -1 ~139
(3)表示基于程序的靜态優先級static_prio和排程政策計算出的優先級。普通程序static_prio = normal_prio
(4)程序fork時, 子程序會繼承父程序的普通優先級
下面代碼即為normal_prio計算方式
https://elixir.bootlin.com/linux/v5.1.5/source/kernel/sched/core.c#L820 /* * __normal_prio - return the priority that is based on the 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)) 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; }
-
rt_priority
實時優先級
(1)用于表示實時程序優先級
(2)值越大,程序優先級越高
(3)rt_priority值為 0~99,0是普通程序,1~99是實時程序,99的優先級最高
-
為什麼會有-1這個優先級?
-1 是 DEADLINE類程序來說固定值,采用EDF排程政策,即對應SCHED_DEADLINE這個政策。比RT程序和normal程序的優先級還要高,在規定的期限内,cpu必須要花指定的時間在本程序上。
-
為什麼表示動态優先級需要兩個值prio和normal_prio?
排程器會考慮的優先級則儲存在prio. 由于在某些情況下核心需要暫時提高程序的優先級, 是以需要用prio表示. 由于這些改變不是持久的, 是以靜态優先級static_prio和普通優先級normal_prio不受影響.
-
rt_priority數值越大, 實時程序優先級越高, rt_priority 與 prio 如何對應?
在核心代碼裡有時候會這樣調整一個程序的優先級,這裡sched_priority優先級指的是rt_priority,越大優先級越高
其轉化代碼在這塊struct sched_param param = { .sched_priority = 2 }; rv = sched_setscheduler(current, SCHED_RR, ¶m);
即:prio = 99 - rt_priorityprio = MAX_RT_PRIO-1 - p->rt_priority;
static inline int normal_prio(struct task_struct *p) { int prio; if (task_has_dl_policy(p)) prio = MAX_DL_PRIO-1; else if (task_has_rt_policy(p)) prio = MAX_RT_PRIO-1 - p->rt_priority; // 99 - rt_priority else prio = __normal_prio(p); return prio; }
2.3 各個指令看到優先級
在使用者空間,程序優先級有兩種含義:nice value和scheduling priority。對于普通程序而言,程序優先級就是nice value,從-20(優先級最高)~19(優先級最低),通過修改nice value可以改變普通程序擷取cpu資源的比例。随着實時需求的提出,程序又被賦予了另外一種屬性scheduling priority,而這些程序被稱為實時程序。實時程序的優先級的範圍可以通過sched_get_priority_min和sched_get_priority_max,對于linux而言,實時程序的scheduling priority的範圍是1(優先級最低)~99(優先級最高)。當然,普通程序也有scheduling priority,被設定為0。
-
ps
ps看到的優先級是越大優先級越高
-
systrace
越小優先級越高
-
top
小于99會标為RT,[100~149] --> [-20 ~ 19]
- ps -e -o pri,rtprio,cmd
使用者空間優先級
在使用者空間,程序優先級有兩種含義:nice value和scheduling priority。對于普通程序而言,程序優先級就是nice value,從-20(優先級最高)~19(優先級最低),通過修改nice value可以改變普通程序擷取cpu資源的比例。随着實時需求的提出,程序又被賦予了另外一種屬性scheduling priority,而這些程序被稱為實時程序。實時程序的優先級的範圍可以通過sched_get_priority_min和sched_get_priority_max,對于linux而言,實時程序的scheduling priority的範圍是1(優先級最低)~99(優先級最高)。當然,普通程序也有scheduling priority,被設定為0。

-
程序優先級檢視
systrace 中看到的優先級是越小越高,
在ps -lA看到的優先級是越大優先級越高,ps看到0 - 39對應核心優先級中的100 - 139,而40 - 139 對應核心優先級中的RT優先級0 - 99,實時優先級是越大優先級越高
在核心設定實時排程政策 0~99 越大優先級越高
參考:
Linux程序優先級的處理–Linux程序的管理與排程(二十二)
Linux程序和線程的排程與優先級
Linux排程器:程序優先級