iT邦幫忙

2025 iThome 鐵人賽

DAY 14
0

如果覺得文章對你有所啟發,可以考慮用 🌟 支持 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 實際的運作。


上一篇
Scheduling Cycle
系列文
30 篇文帶你用 eBPF 與 Golang 打造 Linux Scheduler14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言