Linux内核源码分析-进程调度(五)-组调度

出现的背景

总结来说是希望不同分组的任务在高负载下能分配可控比例的CPU资源。为什么会有这个需求呢,假设多用户计算机系统每个用户的所有任务划分到一个分组中,A用户90个任务,而B用户只有10个任务(这100个任务假设都是优先级一样的普通进程),在CPU完全跑满的情况下,那么A用户将占90%的CPU时间,而B用户只占到了10%的CPU时间,这对B用户显然是不公平的。再或者同一个用户,既想-j64快速编译,又不想被编译任务影响使用体验,也可将编译任务设置到对应分组中,限制其CPU资源。组调度的引入,正是解决此问题的,即可以将任务分配给不同的任务组来实现CPU资源的合理利用。

我们举个例子来进一步阐述一下上面这段话。现在的计算机都支持多用户登录,如果一台计算机被两个用户A和B同时使用,假设用户A运行8个进程,用户B运行2个进程,按照之前对CFS的理解,CFS的调度粒度都是一个个的进程,我们认为用户A获得80%的cpu时间,用户B获得20%的cpu时间。随着用户A不停的增加运行进程数量,用户B可使用的CPU时间越来越少,这就完全不符合我们的预期了。因此,我们引入了组调度(Group Scheduling)的概念。我们将一个用户的任务放在同一个任务组中,这样用户A和用户B各获得50%cpu时间。用户A中的每个进程获得6.25%(50% / 8)cpu时间,用户B的每个进程获得25%(50% / 2)cpu时间,这样的结果是符合我们预期的。

task group

前面我们说过,CFS调度器管理的是调度实体。每一个进程通过task_struct描述,task_struct对应一个调度实体sched_entity。针对task_struct对应的调度实体,我们称之为task se。现在我们引入任务组的概念,我们使用task_group描述一个任务组,这个组管理组内所有的进程。因为CFS就绪队列管理的单位是调度实体,因此,task_group也脱离不了sched_entity,即task_group也映射为一个调度实体,我们称这种调度实体为group se。

/* Task group related information */
/*
 * 组调度,Linux支持将任务分组来对CPU资源进行分配管理。
 * 该结构中为系统中的每个CPU都分配了struct sched_entity调度实体和struct cfs_rq运行队列,
 * 其中struct sched_entity用于参与CFS的调度。
 */
struct task_group {
	struct cgroup_subsys_state css;

#ifdef CONFIG_FAIR_GROUP_SCHED
	/* schedulable entities of this group on each CPU */
	/*
	 * 所以se代表cpu数量个group se。
	 * 在alloc_fair_sched_group()中进程初始化及分配内存。
	 */
	struct sched_entity	**se;
	/* runqueue "owned" by this group on each CPU */
	struct cfs_rq		**cfs_rq;  // 每一个se[cpu]对应一个group cfs_rq。
	unsigned long		shares;  // 整个调度组的权重。

#ifdef	CONFIG_SMP
	/*
	 * load_avg can be heavily contended at clock tick time, so put
	 * it in its own cacheline separated from the fields above which
	 * will also be accessed at each tick.
	 */
	atomic_long_t		load_avg ____cacheline_aligned;  // 整个tg的负载贡献总和。
#endif
#endif

	struct cfs_bandwidth	cfs_bandwidth;  // cpu带宽控制
};
struct task_group root_task_group;

task group与cpu rq的cfs_rq的关系

在这里插入图片描述

现在我们来详细说一下这张图:
系统启动后默认有一个root_task_group,管理系统中最顶层CFS就绪队列cfs_rq(即cpu rq对应的CFS就绪队列),对应上图即为root tg的cfs_rq[cpu1]和cfs_rq[cpu2]。
cpu2 rq的cfs_rq队列包含9个task se和一个group se,此group se又包含9个task se,且此group se会对应一个task group,即有几层group se,就会有几层tg(不包含root tg)。
tg的parent指向了上一级tg,se维护了cpu数量的group se,cfs_rq[cpu]维护了对应的group se下属的se。
cfs_rq的nr_running:就绪队列上调度实体的个数(包括task se和group se,比如上图中的cpu rq的cfs_rq的task se个数为9,group se个数为1,则nr_running为10)。
cfs_rq的h_nr_running:就绪队列上真实的调度实体的个数(比如上图中的cpu rq的cfs_rq的task se个数为9,group se个数为1(group se中包含9个task se,则),则h_nr_running为18)。

组进程调度

组内的进程该如何调度呢?通过上面的分析,我们可以通过cpu rq的CFS就绪队列(也称根就绪队列)一层层往下遍历选择合适进程。例如,先从根就绪队列选择适合运行的group se,然后找到对应的group cfs_rq,再从group cfs_rq上选择task se。在CFS调度类中,选择进程的函数是pick_next_task_fair()。

struct task_struct *
pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
{
	struct cfs_rq *cfs_rq = &rq->cfs;  // 从per-cpu rq中获取cfs就绪队列
	struct sched_entity *se;
	struct task_struct *p;
	int new_tasks;

again:
	if (!sched_fair_runnable(rq))  // 判断per-cpu rq的cfs就绪队列上是否还有调度实体,若无则选择idle调度器。
		goto idle;

#ifdef CONFIG_FAIR_GROUP_SCHED
	if (!prev || prev->sched_class != &fair_sched_class)
		goto simple;

	/*
	 * Because of the set_next_buddy() in dequeue_task_fair() it is rather
	 * likely that a next task is from the same cgroup as the current.
	 *
	 * Therefore attempt to avoid putting and setting the entire cgroup
	 * hierarchy, only change the part that actually changes.
	 */

	do {
		struct sched_entity *curr = cfs_rq->curr;  // 获取当前正在cpu上运行的调度实体。

		/*
		 * Since we got here without doing put_prev_entity() we also
		 * have to consider cfs_rq->curr. If it is still a runnable
		 * entity, update_curr() will update its vruntime, otherwise
		 * forget we've ever seen it.
		 */
		if (curr) {
			if (curr->on_rq)
				update_curr(cfs_rq);
			else
				curr = NULL;

			/*
			 * This call to check_cfs_rq_runtime() will do the
			 * throttle and dequeue its entity in the parent(s).
			 * Therefore the nr_running test will indeed
			 * be correct.
			 */
			if (unlikely(check_cfs_rq_runtime(cfs_rq))) {
				cfs_rq = &rq->cfs;

				if (!cfs_rq->nr_running)
					goto idle;

				goto simple;
			}
		}

		se = pick_next_entity(cfs_rq, curr);  // 从rq的cfs队列中选取虚拟运行时间最小的调度实体。
		cfs_rq = group_cfs_rq(se);  // 返回se->my_q成员(即获取se的就绪队列)。如果是task se,则返回NULL;如果是group se,则返回group se中的csf_rq就绪队列。
	} while (cfs_rq);  // 如果是group se,则需要继续在group se中的cfs_rq上选择虚拟运行时间最小的se,直到找到可以最小虚拟运行时间的task se。

	p = task_of(se);  // 获取调度实体se对应的进程p。

	return p;
}

组进程抢占

组进程抢占即为周期性调度,会调用task_tick_fair()函数。

/*
 * 周期性调度
 */
static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued)
{
	struct cfs_rq *cfs_rq;
	struct sched_entity *se = &curr->se;  // 

	for_each_sched_entity(se) {  // for_each_sched_entity(se)是一个宏定义for (; se; se = se->parent),顺着se的parent链表往上走。更新子调度实体的同时必须更新父调度实体
		cfs_rq = cfs_rq_of(se);  // 获取se所属的cfs_rq;
		entity_tick(cfs_rq, se, queued);  // 完成周期性调度
	}
}

entity_tick的函数实现可以参考前面的文章。
entity_tick()函数继续调用check_preempt_tick()函数,这部分在之前的文章已经说过了。check_preempt_tick()函数会根据满足抢占当前进程的条件下设置TIF_NEED_RESCHED标志位。满足抢占条件也很简单,只要顺着se->parent这条链表便利下去,如果有一个se运行时间超过分配限额时间就需要重新调度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/24299.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python 下载的 11 种姿势,一种比一种高级

今天我们一起学习如何使用不同的Python模块从web下载文件。此外,你将下载常规文件、web页面、Amazon S3和其他资源。 通过本文的学习,你将学到如何克服可能遇到的各种挑战,例如下载重定向的文件、下载大型文件、完成一个多线程下载以及其他策…

C# WPF窗体设计器显示以及App.xaml文件打不开(VS 2022)

问题描述: 在项目中遇到了App.xaml设计器打不开以及窗体设计器不显示,只有代码,如图所示: 可以明显的看见左下角的设计器不见,但是用户控件又有设计器 解决方法: (一、App.xaml不能正常打开) ①清理项…

定薪17K*15,阿里测开岗上岸面经分享....

先简单介绍一下我自己吧,等会大家以为我是什么学历狂人,技术大牛,我毕业于广东一个普通本科院校,绝对不是什么双一流大学,大家不要有距离感,这也是我为什么来分享的原因,因为我觉得我这段经验还…

硬件软件【部署】

开发板和主机 1.功能不同:帮助开发者进行嵌入式系统的开发和调试,具有较强的硬件拓展能力,可以连接各种传感器/执行器等外设。主机为满足一般的计算需求而设计,具备更强的计算和图形处理能力。 2.架构不同:开发板通常…

【接口测试】JMeter测试WebSocket接口

目录 一、WebSocket简介 二、JMeter测试WebSocket接口 三、WebSocket和Socket的区别 最近老被问到WebSocket,突然想到以前大学时上Java课的时候,老师教我们socket连接,一个同学电脑做客户端,一个同学电脑做服务端,…

LAMP平台搭建

文章目录 LAMP概述安装apache安装mysql安装php LAMP概述 LAMP架构是目前成熟的企业网站应用模式之一,指的是协同工作的一整套系统和相关软件,能够提供动态Web站点服务及其应用开发环境。LAMP是一个缩写词,具体包括Linux操作系统、Apache网站…

Java --- 期末复习卷

一、单选题 1.所有Java应用程序主类必须有一个名叫( )的方法。[ ] A.method B.main() C.java() D.hello 2.编写并保存了一个Java程序文件之后,( )它。[ …

node笔记_http服务搭建(渲染html、json)

文章目录 ⭐前言⭐初始化项目调整npm 的script运行入口搭建hello world的http服务npm run dev执行主函数的http服务 ⭐http返回类型html模板文件返回安装express渲染html的字符串 渲染html文件 sendFile渲染json返回数据类型 res.json ⭐结束 ⭐前言 大家好,我是ym…

TensorFlow 1.x学习(系列二 :4):自实现线性回归

目录 线性回归基本介绍常用的op自实现线性回归预测tensorflow 变量作用域模型的保存和加载 线性回归基本介绍 线性回归: w 1 ∗ x 1 w 2 ∗ x 2 w 3 ∗ x 3 . . . w n ∗ x n b i a s w_1 * x_1 w_2 * x_2 w_3 * x_3 ... w_n * x_n bias w1​∗x1​w2​∗…

MySQL 对日期使用 DATE_FORMAT()函数

文章目录 DATE_FORMAT()函数显示今天是星期几只显示年月显示当前时间的分钟数和秒数 DATE_FORMAT()函数 前面使用日期时间函数,获取到的要么是 yyyy-mm-dd 形式的日期,要么是 hh:MM:ss 形式的时间,或者是 yyyy-mm-dd hh:mm:ss 形式的日期及时…

算法基础学习笔记——⑧堆\哈希表

✨博主:命运之光 ✨专栏:算法基础学习 目录 ✨堆 🍓堆模板: ✨哈希表 🍓一般哈希模板: 🍓字符串哈希模板: 前言:算法学习笔记记录日常分享,需要的看哈O(…

Qt文件系统源码分析—第六篇QSaveFile

深度 本文主要分析Windows平台,Mac、Linux暂不涉及 本文只分析到Win32 API/Windows Com组件/STL库函数层次,再下层代码不做探究 本文QT版本5.15.2 类关系图 QTemporaryFile继承QFile QFile、QSaveFile继承QFileDevice QFileDevice继承QIODevice Q…

远程访问本地jupyter notebook服务 - 无公网IP端口映射

文章目录 前言视频教程1. Python环境安装2. Jupyter 安装3. 启动Jupyter Notebook4. 远程访问4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5. 固定公网地址 转载自远控源码文章:公网远程访问jupyter notebook【cpolar内网穿透】 前言 Jupyter Notebook&am…

网络原理(六):http 协议(上)

目录 HTTP 协议是什么 抓包工具 Fiddler 的下载 使用Fiddler HTTP 请求 (Request) HTTP 请求格式 首行 请求头(Header) Cookie HTTP 协议是什么 还是老样子,在讲解http 之前我们先来了解以下什么叫做 http 。 HTTP(Hyp…

(转载)从0开始学matlab(第14天)—while循环结构

循环(loop) 是一种 matlab 结构,它允许我们多次执行一系列的语句。循环结构有两种基本形式 :while 循环和 for 循环。两者之间的最大不同在于代码的重复是如何控制的。在while 循环中,代码的重复的次数是不能确定的,只要满足用户定义的条件…

整理6个超好用的在线编辑器!

随着 Web 开发对图像可扩展性、响应性、交互性和可编程性的需求增加,SVG 图形成为最适合 Web 开发的图像格式之一。它因文件小、可压缩性强并且无论如何放大或缩小,图像都不会失真而受到欢迎。然而,为了编辑 SVG 图像,需要使用 SV…

《五》 Git 中的标签和分支

标签 tag: Git 可以给仓库中某一次 commit 的提交打上标签。对于重大的版本经常会打上一个标签来表示它的重要性。 创建标签: git tag【tag 名称】:创建标签。 查看标签: git tag:查看标签。 推送标签到远程仓库…

任务40 评奖系统设计

系列文章 任务40 评奖系统设计 为教务处设计一个学生评价老师的程序: 每位学生投一张票,选出自己最喜爱的老师,选票格式为: | 第一喜爱的老师 | 第二喜爱的老师 |第三喜爱的老师 | | 工号 |工号 |工号 | 上述数据存放在一个数据…

随机网络构建

随机网络构建 文章目录 随机网络构建[toc]1 随机网络定义2 网络拓扑性质2.1 边数分布2.2 度分布 3 代码实现 1 随机网络定义 随机网络与规则网络相对应,最为经典的随机网络模型是Erds和Rnyi研究的ER随机图模型,ER随机图模型有两种定义方式: …

三种快速转换PDF为TXT的方法:简单、高效、免费

如何将PDF转换为TXT文件?在日常生活中,PDF和TXT是常见的文本格式。PDF格式文件具有稳定的布局和易于存储的特点。然而,许多在线下载的电子书通常是以PDF格式提供的,而电子阅读器通常不支持PDF格式,这就导致了无法方便地…