SCHED_DEALINE调度类分析(一)

本文深入探讨了EDF(Earliest Deadline First)调度算法,这是一种适用于需要精确时间响应和调度方法场景的算法,例如多媒体业务。文章详细介绍了EDF的基本概念、工作原理及其实现方式,并对比了其与Linux内核中常用的CFS和FIFO调度类的不同。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下是本人分析的内核新的调度类SCHED_DEADLINE调度类,这个调度类没有进主线之前叫EDF(Earliest DeadlineFirst)。在3.14的内核时进入了主线。本文是基于没有进主线之前的分析。思想基本一致。
EDF介绍
EDF(Earliest DeadlineFirst)它是一种最早到期优先的调度算法。当前Linux内核中使用的调度的算法是主要是cfs和fifo调度类,但是这两种算法的应用都是在一定场景下是最好的,有一定的局限性。当应用需要更精确的时间响应和调度方法的时候(比如多媒体业务等),就无法胜任了。
EDF的基本思想
首先,介绍edf中涉及的概念[1]:
Wakeup time: 时钟中断到期的时间;
Event response time: 调度的时延;
Deadline:任务到期的时间;
runtime: 任务运行的时间,就是deadline到期前必须运行的时间。也叫budget;
period:任务的周期时间,一般等于deadline;
下面通过如解释一下上面的概念:
这里写图片描述
图1 EDF结构图

EDF算法是以deadline为优先级,在deadline期间内必须运行完预定的配额。精度区别于时钟,x86的时钟是很精确的。每个cpu都有专门的定时器。Linux的EDF在x86上的精度可以精确到10us。
EDF样例:
Task1:runtime 1ms deadline 8ms
Task2:runtime 2ms deadline 5ms
Task3: runtime 4ms deadline 10ms
他们运行的时序如图
这里写图片描述
图2 运行时序图
EDF方案是内核态的调度方案,其定时是准的,正因为这样用户态的业务程序运行的时间就长了。表现出来的就是业务的转发能力增强了Edf的关键的特性如下:
每个任务的时间的行为相互独立,比如到期时间,不会受到系统中其他的任务或者任务数量的影响每个任务的行为由如下几个变量变量定义:
Budget: sched_runtime
Period: shced_period和deadline,一般来说这两个值是相等的。
EDF 的用法
Edf 提供出来的参数只有一个,这是路径如下:
/proc/sys/kernel/sched_dl_runtime_us
可以通过它来修改内核中的全局变量sysctl_sched_dl_runtime_us,它的作用就是用来设置edf调度类类队列中的所有实体能够占到cpu的比列。它的设置必须 和rt调度类的两个参数共同使用。
/proc/sys/kernel/sched_rt_period_us
/proc/sys/kernel/sched_rt_runtime_us
上面两个参数分别代表实时进程的周期和周期内能够运行的时间。
默认的情况下,这三个参数的值分别为:
Sched_dl_runtime_us = 400000
Sched_dl_period_us = 1000000
Sched_rt_runtime_us = 950000
那么如果机器上是四个cpu的话,edf的调度实体总共最大能占的cpu比例为:
100*4*950000/1000000*400000/1000000/100=152%
在sctual_dl_runtime的函数中会去计算这个值。
Edf提供的系统调用
__SYSCALL_I386(350,sys_sched_setparam2,sys_sched_setparam2)
__SYSCALL_I386(351,sys_sched_getparam2,sys_sched_getparam2)
__SYSCALL_I386(352,sys_sched_setscheduler2,sys_sched_setscheduler2)
4.3 EDF调度类实现
EDF和FIFO以及CFS一样,都是以调度类的方式实现调度算法。这样的结构是linux的一个特性。可以很好的将各种调度实现解耦。使其一个发生了问题,不会影响其它的调度。EDF的调度类在内核的位置如下所示:
这里写图片描述
图3 EDF调度类结构
EDF调度类
EDF的算法在linux中是以调度类形式存在的,其数据结构如下:
const struct sched_class dl_sched_class = {
.next = &rt_sched_class,
.enqueue_task = enqueue_task_dl,
.dequeue_task = dequeue_task_dl,
.yield_task = yield_task_dl,
.check_preempt_curr = check_preempt_curr_dl,
.pick_next_task = pick_next_task_dl,
.put_prev_task = put_prev_task_dl,

ifdef CONFIG_SMP

.select_task_rq     = select_task_rq_dl,
.set_cpus_allowed       = set_cpus_allowed_dl,
.rq_online             = rq_online_dl,
.rq_offline             = rq_offline_dl,
.pre_schedule       = pre_schedule_dl,
.post_schedule      = post_schedule_dl,
.task_woken     = task_woken_dl,

endif

.set_curr_task      = set_curr_task_dl,
.task_tick      = task_tick_dl,
.task_fork          = task_fork_dl,
.task_dead      = task_dead_dl,
.prio_changed           = prio_changed_dl,
.switched_from      = switched_from_dl,
.switched_to        = switched_to_dl,

};
从上面的数据结构可以看出,EDF的调度类在RT的前面(.next = &rt_sched_class),它的下面才是linux默认的实时调度类。当linux在调度的时候执行的函数如下:

pick_next_task(struct rq *rq)
{
……
for_each_class(class) {
p = class->pick_next_task(rq);
if (p)
return p;
……
}
上面的说明在系统调度的时刻,首先遍历调度类的链表,最左面的是最高的调度类。当这个rq上,也就是cpu上有最高的调度类,那首先从最高的调度类中查找在此队列上有没有任务,如果有就运行此任务。
enqueue_task_dl
将edf任务插入实时运行的队列中,此函数在中断启动后,就是一个实时任务执行完毕后,在等到周期减去运行的时间就是剩余的时间,edf的任务在一个周期内有两个定时器,一个是任务的运行的定时器,一个是运行后剩余时间的定时器。如下图所示:
这里写图片描述
图4
上图所示:定时器1是任务运行的定时器,当任务运行时,这是个定时器中

图16 定时器在EDF中的作用
中断产生,在中断里将任务放进运行对列,只有在运行队列里的任务才能得到cpu的调度。在此中断中就调用了enqueue_task_dl函数,在任务得到调度的时刻就会运行这个函数。定时器2是一个剩余时间的定时器。这个在后续讲解到。
dequeue_task_dl:将任务从运行队列中摘去,如果在可移出的列表中有这个任务,也将这个任务从可移出列表中删除。
yield_task_dl:当应用程序调用了sched_yield函数则调用此函数,作用就是将还没有运行完的runtime归零。更新当前的时间,然后退出运行队列。
check_preempt_curr_dl:判断如果当前的任务和唤醒的任务都是EDF任务的时候判断是否抢占。抢占的条件就是谁的绝对的deadline最小。时机是在一个任务插入运行对列和当一个任务由非EDF任务变成EDF任务的时候。
pick_next_task_dl:判断rq上dl队列是否有EDF任务,如果有则从红黑树中选择一个最小的deadline的任务。启动定时器。定时时间为当前的时间+剩余的时间。
put_prev_task_dl:更新当前任务的时间,如果在本cpu上还有其他的任务,将自己放到可以push的队列。以便在合适的时候在其他的cpu上运行。

<think>好的,我需要详细解释Linux内核4.19版本中的fair_sched_class调度类。首先,我得回顾下进程管理的基础知识,特别是完全公平调度器(CFS)的原理,因为fair_sched_class就是CFS的实现。 用户可能想了解CFS如何工作,包括时间片计算、红黑树的使用、调度策略等。我需要确保提到关键概念,比如虚拟运行时间(vruntime)、权重、优先级映射等。同时,要说明fair_sched_class在内核中的角色,比如它如何处理进程调度,如何与其他调度类(如实时调度类)交互。 还要注意内核4.19是否有特别的改进或特性。可能需要查阅相关文档或源码注释,确认是否有变化。例如,CFS的负载均衡机制或者组调度功能是否有更新。 在组织内容时,应该分步骤讲解,先概述调度类的作用,再深入CFS的具体实现,包括数据结构(如sched_entity)、调度队列的管理、vruntime的计算,以及如何选择下个进程。同时,解释权重如何影响CPU时间的分配,特别是nice值到权重的转换。 需要避免过于技术化的术语,或者至少在使用时给出简单解释,确保内容对不同程度的读者都友好。此外,检查LaTeX格式是否正确,特别是数学公式部分,比如vruntime的计算公式可能需要用$$包围,并且正确使用符号。 可能还需要对比之前的版本,如果有变化的话,指出4.19版本的改进点。例如,调度算法的优化,或者修复的bug。如果找不到具体的变化,就专注于该版本中的通用实现。 最后,确保结构清晰,分点或分节,帮助用户逐步理解。可能的结构是:1. 调度类概述;2. CFS的核心思想;3. fair_sched_class的结构与功能;4. 关键数据结构和算法;5. 与其他调度类的协作;6. 内核4.19中的特定实现细节。 需要验证所有技术细节的准确性,比如函数名、数据结构名称是否与内核代码致。如果有不确定的地方,可能需要查阅源码或权威资料。例如,sched_class结构体中的enqueue_task、dequeue_task等函数指针的具体作用。 另外,红黑树在CFS中的应用是关键点,要解释为什么选择红黑树,以及如何通过它快速找到最小vruntime的进程。同时,说明调度周期的处理,如何计算时间片,以及抢占机制。 总结时,强调CFS的设计目标,即公平性和高效性,以及fair_sched_class如何实现这些目标。可能还要提到相关的配置选项或参数,比如sched_min_granularity_ns或sched_latency_ns,这些在4.19版本中的默认值或调整方式。 需要确保整个回答流畅,逻辑连贯,没有技术错误,并且符合用户要求的格式,特别是正确使用LaTeX数学表达式,行内公式用$...$,独立公式用$$...$$。例如,vruntime的计算公式可能需要独立展示。</think>Linux内核的进程调度由多个调度类Scheduler Class)协作完成,`fair_sched_class`是**完全公平调度器(CFS)**对应的调度类,专为普通进程设计。以下是对其核心机制的逐步解析: --- ### 1. CFS的设计目标 CFS的核心思想是**按权重分配CPU时间**,确保每个进程获得公平的CPU份额。其关键概念包括: - **虚拟运行时间(vruntime)**:进程实际运行时间经权重调整后的值,公式为: $$ \text{vruntime} = \text{实际运行时间} \times \frac{\text{NICE_0_LOAD}}{\text{进程权重}} $$ 权重由进程的`nice`值决定(范围通常为-20到19),优先级越高的进程权重越大。 --- ### 2. `fair_sched_class`的关键数据结构 #### (a) 调度实体(`sched_entity`) 每个进程或进程组对应调度实体,存储调度信息: ```c struct sched_entity { struct load_weight load; // 权重(含NICE值映射) u64 vruntime; // 虚拟运行时间 struct rb_node run_node; // 红黑树节点 // 其他字段(如组调度相关) }; ``` #### (b) 红黑树(`cfs_rq->tasks_timeline`) - **作用**:按`vruntime`排序所有可运行进程,左侧节点`vruntime`最小。 - **选择下个进程**:直接取最左侧节点(即`vruntime`最小的进程)。 --- ### 3. 调度流程详解 #### (a) 进程入队(`enqueue_task_fair`) 1. 将进程的`sched_entity`插入红黑树。 2. 更新CFS运行队列(`cfs_rq`)的负载统计。 #### (b) 进程出队(`dequeue_task_fair`) 1. 从红黑树中移除`sched_entity`。 2. 更新负载统计,触发负载均衡(若需要)。 #### (c) 选择下个进程(`pick_next_task_fair`) 1. 从红黑树中选择`vruntime`最小的进程。 2. 检查进程的时间片是否用完,决定是否抢占。 --- ### 4. 时间片与抢占机制 - **时间片计算**:基于`sched_latency_ns`(默认6ms)和进程权重动态分配。 $$ \text{时间片} = \text{sched_latency_ns} \times \frac{\text{进程权重}}{\text{总权重}} $$ - **抢占触发**:当进程的`vruntime`超过红黑树中最左侧进程的`vruntime`超过定阈值时,触发调度。 --- ### 5. 内核4.19的改进 在4.19版本中,CFS的优化包括: 1. **负载均衡增强**:减少跨NUMA节点的迁移开销。 2. **组调度优化**:更精确控制`cgroup`的CPU配额分配。 3. **调试工具改进**:通过`/proc/sched_debug`更直观查看CFS队列状态。 --- ### 6. 与其他调度类的关系 - **层级结构**:`fair_sched_class`优先级低于实时调度类(`rt_sched_class`),确保实时进程优先执行。 - **协作流程**:调度器按优先级遍历调度类(如`stop_sched_class` → `dl_sched_class` → `rt_sched_class` → `fair_sched_class`),选择第个可运行的进程。 --- ### 总结 `fair_sched_class`通过红黑树和`vruntime`机制,实现了对普通进程的高效公平调度。内核4.19进步优化了负载均衡和资源隔离,适用于需要高吞吐量的通用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值