第四十六章:Deadline
结丹后期涉及内核源码:
一
调度竞技场的最深处,林小源听到了一阵急促的滴答声。
那声音不是来自时钟中断,而是来自一座巨大的沙漏。沙漏悬浮在半空中,金色的砂粒不断落下,每一粒落下都发出清脆的"叮"声。沙漏的两侧刻着密密麻麻的数字——runtime、deadline、period。
"你终于来了。"一个声音从沙漏背后传来。
一个身穿金色长袍的女子走出阴影。她的长袍上绣着无数个倒计时的钟面,每一个都在以不同的速度流逝。她的眼神锐利而紧迫,仿佛每一秒都在计算着什么。
"我是 Deadline。"她说,"调度竞技场的第三位守关人。"
林小源抱拳行礼:"晚辈林小源,见过 Deadline 前辈。"
Deadline 没有回礼,而是直接抬手,三道光芒从她掌心射出,在空中凝成三个悬浮的符文。
"视频解码器,"她指着第一个符文,"每三十三毫秒必须解码一帧,解码需要十毫秒的 CPU 时间。runtime 十毫秒,deadline 三十三毫秒,period 三十三毫秒。"
"音频处理器,"她指向第二个符文,"每二十毫秒必须处理一个音频包,处理需要五毫秒。runtime 五毫秒,deadline 二十毫秒,period 二十毫秒。"
"传感器采集器,"她指向第三个符文,"每十毫秒必须读取一次数据,读取需要两毫秒。runtime 两毫秒,deadline 十毫秒,period 十毫秒。"
林小源仔细看着三个符文,问道:"前辈,这三个参数之间是什么关系?"
Deadline 的目光微微柔和了一些:"runtime 是每个周期内需要的 CPU 时间,deadline 是每个周期内的截止时刻,period 是任务的周期。我调度的规则很简单——截止时间最近的任务最先运行。"
"那如果一个任务无法在截止时间前完成呢?"
"拒绝。"Deadline 的语气冰冷,"内核在任务入队时会做可调度性测试——所有任务的 CPU 需求总和不能超过百分之百。如果超过,任务被拒绝入队。我不会做出无法兑现的承诺。"
二
林小源跟着 Deadline 走过一条长长的走廊。走廊的墙壁上挂满了钟面,每一个钟面都在倒计时,有的还剩几毫秒,有的还剩几秒,有的还剩几分钟。
"你和 RT 调度器前辈有什么不同?"林小源问。
Deadline 停下脚步,转过身来:"RT 追求的是确定性——高优先级的进程总是先运行。但确定性不等于时间保证。一个 RT 进程可能被更高优先级的 RT 进程抢占,导致它错过截止时间。"
她抬手在空中画了一个圈,圈中浮现出一幅画面:一个 RT 进程正在运行,突然被另一个更高优先级的 RT 进程抢占,等它重新获得 CPU 时,已经错过了截止时间。
"而我,"Deadline 说,"用数学保证每个任务都能在截止时间前完成。可调度性测试在入队时就排除了不可能完成的任务。这不是启发式,不是猜测,是证明。"
林小源心中一震。他想起了 CFS 的 vruntime——那也是一种数学上的公平。但 Deadline 更进一步,它不只是公平,它还保证了时间。
"优先级呢?"林小源又问。
"Deadline 任务的优先级高于 RT,RT 高于 CFS。"Deadline 说,"如果有 Deadline 任务和 RT 任务同时等待,Deadline 任务先运行。因为我承诺了时间,就必须兑现。"
三
林小源站在沙漏前,看着金色的砂粒不断落下。
"前辈,"他说,"CFS 追求公平,RT 追求确定性,您追求时间保证。这三种调度器,哪一种最好?"
Deadline 笑了,这是她第一次笑:"没有最好,只有最合适。CFS 适合普通进程,RT 适合软实时任务,我适合硬实时任务。视频解码、音频处理、工业控制——这些任务不能容忍延迟,它们需要我。"
她伸出手,掌心浮现出一行字:sum(runtime_i / period_i) <= 1。
"这是可调度性测试的公式,"她说,"所有任务的 CPU 需求总和不超过百分之百。满足这个条件,我就能保证所有任务都在截止时间前完成。"
林小源郑重地记下了这个公式。他知道,这不是一个普通的公式——这是时间的契约。
调度也能"约法三章"——跟时间签合同。
/*
* Deadline 调度器的参数:
* runtime — 每个周期内需要的 CPU 时间
* deadline — 每个周期内的截止时刻
* period — 任务的周期
*
* 例如:视频解码器
* 每 33ms 需要解码一帧 (30fps)
* 解码需要 10ms 的 CPU 时间
* 必须在 33ms 内完成
* → runtime=10ms, deadline=33ms, period=33ms
*
* Deadline 调度器的规则:
* 截止时间最近的任务最先运行
* 保证任务在截止时间前完成
* 优先级:Deadline > RT > CFS
*/
struct dl_entity {
int pid;
char comm[16];
unsigned long runtime; /* 纳秒 */
unsigned long deadline; /* 纳秒 */
unsigned long period; /* 纳秒 */
unsigned long dl_time; /* 绝对截止时间 */
};
printf("=== Deadline 调度器 — 时间之约 ===\n\n");
struct dl_entity dl_procs[] = {
{ 100, "video-dec", 10000000, 33000000, 33000000, 33000000 },
{ 200, "audio-dec", 5000000, 20000000, 20000000, 20000000 },
{ 300, "sensor", 2000000, 10000000, 10000000, 10000000 },
};
int nr = sizeof(dl_procs) / sizeof(dl_procs[0]);
printf("Deadline 进程:\n");
printf("%-6s %-12s %-10s %-10s %-10s\n",
"PID", "COMM", "runtime", "deadline", "period");
printf("%-6s %-12s %-10s %-10s %-10s\n",
"---", "---", "---", "---", "---");
for (int i = 0; i < nr; i++) {
printf("%-6d %-12s %-8.1fms %-8.1fms %-8.1fms\n",
dl_procs[i].pid, dl_procs[i].comm,
dl_procs[i].runtime / 1000000.0,
dl_procs[i].deadline / 1000000.0,
dl_procs[i].period / 1000000.0);
}
printf("\n--- Deadline 调度的规则 ---\n");
printf("1. 截止时间最近的任务最先运行\n");
printf("2. 任务在截止时间前完成\n");
printf("3. 如果无法满足截止时间,任务被拒绝\n\n");
printf("--- 优先级层次 ---\n");
printf("Deadline > RT > CFS > Idle\n\n");
printf("Deadline 进程总是优先于 RT 进程\n");
printf("RT 进程总是优先于 CFS 进程\n");
printf("CFS 进程总是优先于 Idle 进程\n");
printf("\n--- 可调度性测试 ---\n");
printf("内核在任务入队时检查:\n");
printf(" sum(runtime_i / period_i) ≤ 1\n");
printf(" 即所有任务的 CPU 需求总和不超过 100%%\n");
printf(" 如果超过,任务被拒绝入队\n");#include <stdio.h>
/*
* Deadline 调度器的参数:
* runtime — 每个周期内需要的 CPU 时间
* deadline — 每个周期内的截止时刻
* period — 任务的周期
*
* 例如:视频解码器
* 每 33ms 需要解码一帧 (30fps)
* 解码需要 10ms 的 CPU 时间
* 必须在 33ms 内完成
* → runtime=10ms, deadline=33ms, period=33ms
*
* Deadline 调度器的规则:
* 截止时间最近的任务最先运行
* 保证任务在截止时间前完成
* 优先级:Deadline > RT > CFS
*/
struct dl_entity {
int pid;
char comm[16];
unsigned long runtime; /* 纳秒 */
unsigned long deadline; /* 纳秒 */
unsigned long period; /* 纳秒 */
unsigned long dl_time; /* 绝对截止时间 */
};
int main() {
printf("=== Deadline 调度器 — 时间之约 ===\n\n");
struct dl_entity dl_procs[] = {
{ 100, "video-dec", 10000000, 33000000, 33000000, 33000000 },
{ 200, "audio-dec", 5000000, 20000000, 20000000, 20000000 },
{ 300, "sensor", 2000000, 10000000, 10000000, 10000000 },
};
int nr = sizeof(dl_procs) / sizeof(dl_procs[0]);
printf("Deadline 进程:\n");
printf("%-6s %-12s %-10s %-10s %-10s\n",
"PID", "COMM", "runtime", "deadline", "period");
printf("%-6s %-12s %-10s %-10s %-10s\n",
"---", "---", "---", "---", "---");
for (int i = 0; i < nr; i++) {
printf("%-6d %-12s %-8.1fms %-8.1fms %-8.1fms\n",
dl_procs[i].pid, dl_procs[i].comm,
dl_procs[i].runtime / 1000000.0,
dl_procs[i].deadline / 1000000.0,
dl_procs[i].period / 1000000.0);
}
printf("\n--- Deadline 调度的规则 ---\n");
printf("1. 截止时间最近的任务最先运行\n");
printf("2. 任务在截止时间前完成\n");
printf("3. 如果无法满足截止时间,任务被拒绝\n\n");
printf("--- 优先级层次 ---\n");
printf("Deadline > RT > CFS > Idle\n\n");
printf("Deadline 进程总是优先于 RT 进程\n");
printf("RT 进程总是优先于 CFS 进程\n");
printf("CFS 进程总是优先于 Idle 进程\n");
printf("\n--- 可调度性测试 ---\n");
printf("内核在任务入队时检查:\n");
printf(" sum(runtime_i / period_i) ≤ 1\n");
printf(" 即所有任务的 CPU 需求总和不超过 100%%\n");
printf(" 如果超过,任务被拒绝入队\n");
return 0;
}道藏笔记
内核启示
Deadline 调度器为硬实时任务提供时间保证。
每个 Deadline 任务带三个参数: 是每周期需要多少 CPU 时间, 是每周期的截止时刻, 是任务的周期。调度规则很直白——谁的截止时间最近谁先跑,而且内核在入队时就做可调度性测试,所有任务的 sum(runtime_i / period_i) 不能超过 1,超了直接拒绝。
优先级方面,Deadline 排在最前面:Deadline > RT > CFS > Idle。三种调度器各有分工——CFS 管普通进程的公平,RT 管实时任务的确定性,Deadline 管硬实时任务的时间保证。
Deadline 调度器是"时间的守护者"——它保证任务在截止时间前完成。
Deadline 之试
Deadline 调度必须先确认总利用率不超过一,本章给出的准入公式是什么?