进程调度

一、调度器演化

二、CFS 核心概念

1. 关键思想

2. 关键数据结构

struct task_struct {
    int prio;            // 优先级
    int static_prio;
    int normal_prio;
    unsigned int policy; // SCHED_NORMAL / FIFO / RR / DEADLINE / IDLE
    int on_rq;
    struct sched_entity se;   // 调度实体
    struct sched_rt_entity rt;
    // ...
};

struct sched_entity {
    u64 vruntime;            // 虚拟运行时间
    u64 sum_exec_runtime;
    u64 prev_sum_exec_runtime;
    // ...
};

struct rq {
    struct cfs_rq cfs;
    struct rt_rq  rt;
    unsigned long nr_running;
    // ...
};

struct cfs_rq {
    struct rb_root tasks_timeline;   // 红黑树
    struct sched_entity *curr;
    u64 min_vruntime;
};

3. 优先级与权重

4. 时间片

三、调度策略

策略 说明
SCHED_NORMAL 普通任务(CFS)
SCHED_BATCH 后台批处理(CFS)
SCHED_IDLE 极低优先级
SCHED_FIFO 实时,先入先出
SCHED_RR 实时,时间片轮转
SCHED_DEADLINE 截止时间调度(CBS)

四、调度类(sched_class)

struct sched_class {
    const struct sched_class *next;
    void (*enqueue_task)(struct rq *rq, struct task_struct *p, int flags);
    void (*dequeue_task)(struct rq *rq, struct task_struct *p, int flags);
    void (*yield_task)(struct rq *rq, struct task_struct *p);
    void (*check_preempt_curr)(struct rq *rq, struct task_struct *p, int flags);
    struct task_struct *(*pick_next_task)(struct rq *rq);
    void (*put_prev_task)(struct rq *rq, struct task_struct *p);
    void (*task_tick)(struct rq *rq, struct task_struct *p, int queued);
    // ...
};

调度类优先级:

stop_sched_class   → 最高(CPU 停止)
dl_sched_class     → deadline
rt_sched_class     → SCHED_FIFO/RR
fair_sched_class   → SCHED_NORMAL
idle_sched_class   → 最低

五、调度点

抢占模型(preempt 模型)

查看:zcat /proc/config.gz | grep PREEMPT

六、CFS 调优参数

# /proc/sys/kernel/sched_*
sched_latency_ns          # 调度周期
sched_min_granularity_ns  # 最小时间片
sched_wakeup_granularity_ns
sched_child_runs_first
sched_tunable_scaling     # 0/1
sched_migration_cost_ns
sched_cfs_bandwidth_slice_us

七、实时调度

struct sched_param sp = { .sched_priority = 80 };
pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp);
// 80/99 普通实时;99 最高

// 进程
sched_setscheduler(pid, SCHED_FIFO, &sp);

注意:
- 需要 CAP_SYS_NICE 权限
- 优先级反转(priority inversion):用优先级继承(mutex)
- 实时任务不能睡眠

八、组调度(cgroup)

# 创建 cpu cgroup
mkdir /sys/fs/cgroup/cpu/mygroup
echo 50000 > /sys/fs/cgroup/cpu/mygroup/cpu.shares   # 权重
echo 100000 > /sys/fs/cgroup/cpu/mygroup/cpu.cfs_quota_us
echo $$ > /sys/fs/cgroup/cpu/mygroup/tasks

九、CPU 亲和性

cpu_set_t set;
CPU_ZERO(&set);
CPU_SET(0, &set);
CPU_SET(2, &set);
sched_setaffinity(0, sizeof(set), &set);

十、调度延迟监控

# 调度延迟直方图
cat /proc/sys/kernel/sched_latency_ns
cat /proc/sched_debug

# perf
perf stat -e sched:sched_wakeup -e sched:sched_switch sleep 1
perf sched record sleep 5
perf sched latency -s max ./prog

十一、嵌入式注意点