首页 > 其他分享 >CFS(一)设计理念与实现架构

CFS(一)设计理念与实现架构

时间:2023-10-11 11:47:14浏览次数:31  
标签:sched struct 调度 class rb 架构 CFS 理念

前言

本文对CFS的基础的设计理念以及在内核实现上的基本代码架构进行了分析,从宏观上梳理调度和CFS的脉络。本文所有的代码基于Linux 4.19。

CFS的设计理念和目标

CFS(Completely Fair Scheduler)完全公平调度器,从字面上看定义的很清晰,首先CFS的本质是一个调度器,所谓调度就是决定CPU的执行权在每个时刻的归属,调度管理的对象就是CPU资源。所谓完全公平追求的是一种理想的多任务CPU模型,CPU资源能够平等分配给每一个任务,比如有两个任务,每个任务能够得到50%的CPU资源,但是这是一个不可能完成的任务,首先,对于CPU来说一个时刻只能有一个任务在执行,不存在并行执行;第二点,在执行的过程中不断地有任务的加入和退出。在这样的复杂场景下只能追求近似的完全公平。

设计中的关键点

CFS调度器在Linux 2.6中被引入,CFS在设计上有一些关键的点,提前了解可以有助于后续阅读源码:

  1. 虚拟时间(vruntime):在CFS中使用vruntime来表示一个task在该CPU上的运行时间,vruntime累计值的计算与任务的优先级(权重)以及runq中的任务数量有关。CFS的调度逻辑也很简单,当一个调度时机出现时选择当前runq中vruntime最少的任务获得CPU。vruntime可以说是CFS调度器的灵魂,通过vruntimeCFS间接实现了任务优先级,高优先级能够得到更多的CPU时间。
  2. runq的实现基于红黑树实现,从逻辑上说任何能实现虚拟时间排序的数据结构都是可以作为runq的,但是红黑树在内存、性能的综合考虑下表现最好,在查找、删除、插入等场景下性能表现稳定。
  3. cgroup:支持按group来分配时间片,以组为单位划分CPU资源。

CFS内核实现的相关数据结构

调度类

任何机制都是对数据的操作,在理解或者了解一项技术前需要先纵览它的设计架构。首先,在内核中CFS只是调度器中的一种,还有针对于实时系统的实时调度器,同时为了满足调度器的可拓展性,调度器被抽象为调度类(Scheduling Class),类似于C++中的虚基类,只定义了函数的类型具体的实现交给具体的子类,CFS就是其子类之一。

sched_class定义了一个调度器应该具备的基本操作,CFS调度器的实现在fair.c中,fair_sched_class变量就是CFS的调度类对象,初始化了所有的函数指针。

const struct sched_class fair_sched_class = {
	.next			= &idle_sched_class,
	.enqueue_task		= enqueue_task_fair,
	.dequeue_task		= dequeue_task_fair,
                    ....
	.update_curr		= update_curr_fair,
};

sched_class中的next指针指向下一个调度类,所有的调度类按照优先级从高到低存放在单链表中。优先级从高到底依次是stop_sched_classdl_sched_classrt_sched_classfair_sched_class以及idle_sched_class。不同的调度类实现了不同的调度策略,在本文中只需要关注fair_sched_class,但是需要清楚存在这样一个逻辑,调度时会优先选择高优先级调度器中的任务获取CPU执行权。

graph LR A[stop_sched_class] -.-> B[dl_sched_class] -.-> C[rt_sched_class] -.-> D[fair_sched_class] -.-> E[idle_sched_class]
调度类优先级

就绪队列

在调度类中只定义了CFS的基本操作,这些函数的操作对象包括就绪队列和任务。在内核中就绪队列通过struct rq实现。struct rq是一个per-cpu的数据结构,可以看到struct rq下包含了cfsrtdl三个队列对应着三个不同的调度类。

NOTE:1. 不同调度类的就绪队列实现是不同的,与其策略相关。2. 每一个CPU上的就绪队列是独立的。

struct rq {
	struct cfs_rq		cfs;
	struct rt_rq		rt;
	struct dl_rq		dl;
    ....
    struct task_struct	*curr; // 当前在运行的task
	struct task_struct	*idle; // idle task
	struct task_struct	*stop; // stop task	
};

这里存在一个问题,为什么调度类有五个只有三个就绪队列,因为stop和idle两个调度类只执行固定的进程,stop调度类用于stop_machine.c,停机线程的优先级高于所有的task,这也是stop调度类的优先级最高的原因。idle调度类执行的是固定的idle线程。因此这两个调度类不需要就绪队列。

graph TB subgraph CPUS C1[CPU0] Cx[....] C2[CPUn] end C1 -.-> rq subgraph rq cfs1[cfs_rq] rq1[rt_rq] dl1[dl_rq] end cfs1 -.->|tasks_timeline| rb_root_cached subgraph rb_root_cached rb_leftmost rb_root end rb_root -.-> 27 rb_leftmost -.-> 2 subgraph 27((27)) --> 19((19)) 19 --> 7((7)) --> 2((2)) 19 --> 25((25)) 27-->34 34--> 31((31)) 34((34)) --> 65((65)) --> 49((49)) 65 --> 98((98)) end subgraph task_struct se[sched_entity se] end se -.-> sched_entity subgraph sched_entity run_node[rb_node] vruntime[vruntime=98] end run_node -.-> 98
CFS数据组织结构

这里我们重点关注的是CFS的就绪队列cfs_rqcfs_rq中最关键的就是存放调度实体的队列,也就是上述的红黑树的数据结构。但是内核中使用的红黑树还存在一点优化,在rb_root_cached中不仅存放了红黑树的根节点,还缓存最小元素的节点指针,将访问最小元素的操作简化到O(1)。除此之外,内核中的红黑树实现是一个通用的数据结构,具体的实现细节这里不详细说明,只需要明确通过rb_leftmost这个struct rb_node指针我们可以找到其对应的调度实体即可,中间的转化会涉及一些编译器与指针的trick。

struct cfs_rq {
	struct rb_root_cached	tasks_timeline;
    ...
}

struct rb_root_cached {
	struct rb_root rb_root;
	struct rb_node *rb_leftmost;
};

标签:sched,struct,调度,class,rb,架构,CFS,理念
From: https://www.cnblogs.com/wodemia/p/17756356.html

相关文章

  • 微宏科技基于 KubeSphere 的微服务架构实践
    作者:尹珉,KubeSphereAmbassador、contributor,KubeSphere社区用户委员会杭州站站长。公司简介杭州微宏科技有限公司于2012年成立,专注于业务流程管理和自动化(BPM&BPA)软件研发和解决方案供应商。创始团队毕业于浙江大学、清华大学、美国Rice大学和UniversityofTexas等......
  • 《解决方案架构师的修炼之道》阅读目录
    大纲章节 ......
  • 《架构师之路:软件架构之美》第四,五章读书笔记
    第四章:系统可伸缩性的重要性第四章讨论了系统可伸缩性的重要性。在现代软件开发中,可伸缩性是一个关键概念,它涉及到系统在不同负载下的性能表现。以下是一些关键观点:可伸缩性是应对用户增长和数据量增加的关键。一个好的架构应该能够轻松扩展以满足这些需求,而不需要完全重新设......
  • 2023年最全得软件测试工程师 学习知识架构体系
    一、Python编程入门到精通 二、接口自动化项目实战 三、Web自动化项目实战 四、App自动化项目实战 五、一线大厂简历 六、测试开发DevOps体系 七、常用自动化测试工具 八、JMeter性能测试 只有不断超越自己的勇气,才能让梦想破茧而出......
  • 行行AI公开课:风平智能高级业务架构师-段泽鹏《AI数字人场景化应用》
    随着人工智能技术的飞速发展,AI数字人逐渐成为各行各业的“香饽饽”。AI数字人如今已经不再只是企业品牌单纯制造营销噱头博得流量的工具,而是具有品牌理念属性、提供服务体验升级、降本增效等多元的商业价值。AI数字人的使用场景也正在逐渐解锁,逐渐成为一种新颖的企业与用户交互的......
  • 直播预约丨《实时湖仓实践五讲》第二讲:实时湖仓功能架构设计与落地实战
    如今,大规模、高时效、智能化数据处理已是“刚需”,企业需要更强大的数据平台,来应对数据查询、数据处理、数据挖掘、数据展示以及多种计算模型并行的挑战,湖仓一体方案应运而生。《实时湖仓实践五讲》是袋鼠云打造的系列直播活动,将围绕实时湖仓的建设趋势和通用问题,邀请奋战于企业数......
  • 云边端架构国标GB28181视频智能分析平台如何配置EasyGBS语音对讲
    云边端架构内的国标视频智能分析平台EasyGBS在更新到目前的新版本后,已经增加了对海康摄像头的对讲功能的支持。这意味着客户可以通过摄像头与PC端进行语音的对讲沟通,进一步提高了视频监控的交互性和便捷性。但是在配置该功能的时候,需要客户对EasyGBS服务器以及摄像头的配置页......
  • 架构师养成记-mybatis一级缓存,二级缓存
    一级缓存级缓存是MyBatis中的默认提供的缓存的,也就是说,我们在使用ybatis的时候本身就在使用,他是默认开启的,级缓存是sqlsession级别的缓存,只有在一个salSession内的查询才能共享缓存的数据,当我们关闭sqlsession的时候或者执行增删改查的操作的时候,缓存就会被清空 验证......
  • 架构师养成记-springboot自动装配
    @SpringBootApplication 这其中有两个比较容易引起我们注意的地方,一个是@springBoot(onfiguration注解,另一个是@nableAutoConfiguration注解; 进入了AutoConfigurationImportselector,class类,因为谷歌翻译告诉我们,这个是自动配置导入选择器.publicclassAutoConfigu......
  • 阿里云ECS高可用应用架构部署方案
    高可用架构是指计算机系统能够保证无故障持续运行的概率,通常采用百分比的方式来表示系统的高可用性等级,我们在生活中采用高可用概率=可用时间/总时间*100%来计算实现的高可用性等级,要想实现较高的高可用性等级,需要引入系统冗余的理念。7x24 小时不间断的运行并对外提供正常的服务,......