CFS 完全公平调度策略简述
- 调度器认为每个进程都应该运行同样的时间(公平可能就指此)
- 总是选择时间运行的最少的进程
- nice 值高的进程时间增长的快,nice值低的进程时间增长的慢
这里的时间是虚拟时间,即 vruntime,是经过权重加权过的时间,每个进程都会记录。
具体实现
每个进程都包含一个调度实体,调度实体内有 vruntime 变量。
struct sched_entity {
struct load_weight load; /* for load-balancing */
struct rb_node run_node;
struct list_head group_node;
unsigned int on_rq;
u64 exec_start;
u64 sum_exec_runtime;
u64 vruntime; /* 进程运行的虚拟时间 */
u64 prev_sum_exec_runtime;
...
};
系统为每个nice 值 [-20, 19] 都设定了一个权重。
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,
};
每次更新虚拟时间时,都会考虑到相应权重。从这里可以看出,低 nice 值,即高权重的进程,时间增长更慢;相反,高 nice 值,时间增长会更快。
vruntime += realtime / weight;
利用红黑树的特性,排序出最小时间值,红黑树的排序标准是 vruntime。
static inline s64 entity_key(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
return se->vruntime - cfs_rq->min_vruntime;
}
每次调度挑选进程时总是选择最左侧节点,即虚拟运行时间 vruntime 最少的进程。
static struct sched_entity *__pick_next_entity(struct cfs_rq *cfs_rq)
{
struct rb_node *left = cfs_rq->rb_leftmost;
if (!left)
return NULL;
return rb_entry(left, struct sched_entity, run_node);
}