首页 > 其他分享 >调度器69—ENQUEUE/DEQUEUE flags

调度器69—ENQUEUE/DEQUEUE flags

时间:2024-12-04 18:10:27浏览次数:4  
标签:task rq ENQUEUE DEQUEUE enqueue flags 69

基于 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);

 

标签:task,rq,ENQUEUE,DEQUEUE,enqueue,flags,69
From: https://www.cnblogs.com/hellokitty2/p/18586911

相关文章

  • Sitecore CMS 未经身份验证任意文件读取漏洞复现(CVE-2024-46938)
    0x01产品描述:        SitecoreExperiencePlatform™(XP)是一款基于.NETWebForm技术构建的内容管理系统,可以将客户数据、分析、人工智能与营销自动化功能相结合,在任何渠道上实时提供个性化的内容,从而在客户旅程中与客户建立良好的关系。0x02漏洞描述:     ......
  • Acwing1696. 困牛排序
    题意给定一个n个数的排列,每次操作将第一个数插入到任意数之后,求多少次操作后排列为升序若\(a_i>a_{i+1}\)那么至少操作i次才能将a_i插入到\(a_{i+1}\)之后这时我们思考是否可以通过i次操作,使得序列有序,假如此时\(a_{i+1~n}\)有序于是我们可以通过插入排序,使得序列有序如何......
  • 1469: CJ061 闰年判断
    题目描述输入一个2000至2500年间(包含2000年和2500年)的任意年份,判断是否是闰年。输入输入一个整数year,表示年份。输入保证2000≤year≤2500。输出如果输入的年份是闰年,请输出“leapyear”,否则请输出“notleapyear”。请注意不需要输出引号,行尾输出换行。样例输入 复......
  • Educational Codeforces Round 169 (Rated for Div2)
    EducationalCodeforcesRound169(RatedforDiv.2)-CodeforcesProblem-A-Codeforces构造签到题,明显只有\(n\leq2\)的时候有解#include<bits/stdc++.h>usingnamespacestd;constintN=2e5+10;typedefpair<int,int>pii;intn,m;inta[N];voidsolve(......
  • AGC 069
    D.TreeandIntervals感觉这个题可做啊,真该先开这个题的/fn\(x_i\)可以看作一端\(\lei\),另一端\(>i\)的边数,进一步可以转化为:把\(\lei\)的点染成黑色,\(>i\)的点染成白色,得到的总连通块数。考虑判定怎样的“总连通块数”序列是可以被生成的。一个个把点染黑,维护当前......
  • 牛客周赛 Round 69
    构造C的歪思路取\(|a-b|+\max(a,b)\)即可构造第三项。代码#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;intmain(){ios::sync_with_stdio(false);cin.tie(nullptr);inta,b;cin>>a>>b;intd=abs(......
  • leetcode hot100【LeetCode 169. 多数元素】java实现
    LeetCode169.多数元素题目描述给定一个大小为n的数组nums,找到其中的多数元素。多数元素是指在数组中出现次数大于n/2的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。示例1:输入:nums=[3,2,3]输出:3示例2:输入:nums=[2,2,1,1,1,2,......
  • 牛客周赛 Round 69(A~E)
    文章目录A构造C的歪思路codeB不要三句号的歪思路codeC仰望水面的歪思路codeD小心火烛的歪思路codeE喜欢切数组的红思路code牛客周赛Round69A构造C的歪思路签到题,求出公差d,让最大的数加上公差d即可code inta,b; cin>>a>>b; intk=max(a,b)-mi......
  • 牛客周赛 Round 69
    题解赛时做题A入门题等差数列,找公差,构造第三个即可B题意简单,考察字符串转化成数字C几何题,大概初中难度,用全等或者向量都可以(初做时废了半天劲,果然上了大学就废了赛后补题D纯暴力,但是可以收获的有两点将二维转化成一维处理bitset的使用和二进制操作__builtin_popco......
  • 【牛客训练记录】牛客周赛 Round 69
    训练情况赛后反思好吧,D题没想到二进制枚举,以为\(O(2^knm)\)不可做。。。A题要求要等差数列,我们先求公差,为两元素的最大值-最小值,再在最大值的基础上加上公差即可。#include<bits/stdc++.h>//#defineintlonglong#defineendl'\n'usingnamespacestd;voidsol......