chrt —— 查看/修改进程的调度策略与实时优先级
这个工具是做什么的
chrt(change real-time attributes)用来查看或修改一个进程/线程的调度策略和优先级。Linux 内核有五层调度类(见 scheduling),默认的 SCHED_OTHER 只是其中一层——还有 SCHED_FIFO、SCHED_RR、SCHED_DEADLINE 等实时调度策略。chrt 就是操作这些策略的命令行接口。
可以回答什么问题
| 问题 | 怎么用 |
|---|---|
| 某个进程用的是哪种调度策略?是普通还是实时? | chrt -p <PID> |
| 某个进程的实时优先级是多少? | chrt -p <PID> 看 current scheduling priority |
| 想测试把进程改成实时调度会不会改善延迟? | chrt -f -p 50 <PID> |
应用要求必须跑在 SCHED_FIFO 上,设对了吗? | chrt -p <PID> 确认 scheduling policy |
| 想给内核迁移线程/中断线程改优先级? | 通常不需要——内核关键线程已有合适的调度类 |
数据来源
- 读取:
sched_getattr(2)/sched_getscheduler(2)系统调用,直接从task_struct的sched_class/prio字段读取。 - 修改:
sched_setattr(2)系统调用,受CAP_SYS_NICE能力限制(提升优先级需 root)。
一、查看:chrt -p
chrt -p <PID> # 查看指定进程
chrt -p <TID> # 查看指定线程(TID)
chrt -p $$ # 查看当前 shell输出示例:
pid 1234's current scheduling policy: SCHED_OTHER
pid 1234's current scheduling priority: 0pid 5678's current scheduling policy: SCHED_FIFO
pid 5678's current scheduling priority: 50| 输出项 | 含义 | 对应内核 |
|---|---|---|
scheduling policy | 调度策略:SCHED_OTHER/SCHED_FIFO/SCHED_RR/SCHED_BATCH/SCHED_IDLE/SCHED_DEADLINE | task_struct.policy |
scheduling priority | 优先级值 | task_struct.rt_priority(实时)或 0(普通) |
二、修改调度策略(常用选项)
# --- 实时调度 ---
chrt -f -p 50 <PID> # 改成 SCHED_FIFO,优先级 50(0-99,越高越优先)
chrt -r -p 50 <PID> # 改成 SCHED_RR(时间片轮转实时),优先级 50
# --- 普通调度 ---
chrt -o -p 0 <PID> # 改回 SCHED_OTHER(普通分时调度)
chrt -b -p 0 <PID> # 改成 SCHED_BATCH(批处理,更不爱抢占)
chrt -i -p 0 <PID> # 改成 SCHED_IDLE(极低优先级,只在空闲时跑)
# --- 启动新进程时指定 ---
chrt -f 50 ./my_realtime_app # 以 FIFO 实时优先级 50 启动新程序
chrt -r 10 command # 以 RR 优先级 10 启动| 选项 | 策略 | 含义 | 优先级范围 |
|---|---|---|---|
-f / --fifo | SCHED_FIFO | 固定优先级、不设时间片:跑到底才让出,或被更高优先级抢占。一直占着 CPU 直到主动阻塞/yield | 1-99(默认 0 不高不低) |
-r / --rr | SCHED_RR | 固定优先级但带时间片轮转:同优先级的多个 RR 任务轮流跑,每个跑满时间片后换下一个 | 1-99 |
-o / --other | SCHED_OTHER | 默认普通分时(CFS/EEVDF),nice 值影响权重而非硬优先级 | nice -20~+19 |
-b / --batch | SCHED_BATCH | 批处理:不会被唤醒抢占,比 OTHER 更不打扰交互任务 | nice -20~+19 |
-i / --idle | SCHED_IDLE | 极低优先级:只在没有任何 OTHER/BATCH/RT 任务要跑时才得到 CPU | — |
-d / --deadline | SCHED_DEADLINE | 硬实时截止期限调度,需同时指定 --sched-runtime --sched-deadline --sched-period 三个参数 | — |
实时策略的执行区别
SCHED_FIFO 优先级 99:---------一直跑--------->(不主动让出就饿死所有低优先级)
SCHED_FIFO 优先级 50: ----被 99 抢占---- ----重新跑----
SCHED_RR 优先级 50-1: |A|B|A|B| (同优先级轮流,每个时间片后切)
SCHED_RR 优先级 50-2: |C|C|C| (不同优先级之间,高的一直跑)
SCHED_OTHER: ........nice 加权公平........(被实时任务完全饿死)⚠️
SCHED_FIFO非常危险:一个SCHED_FIFO 99的任务如果在用户态死循环(没有 sleep/阻塞),它会永久占住 CPU——连内核的 per-CPU 工作队列都得不到 CPU,系统会看起来像挂了一样。内核有sched_rt_runtime_us限流兜底(默认实时任务每 1 秒最多跑 0.95 秒,留 0.05 秒给普通任务),但不能完全信赖它,实时优先级要慎之又慎。
三、SCHED_DEADLINE 用法(硬实时截止期限)
这是 Linux 3.14+ 引入的最严格调度策略——不给固定优先级,而是给运行时间/截止期限/周期三个约束,内核保证在截止期限内完成任务:
# 语法:chrt -d --sched-runtime <RT> --sched-deadline <DL> --sched-period <PR> <command>
chrt -d --sched-runtime 5000000 --sched-deadline 10000000 --sched-period 10000000 0 ./my_dl_app
# 3 个参数单位是纳秒(ns), 0 是占位符(被忽略)
# 含义:每 10ms 周期内,保证有 5ms 的 CPU 时间--sched-runtime:每周期内保证的运行时间--sched-deadline:任务必须在此时间前完成--sched-period:调度周期
三个参数必须满足:runtime ≤ deadline ≤ period。需要 CAP_SYS_NICE。
这不是性能调优的常规操作,是硬实时系统的需求——普通性能排查 99% 的场景用不到。
四、典型使用场景与示例
场景1:排查一个进程为何 CPU 利用率很高
# 先看进程的调度策略——是不是某个实时任务抢了所有 CPU
chrt -p $(pgrep cpu_demo)
# SCHED_OTHER → 正常,非实时
# SCHED_FIFO 99 → 这本身就是问题!如果不是故意设置的,谁把它提权的场景2:测试延迟敏感性——临时提升到实时
# 把待测程序提权到 FIFO 实时优先级 50,测延迟抖动
chrt -f 50 ./my_latency_sensitive_app
# 另开终端观测调度情况
pidstat -w -p $(pgrep my_latency_sensitive_app) 1
# 看 cswch/s(自愿切换)、nvcswch/s(非自愿抢占)的变化
# 实验完记得杀掉,别让实时任务长久跑着场景3:发现系统被实时任务"锁住"
# 症状:top 里 %Cpu sy 不高,但 SSH 反应很慢,或部分核 idle 一直是 0
# 排查:找出所有非 SCHED_OTHER 的进程
ps -eo pid,tid,class,rtprio,ni,comm | grep -v "TS"
# class=FF(FIFO)/RR 且 rtprio 高的,就是嫌疑犯
# 处理方法:
chrt -o -p 0 <PID> # 把它改回普通调度
# 或
kill -9 <PID> # 杀不掉?FIFO 99 的进程优先响应中断信号——先用 chrt 降级再杀五、常见指标判读
| 观测手段 | 指标 | 判读 |
|---|---|---|
chrt -p <PID> | SCHED_FIFO + 高 rtprio | 实时任务,确认是故意设置的 |
ps -eo class,rtprio,comm | class=FF/RR | 系统中所有实时任务一览 |
pidstat -w -p <PID> | nvcswch/s | FIFO 任务这个值应该很低(不被抢占)。如果高 = 有更高优先级的任务在抢 |
top -H | PR 列出现负数 | 实时优先级:PR = -rtprio - 1(如 rtprio=50 显示 PR=-51) |
/proc/<PID>/sched | policy 字段 | 0=OTHER, 1=FIFO, 2=RR, 6=DEADLINE |
六、常见排查方法与分析
6.1 排查系统是否被实时任务锁定
症状:top 里 %Cpu sy 不高但登录响应极慢,或部分核 idle 一直是 0,SSH 操作明显卡顿。
# 找出所有非 SCHED_OTHER 的进程
ps -eo pid,tid,class,rtprio,ni,comm | grep -v "TS"
# class=FF(FIFO)/RR 且 rtprio 高的 → 嫌疑犯
# 逐个确认是不是故意的
chrt -p <PID>
# 若是不知来历的高优先级实时任务 → 降级
chrt -o -p 0 <PID>
# 或先降级再 kill
chrt -o -p 0 <PID> && kill -9 <PID>6.2 延迟敏感应用测试实时调度效果
# 基线:SCHED_OTHER 运行,测延迟
./my_latency_app > baseline.log
# 测试:SCHED_FIFO 优先级 50
chrt -f 50 ./my_latency_app > rt.log
# 对比观测量:
pidstat -w -p <PID> 1 # cswch/nvcswch 变化
pidstat -u -p <PID> 1 # CPU 列是否稳定不迁移
# 注意:nvcswch 应该很低(不被抢占);如有高优先级竞争会有抢占6.3 检查调度策略是否配置正确
# 关键进程是否用了正确的调度策略
for pid in $(pgrep -f "my_rt_app"); do
echo "PID=$pid $(chrt -p $pid)"
done
# 对 SCHED_FIFO 任务,检查优先级是否合理
# rtprio 50 → 可能被 51-99 的任务抢占
# rtprio 99 → 最高,可能饿死一切(慎用)6.4 实时任务饿死普通任务的急救
# 症状:普通 SSH 都连不上
# 可通过 console 或 BMC/IPMI 紧急登录
# 或提前配置好 sched_rt_runtime_us 兜底
cat /proc/sys/kernel/sched_rt_runtime_us # 默认 950000(95%)
# 即每 1 秒实时任务最多跑 0.95 秒,留 0.05 秒给普通任务
# 极端情况可调小:echo 500000 > /proc/sys/kernel/sched_rt_runtime_us七、交叉引用
- 调度器原理:调度类与 CFS(五层调度类的优先级排序)
- 上下文切换:context-switch(FIFO 任务为何切换少)
- 调度观测:scheduling-observation(从系统层面看调度是否健康)
- 绑核:thread-affinity(taskset 绑核 + chrt 改优先级)
- /proc 接口:procfs §二(
/proc/<pid>/sched中 policy/prio 字段)
八、一句话总结
- 调度类分层:调度类与 CFS——为什么 FIFO>RR>CFS,优先级怎么排序
- 优先级与 nice:nice 是 CFS 内的权重因子,rtprio 是实时类的硬优先级,二者是不同的体系
- 上下文切换与抢占:context-switch——FIFO 任务为什么上下文切换少
- 观测调度情况:scheduling-observation——从系统层面看调度是否健康
- 绑核:thread-affinity——chrt 改优先级 + taskset 绑核,是实时任务的常用组合
七、一句话总结
chrt是 Linux 调度策略的命令行接口——chrt -p看进程用的哪种策略,chrt -f/-r改成实时。SCHED_FIFO不设时间片、高优先级能饿死所有低优先级任务,用错了系统会像挂了一样。除非明确需要实时调度(如 DPDK 轮询线程、JACK 音频线程),否则保持默认的SCHED_OTHER最安全。