From 0a46b1a99ba76574fc74f0bb72ca7715cc63ff56 Mon Sep 17 00:00:00 2001 From: gatieme Date: Tue, 21 Jun 2016 23:36:30 +0800 Subject: [PATCH] =?UTF-8?q?=E8=BF=9B=E7=A8=8B=E8=B0=83=E5=BA=A6=E4=B9=8B?= =?UTF-8?q?=E4=BC=98=E5=85=88=E7=BA=A7=E8=AF=A6=E8=A7=A3...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../05-schedule/01-introduction/README.md | 7 + .../05-schedule/03-design/README.md | 121 ++++++++++++++---- .../05-schedule/04-priority/README.md | 66 +++++++--- .../05-schedule/05-core scheduler/README.md | 93 +++++++------- .../05-schedule/06-load_weight/README.md | 62 +++++++-- 5 files changed, 255 insertions(+), 94 deletions(-) diff --git a/study/kernel/01-process/05-schedule/01-introduction/README.md b/study/kernel/01-process/05-schedule/01-introduction/README.md index 7054134..a497f9d 100644 --- a/study/kernel/01-process/05-schedule/01-introduction/README.md +++ b/study/kernel/01-process/05-schedule/01-introduction/README.md @@ -57,6 +57,8 @@ Linux进程调度器概述 #进程饥饿 ------- + + 进程饥饿,即为Starvation,指当等待时间给进程推进和响应带来明显影响称为进程饥饿。当饥饿到一定程度的进程在等待到即使完成也无实际意义的时候称为饥饿死亡。 **产生饥饿的主要原因是** @@ -212,8 +214,13 @@ stop_sched_class -> dl_sched_class -> rt_sched_class -> fair_sched_class -> idle 调度器不限于调度进程, 还可以调度更大的实体, 比如实现组调度: 可用的CPUI时间首先在一半的进程组(比如, 所有进程按照所有者分组)之间分配, 接下来分配的时间再在组内进行二次分配. + 这种一般性要求调度器不直接操作进程, 而是处理可调度实体, 因此需要一个通用的数据结构描述这个调度实体,即seched_entity结构, 其实际上就代表了一个调度对象,可以为一个进程,也可以为一个进程组. + +linux中针对当前可调度的实时和非实时进程, 定义了类型为seched_entity的3个调度实体 + + | 调度实体 | 名称 | 描述 | 对应调度器类 | | ------- |:-------:|:-------:| | sched_dl_entity | DEADLINE调度实体 | 采用EDF算法调度的实时调度实体 | dl_sched_class | diff --git a/study/kernel/01-process/05-schedule/03-design/README.md b/study/kernel/01-process/05-schedule/03-design/README.md index 2850756..f30a698 100644 --- a/study/kernel/01-process/05-schedule/03-design/README.md +++ b/study/kernel/01-process/05-schedule/03-design/README.md @@ -75,7 +75,8 @@ linux把进程区分为实时进程和非实时进程, 其中非实时进程进 ------- -**2个调度器** +##2个调度器 +------- 可以用两种方法来激活调度 @@ -87,55 +88,127 @@ linux把进程区分为实时进程和非实时进程, 其中非实时进程进 并且每个调度器包括两个内容:**调度框架**(其实质就是两个函数框架)及**调度器类** -调度器类是实现了不同调度策略的实例,如 CFS, RT, DL class等。 - -当前的内核支持3种调度器类(sched_setscheduler系统调用可修改进程的策略):CFS(公平)、RT和DL(实时); - -6种调度策略:SCHED_NORAML(最常见的策略)、SCHED_BATCH(除了不能抢占外与常规任务一样,允许任务运行更长时间,更好地使用高速缓存,适合于成批处理的工作)、SCHED_IDLE(它甚至比nice 19还有弱,为了避免优先级反转使用)和SCHED_RR(循环调度,拥有时间片,结束后放在队列末)、SCHED_FIFO(没有时间片,可以运行任意长的时间)和SCHED_DEADLINE( 新支持的实时进程调度策略, 基于Earliest Deadline First-EDF调度算法), 其中前面三种策略使用的是cfs调度器类,后面两种使用rt调度器类, 最后那个使用了dl调度器类. - -它们的关系如下图 - -![调度器的组成](../images/level.jpg) +##6种调度策略 +------- +linux内核目前实现了6中调度策略(即调度算法), 用于对不同类型的进程进行调度, 或者支持某些特殊的功能 -**3个调度器类** - -当前的内核支持2种调度器类(sched_setscheduler系统调用可修改进程的策略):**CFS(公平调度器)**、**RT(实时调度器)**、以及内核新增的**DL(基于EDF最早截至时间优先的实时调度器)** +比如SCHED_NORMAL和SCHED_BATCH调度普通的非实时进程, SCHED_FIFO和SCHED_RR和SCHED_DEADLINE则采用不同的调度策略调度实时进程, SCHED_IDLE则在系统空闲时调用idle进程. -**6种调度策略** +>idle的运行时机 +> +>idle 进程优先级为MAX_PRIO,即最低优先级。 +> +>早先版本中,idle是参与调度的,所以将其优先级设为最低,当没有其他进程可以运行时,才会调度执行 idle +> +>而目前的版本中idle并不在运行队列中参与调度,而是在cpu全局运行队列rq中含idle指针,指向idle进程, 在调度器发现运行队列为空的时候运行, 调入运行 + | 字段 | 描述 | 所在调度器类 | | ------------- |:-------------:|:-------------:| | SCHED_NORMAL | (也叫SCHED_OTHER)用于普通进程,通过CFS调度器实现。SCHED_BATCH用于非交互的处理器消耗型进程。SCHED_IDLE是在系统负载很低时使用 | CFS | | SCHED_BATCH | SCHED_NORMAL普通进程策略的分化版本。采用分时策略,根据动态优先级(可用nice()API设置),分配CPU运算资源。注意:这类进程比上述两类实时进程优先级低,换言之,在有实时进程存在时,实时进程优先调度。但针对吞吐量优化, 除了不能抢占外与常规任务一样,允许任务运行更长时间,更好地使用高速缓存,适合于成批处理的工作 | CFS | -| SCHED_IDLE | 优先级最低,在系统空闲时才跑这类进程(如利用闲散计算机资源跑地外文明搜索,蛋白质结构分析等任务,是此调度策略的适用者)| CFS | +| SCHED_IDLE | 优先级最低,在系统空闲时才跑这类进程(如利用闲散计算机资源跑地外文明搜索,蛋白质结构分析等任务,是此调度策略的适用者)| CFS-IDLE | | SCHED_FIFO | 先入先出调度算法(实时调度策略),相同优先级的任务先到先服务,高优先级的任务可以抢占低优先级的任务 | RT | -| SCHED_RR | 轮流调度算法(实时调度策略),后者提供 Roound-Robin 语义,采用时间片,相同优先级的任务当用完时间片会被放到队列尾部,以保证公平性,同样,高优先级的任务可以抢占低优先级的任务。不同要求的实时任务可以根据需要用sched_setscheduler()API 设置策略 | RT | -| SCHED_DEADLINE | 新支持的实时进程调度策略,针对突发型计算,且对延迟和完成时间高度敏感的任务适用。基于Earliest Deadline First (EDF) 调度算法| +| SCHED_RR | 轮流调度算法(实时调度策略),后者提供 Roound-Robin 语义,采用时间片,相同优先级的任务当用完时间片会被放到队列尾部,以保证公平性,同样,高优先级的任务可以抢占低优先级的任务。不同要求的实时任务可以根据需要用sched_setscheduler() API设置策略 | RT | +| SCHED_DEADLINE | 新支持的实时进程调度策略,针对突发型计算,且对延迟和完成时间高度敏感的任务适用。基于Earliest Deadline First (EDF) 调度算法| DL | + +linux内核实现的6种调度策略, 前面三种策略使用的是cfs调度器类,后面两种使用rt调度器类, 最后一个使用DL调度器类 + + +##5个调度器类 +------- + +而依据其调度策略的不同实现了5个调度器类, 一个调度器类可以用一种种或者多种调度策略调度某一类进程, 也可以用于特殊情况或者调度特殊功能的进程. + + +| 调度器类 | 描述 | 对应调度策略 | +| ------- |:-------:|:-------:| +| stop_sched_class | 优先级最高的线程,会中断所有其他线程,且不会被其他任务打断
作用
1.发生在cpu_stop_cpu_callback 进行cpu之间任务migration
2.HOTPLUG_CPU的情况下关闭任务 | 无, 不需要调度普通进程 | +| dl_sched_class | 采用EDF最早截至时间优先算法调度实时进程 | SCHED_DEADLINE | +| rt_sched_class | 采用提供 Roound-Robin算法或者FIFO算法调度实时进程
具体调度策略由进程的task_struct->policy指定 | SCHED_FIFO, SCHED_RR | +| fair_sched_clas | 采用CFS算法调度普通的非实时进程 | SCHED_NORMAL, SCHED_BATCH | +| idle_sched_class | 采用CFS算法调度idle进程, 每个cup的第一个pid=0线程:swapper,是一个静态线程。调度类属于:idel_sched_class,所以在ps里面是看不到的。一般运行在开机过程和cpu异常的时候做dump | SCHED_IDLE | + +其所属进程的优先级顺序为 +````c +stop_sched_class -> dl_sched_class -> rt_sched_class -> fair_sched_class -> idle_sched_class +``` + +##3个调度实体 +------- + +调度器不限于调度进程, 还可以调度更大的实体, 比如实现组调度: 可用的CPUI时间首先在一半的进程组(比如, 所有进程按照所有者分组)之间分配, 接下来分配的时间再在组内进行二次分配. + +这种一般性要求调度器不直接操作进程, 而是处理可调度实体, 因此需要一个通用的数据结构描述这个调度实体,即seched_entity结构, 其实际上就代表了一个调度对象,可以为一个进程,也可以为一个进程组. + +linux中针对当前可调度的实时和非实时进程, 定义了类型为seched_entity的3个调度实体 + +| 调度实体 | 名称 | 描述 | 对应调度器类 | +| ------- |:-------:|:-------:| +| sched_dl_entity | DEADLINE调度实体 | 采用EDF算法调度的实时调度实体 | dl_sched_class | +| sched_rt_entity | RT调度实体 | 采用Roound-Robin或者FIFO算法调度的实时调度实体 | rt_sched_class | +| sched_entity | CFS调度实体 | 采用CFS算法调度的普通非实时进程的调度实体 | fair_sched_class | + + + +##调度器类的就绪队列 +------- -其中前面三种策略使用的是cfs调度器类,后面两种使用rt调度器类, 最后一个使用DL调度器类 另外,对于调度框架及调度器类,它们都有自己管理的运行队列,调度框架只识别rq(其实它也不能算是运行队列),而对于cfs调度器类它的运行队列则是cfs_rq(内部使用红黑树组织调度实体),实时rt的运行队列则为rt_rq(内部使用优先级bitmap+双向链表组织调度实体), 此外内核对新增的dl实时调度策略也提供了运行队列dl_rq +##调度器整体框架 +------- + + 本质上, 通用调度器(核心调度器)是一个分配器,与其他两个组件交互. * 调度器用于判断接下来运行哪个进程. 内核支持不同的调度策略(完全公平调度, 实时调度, 在无事可做的时候调度空闲进程,即0号进程也叫swapper进程,idle进程), 调度类使得能够以模块化的方法实现这些侧露额, 即一个类的代码不需要与其他类的代码交互 当调度器被调用时, 他会查询调度器类, 得知接下来运行哪个进程 -* 在选中将要运行的进程之后, 必须执行底层的任务切换. +* 在选中将要运行的进程之后, 必须执行底层的任务切换. 这需要与CPU的紧密交互. 每个进程刚好属于某一调度类, 各个调度类负责管理所属的进程. 通用调度器自身不涉及进程管理, 其工作都委托给调度器类. ->最早截止时间优先(Earliest Dealine First, EDF)是实时系统中常用的一种调度算法,系统中有多个任务时,由调度算法决定哪个任务当前占用处理器,那么EDF算法就是按照任务的截止时间(deadline)来确定任务的执行顺序,最早截止的任务先执行。 -> -1. 最早截止时间优先EDF(Earliest DeadlineFirst)算法是非常著名的实时调度算法之一。在每一个新的就绪状态,调度器都是从那些已就绪但还没有完全处理完毕的任务中选择最早截止时间的任务,并将执行该任务所需的资源分配给它。在有新任务到来时,调度器必须立即计算EDF,排出新的定序,即正在运行的任务被剥夺,并且按照新任务的截止时间决定是否调度该新任务。如果新任务的最后期限早于被中断的当前任务,就立即处理新任务。按照EDF算法,被中断任务的处理将在稍后继续进行。 -> ->2. 该算法的思想是从两个任务中选择截至时间最早的任务,把它暂作为当前处理任务,再判断该任务是否在当前周期内,若不在当前周期内,就让另一任务暂作当前处理任务,若该任务也不在当前周期内,就让CPU空跑到最靠近的下一个截至时间的开始,若有任务在该周期内,就判断该任务的剩余时间是否小于当前截至时间与当前时间的差,若小于,则让该任务运行到结束.否则,就让该任务运行到该周期的截止时间,就立即抢回处理器,再判断紧接着的最早截至时间,并把处理器给它,做法同上,如此反复执行. +每个进程都属于某个调度器类(由字段task_struct->sched_class标识), 由调度器类采用进程对应的调度策略调度(由task_struct->policy )进行调度, task_struct也存储了其对应的调度实体标识 + +linux实现了6种调度策略, 依据其调度策略的不同实现了5个调度器类, 一个调度器类可以用一种或者多种调度策略调度某一类进程, 也可以用于特殊情况或者调度特殊功能的进程. + + +| 调度器类 | 调度策略 | 调度策略对应的调度算法 | 调度实体 | 调度实体对应的调度对象 | +| ------- |:-------:|:-------:|:-------:| +| stop_sched_class | 无 | 无 | 无 | 特殊情况, 发生在cpu_stop_cpu_callback 进行cpu之间任务迁移migration或者HOTPLUG_CPU的情况下关闭任务 | +| dl_sched_class | SCHED_DEADLINE | Earliest-Deadline-First最早截至时间有限算法 | sched_dl_entity | 采用DEF最早截至时间有限算法调度实时进程 | +| rt_sched_class | SCHED_RR

SCHED_FIFO | Roound-Robin时间片轮转算法

FIFO先进先出算法 | sched_rt_entity | 采用Roound-Robin或者FIFO算法调度的实时调度实体 | +| fair_sched_class | SCHED_NORMAL

SCHED_BATCH | CFS完全公平懂调度算法 |sched_entity | 采用CFS算法普通非实时进程 | +| idle_sched_class | SCHED_IDLE | 无 | 特殊进程, 用于cpu空闲时调度空闲进程idle | + +它们的关系如下图 + +![调度器的组成](../images/level.jpg) + + +##5种调度器类为什么只有3种调度实体? +------- + +正常来说一个调度器类应该对应一类调度实体, 但是5种调度器类却只有了3种调度实体? + +这是因为调度实体本质是一个可以被调度的对象, 要么是一个进程(linux中线程本质上也是进程), 要么是一个进程组, 只有dl_sched_class, rt_sched_class调度的实时进程(组)以及fair_sched_class调度的非实时进程(组)是可以被调度的实体对象, 而stop_sched_class和idle_sched_class + + +##为什么采用EDF实时调度需要单独的调度器类, 调度策略和调度实体 +------- + +linux针对实时进程实现了Roound-Robin, FIFO和Earliest-Deadline-First(EDF)算法, 但是为什么SCHED_RR和SCHED_FIFO两种调度算法都用rt_sched_class调度类和sched_rt_entity调度实体描述, 而EDF算法却需要单独用rt_sched_class调度类和sched_dl_entity调度实体描述 + +为什么采用EDF实时调度不用rt_sched_class调度类调度, 而是单独实现调度类和调度实体? + diff --git a/study/kernel/01-process/05-schedule/04-priority/README.md b/study/kernel/01-process/05-schedule/04-priority/README.md index 8f28913..2d0157b 100644 --- a/study/kernel/01-process/05-schedule/04-priority/README.md +++ b/study/kernel/01-process/05-schedule/04-priority/README.md @@ -29,6 +29,7 @@ Linux进程优先级的处理 ##进程的分类 ------- + linux把进程区分为实时进程和非实时进程, 其中非实时进程进一步划分为交互式进程和批处理进程 | 类型 | 描述 | 示例 | @@ -88,27 +89,60 @@ linux把进程区分为实时进程和非实时进程, 其中非实时进程进 并且每个调度器包括两个内容:**调度框架**(其实质就是两个函数框架)及**调度器类** -调度器类是实现了不同调度策略的实例,如 CFS, RT, DL class等。 + + +**6种调度策略** + +linux内核目前实现了6中调度策略(即调度算法), 用于对不同类型的进程进行调度, 或者支持某些特殊的功能 + +* SCHED_NORMAL和SCHED_BATCH调度普通的非实时进程 + +* SCHED_FIFO和SCHED_RR和SCHED_DEADLINE则采用不同的调度策略调度实时进程 + +* SCHED_IDLE则在系统空闲时调用idle进程. -**3个调度器类** +**5个调度器类** -当前的内核支持3种调度器类(sched_setscheduler系统调用可修改进程的策略):CFS(公平)、RT和DL(实时); +而依据其调度策略的不同实现了5个调度器类, 一个调度器类可以用一种种或者多种调度策略调度某一类进程, 也可以用于特殊情况或者调度特殊功能的进程. -**6个调度策略** -6种调度策略: +其所属进程的优先级顺序为 +````c +stop_sched_class -> dl_sched_class -> rt_sched_class -> fair_sched_class -> idle_sched_class +``` -| 调度策略 | 描述 | 所属调度类 | -| ------------- |:-------------:|:-------------:| -| SCHED_NORAML | 最常见的策略 | CFS | -| SCHED_BATCH | 除了不能抢占外与常规任务一样,允许任务运行更长时间,更好地使用高速缓存,适合于成批处理的工作 | CFS | -| SCHED_IDLE | 它甚至比nice 19还有弱,为了避免优先级反转使用 | CFS | -| SCHED_RR | 循环调度,拥有时间片,结束后放在队列末 | RT | -| SCHED_FIFO | 没有时间片,可以运行任意长的时间 | RT | -| SCHED_DEADLINE | 新支持的实时进程调度策略, 基于Earliest Deadline First-EDF调度算法 | DL | +**3个调度实体** +调度器不限于调度进程, 还可以调度更大的实体, 比如实现组调度. + +这种一般性要求调度器不直接操作进程, 而是处理可调度实体, 因此需要一个通用的数据结构描述这个调度实体,即seched_entity结构, 其实际上就代表了一个调度对象,可以为一个进程,也可以为一个进程组. + +linux中针对当前可调度的实时和非实时进程, 定义了3个调度实体 + + +* sched_dl_entity 采用EDF算法调度的实时调度实体 + +* sched_rt_entity 采用Roound-Robin或者FIFO算法调度的实时调度实体 rt_sched_class + +* sched_entity 采用CFS算法调度的普通非实时进程的调度实体 + + +**调度器整体框架** + +每个进程都属于某个调度器类(由字段task_struct->sched_class标识), 由调度器类采用进程对应的调度策略调度(由task_struct->policy )进行调度, task_struct也存储了其对应的调度实体标识 + +linux实现了6种调度策略, 依据其调度策略的不同实现了5个调度器类, 一个调度器类可以用一种或者多种调度策略调度某一类进程, 也可以用于特殊情况或者调度特殊功能的进程. + + +| 调度器类 | 调度策略 | 调度策略对应的调度算法 | 调度实体 | 调度实体对应的调度对象 | +| ------- |:-------:|:-------:|:-------:| +| stop_sched_class | 无 | 无 | 无 | 特殊情况, 发生在cpu_stop_cpu_callback 进行cpu之间任务迁移migration或者HOTPLUG_CPU的情况下关闭任务 | +| dl_sched_class | SCHED_DEADLINE | Earliest-Deadline-First最早截至时间有限算法 | sched_dl_entity | 采用DEF最早截至时间有限算法调度实时进程 | +| rt_sched_class | SCHED_RR

SCHED_FIFO | Roound-Robin时间片轮转算法

FIFO先进先出算法 | sched_rt_entity | 采用Roound-Robin或者FIFO算法调度的实时调度实体 | +| fair_sched_class | SCHED_NORMAL

SCHED_BATCH | CFS完全公平懂调度算法 |sched_entity | 采用CFS算法普通非实时进程 | +| idle_sched_class | SCHED_IDLE | 无 | 特殊进程, 用于cpu空闲时调度空闲进程idle | 它们的关系如下图 @@ -116,6 +150,7 @@ linux把进程区分为实时进程和非实时进程, 其中非实时进程进 + #linux优先级的表示 ------- @@ -135,7 +170,8 @@ linux把进程区分为实时进程和非实时进程, 其中非实时进程进 从0~99的范围专供实时进程使用, nice的值[-20,19]则映射到范围100~139 ->linux2.6内核将任务优先级进行了一个划分, 实时优先级范围是0到MAX_RT_PRIO-1(即99),而普通进程的静态优先级范围是从MAX_RT_PRIO到MAX_PRIO-1(即100到139)。 +>linux2.6内核将任务优先级进行了一个划分, 实时优先级范围是0到MAX_RT_PRIO-1(即99),而普通进程的静态优先级范围是从MAX_RT_PRIO到MAX_PRIO-1(即100到139). + | 优先级范围 | 描述 | | ------------- |:-------------:| @@ -147,7 +183,7 @@ linux把进程区分为实时进程和非实时进程, 其中非实时进程进 **内核的优先级表示** -内核表示优先级的所有信息基本都放在[include/linux/sched/prio.h](http://lxr.free-electrons.com/source/include/linux/sched/prio.h?v=4.6)中, 其中定义了一些表示优先级的宏和函数, +内核表示优先级的所有信息基本都放在[include/linux/sched/prio.h](http://lxr.free-electrons.com/source/include/linux/sched/prio.h?v=4.6)中, 其中定义了一些表示优先级的宏和函数. 优先级数值通过宏来定义, 如下所示, diff --git a/study/kernel/01-process/05-schedule/05-core scheduler/README.md b/study/kernel/01-process/05-schedule/05-core scheduler/README.md index d272371..2fd6cb1 100644 --- a/study/kernel/01-process/05-schedule/05-core scheduler/README.md +++ b/study/kernel/01-process/05-schedule/05-core scheduler/README.md @@ -14,16 +14,11 @@ Linux进程周期性调度器 我们前面提到linux有两种方法激活调度器:核心调度器和 - - * 一种是直接的, 比如进程打算睡眠或出于其他原因放弃CPU - - * 另一种是通过周期性的机制, 以固定的频率运行, 不时的检测是否有必要 - 因而内核提供了两个调度器**主调度器**,**周期性调度器**,分别实现如上工作, 两者合在一起就组成了**核心调度器(core scheduler)**, 也叫**通用调度器(generic scheduler)**. @@ -33,8 +28,6 @@ Linux进程周期性调度器 而我们的周期性调度器以固定的频率激活负责当前进程调度类的周期性调度方法, 以保证系统的并发性 - - 首先还是让我们简单回顾一下子之前的的内容 @@ -43,37 +36,26 @@ Linux进程周期性调度器 ------- - ##进程调度 ------- - 内存中保存了对每个进程的唯一描述, 并通过若干结构与其他进程连接起来. - **调度器**面对的情形就是这样, 其任务是在程序之间共享CPU时间, 创造并行执行的错觉, 该任务分为两个不同的部分, 其中一个涉及**调度策略**, 另外一个涉及**上下文切换**. - - - 内核必须提供一种方法, 在各个进程之间尽可能公平地共享CPU时间, 而同时又要考虑不同的任务优先级. - 调度器的一般原理是, 按所需分配的计算能力, 向系统中每个进程提供最大的公正性, 或者从另外一个角度上说, 他试图确保没有进程被亏待. - - ##进程的分类 ------- - - linux把进程区分为**实时进程**和**非实时进程**, 其中非实时进程进一步划分为交互式进程和批处理进程 根据进程的不同分类Linux采用不同的调度策略. @@ -83,8 +65,6 @@ linux把进程区分为**实时进程**和**非实时进程**, 其中非实时 但是普通进程的调度策略就比较麻烦了, 因为普通进程不能简单的只看优先级, 必须公平的占有CPU, 否则很容易出现进程饥饿, 这种情况下用户会感觉操作系统很卡, 响应总是很慢,因此在linux调度器的发展历程中经过了多次重大变动, linux总是希望寻找一个最接近于完美的调度策略来公平快速的调度进程. - - ##linux调度器的演变 ------- @@ -103,20 +83,12 @@ linux把进程区分为**实时进程**和**非实时进程**, 其中非实时 | CFS调度器 | linux-2.6~至今 | - - - ##Linux的调度器组成 ------- - - - **2个调度器** - - 可以用两种方法来激活调度 * 一种是直接的, 比如进程打算睡眠或出于其他原因放弃CPU @@ -127,35 +99,70 @@ linux把进程区分为**实时进程**和**非实时进程**, 其中非实时 并且每个调度器包括两个内容:**调度框架**(其实质就是两个函数框架)及**调度器类** -**2种5个调度器类** -当前的内核支持2种调度器类(sched_setscheduler系统调用可修改进程的策略):CFS(公平-非实时)、RT(实时); -而依据其调度策略的不同实现了5个调度器类, 其所属进程的优先级顺序为 +**6种调度策略** + +linux内核目前实现了6中调度策略(即调度算法), 用于对不同类型的进程进行调度, 或者支持某些特殊的功能 + +* SCHED_NORMAL和SCHED_BATCH调度普通的非实时进程 + +* SCHED_FIFO和SCHED_RR和SCHED_DEADLINE则采用不同的调度策略调度实时进程 + +* SCHED_IDLE则在系统空闲时调用idle进程. + + + +**5个调度器类** + +而依据其调度策略的不同实现了5个调度器类, 一个调度器类可以用一种种或者多种调度策略调度某一类进程, 也可以用于特殊情况或者调度特殊功能的进程. + + +其所属进程的优先级顺序为 ````c stop_sched_class -> dl_sched_class -> rt_sched_class -> fair_sched_class -> idle_sched_class ``` -**6个调度策略** +**3个调度实体** -6种调度策略: +调度器不限于调度进程, 还可以调度更大的实体, 比如实现组调度. -| 调度策略 | 描述 | 所属调度类 | -| ------------- |:-------------:|:-------------:| -| SCHED_NORAML | 最常见的策略 | CFS | -| SCHED_BATCH | 除了不能抢占外与常规任务一样,允许任务运行更长时间,更好地使用高速缓存,适合于成批处理的工作 | CFS | -| SCHED_IDLE | 它甚至比nice 19还有弱,为了避免优先级反转使用 | CFS | -| SCHED_RR | 循环调度,拥有时间片,结束后放在队列末 | RT | -| SCHED_FIFO | 没有时间片,可以运行任意长的时间 | RT | -| SCHED_DEADLINE | 新支持的实时进程调度策略, 基于Earliest Deadline First-EDF调度算法 | DL | +这种一般性要求调度器不直接操作进程, 而是处理可调度实体, 因此需要一个通用的数据结构描述这个调度实体,即seched_entity结构, 其实际上就代表了一个调度对象,可以为一个进程,也可以为一个进程组. + +linux中针对当前可调度的实时和非实时进程, 定义了3个调度实体 + +* sched_dl_entity 采用EDF算法调度的实时调度实体 + +* sched_rt_entity 采用Roound-Robin或者FIFO算法调度的实时调度实体 rt_sched_class + +* sched_entity 采用CFS算法调度的普通非实时进程的调度实体 -结构如图所示 +**调度器类的就绪队列** -![调度器的框架](../images/level.jpg) +另外,对于调度框架及调度器类,它们都有自己管理的运行队列,调度框架只识别rq(其实它也不能算是运行队列),而对于cfs调度器类它的运行队列则是cfs_rq(内部使用红黑树组织调度实体),实时rt的运行队列则为rt_rq(内部使用优先级bitmap+双向链表组织调度实体), 此外内核对新增的dl实时调度策略也提供了运行队列dl_rq +**调度器整体框架** + +每个进程都属于某个调度器类(由字段task_struct->sched_class标识), 由调度器类采用进程对应的调度策略调度(由task_struct->policy )进行调度, task_struct也存储了其对应的调度实体标识 + +linux实现了6种调度策略, 依据其调度策略的不同实现了5个调度器类, 一个调度器类可以用一种或者多种调度策略调度某一类进程, 也可以用于特殊情况或者调度特殊功能的进程. + + +| 调度器类 | 调度策略 | 调度策略对应的调度算法 | 调度实体 | 调度实体对应的调度对象 | +| ------- |:-------:|:-------:|:-------:| +| stop_sched_class | 无 | 无 | 无 | 特殊情况, 发生在cpu_stop_cpu_callback 进行cpu之间任务迁移migration或者HOTPLUG_CPU的情况下关闭任务 | +| dl_sched_class | SCHED_DEADLINE | Earliest-Deadline-First最早截至时间有限算法 | sched_dl_entity | 采用DEF最早截至时间有限算法调度实时进程 | +| rt_sched_class | SCHED_RR

SCHED_FIFO | Roound-Robin时间片轮转算法

FIFO先进先出算法 | sched_rt_entity | 采用Roound-Robin或者FIFO算法调度的实时调度实体 | +| fair_sched_class | SCHED_NORMAL

SCHED_BATCH | CFS完全公平懂调度算法 |sched_entity | 采用CFS算法普通非实时进程 | +| idle_sched_class | SCHED_IDLE | 无 | 特殊进程, 用于cpu空闲时调度空闲进程idle | + +它们的关系如下图 + +![调度器的组成](../images/level.jpg) + #周期性调度器 ------- diff --git a/study/kernel/01-process/05-schedule/06-load_weight/README.md b/study/kernel/01-process/05-schedule/06-load_weight/README.md index 68811d0..3e0783f 100644 --- a/study/kernel/01-process/05-schedule/06-load_weight/README.md +++ b/study/kernel/01-process/05-schedule/06-load_weight/README.md @@ -69,6 +69,7 @@ linux把进程区分为实时进程和非实时进程, 其中非实时进程进 | O(1)调度器 | linux-2.5 | | CFS调度器 | linux-2.6~至今 | + ##Linux的调度器组成 ------- @@ -85,22 +86,59 @@ linux把进程区分为实时进程和非实时进程, 其中非实时进程进 并且每个调度器包括两个内容:**调度框架**(其实质就是两个函数框架)及**调度器类** -**3个调度器类** -当前的内核支持3种调度器类(sched_setscheduler系统调用可修改进程的策略):CFS(公平)、RT和DL(实时); -**6个调度策略** +**6种调度策略** -6种调度策略: +linux内核目前实现了6中调度策略(即调度算法), 用于对不同类型的进程进行调度, 或者支持某些特殊的功能 -| 调度策略 | 描述 | 所属调度类 | -| ------------- |:-------------:|:-------------:| -| SCHED_NORAML | 最常见的策略 | CFS | -| SCHED_BATCH | 除了不能抢占外与常规任务一样,允许任务运行更长时间,更好地使用高速缓存,适合于成批处理的工作 | CFS | -| SCHED_IDLE | 它甚至比nice 19还有弱,为了避免优先级反转使用 | CFS | -| SCHED_RR | 循环调度,拥有时间片,结束后放在队列末 | RT | -| SCHED_FIFO | 没有时间片,可以运行任意长的时间 | RT | -| SCHED_DEADLINE | 新支持的实时进程调度策略, 基于Earliest Deadline First-EDF调度算法 | DL | +* SCHED_NORMAL和SCHED_BATCH调度普通的非实时进程 + +* SCHED_FIFO和SCHED_RR和SCHED_DEADLINE则采用不同的调度策略调度实时进程 + +* SCHED_IDLE则在系统空闲时调用idle进程. + + + +**5个调度器类** + +而依据其调度策略的不同实现了5个调度器类, 一个调度器类可以用一种种或者多种调度策略调度某一类进程, 也可以用于特殊情况或者调度特殊功能的进程. + + +其所属进程的优先级顺序为 +````c +stop_sched_class -> dl_sched_class -> rt_sched_class -> fair_sched_class -> idle_sched_class +``` + +**3个调度实体** + +调度器不限于调度进程, 还可以调度更大的实体, 比如实现组调度. + +这种一般性要求调度器不直接操作进程, 而是处理可调度实体, 因此需要一个通用的数据结构描述这个调度实体,即seched_entity结构, 其实际上就代表了一个调度对象,可以为一个进程,也可以为一个进程组. + +linux中针对当前可调度的实时和非实时进程, 定义了3个调度实体 + +* sched_dl_entity 采用EDF算法调度的实时调度实体 + +* sched_rt_entity 采用Roound-Robin或者FIFO算法调度的实时调度实体 + +* sched_entity 采用CFS算法调度的普通非实时进程的调度实体 + + +**调度器整体框架** + +每个进程都属于某个调度器类(由字段task_struct->sched_class标识), 由调度器类采用进程对应的调度策略调度(由task_struct->policy )进行调度, task_struct也存储了其对应的调度实体标识 + +linux实现了6种调度策略, 依据其调度策略的不同实现了5个调度器类, 一个调度器类可以用一种或者多种调度策略调度某一类进程, 也可以用于特殊情况或者调度特殊功能的进程. + + +| 调度器类 | 调度策略 | 调度策略对应的调度算法 | 调度实体 | 调度实体对应的调度对象 | +| ------- |:-------:|:-------:|:-------:| +| stop_sched_class | 无 | 无 | 无 | 特殊情况, 发生在cpu_stop_cpu_callback 进行cpu之间任务迁移migration或者HOTPLUG_CPU的情况下关闭任务 | +| dl_sched_class | SCHED_DEADLINE | Earliest-Deadline-First最早截至时间有限算法 | sched_dl_entity | 采用DEF最早截至时间有限算法调度实时进程 | +| rt_sched_class | SCHED_RR

SCHED_FIFO | Roound-Robin时间片轮转算法

FIFO先进先出算法 | sched_rt_entity | 采用Roound-Robin或者FIFO算法调度的实时调度实体 | +| fair_sched_class | SCHED_NORMAL

SCHED_BATCH | CFS完全公平懂调度算法 |sched_entity | 采用CFS算法普通非实时进程 | +| idle_sched_class | SCHED_IDLE | 无 | 特殊进程, 用于cpu空闲时调度空闲进程idle | 它们的关系如下图