This commit is contained in:
gatieme committed 2016-07-10 19:25:43 +08:00
1 parent d82fefe7be
commit 1f324cb909
7 files changed
+108 -72

No files matched your search

@@ -476,7 +476,7 @@ global queue only ever has, at most,
在schedule核心函数中,使用return_task来把prev进程重新入队,在earliest_deadline_task这个pick-next中,使用take_task将选中的next从队列取出,从而实现队列外执行。
##6 结论
##5.10 结论
-------
从上面的论述,我们丝毫没有看到有任何的诸如“SMP负载均衡”,“CPU亲和力”,“补偿”,“惩罚”之类的字眼,是的,这些字眼在BFS中完全不需要,BFS也正是摒弃了这些字眼才获得成功的,毕竟在一个一般人使用的桌面操作系统中,没有这么多的套套,大多数人使用的就是一个只有一个到两个处理器核心的系统,难道有必要搞什么调度域么?难道有必要搞什么NUMA么?需求决定一切,面对大型服务器,有UNIX的机制站在那里,而如果我们想把Linux推广到每一个掌上设备,那就没必要复制UNIX的那套了,BFS完全可以完美的搞定一切。小手段的去除,说明BFS调度器的发展方向起码是正确的。
@@ -135,7 +135,7 @@ linux内核实现的6种调度策略, 前面三种策略使用的是cfs调度器
| idle_sched_class | 采用CFS算法调度idle进程, 每个cup的第一个pid=0线程:swapper,是一个静态线程。调度类属于:idel_sched_class,所以在ps里面是看不到的。一般运行在开机过程和cpu异常的时候做dump | SCHED_IDLE |
其所属进程的优先级顺序为
````c
```c
stop_sched_class -> dl_sched_class -> rt_sched_class -> fair_sched_class -> idle_sched_class
```
@@ -167,6 +167,7 @@ linux中针对当前可调度的实时和非实时进程, 定义了类型为sech
-------
本质上, 通用调度器(核心调度器)是一个分配器,与其他两个组件交互.
* 调度器用于判断接下来运行哪个进程.
@@ -176,9 +177,12 @@ linux中针对当前可调度的实时和非实时进程, 定义了类型为sech
* 在选中将要运行的进程之后, 必须执行底层的任务切换.
这需要与CPU的紧密交互. 每个进程刚好属于某一调度类, 各个调度类负责管理所属的进程. 通用调度器自身不涉及进程管理, 其工作都委托给调度器类.
<font color=0x00ffff>
每个进程都属于某个调度器类(由字段task_struct->sched_class标识), 由调度器类采用进程对应的调度策略调度(由task_struct->policy )进行调度, task_struct也存储了其对应的调度实体标识
linux实现了6种调度策略, 依据其调度策略的不同实现了5个调度器类, 一个调度器类可以用一种或者多种调度策略调度某一类进程, 也可以用于特殊情况或者调度特殊功能的进程.
</font>
| 调度器类 | 调度策略 | 调度策略对应的调度算法 | 调度实体 | 调度实体对应的调度对象 |
@@ -1369,7 +1373,9 @@ struct task_group {
**通过的调度策略对象--调度类**
<font color=0x00ffff>
linux下每个进程都由自身所属的调度类进行管理, sched_class结构体表示调度类, 调度类提供了通用调度器和各个调度器之间的关联, 调度器类和特定数据结构中汇集地几个函数指针表示, 全局调度器请求的各个操作都可以用一个指针表示, 这使得无需了解调度器类的内部工作原理即可创建通用调度器, 定义在[kernel/sched/sched.h](http://lxr.free-electrons.com/source/kernel/sched/sched.h?v=4.6#L1184)
</font>
开发者可以根据己的设计需求,來把所属的Task配置到不同的Scheduling Class中.
用户层应用程序无法直接与调度类交互, 他们只知道上下文定义的常量SCHED_XXX(用task_struct->policy表示), 这些常量提供了调度类之间的映射。
@@ -1382,8 +1388,11 @@ stop_sched_class -> dl_sched_class -> rt_sched_class -> fair_sched_class -> idle
**被调度的实体--进程或者进程组**
<font color=0x00ffff>
linux下被调度的不只是进程, 还可以是进程组. 因此需要一种更加通用的形式组织被调度数据结构, 即调度实体, 同样不同的进程用不同的调度实体表示
</font>
| 普通进程 | 实时进程 |
| ------------- |:-------------:|
| sched_entity | rt_entity, sched_dl_entity |
@@ -5,7 +5,7 @@ Linux进程核心调度器之周期性调度器
| 日期 | 内核版本 | 架构| 作者 | GitHub| CSDN |
| ------- |:-------:|:-------:|:-------:|:-------:|:-------:|
| 2016-06-24 | [Linux-4.6](http://lxr.free-electrons.com/source/?v=4.6) | X86 & arm | [gatieme](http://blog.csdn.net/gatieme) | [LinuxDeviceDrivers](https://github.com/gatieme/LDD-LinuxDeviceDrivers) | [Linux进程管理与调度](http://blog.csdn.net/gatieme/article/category/6225543) |
| 2016-06-29 | [Linux-4.6](http://lxr.free-electrons.com/source/?v=4.6) | X86 & arm | [gatieme](http://blog.csdn.net/gatieme) | [LinuxDeviceDrivers](https://github.com/gatieme/LDD-LinuxDeviceDrivers) | [Linux进程管理与调度](http://blog.csdn.net/gatieme/article/details/51456569) |
@@ -34,7 +34,7 @@ Linux进程核心调度器之周期性调度器
首先还是让我们简单回顾一下子之前的的内容
##进程调度
##1.1 进程调度
-------
@@ -51,7 +51,7 @@ Linux进程核心调度器之周期性调度器
##1.1 进程的分类
##1.2 进程的分类
-------
linux把进程区分为**实时进程**和**非实时进程**, 其中非实时进程进一步划分为交互式进程和批处理进程
@@ -63,11 +63,9 @@ linux把进程区分为**实时进程**和**非实时进程**, 其中非实时
对于普通进程则采用CFS完全公平调度器进行调度
##1.2 linux调度器的演变
##1.3 linux调度器的演变
-------
| 字段 | 版本 |
| ------------- |:-------------:|
| O(n)的始调度算法 | linux-0.11~2.4 |
@@ -75,7 +73,7 @@ linux把进程区分为**实时进程**和**非实时进程**, 其中非实时
| CFS调度器 | linux-2.6~至今 |
##1.3 Linux的调度器组成
##1.4 Linux的调度器组成
-------
@@ -111,7 +109,7 @@ linux内核目前实现了6中调度策略(即调度算法), 用于对不同类
其所属进程的优先级顺序为
````c
```c
stop_sched_class -> dl_sched_class -> rt_sched_class -> fair_sched_class -> idle_sched_class
```
@@ -367,6 +365,6 @@ void do_timer(struct pt_regs *regs)
>参考
>参考
>
>[进程管理与调度5 -- 进程调度、进程切换原理详解](http://wanderer-zjhit.blogbus.com/logs/156738683.html)
File diff suppressed because it is too large. Load diff
@@ -172,7 +172,7 @@ linux中针对当前可调度的实时和非实时进程, 定义了类型为sech
#3 linux用户抢占
-------
#3.1 #linux用户抢占
##3.1 #linux用户抢占
-------
当内核即将返回用户空间时, 内核会检查need_resched是否设置, 如果设置, 则调用schedule(),此时,发生用户抢占.
@@ -1,4 +1,4 @@
Linux用户抢占和内核抢占详解(概念, 实现和触发时机)
Linux进程上下文切换过程context_switch详解
=======
@@ -101,8 +101,11 @@ linux中针对当前可调度的实时和非实时进程, 定义了类型为sech
而__schedule则执行了如下操作
**__schedule如何完成内核抢占**
<font color=0x00ffff>
1. 完成一些必要的检查, 并设置进程状态, 处理进程所在的就绪队列
2. 调度全局的pick_next_task选择抢占的进程
@@ -117,6 +120,8 @@ linux中针对当前可调度的实时和非实时进程, 定义了类型为sech
那么我们今天就详细讲解一下context_switch完成进程上下文切换的原理
</font>
#2 进程上下文
-------
@@ -179,24 +184,29 @@ linux中进程调度时, 内核在选择新进程之后进行抢占时, 通过co
>
>在进程发生调度时, 只有当前内核发生当前进程因为主动或者被动需要放弃CPU时, 内核才会选择一个与当前活动进程不同的进程来抢占CPU
context_switch其实是一个分配器, 他会调用所需的特定体系结构的方法
* 调用switch_mm(), 把虚拟内存从一个进程映射切换到新进程中
switch_mm更换通过task_struct->mm描述的内存管理上下文, 该工作的细节取决于处理器, 主要包括加载页表, 刷出地址转换后备缓冲器(部分或者全部), 向内存管理单元(MMU)提供新的信息
switch_mm更换通过task_struct->mm描述的内存管理上下文, 该工作的细节取决于处理器, 主要包括加载页表, 刷出地址转换后备缓冲器(部分或者全部), 向内存管理单元(MMU)提供新的信息
* 调用switch_to(),从上一个进程的处理器状态切换到新进程的处理器状态。这包括保存、恢复栈信息和寄存器信息
switch_to切换处理器寄存器的呢内容和内核栈(虚拟地址空间的用户部分已经通过switch_mm变更, 其中也包括了用户状态下的栈, 因此switch_to不需要变更用户栈, 只需变更内核栈), 此段代码严重依赖于体系结构, 且代码通常都是用汇编语言编写.
<font color=0x00ffff>
context_switch函数建立next进程的地址空间。进程描述符的active_mm字段指向进程所使用的内存描述符,而mm字段指向进程所拥有的内存描述符。对于一般的进程,这两个字段有相同的地址,但是,内核线程没有它自己的地址空间而且它的 mm字段总是被设置为 NULL
context_switch( )函数保证:如果next是一个内核线程, 它使用prev所使用的地址空间
</font>
由于不同架构下地址映射的机制有所区别, 而寄存器等信息弊病也是依赖于架构的, 因此switch_mm和switch_to两个函数均是体系结构相关的
##3.1 context_switch完全注释
-------
@@ -639,7 +649,11 @@ __switch_to函数
在进程A被选中再次执行的时候, 会出现一个问题, 此时控制权即将回到A, switch_to函数返回, 内核开始执行switch_to之后的点, 此时内核栈准确的恢复到切换之前的状态, 即进程A上次被切换出去时的状态, prev = A, next = B. 此时, 内核无法知道实际上在进程A之前运行的是进程C.
<font color=0x00ffff>
因此, 在新进程被选中执行时, 内核恢复到进程被切换出去的点继续执行, 此时内核只知道谁之前将新进程抢占了, 但是却不知道新进程再次执行是抢占了谁, 因此底层的进程切换机制必须将此前执行的进程(即新进程抢占的那个进程)提供给context_switch. 由于控制流会回到函数的该中间, 因此无法通过普通函数的返回值来完成. 因此使用了一个3个参数, 但是逻辑效果是相同的, 仿佛是switch_to是带有两个参数的函数, 而且返回了一个指向此前运行的进程的指针.
</font>
>switch_to(prev, next, last);
>
@@ -868,7 +882,5 @@ static struct rq *finish_task_switch(struct task_struct *prev)
```
#4 linux下进程切换性能分析
-------
File diff suppressed because it is too large. Load diff