调度器69—ENQUEUE/DEQUEUE flags

基于 msm-4.14

一、简介

1. 在 enqueue_task/dequeue_task 向就绪队列插入和移除任务的时候,通过 flags 参数判断是由于什么原因触发的enqueue和dequeue,并进行不同的响应。

2. 相关函数:

//kernel/sched/core.c

static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags);
static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags);
/* 这两个是对上面两个函数的封装 */
void activate_task(struct rq *rq, struct task_struct *p, int flags);
void deactivate_task(struct rq *rq, struct task_struct *p, int flags);


3. flags参数

//kernel/sched/sched.h

#define DEQUEUE_SLEEP        0x01
#define DEQUEUE_SAVE        0x02 /* matches ENQUEUE_RESTORE */
#define DEQUEUE_MOVE        0x04 /* matches ENQUEUE_MOVE */
#define DEQUEUE_NOCLOCK        0x08 /* matches ENQUEUE_NOCLOCK */

#define ENQUEUE_WAKEUP        0x01
#define ENQUEUE_RESTORE        0x02
#define ENQUEUE_MOVE        0x04
#define ENQUEUE_NOCLOCK        0x08

#define ENQUEUE_HEAD        0x10
#define ENQUEUE_REPLENISH    0x20
#define ENQUEUE_MIGRATED    0x40

各值的含义:

DEQUEUE_SLEEP - 任务不再处于可运行状态了,表示自己是由于要进入阻塞休眠状态而dequeue出去的。

ENQUEUE_WAKEUP - 表示任务刚被唤醒,变为可运行状态时的enqueue.

DEQUEUE_SAVE/ENQUEUE_RESTORE - 否则,会出现虚假的出队/入队,以确保任务处于已知状态,允许修改。此类对应尽可能多地保留状态。

DEQUEUE_MOVE/ENQUEUE_MOVE - 与 SAVE/RESTORE 配对,明确不保留就绪队列中的位置。

ENQUEUE_HEAD - 放置在运行队列的前面(如果未指定,则放置在尾部)

ENQUEUE_REPLENISH - CBS(补充运行时间并推迟截止时间)

ENQUEUE_MIGRATED - 任务在唤醒期间被迁移


二、对flags的使用

1. DEQUEUE_SLEEP

表示是由于要进入阻塞休眠状态而dequeue出去的。使用位置:

__schedule //core.c
    if (!preempt && prev->state) //【】阻塞休眠触发的切换以SLEEP类型dequeue出去
        deactivate_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK);

dequeue_task //core.c
    if (!(flags & DEQUEUE_SAVE))
        psi_dequeue(p, flags & DEQUEUE_SLEEP); //【】根据此标志判断PSI应该统计的状态

dequeue_entity //fair.c
    update_stats_dequeue //fair.c
        if (flags & DEQUEUE_SLEEP) //【】对SLEEP类型的dequeue更新任务休眠的开始时间
            if (tsk->state & TASK_INTERRUPTIBLE)
                schedstat_set(se->statistics.sleep_start, rq_clock(rq_of(cfs_rq)));
            if (tsk->state & TASK_UNINTERRUPTIBLE)
                schedstat_set(se->statistics.block_start, rq_clock(rq_of(cfs_rq)));

dequeue_entity //fair.c
    if (!(flags & DEQUEUE_SLEEP)) 【】若非SLEEP的dequeue,se->vruntime保存的就是delta值
        se->vruntime -= cfs_rq->min_vruntime;
enqueue_entity
    bool renorm = !(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_MIGRATED);
    bool curr = cfs_rq->curr == se;
    if (renorm && !curr) //若不是WAKEUP的enqueue或是MIGRATED类型的enqueue则在新就绪队列上加回来
        se->vruntime += cfs_rq->min_vruntime;

throttle_cfs_rq //fair.c
    dequeue_entity(qcfs_rq, se, DEQUEUE_SLEEP); //【】被throttle的任务是SLEEP的方式dequeue出去的


2. DEQUEUE_SAVE/ENQUEUE_RESTORE

看起来使用这两个标志主要是为了避免更新 sched_info 和 psi 信息。

dequeue_task //core.c
    if (!(flags & DEQUEUE_SAVE)) {
        sched_info_dequeued(rq, p);
        psi_dequeue(p, flags & DEQUEUE_SLEEP);
    }

dequeue_entity
    if ((flags & (DEQUEUE_SAVE | DEQUEUE_MOVE)) != DEQUEUE_SAVE)
        update_min_vruntime(cfs_rq);

move_entity //rt.c
    if ((flags & (DEQUEUE_SAVE | DEQUEUE_MOVE)) == DEQUEUE_SAVE)
        return false;

dequeue_task_dl //deadline.c
    if (flags & DEQUEUE_SAVE) {
        sub_running_bw(p->dl.dl_bw, &rq->dl);
        sub_rq_bw(p->dl.dl_bw, &rq->dl);
    }

/*-------------------------------*/

enqueue_task //core.c
    if (!(flags & ENQUEUE_RESTORE)) {
        sched_info_queued(rq, p);
        psi_enqueue(p, flags & ENQUEUE_WAKEUP);
    }

enqueue_dl_entity
    if (flags & ENQUEUE_RESTORE)
        setup_new_dl_entity(dl_se);


3. DEQUEUE_MOVE/ENQUEUE_MOVE

包含 DEQUEUE_MOVE 可以避免更新 cfs_rq->min_vruntime。ENQUEUE_MOVE 没有使用位置。

dequeue_entity //fair.c
    if ((flags & (DEQUEUE_SAVE | DEQUEUE_MOVE)) != DEQUEUE_SAVE)
        update_min_vruntime(cfs_rq);

move_entity //rt.c
    if ((flags & (DEQUEUE_SAVE | DEQUEUE_MOVE)) == DEQUEUE_SAVE)
        return false;

/*-------------------------------*/


4. DEQUEUE_NOCLOCK/ENQUEUE_NOCLOCK

使用这两个标志可以避免更新 rq->clock。

dequeue_task //core.c 
    if (!(flags & DEQUEUE_NOCLOCK))
        update_rq_clock(rq);

enqueue_task
    if (!(flags & ENQUEUE_NOCLOCK))
        update_rq_clock(rq);


5. ENQUEUE_WAKEUP

主要用于判断是否是唤醒类型的入队。

update_stats_enqueue //fair.c
    if (flags & ENQUEUE_WAKEUP)
        update_stats_enqueue_sleeper(cfs_rq, se);

enqueue_entity //fair.c
    bool renorm = !(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_MIGRATED);
    bool curr = cfs_rq->curr == se;
    if (renorm && !curr) //若不是WAKEUP的enqueue或是MIGRATED类型的enqueue则在新就绪队列上加回来
        se->vruntime += cfs_rq->min_vruntime;
    if (flags & ENQUEUE_WAKEUP) //只有WAKEUP类型的入队才会进行虚拟时间的奖励和惩罚
        place_entity(cfs_rq, se, 0);

enqueue_task_fair //fair.c
    int task_new = !(flags & ENQUEUE_WAKEUP);
    if (!task_new)
        update_overutilized_status(rq);

enqueue_task_rt //rt.c
    if (flags & ENQUEUE_WAKEUP)
        rt_se->timeout = 0;

enqueue_dl_entity //deadline.c
    if (flags & ENQUEUE_WAKEUP) {
        task_contending(dl_se, flags);
        update_dl_entity(dl_se, pi_se);

enqueue_task_dl //deadline.c
    if (flags & ENQUEUE_WAKEUP)
        task_contending(&p->dl, flags);


6. ENQUEUE_HEAD

决定插入在链表头还是链表尾,默认插入链表尾,带这个标志插入链表头。

rt_mutex_setprio //core.c
    if (oldprio < prio)
        queue_flags |= ENQUEUE_HEAD;
__sched_setscheduler //core.c
    if (oldprio < p->prio)
        queue_flags |= ENQUEUE_HEAD;
            enqueue_task(rq, p, queue_flags);
                __enqueue_rt_entity //rt.c
                    if (flags & ENQUEUE_HEAD)
                        list_add(&rt_se->run_list, queue);
                    else
                        list_add_tail(&rt_se->run_list, queue);


7. ENQUEUE_REPLENISH

只有DL任务使用。

enqueue_dl_entity //deadline.c
    if (flags & ENQUEUE_REPLENISH) {
        replenish_dl_entity(dl_se, pi_se);


8. ENQUEUE_MIGRATED

看起来主要使用在任务迁移后的enqueue,控制 se->vruntime 由delta值转换为当前CPU上的虚拟时间。

enqueue_entity //fair.c
    bool renorm = !(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_MIGRATED);
    bool curr = cfs_rq->curr == se;
    if (renorm && !curr) //若不是WAKEUP的enqueue或是MIGRATED类型的enqueue则在新就绪队列上加回来
        se->vruntime += cfs_rq->min_vruntime;

task_contending //deadline.c
    if (flags & ENQUEUE_MIGRATED)
        add_rq_bw(dl_se->dl_bw, dl_rq);

 

posted on 2024-12-04 18:08  Hello-World3  阅读(15)  评论(0编辑  收藏  举报

导航