1.进程优先级内核表示
进程的优先级的nice值在-20~+19之间。0~139表示内部优先级,0~99的范围专供实时进程使用。nice值在[-20,+19]映射到100~139之间。如下图所示。
进程优先级宏在不同形式间转换:
/* 从用户优先级的nice值和静态优先级的转换 */
#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)
/* 用户优先级根据调度参数转变到最佳共作级别 */
#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))
2.进程优先级的计算
static是计算的起点,假定已经设置成功。
则计算当前进程优先级,p->prio = effective_prio(p);
static int effective_prio(struct task_struct *p)
{
p->normal_prio = normal_prio(p);
/*
* 如果是实时进程或已经提高到实时优先级,则保持优先级不变。
* 否则返回普通优先级
*/
if (!rt_prio(p->prio))
return p->normal_prio;
return p->prio;
}
普通进程优先级计算的实现:
static inline int normal_prio(struct task_struct *p)
{
int prio;
if (task_has_rt_policy(p))
prio = MAX_RT_PRIO-1 - p->rt_priority;
else
prio = __normal_prio(p);
return prio;
}
普通进程的优先级只是返回了静态优先级而已。
static inline int __normal_prio(struct task_struct *p)
{
return p->static_prio;
}
下面表格对上述的实现做了总结, 对各种类型的进程计算优先级。
注意:在进程支出子进程时,子进程的静态优先级继承自父进程。子进程的动态优先级则设置为父进程的普通父进程,这确保了实时互斥量引起的优先级提高不会传递给子进程。
3.计算负荷权重
进程的重要性由优先级和task_struct->se.load的负荷权重。set_load_weight负责根据进程类型及其静态优先级计算负荷权重。
其实现过程如下:
static void set_load_weight(struct task_struct *p)
{
if (task_has_rt_policy(p)) {
p->se.load.weight = prio_to_weight[0] * 2;
p->se.load.inv_weight = prio_to_wmult[0] >> 1;
return;
}
/*
* SCHED_IDLE tasks get minimal weight:
*/
if (p->policy == SCHED_IDLE) {
p->se.load.weight = WEIGHT_IDLEPRIO;
p->se.load.inv_weight = WMULT_IDLEPRIO;
return;
}
p->se.load.weight = prio_to_weight[p->static_prio - MAX_RT_PRIO];
p->se.load.inv_weight = prio_to_wmult[p->static_prio - MAX_RT_PRIO];
}
负荷权重包含在数据结构load_weight中:
<sched.h>
struct load_weight {
unsigned long weight, inv_weight;
};
一般进程每降低一个nice值,则看获得10%的CPU时间。内核将优先级转换为权重值,下面是这个转换表。
static const int prio_to_weight[40] = {
/* -20 */ 88761, 71755, 56483, 46273, 36291,
/* -15 */ 29154, 23254, 18705, 14949, 11916,
/* -10 */ 9548, 7620, 6100, 4904, 3906,
/* -5 */ 3121, 2501, 1991, 1586, 1277,
/* 0 */ 1024, 820, 655, 526, 423,
/* 5 */ 335, 272, 215, 172, 137,
/* 10 */ 110, 87, 70, 56, 45,
/* 15 */ 36, 29, 23, 18, 15,
};
不仅进程,就绪队列也关联到了一个负载权重。在进程被加载进就绪队列时,内核会调用inc_nr_running,还将进程的权重添加到就绪队列的权重中。
static inline void update_load_add(struct load_weight *lw, unsigned long inc)
{
lw->weight += inc;
}
static inline void update_load_sub(struct load_weight *lw, unsigned long dec)
{
lw->weight -= dec;
}
static void inc_nr_running(struct task_struct *p, struct rq *rq)
{
rq->nr_running++;
inc_load(rq, p);
}