【W(wǎng)ALT】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;

    // 用于判斷是否進(jìn)入新窗口的標(biāo)志位
    new_window = mark_start < window_start;
    // ⑴ 不累加任務(wù)運(yùn)行時(shí)間的條件判斷
    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);
    }

    // ⑶ 進(jìn)入新窗口
    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;
}

代碼邏輯

用于判斷是否進(jìn)入新窗口的標(biāo)志位

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

先介紹幾個(gè)名詞:

  • ws:window_start,當(dāng)前窗口的開(kāi)始時(shí)間
  • ms:mark_start,當(dāng)前任務(wù)的開(kāi)始時(shí)間
  • wc:wallclock辜御,進(jìn)入 WALT 算法的時(shí)間
  • nr_full_windows,如果進(jìn)入新窗口琳拨,則代表舊窗口到當(dāng)前窗口所經(jīng)歷的完整的窗口個(gè)數(shù)
  • delta:從任務(wù)開(kāi)始到當(dāng)前時(shí)間/新窗口開(kāi)始時(shí)間所經(jīng)歷的時(shí)長(zhǎng)

窗口分三種情況進(jìn)行劃分:

  1. 仍在舊窗口中
                    ws   ms  wc
                    |    |   |
                    V    V   V
    |---------------|===============|
    即進(jìn)入 WALT 算法到時(shí)間還在 window_start 到 window_start + sched_ravg_window 之間
    這種情況下等浊,delta = wc - ms,只需要累加進(jìn)任務(wù)時(shí)間抄谐,不需要更新
    
  2. 剛離開(kāi)舊窗口渺鹦,進(jìn)入下一個(gè)窗口
               ms   ws   wc
               |    |    |
               V    V    V
    |---------------|===============|
    即進(jìn)入 WALT 算法到時(shí)間超過(guò)了 window_start + sched_ravg_window
    但還沒(méi)超過(guò) window_start + sched_ravg_window * 2
    這種情況下,delta 分為兩塊蛹含,一塊是 ws - ms毅厚,一塊是 wc - ws
    兩塊都需要累加進(jìn)任務(wù)時(shí)間,但 ws - ms 塊需要進(jìn)行更新浦箱,因?yàn)樗谂f窗口中
    
  3. 經(jīng)過(guò)了數(shù)個(gè)窗口后抵達(dá)新窗口
               ms   ws_tmp                    ws   wc
               |    |                         |    |
               V    V                         V    V
    |---------------|----------|...|----------|===============|
                    |                         |
                    |<--- nr_full_windows --->|
    即進(jìn)入 WALT 算法到時(shí)間超過(guò)了 window_start + sched_ravg_window * 2
    其中經(jīng)過(guò)了 nr_full_windows 個(gè)完整窗口
    這種情況下卧斟,delta 分為三塊,一塊是 ws_tmp - ms憎茂,一塊是 wc - ws,
    一塊是 sched_ravg_window * nr_full_windows
    三塊都需要累加進(jìn)任務(wù)時(shí)間锤岸,但只有 wc - ws 塊不需要進(jìn)行更新竖幔,因?yàn)樗谛麓翱谥?

通過(guò) new_window = mark_start < window_start; 來(lái)判斷是否處在 2、3 種情況之中是偷,如果 new_window == 1拳氢,則處在 2募逞、3 種情況之中,否則處于第 1 種情況馋评。

⑴ 不累加任務(wù)運(yùn)行時(shí)間的條件判斷

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;
}

在函數(shù) account_busy_for_task_demand() 中會(huì)判斷任務(wù)經(jīng)過(guò)的時(shí)間是否是 runnable 或 running 時(shí)間放接,返回 1 則是,返回 0 則不是留特。

  1. 任務(wù)經(jīng)過(guò)的時(shí)間是 runnable 或 running纠脾,即返回 1 的情況
    在當(dāng)前版本內(nèi)核中,SCHED_ACCOUNT_WAIT_TIME 默認(rèn)為 1
    • 任務(wù)更新且任務(wù)在就緒隊(duì)列中蜕青,無(wú)論是不是當(dāng)前任務(wù)
    • 其他情況
  2. 任務(wù)經(jīng)過(guò)的時(shí)間不是 runnable 或 running苟蹈,即返回 0 的情況
    • 任務(wù)正在退出
    • 任務(wù)是 idle 任務(wù)
    • 任務(wù)剛被喚醒
    • 任務(wù)更新切任務(wù)不在就緒隊(duì)列中

如果任務(wù)經(jīng)過(guò)的時(shí)間不是 runnable 或 running 時(shí)間,且正好進(jìn)入新窗口右核,就不累加任務(wù)時(shí)間慧脱,直接通過(guò) update_history() 將上一個(gè)窗口中已經(jīng)累加的時(shí)間更新至任務(wù)結(jié)構(gòu)體中(task_struct)。
點(diǎn)擊此處查看 update_history() 代碼詳解贺喝。

⑵ 仍在舊窗口中

根據(jù)開(kāi)頭的分析菱鸥,我們知道這種情況下不需要通過(guò) update_history() 更新時(shí)間,只需要通過(guò) add_to_task_demand() 累加任務(wù)時(shí)間躏鱼。

static u64 add_to_task_demand(struct rq *rq, struct task_struct *p, u64 delta)
{
    // 1. 將 delta 時(shí)間進(jìn)行歸一化
    delta = scale_exec_time(delta, rq);
    // 2. 累加進(jìn) p->ravg.sum 中
    p->ravg.sum += delta;
    if (unlikely(p->ravg.sum > sched_ravg_window))
        p->ravg.sum = sched_ravg_window;

    return delta;
}

將歸一化后的任務(wù)時(shí)間累加進(jìn) p->ravg.sum 中氮采,在之后的 update_history() 中會(huì)將 p->ravg.sum 放進(jìn) p->ravg.sum_history 結(jié)構(gòu)體中。

其中挠他,任務(wù)時(shí)間的歸一化是 WALT 算法中的重要部分扳抽。點(diǎn)擊此處查看 scale_exec_time() 代碼詳解。

⑶ 進(jìn)入新窗口

根據(jù)開(kāi)頭的分析殖侵,我們知道進(jìn)入新窗口分為兩種情況贸呢,無(wú)論是哪種情況,都需要累加 ws_tmp - ms 和 wc - ws 兩部分拢军。其中楞陷,如果剛離開(kāi)舊窗口進(jìn)入下一個(gè)窗口,則 ws = ws_tmp茉唉。

我們先處理 ws_tmp - ms 部分:

  • 先通過(guò) delta = window_start - mark_start; 計(jì)算總體經(jīng)過(guò)的時(shí)間固蛾;
  • 再通過(guò) nr_full_windows = div64_u64(delta, window_size); 計(jì)算經(jīng)過(guò)的完整窗口的數(shù)量;
  • 最后得到 ws_tmp:window_start -= (u64)nr_full_windows * (u64)window_size;
  • 累加 ws_tmp - ms 部分時(shí)間:runtime = add_to_task_demand(rq, p, window_start - mark_start);
  • 更新 ws_tmp - ms 部分時(shí)間:update_history(rq, p, p->ravg.sum, 1, event);

然后針對(duì)經(jīng)過(guò)多個(gè)完整窗口情況進(jìn)行時(shí)間更新度陆。此處不需要通過(guò) add_to_task_demand() 累加任務(wù)時(shí)間艾凯,因?yàn)槿蝿?wù)在這些完整窗口中的時(shí)間都是從窗口開(kāi)始到窗口結(jié)束。

  • 先對(duì)窗口時(shí)間進(jìn)行歸一化:scaled_window = scale_exec_time(window_size, rq);
  • 更新時(shí)間:update_history(rq, p, scaled_window, nr_full_windows, event);

最后處理 wc - ws 部分懂傀。

  • 把 ws 時(shí)間還原:window_start += (u64)nr_full_windows * (u64)window_size;
  • mark_start = window_start; 此處不是更新任務(wù)的開(kāi)始時(shí)間趾诗,任務(wù)開(kāi)始時(shí)間在 WALT 算法的 done 部分進(jìn)行更新。如果任務(wù)開(kāi)始時(shí)間在此處更新,會(huì)影響到 update_cpu_busy_time() 中的計(jì)算恃泪。
  • 累加 wc - ws 部分時(shí)間:runtime += add_to_task_demand(rq, p, wallclock - mark_start);

⑷ 返回值 runtime

最后的返回值 runtime 在該版本內(nèi)核中并未使用到郑兴,它是此次執(zhí)行 update_task_demand() 時(shí)一共累加的任務(wù) runnable 和 running 時(shí)間,也就是上一次 WALT 算法開(kāi)始到這一次 WALT 算法開(kāi)始過(guò)程中贝乎,該任務(wù)的 runnable 和 running 時(shí)間情连。

點(diǎn)擊此處回到 WALT 入口函數(shù) update_task_ravg()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市览效,隨后出現(xiàn)的幾起案子却舀,更是在濱河造成了極大的恐慌,老刑警劉巖朽肥,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件禁筏,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡衡招,警方通過(guò)查閱死者的電腦和手機(jī)篱昔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)始腾,“玉大人州刽,你說(shuō)我怎么就攤上這事±思” “怎么了穗椅?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)奶栖。 經(jīng)常有香客問(wèn)我匹表,道長(zhǎng),這世上最難降的妖魔是什么宣鄙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任袍镀,我火速辦了婚禮,結(jié)果婚禮上冻晤,老公的妹妹穿的比我還像新娘苇羡。我一直安慰自己,他們只是感情好鼻弧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布设江。 她就那樣靜靜地躺著,像睡著了一般攘轩。 火紅的嫁衣襯著肌膚如雪叉存。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,631評(píng)論 1 305
  • 那天度帮,我揣著相機(jī)與錄音鹉胖,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛甫菠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播冕屯,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼寂诱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了安聘?” 一聲冷哼從身側(cè)響起痰洒,我...
    開(kāi)封第一講書(shū)人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎浴韭,沒(méi)想到半個(gè)月后丘喻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡念颈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年泉粉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榴芳。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡嗡靡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出窟感,到底是詐尸還是另有隱情讨彼,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布柿祈,位于F島的核電站哈误,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏躏嚎。R本人自食惡果不足惜蜜自,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望紧索。 院中可真熱鬧袁辈,春花似錦、人聲如沸珠漂。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)媳危。三九已至荞彼,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間待笑,已是汗流浹背鸣皂。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寞缝。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓癌压,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親荆陆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子滩届,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355