Linux内核学习笔记(6)-- 进程优先级详解(prio、static_prio、normal_prio、rt_priority)
linux 中采用了两种不同的优先级范围,一种是 nice 值,一种是实时优先级。在上一篇粗略的说了一下 nice 值和实时优先级,仍有不少疑问,本文来详细说明一下进程优先级。linux 内核版本为 linux 2.6.34 。
进程优先级的相关信息,存放在进程描述符 task_struct 中:
struct task_struct { ... int prio, static_prio, normal_prio; unsigned int rt_priority; ... }
可以看到,有四种进程优先级: prio、static_prio、normal_prio 和 rt_priority,它们的具体定义在 kernel/sched.c 中,在介绍这四种优先级之前,先介绍一下以下宏定义:
/* linux-kernel 2.6.34 /include/linux/sched.h */ /* * 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. * * 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 + 40) #define default_prio (max_rt_prio + 20) // 默认优先级,对应 nice 值为 0 的静态优先级
1、prio 动态优先级
prio 的值是调度器最终使用的优先级数值,即调度器选择一个进程时实际选择的值。prio 值越小,表明进程的优先级越高。prio 值的取值范围是 0 ~ max_prio,即 0 ~ 139(包括 0 和 139),根据调度策略的不同,又可以分为两个区间,其中区间 0 ~ 99 的属于实时进程,区间 100 ~139 的为非实时进程。用语言不好描述,我们通过内核代码来详细描述 prio:
/* linux-kernel 2.6.34 /kernel/sched.c */ #include "sched_idletask.c" #include "sched_fair.c" #include "sched_rt.c" #ifdef config_sched_debug #include "sched_debug.c" #endif /* * __normal_prio - return the priority that is based on the static prio */ static inline int __normal_prio(struct task_struct *p) // _normal_prio 函数,返回静态优先级值 { 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) // normal_prio 函数 { int prio; if (task_has_rt_policy(p)) // task_has_rt_policy 函数,判断进程是否为实时进程,若为实时进程,则返回1,否则返回0 prio = max_rt_prio-1 - p->rt_priority; // 进程为实时进程,prio 值为实时优先级值做相关运算得到: prio = max_rt_prio -1 - p->rt_priority else prio = __normal_prio(p); // 进程为非实时进程,则 prio 值为静态优先级值,即 prio = p->static_prio return prio; } /* * 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) // effective_prio 函数,计算进程的有效优先级,即prio值,这个值是最终调度器所使用的优先级值 { p->normal_prio = normal_prio(p); // 计算 normal_prio 的值 /* * 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; // 若进程是非实时进程,则返回 normal_prio 值,这时的 normal_prio = static_prio return p->prio; // 否则,返回值不变,依然为 prio 值,此时 prio = max_rt_prio -1 - p->rt_priority } /*********************** 函数 set_user_nice ****************************************/ void set_user_nice(struct task_struct *p, long nice) { .... p->prio = effective_prio(p); // 在函数 set_user_nice 中,调用 effective_prio 函数来设置进程的 prio 值 .... }
从上面代码中我们知道,当进程为实时进程时, prio 的值由实时优先级值(rt_priority)计算得来;当进程为非实时进程时,prio 的值由静态优先级值(static_prio)得来。即:
prio = max_rt_prio - 1 - rt_priority // 进程为实时进程
prio = static_prio // 进程为非实时进程
简单计算上面的两个式子,可以知道,prio 值的范围是 0 ~ 139 。
2、static_prio 静态优先级
静态优先级不会随时间改变,内核不会主动修改它,只能通过系统调用 nice 去修改 static_prio,如下:
/* * convert user-nice values [ -20 ... 0 ... 19 ] * to static priority [ max_rt_prio..max_prio-1 ], * and back. */ #define nice_to_prio(nice) (max_rt_prio + (nice) + 20) #define prio_to_nice(prio) ((prio) - max_rt_prio - 20) #define task_nice(p) prio_to_nice((p)->static_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)) /********************* 函数 set_user_nice *****************************/ p->static_prio = nice_to_prio(nice); // 当有需要时,系统会通过调用 nice_to_prio() 来修改 static_prio 的值
由上面代码知道,我们可以通过调用 nice_to_prio(nice) 来修改 static_prio 的值, static_prio 值的计算方法如下:
static_prio = max_rt_prio + nice +20
max_rt_prio 的值为100,nice 的范围是 -20 ~ +19,故 static_prio 值的范围是 100 ~ 139。 static_prio 的值越小,表明进程的静态优先级越高。
3、normal_prio 归一化优先级
normal_prio 的值取决于静态优先级和调度策略,可以通过 _setscheduler 函数来设置 normal_prio 的值 。对于非实时进程,normal_prio 的值就等于静态优先级值 static_prio;对于实时进程,normal_prio = max_rt_prio-1 - p->rt_priority。代码如下:
static inline int normal_prio(struct task_struct *p) // normal_prio 函数 { int prio; if (task_has_rt_policy(p)) // task_has_rt_policy 函数,判断进程是否为实时进程,若为实时进程,则返回1,否则返回0 prio = max_rt_prio-1 - p->rt_priority; // 进程为实时进程,prio 值为实时优先级值做相关运算得到: prio = max_rt_prio -1 - p->rt_priority else prio = __normal_prio(p); // 进程为非实时进程,则 prio 值为静态优先级值,即 prio = p->static_prio return prio; }
4、rt_priority 实时优先级
rt_priority 值的范围是 0 ~ 99,只对实时进程有效。由式子:
prio = max_rt_prio-1 - p->rt_priority;
知道,rt_priority 值越大,则 prio 值越小,故 实时优先级(rt_priority)的值越大,意味着进程优先级越高。
rt_priority 的值也是取决于调度策略的,可以在 _setscheduler 函数中对 rt_priority 值进行设置。