进程调度-1

最近特别有感触,各层面的设计似乎都可以从操作系统中找出相似的设计,操作系统几乎是设计集大成者,所以重新又开始看操作系统相关的书籍。最近可能都是一些记录性的文章,操作系统原理因为是教学课程,所以不会另做笔记。从重读Linux内核开始,记录学习过程。

本文均摘自《Linux内核与实现》。

因为硬件资源总是有限的,而我们哪个进程可以占用资源投入运行,何时运行以及要运行多长时间,就是调度程序要做的事情。进程调度程序就是可运行态进程之间分配有限的处理器时间资源的内核子系统。

首先我们要明确几个概念,多任务系统可以划分为:抢占式多任务和非抢占式多任务。非抢占式多任务就是指,除非进程主动停止运行,否则会一直运行。类unix系统都是抢占式多任务,由调度程序决定什么时候停止一个运行中的程序。这个强制挂起的动作就叫抢占。进程被抢占前运行的时间都是预设好的,叫做时间片。

进程的调度策略决定了何时让什么进程来运行,而进程又可以分为I\O消耗密集型和CPU消耗密集型。对于I\O消耗密集型的进程经常要处于运行状态,但是通常只是运行很短时间,因为他总会等待I\O后又会阻塞。对于CPU消耗密集型进程,通常都是不停的在执行,除非被抢占。

而操作系统为了提高响应速度,CPU消耗密集型进程都常会减少调度频率,而延长执行时间。所以调度策略会有两个矛盾点:进程相应速度和最大系统吞吐率。

那么为了在这两个矛盾中选择一个平衡点,时间片的选定就会很重要。如果时间片过长,会导致系统对与交互程序响应过慢;时间片太短又会进程切换带来的处理器耗时。但是I\O消耗性进程希望越短的时间片越好,这样它可以得到快速响应。而CPU消耗性进程则希望越长的时间片越好,他可以持续的运行,提高运行性能(比如缓存命中率会更高),减少上下文切换。

在Linux中并没有使用绝对数值的时间片,而是采用了分配了一个使用比。为了说明为什么Linux采用时间比,我们需要先理解一个概念,进程优先级。在Linux中进程优先级分为两种:

第一种是nice值,范围是-20到19,默认是0。值越大优先级越低,值越小优先级越高。在类unix系统中,nice值是一个标准化概念,但是不同的操作系统对其的利用方式会有所差别,有的操作系统nice就代表了分配给进程的时间片绝对值。在Linux中nice值代表时间片的比例。

第二种是实时优先级,变化范围是0到99。值越大优先级越高。实时进程的优先级都是高于普通进程的,所以这两个值是互相不重叠的两个范畴。

接下来再看时间比例要比时间片的优势在哪些地方:

1.如果把nice值映射为时间片,那就需要把nice单位值对应到处理器的绝对之间。这样会导致进程切换无法做到最优。比如nice=0对应的时间片为100ms,nice=20对应的时间片是5ms。假设分别有这两个nice值的进程处于可运行状态,那么对于nice=0的高优先级进程可以获得20/21的CPU时间,即105ms中的100ms;而低优先级的可以获得1/21的CPU时间,即105ms中的5ms。假设有两个nice=20的低优先级进程,每个进程可以获得50%的CPU时间,但是每个进程每次只能获得5ms的时间片。也就是说nice=0和nice=20的两个进程,105ms才进行上下文切换,而两个nice=20的进程10ms就要上下文切换。同样两个高优先级nice=0的进程同时运行,每个进程也可以获得50%的CPU时间,但是每个进程每次获得的是100ms。前文讲过,进程分I\O消耗性和CPU消耗性,我们通常希望I\O消耗性进程的响应要快,调度频率高,所以权重高。而对于CPU消耗型进程,我们希望调度频率低,所以权重低。但是按照这样分配,恰好相反,权重高的反而调度频率低,响应慢。

2.是相对nice的问题,同样假设nice=0分配的时间片为100ms,nice=1分配的时间片是95ms。这两个优先级之间时间片差距很小。而nice=18分配的时间片为10ms,nice=19分配的时间片为5ms,同样只差了一个优先级,时间片分配却差了两倍。

3.要执行nice到时间片的映射,我们就需要一个能分配的绝对时间片,比如前两个问题中的5ms,并且这个时间片必须是内核可测量的。所以时间片一定必须是定时器节拍的整数倍,那么我们的时间片分配就会随着定时器节拍的变化而改变了。

4.如果我们给一个要唤醒的程序提高优先级,即使他的时间片已经耗尽,提高优先级后,他又会被分配更多的时间片,他就可以更快的投入运行。虽然提高了响应性能,但是却破坏了公平原则,会导致其他进程无法及时运行。

可见好处如此之多,那么Linux中的进程调度策略CFS就是基于时间比例才做到尽量公平的。CFS的基本设计理念就是:进程调度效果应如同系统具备一哥完美的多任务处理器。

CFS中是在所有可运行进程总数基础上计算出一个进程可以运行多久,而不依靠nice值来计算时间片。CFS中nice值作为进程获得进程运行时间比的权重:nice值越高获得的使用比越低,nice值越低获得的使用比越高。

那么每个进程所获得的CPU时间可以用:调度周期*进程权重/所有可运行进程权重和。所以这个调度周期越小,系统的响应越快,交互性越好,但是上下文切换会更频繁,系统的总吞吐率会很低。比如调度周期是20ms,如果只有2个同优先级进程,每个进程被抢占前都可以运行10ms。如果有10个进程,每个只能运行2ms。如果有20个,每个就仅仅能运行1ms了。

当任务数量无限多时,每个任务可以获得的CPU时间会趋于0,这样带来的上下文切换消耗无法预估。所以CFS给每个进程提供了一个获得时间片的底线,成为最小粒度。默认是1ms。

CFS具体的实现有四个关键组成:时间记账、进程选择、睡眠和唤醒。

时间记账:所有的调度器都必须对进程运行时间做记账。例如我们分配给一个进程时间片后,系统时钟节拍发生时,时间片都会减少一个节拍周期。当一个进程的节拍周期减到0时,会被另一个尚未到0的时间片的可运行进程抢占。

虽然CFS中没有时间片了,但是也需要时间记账,因为他要保证每个进程是在公平的时间范围内运行。CFS中利用vruntime变量存放进程的虚拟运行时间,他表示了该进程运行了多长时间以及还应该运行多久,该时间是经过经过了所有可运行进程总数的标准化。它是以ns为单位,所以与定时器节拍不再相关。

进程选择:CFS中就是选择所有可运行进程中最小vruntime进程来执行。在CFS中所有可运行进程采用红黑树来保存,每个节点的键值就是vruntime。红黑树最左叶子结点就是vruntime最小的进程,所以CFS只需要找到红黑树中最左叶子结点来执行就可以。

睡眠和唤醒:睡眠是进程处于不可运行状态,内核操作是:进程把自己标记为睡眠,把进程从可运行红黑树移除,最后添加到等待队列中,然后调度器选择和执行其他进程。唤醒正好相反,就是把进程标记为可运行,从等待队列删除,添加到可运行红黑树中。

调度器何时执行是依靠内核中的need_resched标志来实现的,系统会在系统调回返回用户空间前、从终端或者异常处理返回用户空间前都会判断该标识状态,如果设置了该标识,则会触发一次调度策略。

设置该标识有三种方式:

1.时钟中断发现当前进程运行时间够了。

2.唤醒某个进程时,发现唤醒进程vruntime比当前最运行进程vruntime小。

3.进程自己让出CPU资源。

 

以上是基本理论概念,总结起来就是CFS采用了时间比例来分配CPU时间,利用vruntime和定时器节拍解耦,利用红黑树保存可运行状态进程,利用need_resched标识触发调度器重新调度。

未完待续......

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值