“机制和策略分离”
中断和虚拟存储为我们提供了进程抽象 (机制)
理解常见的处理器的调度策略
了解调度是操作系统领域重要的、未解决的问题
一组简单的假设
中断机制
让我们关注调度的策略
假设当前 $T_i$ 运行
我们的 thread-os.c 实际上实现了 Round-Robin 的调度器
UNIX niceness
taskset -c 0 nice -n 19 ./a.out &
taskset -c 0 nice -n 9 ./a.out &
不会设置优先级?能不能让系统自动设定?
设置若干个 Round-Robin 队列
调度策略
试图去模拟一个 “Ideal Multi-Tasking CPU”:
“让系统里的所有进程尽可能公平地共享处理器”
让好人的时间变得快一些,坏人的时间变得慢一些……
const int sched_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,
};
子进程继承父进程的 vruntime
static void task_fork_fair(struct task_struct *p) {
struct sched_entity *se = &p->se, *curr;
...
rq_lock(rq, &rf);
update_rq_clock(rq);
cfs_rq = task_cfs_rq(current);
curr = cfs_rq->curr;
if (curr) {
update_curr(cfs_rq);
se->vruntime = curr->vruntime; // 继承父进程的 vruntime
}
place_entity(cfs_rq, se, 1);
...
I/O (例如 1 分钟) 以后回来 vruntime 严重落后
Linux 的实现
if (renorm && curr)
se->vruntime += cfs_rq->min_vruntime;
vruntime 有优先级的 “倍数”
a < b
不再代表 “小于”!假设:系统中最近、最远的时刻差不超过数轴的一半
bool less(u64 a, u64 b) {
return (i64)(a - b) < 0;
}
用什么数据结构维护所有进程的 vruntime?
为每个进程维护映射 $t \mapsto vt(t)$
道理是简单,这得多少代码啊……
线程不是 while (1)
的循环
在此情形下,会发生什么?
while (1)
void bad_guy() { // 高优先级
mutex_lock(&lk);
...
mutex_unlock(&lk);
}
void nice_guy() { // 中优先级
while (1) ;
}
void very_nice_guy() { // 最低优先级
mutex_lock(&lk);
...
mutex_unlock(&lk);
}
very nice guy 在持有锁的时候让出了处理器……
Sojourner “探路者” (PathFinder), 1997 年 7 月 4 日着陆火星,但着陆几天后,出现系统重启和数据丢失
bc_dist
task: 分发任务 (中优先级)bc_sched
task: 总线调度 (高优先级)select -> pipeIoctl -> selNodeAdd -> mutex_lock
pipeWrite -> mutex_lock
Linux: CFS 凑合用吧;实时系统:火星车在 CPU Reset 啊喂??
还没完:我们的 CPU 里有多个共享内存的处理器啊!
“And you have to realize that there are not very many things that have aged as well as the scheduler. Which is just another proof that scheduling is easy.” ——Linus Torvalds, 2001
Linus 以为调度是个挺简单的问题?
还是组里服务器的例子……
- 马上要到 paper deadline 了,A 和 B 要在服务器上跑实验
更糟糕的是,优先级解决不了这个问题……
man 7 cgroups
Snapdragon 888
处理器的计算能力不同
移动平台的考虑 (能耗 vs. 速度 vs. 吞吐量)
线程看起来在 “共享内存”
producer/consumer 位于同一个/不同 module 性能差距可能很大
😂😂😂 我讲不下去了
复杂的系统无人可以掌控
互联网企业如何为数十亿用户提供低延迟高质量的服务?
高优先级的任务 (搜索、购物车、……) → 质量必须得到保证
低优先级的任务 (小广告投放、索引、转码、……) → 尽可能把服务器填满
如何把任务分配到 1,000,000 台机器上?
如何在一台机器上保证高优先级任务执行的效率?
例子: more CPU time, more progress
do_sum
执行$ time taskset -c 0 ./sum-atomic.out
sum = 40000000
(0.168s)
$ time taskset -c 0,1 ./sum-atomic.out
sum = 40000000
(0.587s)
分配了 1/2 的处理器资源,反而加速了 3.5 倍
完成 “同一件事” 的部件可能不止一个
调度是复杂、有着深远考虑的困难问题
巨大的设计空间
本次课内容与目标
Takeaway messages