如果覺得文章對你有所啟發,可以考慮用 🌟 支持 Gthulhu 專案,短期目標是集齊 300 個 🌟 藉此被 CNCF Landscape 採納 [ref]。
scx_simple 的原始程式碼收錄於 scx,採用 GPL 授權。本篇文章會講解該排程器的實作細節,方便大家近一步理解 sched_ext。
參考昨天的文章可以得知,當一個任務被喚醒會進入到 select cpu 環節,所以 simple_select_cpu
會被呼叫:
s32 BPF_STRUCT_OPS(simple_select_cpu, struct task_struct *p, s32 prev_cpu, u64 wake_flags)
{
bool is_idle = false;
s32 cpu;
cpu = scx_bpf_select_cpu_dfl(p, prev_cpu, wake_flags, &is_idle);
if (is_idle) {
stat_inc(0); /* count local queueing */
scx_bpf_dsq_insert(p, SCX_DSQ_LOCAL, SCX_SLICE_DFL, 0);
}
return cpu;
}
如果有找到處於 IDLE 狀態的 CPU,直接把 TASK 放到該 CPU 的 LOCAL DSQ。
否則,傳入 busy cpu 的代號,準備進入 enqueue:
void BPF_STRUCT_OPS(simple_enqueue, struct task_struct *p, u64 enq_flags)
{
stat_inc(1); /* count global queueing */
if (fifo_sched) {
scx_bpf_dsq_insert(p, SHARED_DSQ, SCX_SLICE_DFL, enq_flags);
} else {
u64 vtime = p->scx.dsq_vtime;
/*
* Limit the amount of budget that an idling task can accumulate
* to one slice.
*/
if (time_before(vtime, vtime_now - SCX_SLICE_DFL))
vtime = vtime_now - SCX_SLICE_DFL;
scx_bpf_dsq_insert_vtime(p, SHARED_DSQ, SCX_SLICE_DFL, vtime,
enq_flags);
}
}
進入 simple_enqueue
,如果 FIFO(First In First Out)功能關閉,系統會更新 vtime(可以把它當成 virtual deadline),使用 scx_bpf_dsq_insert_vtime()
會根據 vtime 將任務插入到合適的位置,也就是屬於 priority queue DSQ 的操作。
假設 CPU 已經處理完當前的任務(假設是 cpu0),cpu0 進入到 kernel mode 準備處理下一個任務,首先 cpu0 會檢查自己持有的 Local DSQ,若有任務存在於 DSQ 將任務從 DSQ 取出並執行。若否,則檢查 Global DSQ,將任務取出並執行。
如果仍沒有任務,會進入 dispatch 環節:
void BPF_STRUCT_OPS(simple_dispatch, s32 cpu, struct task_struct *prev)
{
scx_bpf_dsq_move_to_local(SHARED_DSQ);
}
嘗試將 SHARED_DSQ
的任務移至 cpu0 的 Local DSQ,如果順利則執行該任務。否則 cpu0 進入 idle 狀態。
假設有任務成功被執行,這時候會進入到 running 環節:
void BPF_STRUCT_OPS(simple_running, struct task_struct *p)
{
if (fifo_sched)
return;
/*
* Global vtime always progresses forward as tasks start executing. The
* test and update can be performed concurrently from multiple CPUs and
* thus racy. Any error should be contained and temporary. Let's just
* live with it.
*/
if (time_before(vtime_now, p->scx.dsq_vtime))
vtime_now = p->scx.dsq_vtime;
}
用於更新 global deadline vtime_now
。
如果有新的任務被啟動(不是喚醒,是啟動),會進入 enable 環節:
void BPF_STRUCT_OPS(simple_enable, struct task_struct *p)
{
p->scx.dsq_vtime = vtime_now;
}
將該任務的 vtime 指派為當下的 global deadline。
scx_simple 利用不到 150 行的程式碼就實作了一款排程器,藉由追蹤原始程式碼的方式我們也更加的了解 scx 的 scheduling cycle 如何在 kernel 實際的運作。