Linux CFS调度器之周期性调度器scheduler_tick函数
文章目录
- 前言
- 一、简介
- 二、源码分析
- 2.1 scheduler_tick
- 2.2 task_tick
- 2.3 entity_tick
- 2.4 check_preempt_tick
- 2.5 resched_curr
- 参考资料
前言
Linux内核调度器主要是主调度器和周期性调度器,主调度器请参考:Linux 进程调度之schdule主调度器
一、简介
每当定时器中断发生时,都会调用定时器中断处理程序。每当调用定时器中断处理程序时,处理程序会调用update_process_times函数,将一个时钟滴答分配给当前进程。在其中,会调用scheduler_tick函数。scheduler_tick函数执行和调度相关的一些操作,如检查是否有进程需要调度和切换。
时钟中断是调度器的脉搏,内核依靠周期性的时钟来处理器CPU的控制权。时钟中断处理程序,检查当前进程的执行时间是否超额,如果超额则设置重新调度标志(_TIF_NEED_RESCHED);时钟中断处理函数返回时,被中断的进程如果在用户模式下运行,需要检查是否有重新调度标志,设置了则调用schedule()调度。
周期性调度器scheduler_tick()以固定的频率检测是否有必要进行进程调度和切换。在CFS调度类中,scheduler_tick会检测一个进程执行的时间是否过长,以避免过程的延时,是时候让其他CFS就绪队列中的进程运行.
注意周期性调度器scheduler_tick()设置TIF_NEED_RESCHED标志来对进程进行标记需要被抢占,设置该位则表明需要进行调度切换,没有进行实际的抢占,只是将当前进程标记为应该被抢占。而实际的切换将在抢占执行点来完成。
如果当前进程需要重新调度的条件成立,这里只是会设置TIF_NEED_RESCHED标志,并不会马上调用schedule()来进行调度。真正的调度时机发生在从中断/异常返回时,会判断当前进程有没有被设置TIF_NEED_RESCHED,如果设置则调用schedule()来进行调度。
二、源码分析
流程图如下图左边所示:

2.1 scheduler_tick
// linux-4.10.1/kernel/sched/core.c/** This function gets called by the timer code, with HZ frequency.* We call it with interrupts disabled.*/
void scheduler_tick(void)
{(1)int cpu = smp_processor_id();struct rq *rq = cpu_rq(cpu);struct task_struct *curr = rq->curr;(2)raw_spin_lock(&rq->lock);update_rq_clock(rq);curr->sched_class->task_tick(rq, curr, 0);cpu_load_update_active(rq);calc_global_load_tick(rq);raw_spin_unlock(&rq->lock);(3)
#ifdef CONFIG_SMPrq->idle_balance = idle_cpu(cpu);trigger_load_balance(rq);
#endif}
这段代码是调度器的定时器中断处理函数,用于处理定时器中断事件。以下是对代码的详细说明:
(1)
首先,获取当前处理器的ID,并根据ID获取对应的运行队列(rq)和当前正在运行的任务(curr)。
(2)
使用原子自旋锁(raw_spin_lock)锁定运行队列,确保原子操作的执行。
调用update_rq_clock()函数,更新运行队列的时钟。
通过curr->sched_class->task_tick()函数调用,调用当前任务所属调度类的task_tick()函数,执行任务级别的时钟滴答处理。
调用cpu_load_update_active()函数,更新运行队列的活跃CPU负载。即就绪队列的cpu_load[]数据。
调用calc_global_load_tick()函数,计算全局负载的时钟滴答。
解锁运行队列,使用raw_spin_unlock。
(3)
如果编译选项中启用了SMP(对称多处理器)支持,会进行一些额外的处理:
将rq->idle_balance设置为idle_cpu(cpu),表示当前运行队列是否处于空闲状态。
调用trigger_load_balance()函数,触发负载平衡操作。
其中主要是:
curr->sched_class->task_tick(rq, curr, 0);
2.2 task_tick
curr->sched_class->task_tick(rq, curr, 0);
// kernel/sched/fair.cconst struct sched_class fair_sched_class = {.task_tick = task_tick_fair,
}
// kernel/sched/fair.c/** scheduler tick hitting a task of our scheduling class:*/
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) {cfs_rq = cfs_rq_of(se);entity_tick(cfs_rq, se, queued);}if (static_branch_unlikely(&sched_numa_balancing))task_tick_numa(rq, curr);
}
这段代码是调度器中的公平调度类(fair)的任务时钟滴答处理函数。以下是对代码的详细说明:
(1)首先,定义了一个指向当前任务的调度实体(sched_entity)的指针se,并获取与该实体相关联的CFS运行队列(cfs_rq)。
(2)使用for_each_sched_entity迭代当前任务的调度实体,对每个实体执行以下操作:
获取与该实体相关联的CFS运行队列(cfs_rq)。
调用entity_tick()函数,处理该实体的时钟滴答事件。
其中entity_tick函数最为重要,检查该任务是否需要调度,这里表明需要进行调度切换,没有进行实际的抢占,只是将当前进程标记为应该被抢占。而实际的切换将在抢占执行点来完成。
* 在不支持组调度条件下, 只循环一次
* 在组调度的条件下, 调度实体存在层次关系,
* 更新子调度实体的同时必须更新父调度实体
#ifdef CONFIG_FAIR_GROUP_SCHED
/* Walk up scheduling entities hierarchy */
#define for_each_sched_entity(se) \for (; se; se = se->parent)#else /* !CONFIG_FAIR_GROUP_SCHED */#define for_each_sched_entity(se) \for (; se; se = NULL)
#endif /* CONFIG_FAIR_GROUP_SCHED */
static inline struct task_struct *task_of(struct sched_entity *se)
{return container_of(se, struct task_struct, se);
}#define task_rq(p) cpu_rq(task_cpu(p))static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se)
{struct task_struct *p = task_of(se);struct rq *rq = task_rq(p);return &rq->cfs;
}
(3)如果静态分支(static_branch)sched_numa_balancing为真,表示启用了NUMA(非统一内存访问)平衡功能,则调用task_tick_numa()函数,处理与NUMA平衡相关的任务时钟滴答。
2.3 entity_tick
static void
entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued)
{/** Update run-time statistics of the 'current'.*/(1)update_curr(cfs_rq);/** Ensure that runnable average is periodically updated.*/(2)update_load_avg(curr, UPDATE_TG);......(3)if (cfs_rq->nr_running > 1)check_preempt_tick(cfs_rq, curr);
}
(1)update_curr用来更新当前任务调度实体的 vruntime 值和更新cfs_rq就绪队列的min_vruntime成员。
(2)update_load_avg更新该进程调度实体的负载和CFS就绪队列的赋值。
(3)如果CFS运行队列中的可运行任务数大于1,则调用check_preempt_tick()函数,检查是否需要进行抢占,即当前进程是否需要调度。
2.4 check_preempt_tick
/** Preempt the current task with a newly woken task if needed:*/
static void
check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr)
{unsigned long ideal_runtime, delta_exec;struct sched_entity *se;s64 delta;ideal_runtime = sched_slice(cfs_rq, curr);delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime;if (delta_exec > ideal_runtime) {resched_curr(rq_of(cfs_rq));/** The current task ran long enough, ensure it doesn't get* re-elected due to buddy favours.*/clear_buddies(cfs_rq, curr);return;}/** Ensure that a task that missed wakeup preemption by a* narrow margin doesn't have to wait for a full slice.* This also mitigates buddy induced latencies under load.*/if (delta_exec < sysctl_sched_min_granularity)return;se = __pick_first_entity(cfs_rq);delta = curr->vruntime - se->vruntime;if (delta < 0)return;if (delta > ideal_runtime)resched_curr(rq_of(cfs_rq));
}
这段代码是调度器中的检查任务抢占的函数。以下是对代码的详细说明:
(1)首先,定义了一些变量来保存理想运行时间(ideal_runtime)和已执行时间的增量(delta_exec)。
(2)使用sched_slice()函数计算出当前调度实体的理想运行时间。
(3)计算当前调度实体的已执行时间的增量,即sum_exec_runtime减去prev_sum_exec_runtime。
(4)如果已执行时间的增量大于理想运行时间,表示当前任务运行时间超过了预期,将当前任务重新调度,并清除与当前任务相关的伙伴(buddy)任务的优先级。
(5)如果已执行时间的增量小于sysctl_sched_min_granularity(最小调度粒度),则直接返回,避免任务因为执行时间过短而被抢占。
(6)选取CFS运行队列中的第一个调度实体,并计算当前调度实体的虚拟运行时间与选取的调度实体的虚拟运行时间之间的差值(delta)。
(7)如果delta小于0,表示当前调度实体的虚拟运行时间较小,不进行抢占。
(8)如果delta大于理想运行时间,表示当前调度实体的虚拟运行时间较大,将当前任务重新调度。
这段代码用于检查是否需要抢占当前任务。它比较当前任务的已执行时间与理想运行时间的差异,并根据一定的条件决定是否重新调度当前任务。如果当前任务的运行时间超过了预期,或者与其他任务的虚拟运行时间相比较大,将触发任务的重新调度。
因此抢占决策很容易做出决定, 如果检查发现当前进程运行需要被抢占, 那么通过resched_task发出重调度请求.这会在task_struct中设置TIF_NEED_RESCHED标志, 核心调度器会在下一个适当的时机发起重调度.
其实需要抢占的条件有下面两种可能性:
(1)curr进程的实际运行时间delta_exec比期望的时间间隔ideal_runtime长
此时说明curr进程已经运行了足够长的时间
(2)curr进程与红黑树中最左进程left虚拟运行时间的差值大于curr的期望运行时间ideal_runtime
此时说明红黑树中最左结点left与curr节点更渴望处理器, 已经接近于饥饿状态, 这个我们可以这样理解, 相对于curr进程来说, left进程如果参与调度, 其期望运行时间应该域curr进程的期望时间ideal_runtime相差不大, 而此时如果curr->vruntime - se->vruntime > curr.ideal_runtime, 我们可以初略的理解为curr进程已经优先于left进程多运行了一个周期, 而left又是红黑树总最饥渴的那个进程, 因此curr进程已经远远领先于队列中的其他进程, 此时应该补偿其他进程。
如果检查需要发生抢占, 则内核通过resched_curr(rq_of(cfs_rq))设置重调度标识, 从而触发延迟调度
2.5 resched_curr
/** resched_curr - mark rq's current task 'to be rescheduled now'.** On UP this means the setting of the need_resched flag, on SMP it* might also involve a cross-CPU call to trigger the scheduler on* the target CPU.*/
void resched_curr(struct rq *rq)
{struct task_struct *curr = rq->curr;int cpu;if (test_tsk_need_resched(curr))return;cpu = cpu_of(rq);if (cpu == smp_processor_id()) {set_tsk_need_resched(curr);set_preempt_need_resched();return;}
}
这段代码是调度器中的重新调度当前任务的函数。以下是对代码的详细说明:
(1)首先,获取当前运行队列的当前任务指针curr。
(2)如果当前任务的need_resched标志已经被设置,则直接返回,无需进行重新设置。
(3)如果当前处理器ID等于当前运行队列的处理器ID(即在本处理器上执行),则设置当前任务的need_resched标志,并设置调度器的preempt_need_resched标志,表示当前任务需要重新调度。
周期性调度器并不显式进行调度, 而是采用了延迟调度的策略, 如果发现需要抢占, 周期性调度器就设置进程的重调度标识PREEMPT_NEED_RESCHED, 然后由主调度器完成调度工作.
TIF_NEED_RESCHED标识, 表明进程需要被调度, TIF前缀表明这是一个存储在进程thread_info中flag字段的一个标识信息
在内核的一些关键位置, 会检查当前进程是否设置了重调度标志TLF_NEDD_RESCHED, 如果该进程被其他进程设置了TIF_NEED_RESCHED标志, 则函数重新执行进行调度
前面我们在check_preempt_tick中如果发现curr进程已经运行了足够长的时间, 其他进程已经开始饥饿, 那么我们就需要通过resched_curr来设置重调度标识TIF_NEED_RESCHED
参考资料
https://kernel.blog.csdn.net/article/details/52068050
https://xiaolizai.blog.csdn.net/article/details/128646726
https://www.cnblogs.com/LoyenWang/p/12249106.html
https://www.cnblogs.com/LoyenWang/p/12495319.html
https://scslab-intern.gitbooks.io/linux-kernel-hacking/content/chapter04.html
相关文章:
Linux CFS调度器之周期性调度器scheduler_tick函数
文章目录 前言一、简介二、源码分析2.1 scheduler_tick2.2 task_tick2.3 entity_tick2.4 check_preempt_tick2.5 resched_curr 参考资料 前言 Linux内核调度器主要是主调度器和周期性调度器,主调度器请参考:Linux 进程调度之schdule主调度器 一、简介 …...
git生成密钥(免密)
生成SSH密钥对的方法如下: 打开Git Bash。 输入以下命令生成新的SSH密钥对: ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 这里的 -C 参数后面跟的是你的邮箱地址,通常用于标识这个密钥。 当系统提示你“Enter a fil…...
山东大学软件学院2021级编译原理回忆版
一、判断题 1、正则文法可以表示一般的高级程序语言,构成其语法成分和生成句子() 2、NFA的状态和符号有且只有一条边,因此看起来更直观() 3、DFA无法表示这样的语言{anbn,n>1}() …...
为什么都说视频号小店值得做,具体该怎么做?新手必学
大家好,我是电商花花。 所有人都在告诉你2024年应该做视频号小店,但没有人告诉你到底应该怎么做。 今天给大家说一下为什么2024年都推荐大家去做视频号小店,以及分享一些视频号小店的实操干货,可以帮助大家更快更稳的做店。 首先…...
网络安全岗秋招面试题及面试经验分享
Hello,各位小伙伴,我作为一名网络安全工程师曾经在秋招中斩获🔟个offer🌼,并在国内知名互联网公司任职过的职场老油条,希望可以将我的面试的网络安全大厂面试题和好运分享给大家~ 转眼2024年秋招又快到了金…...
如何实现一个AI聊天功能
最近公司的网站上需要对接一个AI聊天功能,领导把这个任务分给了我,从最初的调研,学习,中间也踩过一些坑,碰到过问题,但最后对接成功,还是挺有成就感的,今天把这个历程和项目整理一下…...
实战16:基于apriori关联挖掘FP-growth算法挖掘关联规则的手机销售分析-代码+数据
直接看视频演示: 基于apriori关联挖掘关联规则的手机销售分析与优化策略 直接看结果: 这是数据展示: 挖掘结果展示: 数据分析展示:...
Linux基础指令及其作用之系统信息和管理
系统信息和管理 ps ps 命令用于显示当前系统的进程信息。它是 Unix 和类 Unix 操作系统中的一个重要工具,可以用于监控和管理系统进程。以下是 ps 命令的详细用法和常见选项: ps [选项]常用选项支持的新型开源AI Agent平台,支持多个金融专业AI Agent
财务分析一直是解读市场趋势、预测经济结果和提供投资策略的关键。这一领域传统上依赖数据,但随着时间的推移,越来越多地使用人工智能(AI)和算法方法来处理日益增长的复杂数据。AI在金融领域的作用显著增强,它自动化了…...
【SQL学习进阶】从入门到高级应用(七)
文章目录 ✨数据处理函数✨if函数✨cast函数✨加密函数 ✨分组函数✨max✨min✨avg✨sum✨count✨分组函数组合使用✨分组函数注意事项 ✨分组查询✨group by✨having✨组内排序 ✨总结单表的DQL语句 🌈你好呀!我是 山顶风景独好 💕欢迎来到我…...
20231911 2023-2024-2 《网络攻防实践》实践十一报告
实践内容 (1)web浏览器渗透攻击 任务:使用攻击机和Windows靶机进行浏览器渗透攻击实验,体验网页木马构造及实施浏览器攻击的实际过程。 实验步骤: ①选择使用Metasploit中的MS06-014渗透攻击模块②选择PAYLOAD为任意…...
5G专网驻网失败分析(suci无效)
suci 5G终端第一次驻网时,注册消息Registartion request中携带的5GS mobile identity要携带suci类型的mobile identity。 注册消息协议规范见5G NAS 协议3gpp TS24.501 8.2.6 Registration request。 suci协议规范参见3gpp TS24.501 9.11.3.4 5GS mobile identity …...
【PHP项目实战训练】——laravel框架的实战项目中可以做模板的增删查改功能(1)
👨💻个人主页:开发者-曼亿点 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 曼亿点 原创 👨💻 收录于专栏:…...
go语言使用model Gorm MySQL查询数据 定时十分钟查询一次 查询十分钟前新建的数据
在Go语言中,使用GORM库与MySQL数据库交互并定时查询数据是常见的需求。以下是一个基本的示例,展示了如何设置定时任务,并使用GORM查询十分钟前新建的数据: 首先,你需要安装GORM和MySQL驱动: bash go get -…...
透视AI技术:探索折射技术在去衣应用中的奥秘
引言: 随着人工智能技术的飞速发展,其在图像处理和计算机视觉领域的应用日益广泛。其中,AI去衣技术作为一种颇具争议的应用,引发了广泛的讨论和关注。本文将深入探讨折射技术在AI去衣中的应用及其背后的原理。 一、AI去衣技术简介…...
计算机网络工程师需要掌握的知识点
网络基础 网络协议OSI参考模型TCP/IP 体系结构广域网与接入网技术:HDLC、PPP。xDSL、HFCIEEE802标准、以太网技术。网桥、交换机、无线局域网(WLAN)、VLAN、TRUNK、GVRP、STP、综合布线系统IP地址、子网划分、CIDR、ARP、ICMP、IPV6、TCP、UD…...
Java-Collection家族(List接口)
集合-Collection家族-List接口 List接口 1 特点 有序且可重复(因为List接口中添加了许多针对下标操作的方法) 2 四种实现类的数据类型与特点 a. ArrayList 数据结构:一维数组 特点:存储数据 b. LinkedList 数…...
成绩发布小程序哪个好用?
大家好,今天我要来跟大家分享一个超级实用的小秘密——易查分小程序!作为老师,你是不是还在为发放成绩而头疼?是不是还在为通知家长而烦恼?别急,易查分小程序来帮你啦! 易查分简直是老师们的贴心…...
如何让大模型在智能时代背景下更加先进:一种基于时代特征的探讨
随着人工智能技术的飞速发展,大型模型如深度学习网络和强化学习算法已经在各个领域取得了显著的成果。然而,随着应用场景的不断扩展和复杂化,如何让这些大模型在智能时代背景下更加先进,已经成为了一个亟待解决的问题。本文将从以…...
Mac 分享 WIFI 后,iPhone 连接 WIFI,但无法上网
0x00 分享WIFI 如何分享,可查看这篇: MacOS系统如何创建热点并共享Wi-Fi连接 0x01 iPhone 无法上网 打开设置,点击所连 WIFI 进入 配置 DNS 选择 手动 添加 服务器: 公用的有: 114.114.114.114 、180.76.76.76、1…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
Mysql中select查询语句的执行过程
目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析(Parser) 2.4、执行sql 1. 预处理(Preprocessor) 2. 查询优化器(Optimizer) 3. 执行器…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...
华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)
题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...
FOPLP vs CoWoS
以下是 FOPLP(Fan-out panel-level packaging 扇出型面板级封装)与 CoWoS(Chip on Wafer on Substrate)两种先进封装技术的详细对比分析,涵盖技术原理、性能、成本、应用场景及市场趋势等维度: 一、技术原…...
