Linux源码阅读笔记03-调度器及CFS调度器

调度器

  • 调度器:Linux内核中用来安排调度进程(一段程序的执行过程)执行的模块成为调度器,他可以切换进程状态。比如:执行、可中断睡眠、不可中断睡眠、退出、暂停等;

  • 调度器的主要职责:选择某些就绪的进程来运行、打断某些执行的进程让他们变为就绪态;

  • 调度目的:最大效率使用CPU资源

  • 主动进入阻塞状态:
  • 被动进去阻塞状态:

如果调度器支持就绪状态切换到执行状态,同时支持执行状态切换到就绪状态,则称为抢占式调度器。

调度类sched_class结构体

// 调度类的结构体
struct sched_class {const struct sched_class *next; // 系统中有多个调度类,按照优先级按照调度优先级直接排成链表#ifdef CONFIG_UCLAMP_TASKint uclamp_enabled;
#endif// 将进程加入到执行队列当中,即将调度实体(进程)存放到红黑树当中,并且nr_running变量自动+1void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);// 从执行队列当中删除进程,nr_running变量自动-1void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);// 放弃CPU的执行权限,实际上此函数执行先出队后入队,这种情况下直接将调度实体存放在红黑树的最右端void (*yield_task)   (struct rq *rq);bool (*yield_to_task)(struct rq *rq, struct task_struct *p, bool preempt);// 专门检查当前进程是否可以被新进程抢占void (*check_preempt_curr)(struct rq *rq, struct task_struct *p, int flags);// 选择下一个要运行的进程struct task_struct *(*pick_next_task)(struct rq *rq);// 将进程加入到运行队列中void (*put_prev_task)(struct rq *rq, struct task_struct *p);void (*set_next_task)(struct rq *rq, struct task_struct *p, bool first);#ifdef CONFIG_SMPint (*balance)(struct rq *rq, struct task_struct *prev, struct rq_flags *rf);// 选择合适的CPU'int  (*select_task_rq)(struct task_struct *p, int task_cpu, int sd_flag, int flags);// 迁移任务到另外一个CPUvoid (*migrate_task_rq)(struct task_struct *p, int new_cpu);// 唤醒进程void (*task_woken)(struct rq *this_rq, struct task_struct *task);// 修改进程在CPU的亲和力void (*set_cpus_allowed)(struct task_struct *p,const struct cpumask *newmask);// 启动/禁止运行队列void (*rq_online)(struct rq *rq);void (*rq_offline)(struct rq *rq);
#endifvoid (*task_tick)(struct rq *rq, struct task_struct *p, int queued);void (*task_fork)(struct task_struct *p);void (*task_dead)(struct task_struct *p);/** The switched_from() call is allowed to drop rq->lock, therefore we* cannot assume the switched_from/switched_to pair is serliazed by* rq->lock. They are however serialized by p->pi_lock.*/void (*switched_from)(struct rq *this_rq, struct task_struct *task);void (*switched_to)  (struct rq *this_rq, struct task_struct *task);void (*prio_changed) (struct rq *this_rq, struct task_struct *task,int oldprio);unsigned int (*get_rr_interval)(struct rq *rq,struct task_struct *task);void (*update_curr)(struct rq *rq);#define TASK_SET_GROUP		0
#define TASK_MOVE_GROUP		1#ifdef CONFIG_FAIR_GROUP_SCHEDvoid (*task_change_group)(struct task_struct *p, int type);
#endif
};

调度器分类

extern const struct sched_class stop_sched_class; // 停机调度类
extern const struct sched_class dl_sched_class; // 期限调度类
extern const struct sched_class rt_sched_class; // 实时调度类
extern const struct sched_class fair_sched_class; // 公平调度类
extern const struct sched_class idle_sched_class; // 空闲调度类
  • 优先级(高到低):停机调度类-限期调度类-实时调度类-公平调度类-空闲调度类;
  • 停机调度类:停止进程,优先级最高,可以抢占其他进程;停机进程是优先级最高的进程,可以抢占其他进程;
  • 限期调度类: 最早使用的优先算法,使用红黑树把进程按照绝对截止的期限从小到大排序,每次调度会选择截止期限最小的进程;
  • 实时调度类:为每一个调度优先级维护一个队列;
  • 公平调度类:使用完全公平调度算法。完全公平调度算法引入虚拟运行时间:虚拟运行时间=实际运行实现*nice0对应的权重/进程的权重;
  • 空闲调度类:每个CPU上有一个空闲的线程,即0号线程。空闲调度类优先级最低,仅仅当没有其他进程可以调度的时候才会调度空闲线程。

进程优先级

// Linux 内核优先级
#define MAX_USER_RT_PRIO	100
#define MAX_RT_PRIO		MAX_USER_RT_PRIO#define MAX_PRIO		(MAX_RT_PRIO + NICE_WIDTH)
#define DEFAULT_PRIO		(MAX_RT_PRIO + NICE_WIDTH / 2)
  • 实时进程(Real-Time-Process):优先级高,需要立刻被执行的进程
  • 普通进程(Normal-Process):优先级低,更长执行时间的进程

进程优先级是一个0-139的整数来表示。数字越小,优先级越高,其中优先级0-99留给实时进程,100-139留给普通进程。

内核调度策略

Linux内核提供一些调度策略让用户应用程序选择调度器。Linux内核调度策略源码如下:

  • SCHED_NORMAL:普通进程调度策略,使得ask选择CFS调度器来调度运行;
  • SCHED_FIFO:实时进程调度策略,先进先出调度没有时间片,没有更高级优先级的状态下,只有等待主动让出CPU;
  • SCHED_RR:实时进程调度策略,时间片轮转,进程使用完时间片之后加入优先级对应运行队列中的尾部,把CPU让给同等优先级的其他进程;
  • SCHED_BATCH:普通进程调度策略,批量处理,使task选择CFS调度器来调度运行;
  • SCHED_IDLE:普通进程调度策略,使task以最低优先级选择CFS调度器来运行;
  • SCHED_DEADLINE:限期进程调度策略,使task选择Deadline调度器来运行。

备注:其中 Stop 调度器和 IDLE-task 调度器,仅使用于内核,用户没有办法进行选择。

CFS调度器

完全公平调度算法体现在对每个进程都是公平的,让每个进程都运行一段相同的的时间片,这就是基于时间片轮询调度算法。CFS定义一种新模型,给cfs_rq(CFS的run queue)中的每个进程都设置一个虚拟时钟virtual runtime。古国一个进程得以执行,随着时间的不断增长,他的vruntime也会不断增大,没有得到执行的进程vruntime保持不变。

进程描述符task_struct结构体中,有几个成员与调度相关,具体成员prio、normal_prio、static_prio、rt_priority等。

实际运行时间

CFS(Completely Fair Scheduler,完全公平调度器)。在实际当中必然会有进程优先级高或者进程优先级低,CFS引入权重代表进程的优先级,各个进程按照权重比例分配CPU时间。

假设有两个进程X和Y,X权重为1024,Y权重为2048。

X获得CPU的时间比为:
1024 1024 + 2048 = 33 % \frac{1024}{1024+2048}=33\% 1024+20481024=33%
Y获得CPU的时间比例为:
2048 1024 + 2048 = 66 % \frac{2048}{1024+2048}=66\% 1024+20482048=66%
在引入权重之后分配给进程的时间计算公式如下:
实际运行时间 = 调度曲线 ∗ 进程权重 所有进程权重和 实际运行时间=\frac{调度曲线*进程权重}{所有进程权重和} 实际运行时间=所有进程权重和调度曲线进程权重

虚拟运行时间

虚拟运行时间 = 实际运行时间 ∗ N I C E _ 0 _ L O A D 进程权重 = 调度周期 ∗ 进程权重 所有进程权重 ∗ N I C E _ 0 _ L O A D 进程权重 = 调度周期 ∗ 1024 所有进程权重 虚拟运行时间=\frac{实际运行时间*NICE\_0\_LOAD}{进程权重}=\frac{调度周期*进程权重}{所有进程权重}*\frac{NICE\_0\_LOAD}{进程权重}=\frac{调度周期*1024}{所有进程权重} 虚拟运行时间=进程权重实际运行时间NICE_0_LOAD=所有进程权重调度周期进程权重进程权重NICE_0_LOAD=所有进程权重调度周期1024

在一个调度周期里,所有进程的虚拟运行时间是相同的,所以在进程调度时,只要找到虚拟运行时间最小的进程调度即可。

CFS调度器类

  • enqueue_task:当任务进入可运行状态时,此函数将调度实体存入红黑树,完成入队操作。
  • dequeue_task:当任务退出可运行状态时,此函数将调度实体从红黑树中移除,完成出队操作。

这两个函数接收三个参数运行队列 任务实体 标志,rq是一个抽象出来的运行队列结构体。这个结构体中的包含了完全公平调度器就绪队列 实时调度器就绪队列 限时调度器就绪队列

CFS调度器就绪队列内核源码

/* CFS-related fields in a runqueue */
struct cfs_rq {struct load_weight	load;unsigned long		runnable_weight;unsigned int		nr_running;unsigned int		h_nr_running;      /* SCHED_{NORMAL,BATCH,IDLE} */unsigned int		idle_h_nr_running; /* SCHED_IDLE */u64			exec_clock;u64			min_vruntime;
#ifndef CONFIG_64BITu64			min_vruntime_copy;
#endifstruct rb_root_cached	tasks_timeline;/** 'curr' points to currently running entity on this cfs_rq.* It is set to NULL otherwise (i.e when none are currently running).*/// 可被内核调度的实体struct sched_entity	*curr;struct sched_entity	*next;struct sched_entity	*last;struct sched_entity	*skip;#ifdef	CONFIG_SCHED_DEBUGunsigned int		nr_spread_over;
#endif#ifdef CONFIG_SMP/** CFS load tracking*/struct sched_avg	avg;
#ifndef CONFIG_64BITu64			load_last_update_time_copy;
#endifstruct {raw_spinlock_t	lock ____cacheline_aligned;int		nr;unsigned long	load_avg;unsigned long	util_avg;unsigned long	runnable_sum;} removed;#ifdef CONFIG_FAIR_GROUP_SCHEDunsigned long		tg_load_avg_contrib;long			propagate;long			prop_runnable_sum;/**   h_load = weight * f(tg)** Where f(tg) is the recursive weight fraction assigned to* this group.*/unsigned long		h_load;u64			last_h_load_update;struct sched_entity	*h_load_next;
#endif /* CONFIG_FAIR_GROUP_SCHED */
#endif /* CONFIG_SMP */#ifdef CONFIG_FAIR_GROUP_SCHEDstruct rq		*rq;	/* CPU runqueue to which this cfs_rq is attached *//** leaf cfs_rqs are those that hold tasks (lowest schedulable entity in* a hierarchy). Non-leaf lrqs hold other higher schedulable entities* (like users, containers etc.)** leaf_cfs_rq_list ties together list of leaf cfs_rq's in a CPU.* This list is used during load balance.*/int			on_list;struct list_head	leaf_cfs_rq_list;struct task_group	*tg;	/* group that "owns" this runqueue */#ifdef CONFIG_CFS_BANDWIDTHint			runtime_enabled;s64			runtime_remaining;u64			throttled_clock;u64			throttled_clock_task;u64			throttled_clock_task_time;int			throttled;int			throttle_count;struct list_head	throttled_list;
#endif /* CONFIG_CFS_BANDWIDTH */
#endif /* CONFIG_FAIR_GROUP_SCHED */
};

cfs_rq:跟踪就绪队列信息,管理就绪态调度实体,维护一棵按照虚拟时间排序的红黑树。tasks_timeline->rb_root指向红黑树的根,tasks_timeline->rb_leftmost指向红黑树最左边的调度实体,即虚拟时间最小的调度实体。
推荐课程:https://xxetb.xetslk.com/s/3oyV5o

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

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

相关文章

gbase8s关于客户端和数据库连接的方式和应用建立连接的简单线索分工

应用和数据库的连接分为本地连接和远程连接,当应用程序和数据库在同一台服务器上为本地连接,不在一台服务器上为远程连接 1. 本地连接 本地连接三种方式: 通过共享内存消息系统:应用和数据库在同一台服务器上,应用程…

C语言 | Leetcode C语言题解之第165题比较版本号

题目&#xff1a; 题解&#xff1a; int compareVersion(char * version1, char * version2){int len1 strlen(version1);int len2 strlen(version2);int i 0;int j 0;while (i < len1 || j < len2) {int num1 0;int num2 0;while (i < len1 && versio…

C#实现音乐在线播放和下载——Windows程序设计作业3

1. 作业内容 编写一个C#程序&#xff0c;在作业二实现的本地播放功能的基础上&#xff0c;新增在线播放和在线下载功能&#xff0c;作业二博客地址&#xff1a;C#实现简单音乐文件解析播放——Windows程序设计作业2 2. 架构选择 考虑到需求中的界面友好和跨版本兼容性&#xf…

STM32读取芯片内部温度

基于stm32f103cbt6这款芯片&#xff0c;原理部分请参考其他文章&#xff0c;此文章为快速上手得到结果&#xff0c;以结果为导向。 1.基础配置 打开stm32cubemx只需要勾选中 ADC1 Temperature Sensor Channel 2.代码分析 /** 函数名&#xff1a;float GetAdcAnlogValue(voi…

120.网络游戏逆向分析与漏洞攻防-邮件系统数据分析-邮件发送功能的封装

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 如果看不懂、不知道现在做的什么&#xff0c;那就跟着做完看效果&#xff0c;代码看不懂是正常的&#xff0c;只要会抄就行&#xff0c;抄着抄着就能懂了 内容…

STM32项目分享:家庭环境监测系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板打样焊接图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片&#xff1a; 哔哩哔哩视频链接&#xff1a; https://www.bilibili.…

集群初始配置

假设已经有三台或多台 Linux&#xff0c;可以是虚拟机或真实设备。如果希望使用这些 Linux 组成一个集群&#xff0c;并在上面运行一些分布式系统&#xff0c;可能需要如下操作。 1 设置静态IP 输入命令route -n打印路由表&#xff0c;可以查看网关地址。图形界面操作&#x…

跌倒识别:守护公共安全的AI技术应用场景-免费API调用

随着科技的不断进步&#xff0c;人工智能在各个领域的应用日益广泛&#xff0c;其中在公共安全领域&#xff0c;智能跌倒识别系统正逐渐成为守护人们安全的重要工具。本文将分享智能跌倒识别系统在不同场景下的应用及其重要性。 产品在线体验地址-API调用或本地化部署 AI算法模…

【第一性原理】邓巴数字

这里写自定义目录标题 什么是邓巴数字邓巴数背后的科学历史上各个组织的人数与邓巴数字的关系在人类进化中的意义现代社会中邓巴数字的体现邓巴数字的意义其他与沟通相关的数据注意事项结论参考 罗宾邓巴教授生于1947年&#xff0c;进化心理学家&#xff0c;牛津大学教授&#…

[信号与系统]关于LTI系统的转换方程、拉普拉斯变换和z变换

前言 本文还是作为前置知识。 LTI系统的传递函数 LTI系统的传递函数 H ( z ) H(z) H(z) 是输出信号的z变换 Y ( z ) Y(z) Y(z) 与输入信号的z变换 X ( z ) X(z) X(z) 的比值&#xff1a; H ( z ) Y ( z ) X ( z ) H(z) \frac{Y(z)}{X(z)} H(z)X(z)Y(z)​ 多项式比值表…

C++之提高篇

1.标准输入输出流 cin与cout的使用&#xff0c;就不多说了&#xff0c;说一个有关保留小数位数的操作&#xff0c;使用ostream对象的precision&#xff08;&#xff09;方法&#xff0c;表达的意思是数字总共有几位&#xff0c;注意&#xff0c;此时是包括整数部分的&#xff…

OpenAI策略:指令层级系统让大模型免于恶意攻击

现代的大模型&#xff08;LLMs&#xff09;不再仅仅是简单的自动完成系统&#xff0c;它们有潜力赋能各种代理应用&#xff0c;如网页代理、电子邮件秘书、虚拟助手等。然而&#xff0c;这些应用广泛部署的一个主要风险是敌手可能诱使模型执行不安全或灾难性的行动&#xff0c;…

使用 Python 进行测试(7)...until you make it

总结 我很懒&#xff0c;我想用最少的行动实现目标&#xff0c;例如生成测试数据。我们可以&#xff1a; 使用随机种子保证数据的一致性。 >>> random.seed(769876987698698) >>> [random.randint(0, 10) for _ in range(10)] [10, 9, 1, 9, 10, 6, 5, 10…

计算机组成原理 | 硬件电路整理

计算机组成原理 | 硬件电路整理 桶形移位器原理图 全加器逻辑框图 多位可控加减法电路逻辑框图 可级联的4位先行进位电路 4位快速加法器 16位组内并行、组间并行加法器 实现原码一位乘法的逻辑框图 补码一位乘法的逻辑框图 无符号数阵列乘法器 原码不恢复余数法硬件逻辑框图 基…

规模弹性: 管理谷歌的TPUv4机器学习超级计算机(二)

本文为翻译文章&#xff0c;原文为&#xff1a; Resiliency at Scale: Managing Google’sTPUv4 Machine Learning Supercomputer。 由于字数过长&#xff0c;文章分为两期发布&#xff0c;本片涵盖原文后半部分4&#xff5e;9节&#xff0c;前三章节请参考文章&#xff1a;规…

Springboot应用的信创适配-补充

Springboot应用的信创适配-CSDN博客 因为篇幅限制&#xff0c;这里补全Spring信创适配、数据库信创适配、Redis信创适配、消息队列信创适配等四个章节。 Springboot应用的信创适配 Springboot应用的信创适配&#xff0c;如上图所示需要适配的很多&#xff0c;从硬件、操作系统、…

基于AT89C52单片机的温度报警系统

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/89456321?spm=1001.2014.3001.5503 仿真构造:AT89C52+DS18B20温度模块+三按键+蜂鸣器+四位数码管显示+电源模块。 压缩包构造:源码+仿真图+设计文档+原理图+开题文档+元件…

Java宝藏实验资源库(3)类

一、实验目的 理解面向对象程序的基本概念。掌握类的继承的实现机制。熟悉类中成员的访问控制方法。熟悉ArrayList类的使用。 二、实验内容、过程及结果 *9.5Programming Exerc ise the GregorianCal endar class) Java API has the GregorianCalendar class in the java. uti…

民生银行北京分行金融科技校招面试记录

本文介绍2024届春招中&#xff0c;中国民生银行下属北京分行的金融科技岗位1场面试的基本情况、提问问题等。 2024年04月投递了中国民生银行下属北京分行的金融科技岗位&#xff0c;暂时不清楚所在部门。目前完成了一面与终面&#xff0c;在这里记录一下面试的相关经历。 首先&…

LayoutSystem布局系统

简介: LayoutSystem,是UGUI中由CanvasUpdateSystem发起(m_LayoutRebuildQueue中大部分都是LayoutRebuilder)的关于布局排列的处理系统。 类图: 布局过程 核心代码讲解: LayoutRebuilder