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调度器:进程优先级