在 Linux 内核调度器中,sched_prio_to_weight 是一个非常关键的数组,用于把「静态优先级(nice 值)」映射为调度权重(weight)。
调度器(CFS:Completely Fair Scheduler)不是直接比较 nice 值,而是通过权重控制各任务获得的 CPU 时间比例。
一、sched_prio_to_weight 的定义位置
代码位置(以常见版本为例):
// kernel/sched/core.c 或 kernel/sched/fair.c
const int sched_prio_to_weight[40] = {/* -20 */ 88761, 71755, 56483, 46273, 36291,/* -15 */ 29154, 23254, 18705, 14949, 11916,/* -10 */ 9548, 7620, 6100, 4904, 3906,/* -5 */ 3121, 2501, 1991, 1586, 1277,/* 0 */ 1024, 820, 655, 526, 423,/* 5 */ 335, 272, 215, 172, 137,/* 10 */ 110, 87, 70, 56, 45,/* 15 */ 36, 29, 23, 18, 15,
};
其中索引为 prio - MAX_RT_PRIO,对应 nice 值范围 [-20, +19]。
二、转换关系说明
Linux 的 nice 值范围是 -20 ~ +19:
- 数值越小(更负),优先级越高;
- 数值越大,优先级越低。
调度器通过以下公式近似计算各任务的运行时间份额:
[
\text{runtime share} \propto \text{weight}
]
任务的虚拟运行时间增量:
[
\Delta vruntime = \frac{\text{actual runtime} \times 1024}{\text{weight}}
]
这意味着:
- weight 大 → vruntime 增加得慢 → 任务更容易再次被调度;
- weight 小 → vruntime 增加快 → 任务更少获得 CPU。
三、weight 之间的比例规律
每相邻两个 nice 值之间的 weight 比例大约为 1.25 倍(也就是每增加 1 个 nice,权重乘以 0.8 左右)。
换句话说:
[
\text{weight}(nice+1) ≈ \frac{\text{weight}(nice)}{1.25}
]
即:
- nice -20 → 88761
- nice -19 → 71755(约等于 88761 / 1.24)
- …
- nice 0 → 1024
- nice +19 → 15
这样可以保证:
- nice 值差 10,对应权重比例约为 10 倍;
- nice 值差 20,对应权重比例约为 100 倍。
四、权重的数学近似公式
虽然内核中使用表格查表,但有一个经验公式近似表达:
[
\text{weight}(nice) ≈ 1024 \times (1.25)^{-nice}
]
举例:
| nice | weight(近似) | 实际表中值 |
|---|---|---|
| -20 | 1024×(1.25)^20 ≈ 88366 | 88761 |
| 0 | 1024 | 1024 |
| +19 | 1024×(1.25)^(-19) ≈ 16.4 | 15 |
非常接近。
五、调度比例示例
假设两个任务:
- A:nice = 0 → weight = 1024
- B:nice = +5 → weight = 335
则 CPU 时间分配比:
[
\text{A:B} = 1024:335 ≈ 3.05:1
]
即 A 得到约 75%,B 得到约 25% CPU 时间。
六、与其他表的关系
除了 sched_prio_to_weight 外,还有:
const u32 sched_prio_to_wmult[40];
它存放的是 2^32 / weight 的结果,用于加速计算(避免除法)。
七、总结
| Nice | 权重 (Weight) | 相对比 (相对 nice=0) | CPU 时间占比 |
|---|---|---|---|
| -20 | 88761 | 86.7x | 极高 |
| -10 | 9548 | 9.3x | 高 |
| 0 | 1024 | 1x | 标准 |
| +10 | 110 | 0.107x | 低 |
| +19 | 15 | 0.014x | 极低 |