1. task_struct
task_struct
是描述单个任务(进程或线程)的核心结构体,调度器通过它来管理任务的调度行为。
关键字段:
-
sched_class
:指向调度类(如fair_sched_class
用于 CFS)。 -
se
:sched_entity
,用于 CFS 调度实体。 -
policy
:调度策略(如SCHED_NORMAL
、SCHED_FIFO
)。 -
prio
:任务的动态优先级。 -
nr_cpus_allowed
:任务可以运行的 CPU 数量。 -
cpus_ptr
:任务允许运行的 CPU 掩码。
作用:
-
描述任务的调度属性(如优先级、调度策略)。
-
维护任务的调度实体(如
sched_entity
),用于调度器计算任务的运行时间。 -
记录任务的 CPU 亲和性(
cpus_ptr
),限制任务可以运行的 CPU。
代码分析:
-
任务加入调度队列:
当任务变为可运行状态时,调度器会将其加入运行队列。// kernel/sched/core.c void activate_task(struct rq *rq, struct task_struct *p, int flags) { enqueue_task(rq, p, flags); p->on_rq = TASK_ON_RQ_QUEUED; }
-
调度决策:
调度器通过pick_next_task
选择下一个要运行的任务。// kernel/sched/core.c static inline struct task_struct *pick_next_task(struct rq *rq) { const struct sched_class *class; struct task_struct *p; for_each_class(class) { p = class->pick_next_task(rq); if (p) return p; } return NULL; }
-
任务切换:
调度器通过context_switch
切换到新任务。// kernel/sched/core.c static __always_inline struct rq *context_switch(struct rq *rq, struct task_struct *prev, struct task_struct *next) { switch_to(prev, next, prev); return finish_task_switch(prev); }
2. task_group
task_group
是控制组(cgroup)的核心结构体,用于实现组调度和资源分配。它通过 CFS 的组调度机制,确保任务组的公平性。
关键字段:
-
se
:sched_entity
,表示任务组的调度实体。 -
cfs_rq
:CFS 运行队列,用于管理组内的任务。 -
shares
:任务组的 CPU 份额(权重)。
作用:
-
管理一组任务的调度行为。
-
通过
shares
分配 CPU 资源,确保任务组的公平性。 -
支持层次化调度,任务组可以嵌套。
代码分析:
-
任务组加入调度:
任务组通过task_group
的se
参与调度。// kernel/sched/fair.c static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) { struct sched_entity *se = &p->se; enqueue_entity(cfs_rq_of(se), se, flags); }
-
组调度决策:
调度器会优先选择任务组的se
,然后再选择组内的任务。// kernel/sched/fair.c static struct task_struct *pick_next_task_fair(struct rq *rq) { struct task_struct *p; struct cfs_rq *cfs_rq = &rq->cfs; do { p = pick_next_entity(cfs_rq, NULL); } while (p && !p->se.on_rq); return p; }
-
资源分配:
任务组的 CPU 资源通过shares
分配。// kernel/sched/fair.c static void update_cfs_shares(struct cfs_rq *cfs_rq) { struct task_group *tg = cfs_rq->tg; u64 shares = tg->shares; // 更新任务组的 CPU 份额 }
3. sched_domain
sched_domain
是描述 CPU 拓扑的结构体,用于实现负载均衡和调度优化。它将 CPU 划分为多个层次(如 NUMA 节点、CPU 簇等),以便调度器在不同层次上进行负载均衡。
关键字段:
-
span
:该调度域包含的 CPU 集合。 -
parent
:父调度域。 -
child
:子调度域。 -
flags
:调度域的属性(如负载均衡策略)。
作用:
-
描述 CPU 的拓扑结构,支持层次化负载均衡。
-
在多个 CPU 之间分配任务,避免负载不均衡。
-
优化任务迁移,减少跨 CPU 的开销。
代码分析:
-
负载均衡:
调度器通过sched_domain
进行负载均衡。// kernel/sched/fair.c static void rebalance_domains(struct rq *rq, enum cpu_idle_type idle) { struct sched_domain *sd; for_each_domain(cpu, sd) { if (sd->flags & SD_LOAD_BALANCE) { load_balance(cpu, rq, sd, idle); } } }
-
任务迁移:
调度器根据sched_domain
的层次结构,决定任务迁移的目标 CPU。// kernel/sched/fair.c static int load_balance(int this_cpu, struct rq *this_rq, struct sched_domain *sd, enum cpu_idle_type idle) { // 根据调度域选择目标 CPU }
4. 三者关系与协同工作
-
task_struct
:描述单个任务的调度行为,是调度的基本单位。 -
task_group
:管理一组任务的调度行为,确保任务组的公平性。 -
sched_domain
:描述 CPU 拓扑结构,支持负载均衡和任务迁移。
协同工作流程:
-
任务加入调度:
-
task_struct
被加入运行队列。 -
如果任务属于某个
task_group
,则任务组的se
也会参与调度。
-
-
调度决策:
-
调度器通过
task_struct
和task_group
的se
选择下一个要运行的任务。 -
sched_domain
确保任务在合适的 CPU 上运行,避免负载不均衡。
-
-
负载均衡:
-
sched_domain
定期检查 CPU 负载,决定是否需要迁移任务。 -
任务迁移时,调度器会考虑
task_struct
的 CPU 亲和性和task_group
的资源限制。
-
-
任务切换:
-
调度器通过
context_switch
切换到新任务。 -
如果任务属于某个
task_group
,调度器会更新任务组的资源使用情况。
-
5. 总结
-
task_struct
:管理单个任务的调度行为。 -
task_group
:管理任务组的调度行为,确保公平性。 -
sched_domain
:管理 CPU 拓扑结构,支持负载均衡。
三者通过协同工作,实现了高效的 CPU 调度和负载均衡。task_struct
提供任务的基本信息,task_group
确保任务组的公平性,sched_domain
优化任务的 CPU 分配和迁移。