说明:
- Kernel版本:4.14
- ARM64处理器,Contex-A53,双核
- 使用工具:Source Insight 3.5, Visio
1. 概述
- Completely Fair Scheduler,完全公平调度器,用于Linux系统中普通进程的调度。
- CFS采用了红黑树算法来管理所有的调度实体sched_entity,算法效率为O(log(n))。CFS跟踪调度实体sched_entity的虚拟运行时间vruntime,平等对待运行队列中的调度实体sched_entity,将执行时间少的调度实体sched_entity排列到红黑树的左边。
- 调度实体sched_entity通过enqueue_entity()和dequeue_entity()来进行红黑树的出队入队。
老规矩,先上张图片来直观了解一下原理:
- 每个sched_latency周期内,根据各个任务的权重值,可以计算出运行时间runtime;
- 运行时间runtime可以转换成虚拟运行时间vruntime;
- 根据虚拟运行时间的大小,插入到CFS红黑树中,虚拟运行时间少的调度实体放置到左边;
- 在下一次任务调度的时候,选择虚拟运行时间少的调度实体来运行;
在开始本文之前,建议先阅读下一文讲解Linux进程调度器-基础。
2. 数据结构
2.1 调度类
Linux内核抽象了一个调度类struct sched_class,这是一种典型的面向对象的设计思想,将共性的特征抽象出来封装成类,在实例化各个调度器的时候,可以根据具体的调度算法来实现。这种方式做到了高内聚低耦合,同时又很容易扩展新的调度器。
- 在调度核心代码kernel/sched/core.c中,使用的方式是task->sched_class->xxx_func,其中task表示的是描述任务的结构体struct task_struck,在该结构体中包含了任务所使用的调度器,进而能找到对应的函数指针来完成调用执行,有点类似于C++中的多态机制。
资料直通车:Linux内核源码技术学习路线+视频教程内核源码
2.2 rq/cfs_rq/task_struct/task_group/sched_entity
- struct rq:每个CPU都有一个对应的运行队列;
- struct cfs_rq:CFS运行队列,该结构中包含了struct rb_root_cached红黑树,用于链接调度实体struct sched_entity。rq运行队列中对应了一个CFS运行队列,此外,在task_group结构中也会为每个CPU再维护一个CFS运行队列;
- struct task_struct:任务的描述符,包含了进程的所有信息,该结构中的struct sched_entity,用于参与CFS的调度;
- struct task_group:组调度(参考前文),Linux支持将任务分组来对CPU资源进行分配管理