/*
* MIGRATION
*
* dequeue
* update_curr()
* update_min_vruntime()
* vruntime -= min_vruntime
*
* enqueue
* update_curr()
* update_min_vruntime()
* vruntime += min_vruntime
*
* this way the vruntime transition(过渡) between RQs is done when both
* min_vruntime are up-to-date.
*
* WAKEUP (remote)
*
* ->migrate_task_rq_fair() (p->state == TASK_WAKING)
* vruntime -= min_vruntime
*
* enqueue
* update_curr()
* update_min_vruntime()
* vruntime += min_vruntime
*
* this way we don't have the most up-to-date min_vruntime on the originating
* CPU and an up-to-date min_vruntime on the destination CPU.
*/
static void
enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags)
{
bool renorm = !(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_MIGRATED);
bool curr = cfs_rq->curr == se;
/*
* If we're the current task, we must renormalise(重新规范化) before calling
* update_curr().
*/
/* (4.1) 在enqueue时给se->vruntime重新加上cfs_rq->min_vruntime */
if (renorm && curr)
se->vruntime += cfs_rq->min_vruntime;
/*更新cfs_rq调度实体的vruntime和相关调度的统计信息*/
//更新runtime和vruntime
update_curr(cfs_rq);
/*
* Otherwise, renormalise after, such that we're placed at the current
* moment in time, instead of some random moment in the past. Being
* placed in the past could significantly(显著的) boost this task to the
* fairness detriment(有害的) of existing tasks.
*/
if (renorm && !curr)
se->vruntime += cfs_rq->min_vruntime;
/*
* When enqueuing a sched_entity, we must:
* - Update loads to have both entity and cfs_rq synced with now.
* - Add its load to cfs_rq->runnable_avg
* - For group_entity, update its weight to reflect the new share of
* its group cfs_rq
* - Add its new weight to cfs_rq->load.weight
*/
/*对新进程的调度实体进行util/load进行衰减,根据PELT算法*/
update_load_avg(se, UPDATE_TG);
/*更新cfs_rqrunnable_load_sum/avg负载信息已经struct sched_entity →
struct sched_avg成员变量数值累加到整个struct cfs_rq-->struct sched_avg上去并
触发频率的调整.*/
enqueue_entity_load_avg(cfs_rq, se);
update_cfs_shares(se);
/* 更新cfs_rq队列总权重(就是在原有基础上加上se的权重) */
account_entity_enqueue(cfs_rq, se);
/* 新建的进程flags为0,不会执行这里 */
if (flags & ENQUEUE_WAKEUP)
place_entity(cfs_rq, se, 0); //确定进程正确的虚拟时间
check_schedstat_required();
/*更新调度相关状态和统计信息*/
update_stats_enqueue(cfs_rq, se, flags);
check_spread(cfs_rq, se);
/*如果当前调度实体不是cfs_rq当前的调度实体,则将新进程的调度实体插入rb tree中,根据
vruntime的大小加入rb tree*/
if (!curr)
//将进程置于红黑树中。使用内核的标准方法将进程排序到红黑树中
__enqueue_entity(cfs_rq, se);
/*新进程在rq中*/
se->on_rq = 1;
if (cfs_rq->nr_running == 1) {
list_add_leaf_cfs_rq(cfs_rq);
check_enqueue_throttle(cfs_rq);
}
}
【内核调度】【enqueue_entity】
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.