FIFO/RR
给了优先级,但没”量化时间”。SCHED_DEADLINE(3.14,2014
年)是 Linux
第一个以保证带宽为核心的调度类。它回答一个问题:“我每
20ms 必须跑够 5ms,能保证吗?”
本文讲 DEADLINE 的数学模型、内核实现、API、以及生产部署中真正能用的场景与避坑。
一、先看图:三元组与准入
flowchart TB
U[用户 sched_setattr<br/>runtime=5ms<br/>deadline=20ms<br/>period=20ms] --> K[内核 admission control]
K -->|Σ runtime/period > 1?| R[reject EBUSY]
K -->|OK| ADD[加入 dl_rq]
ADD --> EDF[全局 EDF 选最早 deadline]
EDF --> RUN[运行]
RUN --> CBS[CBS 监控:<br/>runtime 耗完则 throttle<br/>等下周期再给]
CBS --> REFILL[period 到 → 重填 runtime,<br/>deadline += period]
REFILL --> EDF
classDef k fill:#388bfd22,stroke:#388bfd,color:#adbac7;
classDef g fill:#3fb95022,stroke:#3fb950,color:#adbac7;
classDef w fill:#f0883e22,stroke:#f0883e,color:#adbac7;
class U,K k
class EDF,RUN,CBS,REFILL,ADD g
class R w
关键:
- 三元组:
runtime≤deadline≤period - 带宽利用率
bw = runtime / period - 全系统 Σbw ≤ 总 CPU(含迁移松弛系数)才能准入
二、EDF 与 CBS 的双重角色
2.1 EDF:选择策略
每次选”最近 deadline”的任务。单核 EDF 已证明最优——只要任务集 schedulable,EDF 就不 miss deadline。
2.2 CBS:隔离机制
纯 EDF 有个致命弱点:一个任务多跑,会连累其他(deadline 未到但它在跑,真正紧急的被顶)。CBS(Abeni-Buttazzo 1998)给每任务一个”带宽服务器”:
- 每周期内用完 runtime 就 被 throttle,直到下周期
- 带宽隔离——不会影响别的任务
Linux 的 DEADLINE 实现是 EDF + CBS,两者缺一不可。
三、API:sched_setattr
#include <linux/sched/types.h>
struct sched_attr attr = {
.size = sizeof(attr),
.sched_policy = SCHED_DEADLINE,
.sched_flags = 0,
.sched_runtime = 5 * 1000 * 1000, // 5 ms
.sched_deadline = 20 * 1000 * 1000, // 20 ms
.sched_period = 20 * 1000 * 1000, // 20 ms
};
if (sched_setattr(0, &attr, 0) < 0) perror("setattr");没 glibc 包装,用
syscall(SYS_sched_setattr, ...)。
命令行:chrt -d -T 5000000 -D 20000000 -P 20000000 ./app
四、准入控制
Linux 每 CPU 的 DL 带宽上限默认是 95%(0.95):
/proc/sys/kernel/sched_rt_runtime_us # 和 RT 共享 5%
/proc/sys/kernel/sched_rt_period_us
Σ(runtime/period) 超 0.95 则 sched_setattr
返回
EBUSY。这是硬保证——内核拒绝进入无法满足的状态。
多 CPU 情况下,每加入一个 DL 任务,内核会尝试在各 CPU 的剩余带宽里放得下。
五、与 cpuset/cgroup 互斥
DL 需要全系统视角做准入,跟 cpuset、cpu controller 冲突。常见现象:
cpuset.cpus分块后,DL 任务可能无法迁移cpu.max与 DL runtime 打架
Linux 的处理:DL 任务不能进入 cpu cgroup controller(会报错);cpuset 内部要保证 Σ 带宽可行。
实践上:把 DL 系统独立跑,不要混 cgroup CPU 限流。
六、典型应用
6.1 视频播放
每 16.6ms(60fps)要渲染一帧。设 runtime=10ms、period=16ms、deadline=16ms。保证”不掉帧”。
6.2 机器人控制
PLC 控制回路 1kHz。runtime=200μs、period=1000μs。配合 PREEMPT_RT 延迟可控。
6.3 无人机飞控
PX4、ArduPilot 在 NuttX / Linux 上用类似策略。DL + busy loop 兜底。
6.4 音频 DAW
JACK、PipeWire 的 RT 线程:period = buffer_size / sample_rate。DL 保证 period 内完成 mix & encode。
七、为什么生产环境 DL 还不算主流?
- 准入失败应对复杂:服务扩容时 bw 超限要拒绝
- 与容器编排不搭:K8s 的 CPU 请求/限制跟 DL 语义不兼容
- DL 的”runtime”是硬上限,大多数应用不愿或无法估 worst case
- 调试工具缺乏:perf/bcc 对 DL 事件支持较少
主要在专用节点 / 嵌入式 / 实时工作站 用。通用云服务鲜用。
八、诊断
cat /proc/<pid>/sched | grep dl_
# dl.dl_runtime, dl.dl_deadline, dl.dl_period
# dl.runtime (剩余本周期)
/sys/kernel/debug/sched/dl_bw 看每 CPU
带宽使用。
trace-cmd record -e sched_switch,sched:sched_process_exit
+ DL task 可以看 throttle 事件。
九、常见坑
坑 A:sched_setattr EBUSY
原因:全系统或目标 CPU 带宽已满
解决:减小 runtime 或增大 period
坑 B:DL 任务 throttle 过频 原因:runtime 估小,实际需要更多 解决:测量真实 WCET 再设 runtime(留 20% 余量)
坑 C:迁移后 deadline 丢失
原因:跨 CPU 迁移需重新准入;高负载下失败
解决:SCHED_FLAG_RECLAIM
允许借空闲带宽;或固定 CPU
坑 D:DL 任务跟 isolcpus 冲突 原因:isolcpus 限制了 DL 可用 CPU,Σbw 算不过来 解决:调 isolcpus 范围 或 显式绑定
十、与 FIFO 的选择
- FIFO:你有严格优先级顺序,且能保证 RT 任务都能”自愿短”
- DEADLINE:你需要量化的带宽、不想依赖优先级微调
DEADLINE 更现代、更数学、更可预测;但 API 不如 FIFO 普及,工具链少。
十一、小结
- DEADLINE = EDF + CBS,硬性带宽保证
- 三元组 (runtime, deadline, period) + 准入控制
- 与 cgroup CPU 互斥,不适合容器化
- 视频、机器人、音频、飞控是典型场景
- 生产部署需要 WCET 测量与 ops 配合
下一篇 C-24 讲多核负载均衡——调度域、NUMA、big.LITTLE 的骨架是怎样搭起来的。
参考文献
- Abeni, L.; Buttazzo, G. “Integrating multimedia applications in hard real-time systems.” RTSS 1998
- Lelli, J.; Lipari, G.; Cucinotta, T. “An efficient and scalable implementation of global EDF in Linux.” OSPERT 2011
Documentation/scheduler/sched-deadline.rst- Corbet, J. “Deadline scheduling for Linux.” LWN.net 2010-2014(多篇)
- Linux kernel:
kernel/sched/deadline.c - ReTis Lab 的 SCHED_DEADLINE 文档
工具
chrt -d—— 命令行设置 DLschedtool—— 替代命令perf sched、trace-cmd—— 事件追踪- cyclictest 对比 FIFO 与 DL 抖动
上一篇:SCHED_FIFO/RR 与 PREEMPT_RT 下一篇:多核负载均衡
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【操作系统百科】调度理论:为什么『完美调度器』不存在
调度是在有限 CPU 上分配无限需求的艺术。本文从 FCFS/SJF/RR/MLFQ/Fair-share/Lottery/Stride 一路讲到 EDF/CBS,梳理响应-吞吐-公平三难;给出 Mutexpriority inversion、Multi-level feedback、starvation 的定义,以及为什么任何调度目标都不能同时最优。
【操作系统百科】内存回收
Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。
【操作系统百科】交换
swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。
【操作系统百科】Slab/SLUB 分配器
buddy 只管页粒度(4K+),内核大多数对象只有几十到几百字节。slab/SLUB 在 buddy 之上做对象级缓存。本文讲 slab 历史、SLUB 接手、SLOB 退场、kmem_cache、per-CPU cache、KASAN 集成。