Linux进程管理:(四)组调度机制

文章说明:

  • Linux内核版本:5.0

  • 架构:ARM64

  • 参考资料及图片来源:《奔跑吧Linux内核》

  • Linux 5.0内核源码注释仓库地址:

    zhangzihengya/LinuxSourceCode_v5.0_study (github.com)

1. 组调度

CFS的调度粒度是进程,但是在某些应用场景中,用户希望的调度粒度是用户组,如在一台服务器中有N个用户登录,希望这N个用户可以平均分配CPU时间。这在调度粒度为进程的CFS里是很难做到的,拥有进程数量多的登录用户将会被分配比较多的CPU资源,组调度可以满足这方面的应用需求。

CFS定义了一个数据结构task_group来抽象和描述组调度:

struct task_group {/* 任务组与cgroup子系统状态的基础结构 */struct cgroup_subsys_state css;#ifdef CONFIG_FAIR_GROUP_SCHED/* 下面的字段仅在启用公平调度组(CONFIG_FAIR_GROUP_SCHED)时才会存在 */struct sched_entity **se;          /* 指向每个CPU上任务组可调度实体的指针数组 */struct cfs_rq **cfs_rq;            /* 指向每个CPU上任务组所拥有的运行队列的指针数组 */unsigned long shares;               /* 任务组的CPU份额 */#ifdef CONFIG_SMP/** 下面的字段仅在启用对称多处理(CONFIG_SMP)时才会存在,* load_avg 可能在时钟滴答时存在严重争用,因此将其放在自己的缓存行中,与上面的字段分开,这些字段在每个滴答都会访问。*/atomic_long_t load_avg ____cacheline_aligned;
#endif
#endif#ifdef CONFIG_RT_GROUP_SCHED/* 下面的字段仅在启用实时调度组(CONFIG_RT_GROUP_SCHED)时才会存在 */struct sched_rt_entity **rt_se;    /* 指向每个CPU上任务组实时调度实体的指针数组 */struct rt_rq **rt_rq;              /* 指向每个CPU上任务组实时运行队列的指针数组 */struct rt_bandwidth rt_bandwidth;   /* 存储任务组实时调度的带宽信息 */
#endifstruct rcu_head rcu;                /* 用于RCU(Read-Copy-Update)机制的头部,用于进行资源释放 */struct list_head list;              /* 用于将任务组添加到全局链表中 */struct task_group *parent;          /* 指向父任务组的指针 */struct list_head siblings;          /* 用于将任务组添加到兄弟任务组的链表中 */struct list_head children;          /* 用于将子任务组添加到任务组的链表中 */#ifdef CONFIG_SCHED_AUTOGROUP/* 下面的字段仅在启用自动分组(CONFIG_SCHED_AUTOGROUP)时才会存在 */struct autogroup *autogroup;       /* 与自动分组相关的信息 */
#endifstruct cfs_bandwidth cfs_bandwidth; /* 存储任务组公平调度的带宽信息 */
};

2. 组调度的创建

组调度属于cgroup架构中的cpu子系统,在系统配置时需要打开CONFIG_CGROUP_SCHED和CONFIG_FAIR_GROUP_SCHED宏。我们直接从sched_create_group()函数来看如何创建和组织—个组调度:

// 创建和组织一个组调度
// parent 指向上一级的组调度节点,系统中有一个组调度的根,命名为 root_task_group
struct task_group *sched_create_group(struct task_group *parent)
{...// 创建 CFS 需要的组调度数据结构if (!alloc_fair_sched_group(tg, parent))goto err;// 创建 realtime 调度器需要的组调度数据结构if (!alloc_rt_sched_group(tg, parent))goto err;return tg;err:...
}

sched_create_group()->alloc_rt_sched_group():

int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent)
{...// cfs_rq 是一个指针数组,分配 nr_cpu_ids 个 cfs_rq 数据结构并将其存放到该指针数组中tg->cfs_rq = kcalloc(nr_cpu_ids, sizeof(cfs_rq), GFP_KERNEL);...// shares 成员表示该组的权重,这里暂时初始化为 nice 值为 0 的进程权重tg->shares = NICE_0_LOAD;// 初始化 CFS 中与带宽控制相关的信息init_cfs_bandwidth(tg_cfs_bandwidth(tg));// for 循环遍历系统中所有的 CPU,为每个 CPU 分配一个 cfs_rq 调度队列和 sched_entity 调度实体for_each_possible_cpu(i) {cfs_rq = kzalloc_node(sizeof(struct cfs_rq),GFP_KERNEL, cpu_to_node(i));if (!cfs_rq)goto err;se = kzalloc_node(sizeof(struct sched_entity),GFP_KERNEL, cpu_to_node(i));if (!se)goto err_free_rq;// 初始化 cfs_rq 调度队列中的 task_timeline 和 min_vruntime 等信息init_cfs_rq(cfs_rq);// 用于构建组调度结构的关键函数,对组调度的相关数据结构进行初始化init_tg_cfs_entry(tg, cfs_rq, se, i, parent->se[i]);init_entity_runnable_average(se);}...
}

下图所示为在一个双核处理器系统中组调度的数据结构关系:

在这里插入图片描述

3. 把进程添加到组调度

要把进程添加到组调度,需要调用cgroup里的接口函数cpu_cgroup_attach():

// 把进程添加到组调度
static void cpu_cgroup_attach(struct cgroup_taskset *tset)
{...// 遍历参数 tset 包含的进程链表cgroup_taskset_for_each(task, css, tset)// 将进程迁移到组调度中sched_move_task(task);
}

cpu_cgroup_attach()->sched_move_task():

void sched_move_task(struct task_struct *tsk)
{...// 判断该进程是否正在运行running = task_current(rq, tsk);// 判断进程是否在就绪队列里或者正在运行中// task_struct 数据结构中的 on-rq 成员表示该进程的状态,TASK_ON_RQ_QUEUED 表示该进程在就绪队列中或者正在运行中,// TASK_ON_RQ_MIGRATING 表示该进程正在迁移中queued = task_on_rq_queued(tsk);// 如果该进程处于就绪态,那么要让该进程暂时先退出就绪队列if (queued)dequeue_task(rq, tsk, queue_flags);// 如果该进程正在运行中,刚才已经调用 dequeue_task() 函数让进程退出就绪队列,现在只能将其添加回就绪队列中if (running)put_prev_task(rq, tsk);// sched_change_group() 函数调用CFS的调度类的操作方法集中的 task_change_group() 方法。另外,这里还调用// set_task_rq() 函数设置进程调度实体中的 cfs_rq 成员和 parent 成员,cfs_rq成员指问组调度中自身的 CFS // 就绪队列,parent 成员指向组调度中的 se 调度实体sched_change_group(tsk, TASK_MOVE_GROUP);if (queued)// 调用 enqueue_task() 函数把退出就绪队列的进程和组调度重新添加回就绪队列enqueue_task(rq, tsk, queue_flags);if (running)set_curr_task(rq, tsk);...
}

4. 组调度的基本策略

  1. 在创建组调度tg时,tg为每个CPU同时创建组调度内部使用的cfs_rq
  2. 组调度作为—个调度实体添加到系统的CFS就绪队列rq->cfs_rq中
  3. 程添加到一个组中后,进程就脱离了系统的CFS就绪队列,并且添加到组调度里的CFS就绪队列tg->cfs_rq[]中
  4. 在选择下一个进程时,从系统的CFS就绪队列开始,如果选中的调度实体是组调度tg,那么还需要继续遍历tg中的就绪队列,从中选择一个进程来运行。

注意,CFS的组调度机制可以支持N级,这里只以简单的两级为例。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FMEA的局限性表现在哪些方面——SunFMEA软件系统

FMEA作为一种常用的故障分析和风险评估工具,被广泛应用于工程、制造、服务等领域。尽管FMEA具有很多优点,但在实际应用中,我们也必须认识到其存在的局限性。本文SunFMEA软件将从多个方面探讨FMEA的局限性。 首先,FMEA主要关注产品…

Keepalive 解决nginx 的高可用问题

一 说明 keepalived利用 VRRP Script 技术,可以调用外部的辅助脚本进行资源监控,并根据监控的结果实现优先动态调整,从而实现其它应用的高可用性功能 参考配置文件: /usr/share/doc/keepalived/keepalived.conf.vrrp.localche…

【LeetCode: 149. 直线上最多的点数 + 模拟遍历】

🚀 算法题 🚀 🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀 🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨ 🌲 作者简介:硕风和炜,…

四、项目中Camunda的使用

公文流程 保存 //省略其他业务逻辑...... //获取公文的工作流程类型 String processDefinitionKeydocDTO.getDocDocType().getDocType().getWorkflowId(); //启动流程 //将工作流程类型作为流程实例id,公文id 作为流程中业务id this.runtimeService.start…

HttpRequest请求模块设计与实现(http模块二)

目录 类功能 类定义 类实现 编译测试 类功能 类定义 // HttpRequest请求模块 class HttpRequest { public:std::string _method; // 请求方法std::string _path; // 资源路径std::string _version…

docker学习进阶

一、dockerfile解析 官方文档: Dockerfile reference | Docker Docs 1.1、dockfile是什么? dockerfile是用来构建docker镜像的文本文件,由一条条构建镜像所需的指令和参数构成的脚本。 之前我们介绍过通过具体容器反射构建镜像(docker comm…

央企与国企在信创国产化趋势下的数字化转型之道

官.网地址:合合TextIn - 合合信息旗下OCR云服务产品 3月5日,政府工作报告对大力推进现代化产业体系建设、加快发展新质生产力作出部署,提出“充分发挥创新主导作用,以科技创新推动产业创新,加快推进新型工业化&#x…

c1-第三周

文章目录 1月份2.定义一个整形数组arr2.定义整形栈s3.输入一个字符串包括大小写和数字,将其中的大写英文字母改为小写,并且输出数字个数4.根据下面数据,编程实现要求功能: 9月1.编写程序实现以下功能或问题3.完成以下功能4.对运算…

释机器学习中的召回率、精确率、准确率

准确率和召回率之间通常存在一定的折衷关系——当阈值较高时,分类器的准确率较高,但召回率较低; 当阈值较低时,分类器的召回率较高,但准确率较低 召回率(灵敏度):对实际为正类的样本,模型能识别…

NHANES数据(复杂调查数据)亚组交互函数1.7(P for interaction)发布-纠正了目前的一个问题

大家好&#xff0c;有粉丝私信我说NHANES数据(复杂调查数据)亚组交互函数1.版本交互函数有点问题&#xff0c;我查看了一下&#xff0c;有个代码调用失效了。就是下面这个&#xff0c;本来我是这样调用数据的 ids<-match.call()$ids应该是由于R版本或者survy包升级后导致这…

事务失效的八种情况!!!!

EnableAspectJAutoProxy(exposeProxy true)&#xff0c;开启AOP&#xff08;面向切面编程&#xff09;代理&#xff0c;并允许通过AopContext类暴露当前代理对象。这样&#xff0c;你可以在任何地方获取到当前代理对象&#xff0c;以便进行一些特殊的操作 &#xff08;应用与第…

NLP评价指标

一、分类任务常见评估&#xff1a; 准确度(Accuracy) 评估预测正确的比例&#xff0c;精确率(Precision) 评估预测正例的查准率&#xff0c;召回率(Recall) 评估真实正例的查全率。如果是多分类&#xff0c;则每个类别各自求P、R最终求平均值。 TP&#xff08;True Positives…