- 论坛徽章:
- 0
|
- /*
- * Pick the next process, keeping these things in mind, in this order:
- * 1) keep things fair between processes/task groups
- * 2) pick the "next" process, since someone really wants that to run
- * 3) pick the "last" process, for cache locality
- * 4) do not run the "skip" process, if something else is available
- */
- static struct sched_entity *pick_next_entity(struct cfs_rq *cfs_rq)
- {
- struct sched_entity *se = __pick_first_entity(cfs_rq);
- struct sched_entity *left = se;
- /*
- * Avoid running the skip buddy, if running something else can
- * be done without getting too unfair.
- */
- if (cfs_rq->skip == se) {
- struct sched_entity *second = __pick_next_entity(se);
- if (second && wakeup_preempt_entity(second, left) < 1)
- se = second;
- }
- /*
- * Prefer last buddy, try to return the CPU to a preempted task.
- */
- if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1)
- se = cfs_rq->last;
- /*
- * Someone really wants this to run. If it's not unfair, run it.
- */
- if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1)
- se = cfs_rq->next;
- clear_buddies(cfs_rq, se);
- return se;
- }
复制代码 pick_next_entity的代码,它选择进程的规则较书上说的已经有了一些改进。原本cfs总是选择rb树最左边的进程,也就是虚拟时钟最落后的进程。现在又在这个规则之上加入了buddy这个概念:(看函数注释)
1、优先选择next buddy指向的进程。如果实在希望某个进程优先被调度,就让next buddy指向它。比如如下的情况:
1.1、cfs组调度的情况下,总是先选中一个组,再选中组内的一个进程。如果这个被选中的进程睡眠了(在未用完它的配额之前),运行权应该交回这个组,再选择组内的其他进程。这时候就将组对应的se置为next buddy;
1.2、一个进程被唤醒,会调用到check_preempt_wakeup检查它能否抢占current。如果能,则在resched之前将该进程设为next buddy,从而确保resched能调度到它;
1.3、yield_to函数实现了让某个指定的进程得到运行的功能,也是通过将指定的进程设为next buddy来实现的;
2、第二优先选择last buddy指向的进程。last buddy表示上一次运行的进程,在该进程被另一个刚唤醒的进程抢占时,会让last buddy指向它。为了充分利用cache,希望这个进程能尽快回来继续运行;
3、skip buddy是调度器不应该选择的进程。在yield_to的时候会用到,将current设为skip buddy,避免指定要运行的那个进程抢占不了它。
此外,选择next buddy或last buddy还有一个前提条件,就是通过wakeup_preempt_entity比较它与rb树最左边的进程。这个buddy进程可以比rb树最左边的进程差一些,但不能差太多。 |
|