【WALT】update_task_demand() 代码详解

代码版本:Linux4.9 android-msm-crosshatch-4.9-android12

代码展示

static u64 update_task_demand(struct task_struct *p, struct rq *rq,
                   int event, u64 wallclock)
{
    u64 mark_start = p->ravg.mark_start;
    u64 delta, window_start = rq->window_start;
    int new_window, nr_full_windows;
    u32 window_size = sched_ravg_window;
    u64 runtime;

    // 用于判断是否进入新窗口的标志位
    new_window = mark_start < window_start;
    // ⑴ 不累加任务运行时间的条件判断
    if (!account_busy_for_task_demand(rq, p, event)) {
        if (new_window)
            update_history(rq, p, p->ravg.sum, 1, event);
        return 0;
    }
    
    // ⑵ 仍在旧窗口中
    if (!new_window) {
        return add_to_task_demand(rq, p, wallclock - mark_start);
    }

    // ⑶ 进入新窗口
    delta = window_start - mark_start;
    nr_full_windows = div64_u64(delta, window_size);
    window_start -= (u64)nr_full_windows * (u64)window_size;
    
    runtime = add_to_task_demand(rq, p, window_start - mark_start);

    update_history(rq, p, p->ravg.sum, 1, event);
    if (nr_full_windows) {
        u64 scaled_window = scale_exec_time(window_size, rq);

        update_history(rq, p, scaled_window, nr_full_windows, event);
        runtime += nr_full_windows * scaled_window;
    }

    window_start += (u64)nr_full_windows * (u64)window_size;
    
    mark_start = window_start;
    runtime += add_to_task_demand(rq, p, wallclock - mark_start);
    
    // ⑷ 返回值 runtime
    return runtime;
}

代码逻辑

用于判断是否进入新窗口的标志位

WALT 算法中,引入了一个新的概念:窗口(sched_ravg_window)

先介绍几个名词:

  • ws:window_start,当前窗口的开始时间
  • ms:mark_start,当前任务的开始时间
  • wc:wallclock,进入 WALT 算法的时间
  • nr_full_windows,如果进入新窗口,则代表旧窗口到当前窗口所经历的完整的窗口个数
  • delta:从任务开始到当前时间/新窗口开始时间所经历的时长

窗口分三种情况进行划分:

  1. 仍在旧窗口中
                    ws   ms  wc
                    |    |   |
                    V    V   V
    |---------------|===============|
    即进入 WALT 算法到时间还在 window_start 到 window_start + sched_ravg_window 之间
    这种情况下,delta = wc - ms,只需要累加进任务时间,不需要更新
    
  2. 刚离开旧窗口,进入下一个窗口
               ms   ws   wc
               |    |    |
               V    V    V
    |---------------|===============|
    即进入 WALT 算法到时间超过了 window_start + sched_ravg_window
    但还没超过 window_start + sched_ravg_window * 2
    这种情况下,delta 分为两块,一块是 ws - ms,一块是 wc - ws
    两块都需要累加进任务时间,但 ws - ms 块需要进行更新,因为它在旧窗口中
    
  3. 经过了数个窗口后抵达新窗口
               ms   ws_tmp                    ws   wc
               |    |                         |    |
               V    V                         V    V
    |---------------|----------|...|----------|===============|
                    |                         |
                    |<--- nr_full_windows --->|
    即进入 WALT 算法到时间超过了 window_start + sched_ravg_window * 2
    其中经过了 nr_full_windows 个完整窗口
    这种情况下,delta 分为三块,一块是 ws_tmp - ms,一块是 wc - ws,
    一块是 sched_ravg_window * nr_full_windows
    三块都需要累加进任务时间,但只有 wc - ws 块不需要进行更新,因为它在新窗口中
    

通过 new_window = mark_start < window_start; 来判断是否处在 2、3 种情况之中,如果 new_window == 1,则处在 2、3 种情况之中,否则处于第 1 种情况。

⑴ 不累加任务运行时间的条件判断

static int 
account_busy_for_task_demand(struct rq *rq, struct task_struct *p, int event)
{
    if (exiting_task(p) || is_idle_task(p))
        return 0;
        
    if (event == TASK_WAKE || (!SCHED_ACCOUNT_WAIT_TIME &&
             (event == PICK_NEXT_TASK || event == TASK_MIGRATE)))
        return 0;

    if (event == TASK_UPDATE) {
        if (rq->curr == p)
            return 1;
        return p->on_rq ? SCHED_ACCOUNT_WAIT_TIME : 0;
    }

    return 1;
}

在函数 account_busy_for_task_demand() 中会判断任务经过的时间是否是 runnable 或 running 时间,返回 1 则是,返回 0 则不是。

  1. 任务经过的时间是 runnable 或 running,即返回 1 的情况
    在当前版本内核中,SCHED_ACCOUNT_WAIT_TIME 默认为 1
    • 任务更新且任务在就绪队列中,无论是不是当前任务
    • 其他情况
  2. 任务经过的时间不是 runnable 或 running,即返回 0 的情况
    • 任务正在退出
    • 任务是 idle 任务
    • 任务刚被唤醒
    • 任务更新切任务不在就绪队列中

如果任务经过的时间不是 runnable 或 running 时间,且正好进入新窗口,就不累加任务时间,直接通过 update_history() 将上一个窗口中已经累加的时间更新至任务结构体中(task_struct)。
点击此处查看 update_history() 代码详解。

⑵ 仍在旧窗口中

根据开头的分析,我们知道这种情况下不需要通过 update_history() 更新时间,只需要通过 add_to_task_demand() 累加任务时间。

static u64 add_to_task_demand(struct rq *rq, struct task_struct *p, u64 delta)
{
    // 1. 将 delta 时间进行归一化
    delta = scale_exec_time(delta, rq);
    // 2. 累加进 p->ravg.sum 中
    p->ravg.sum += delta;
    if (unlikely(p->ravg.sum > sched_ravg_window))
        p->ravg.sum = sched_ravg_window;

    return delta;
}

将归一化后的任务时间累加进 p->ravg.sum 中,在之后的 update_history() 中会将 p->ravg.sum 放进 p->ravg.sum_history 结构体中。

其中,任务时间的归一化是 WALT 算法中的重要部分。点击此处查看 scale_exec_time() 代码详解。

⑶ 进入新窗口

根据开头的分析,我们知道进入新窗口分为两种情况,无论是哪种情况,都需要累加 ws_tmp - ms 和 wc - ws 两部分。其中,如果刚离开旧窗口进入下一个窗口,则 ws = ws_tmp。

我们先处理 ws_tmp - ms 部分:

  • 先通过 delta = window_start - mark_start; 计算总体经过的时间;
  • 再通过 nr_full_windows = div64_u64(delta, window_size); 计算经过的完整窗口的数量;
  • 最后得到 ws_tmp:window_start -= (u64)nr_full_windows * (u64)window_size;
  • 累加 ws_tmp - ms 部分时间:runtime = add_to_task_demand(rq, p, window_start - mark_start);
  • 更新 ws_tmp - ms 部分时间:update_history(rq, p, p->ravg.sum, 1, event);

然后针对经过多个完整窗口情况进行时间更新。此处不需要通过 add_to_task_demand() 累加任务时间,因为任务在这些完整窗口中的时间都是从窗口开始到窗口结束。

  • 先对窗口时间进行归一化:scaled_window = scale_exec_time(window_size, rq);
  • 更新时间:update_history(rq, p, scaled_window, nr_full_windows, event);

最后处理 wc - ws 部分。

  • 把 ws 时间还原:window_start += (u64)nr_full_windows * (u64)window_size;
  • mark_start = window_start; 此处不是更新任务的开始时间,任务开始时间在 WALT 算法的 done 部分进行更新。如果任务开始时间在此处更新,会影响到 update_cpu_busy_time() 中的计算。
  • 累加 wc - ws 部分时间:runtime += add_to_task_demand(rq, p, wallclock - mark_start);

⑷ 返回值 runtime

最后的返回值 runtime 在该版本内核中并未使用到,它是此次执行 update_task_demand() 时一共累加的任务 runnable 和 running 时间,也就是上一次 WALT 算法开始到这一次 WALT 算法开始过程中,该任务的 runnable 和 running 时间。

点击此处回到 WALT 入口函数 update_task_ravg()

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 175,490评论 5 419
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 74,060评论 2 335
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 124,407评论 0 291
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 47,741评论 0 248
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 56,543评论 3 329
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 43,040评论 1 246
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 34,107评论 3 358
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 32,646评论 0 229
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 36,694评论 1 271
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 32,398评论 2 279
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 33,987评论 1 288
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 30,097评论 3 285
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 35,298评论 3 282
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 27,278评论 0 14
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 28,413评论 1 232
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 38,397评论 2 309
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 38,099评论 2 314