OS调度策略:Proportional Share(比例份额调度)

本文是自己在深入阅读Operating Systems Three Easy Pieces关于Proportional Share(比例份额调度)的知识点总结,后面会不断更新连续每一节,欢迎大家批评指正。 也是面试经典问题总结

0. overview

💡 本节介绍一种不同的调度器→proportional-share(fair-share)比例份额调度器或者称为公平份额的调度器。其想法很简单:不是关注周期时间和响应时间,该调度器而是保证每个进程作业获得**特定比例份额的CPU时间。**

经典的调度有lottery scheduling→彩票调度。其想法很简单:获得彩票的进程应该得到运行,经常运行的进程应该有更多机会去获得彩票。


1. basic idea : random tickets(lottery scheduling)

彩票调度是一个非常基本的概念:彩票ticket,用于表示进程(或用户或其他)应接收的资源份额。

持有彩票很简单:调度程序必须知道总共有多少张彩票(在我们的示例中,有 100 张)。

调度器会随机选一个获奖的彩票(这里假设有100张,则选的号码为0-99),持有获奖彩票的进程能够得到运行。

如A有彩票0到74,B有彩票75-99。则按道理A会运行百分之75的时间。B会运行百分之25

若调度器选获奖的彩票为85,则B开始运行。

这两个工作的时间越长,它们就越有可能达到预期的百分比。
💡 优点:该方法实现简单,不需要记录全局的状态,只要记录总共有多少个ticket和每个进程的ticket数量就好了。 **其不足之处**:调度器随机选一个获奖的彩票号运行,可能不能够满足预期的程序运行的百分比。


1.1 ticket mechanisms

  1. ticket currency票值
  2. ticket transfer :一个进程短暂的将其ticket交给另外的程序,让其获得更高的次数
  3. ticket inflation:一个进程能够短暂地提高或降低其ticket数量

1.2 Implementation

其实现很简单:所需要的只是一个好的随机数生成器来选择获胜的彩票ticket,一个系统进程的数据结构(例如,列表)以及彩票总数。

如此时有三个进程,A,B,C分别有100,50,250的ticket数量,总共有400个ticket。假设调度器随机生成获胜的ticket为300。

其简单的遍历该列表,通过累加每个节点的tix数,直到累加的数大于300,则该节点就是即将运行的进程。

为了能够是程序更加高效,我们可以将其列表排序。


1.3 精确份额的ticket→stride scheduling

原来随机的scheduling其不足之处 :调度器随机选一个获奖的彩票号运行,可能不能够满足预期(不精确)的程序运行的百分比。

这里提出精确的调度方法→stride scheduling步调调度

其思想:系统中的每个作业都有一个步幅stride,与它拥有的票数成反比。初始每个作业有个pass value,初始为0。每次运行时,选择pass value最小的值的作业运行,运行完后将其作业的pass value叠加其stride值。

计算stride步幅:用一个较大数,除以每个作业拥有的ticket数量。

如:A,B,C有100,50,250个ticket,则其stride分别可以计算为用10000除以其每个ticket。→100,200,40。

如上图,初始每个作业的pass value均为0,运行时选择最小的作业进行运行,假设选取A,则运行完后A的pass value叠加成100,此时从pass value在选最小的,假设选B。则B的pass value叠加成200,最后。。。。

最后运行完,发现A,B,C运行的比例和原始的ticket的比例份额事准确一样的。
💡 为什么不用该stride方法呢?而用random彩票调度的方法? **random彩票调度具有stride步幅调度没有的一个很好的属性:没有保存全局状态。** 该步幅调度,需要保存每个作业全局状态信息,如pass value和stride值。**假设此时新来一个进程作业D**,则其初始pass value设置为0,则后面D就会垄断CPU的执行了。

所以对比之下,彩票调度可以更轻松地以合理的方式整合新的作业。


2. The Linux Completely Fair Scheduler (CFS)

当前linux实现了完全公平的调度,提高了效率和可伸缩性。CFS的目标是能够花尽量少的时间做出调度决策。研究表明,调度会使用CPU的5%的时间。

因此,尽可能地减少这种开销是现代调度器架构的一个关键目标。


2.1 CFS basic operation

不像大多数调度器一样,将时间片化成固定的。CFS会将时间片进行变化:公平地将CPU的运行时间均匀划分给每个竞争的进程。当每个进程运行时,会累积其vruntime(虚拟运行时间),随着程序的运行,其vruntime会增加。当调度发生时CFS会选择最低的vruntime进程进行运行。

问题1: CFS什么时候进行调度切换呢?

  1. 通过参数sched-latency 来决定。将sched-latency除以正在运行的进程个数 ,得到其每个进程运行的时间片长度,当每个进程运行完其时间片时,则会发现调度切换,CFS会选择最低的vruntime进程进行运行。

例如,假设sched-latency = 48 ms,如果有 n = 4 个进程正在运行,CFS 会将sched-latency 值除以 n,得出每个进程 12 毫秒的时间片。CFS 然后调度第一个作业并运行它,直到它使用了 12 毫秒的(虚拟)运行时,然后检查是否有一个具有较低 vruntime 的作业来代替运行。在这种情况下,有,CFS 将切换到其他三个工作之一,依此类推。图 9.4 显示了一个示例,其中四个作业(A、B、C、D)分别以这种方式运行两个时间段。然后完成其中两个(C,D),只剩下两个,然后每个以Round-robin方式运行24毫秒。

问题2: 若有太多的进程在运行,那么时间片会不会很短,从而经常发生调度切换,影响其性能?

  1. 第二个参数min_granularity,决定了时间片的最短时间,当sched-latency除以正在运行的进程个数,得到其每个进程运行的时间片长度小于min_granularity时,则会将时间片设置为min_granularity。

2.2 CFS控制程序的优先级→nice table?

CFS 还支持对进程优先级的控制,使用户能够或管理员为某些进程提供更高的 CPU 运行份额。它不是通过ticket来做到这一点,而是通过一种经典的UNIX机制来实现的,这种机制被称为进程的nice level。对于进程,nice 参数可以设置为 -20 到 +19 之间的任意位置,默认值为 0。正值意味着优先级较低负值表示较高优先级;

CFS 将每个过程的nice值映射到一个权重

所以其时间片段计算改为:

假设有两个进程作业A,B,我们更喜欢A,则给A分配低的nice值-5,B分配为0。

则A的权重为3121,B为1024。通过计算,分给A的时间片段是B的三倍。从而改变其份额优先级分配。

除了改变其时间片段,其虚拟时间vruntime的叠加也发生改变

A的vruntime时间的叠加比B慢三分之一,所以A运行的更久

构建上述权重表的一个聪明方面是,当 nice 值的差异是恒定的时,该表保留了 CPU 比例比率。例如,如果进程 A 的 nice 值是 5(不是 -5),而进程 B 的 nice 值是 10(不是 0),CFS 会以与之前完全相同的方式调度它们。


2.3 CFS using Red-Black tree

如上所述,CFS 的一个主要关注点是效率。对于调度器来说,效率有很多方面,但其中之一就是这么简单:当调度器必须找到下一个要运行的作业时,它应该尽快完成。像列表这样的简单数据结构无法扩展:现代系统有时由数千个进程组成,因此每隔几毫秒就搜索一个长列表是一种浪费。

所以CFS使用的是红黑树。CFS并不把所有进程都保留在这个结构中;相反,只有正在运行的(或可运行的)进程被保留在其中。如果进程进入睡眠状态(例如,等待 I/O 完成,或等待网络数据包到达),则会将其从树中删除并跟踪其他位置。

如:假设有 10 个作业,并且它们具有以下 vruntime 值:1、5、9、10、14、18、17、21、22 和 24。如果我们将这些作业保存在有序列表中,则找到下一个要运行的作业将很简单:只需删除第一个元素即可。但是,将该作业放回列表中时(按顺序),则需要找到合适的插入位置进行插入,需要消耗O(n)的时间。但是使用红黑树只需要O(logn)的时间。提高其效率;


2.4 CFS处理I/O等长时间睡眠的进程

选择最低 vruntime 来运行会导致一些问题,如会出现在长时间休眠的进程作业中。想象两个进程,A 和 B,其中一个 (A) 连续运行,另一个 (B) 进入休眠,睡眠很长一段时间(比如 10 秒)。当 B 醒来时,它的 vruntime 将比 A 晚 10 秒,因此B 现在将在接下来的 10 秒内独占 CPU,同时赶上A,实际上使 A 处于饥饿状态。

解决办法

当进程唤醒时,CFS 通过更改作业唤醒时的 vruntime来处理这种情况。将其vruntime设置为红黑树中最小的vruntime值 。这样避免了其他进程的挨饿现象,但睡眠时间短的作业经常无法获得 CPU 的公平份额


3. summary

公平共享的调度程序有其公平的问题。一个问题是,这种方法与I / O不是特别吻合;如上所述,偶尔执行 I/O 的作业可能无法获得其公平的 CPU 份额。另一个问题是,他们留下了ticket或优先级分配的难题,即,应该分配多少ticket,或者设置nice值哪个好值?

相关推荐
拉不动的猪2 小时前
# 关于初学者对于JS异步编程十大误区
前端·javascript·面试
熊猫钓鱼>_>4 小时前
Java面向对象核心面试技术考点深度解析
java·开发语言·面试·面向对象··class·oop
进击的野人6 小时前
CSS选择器与层叠机制
css·面试
T___T9 小时前
全方位解释 JavaScript 执行机制(从底层到实战)
前端·面试
9号达人9 小时前
普通公司对账系统的现实困境与解决方案
java·后端·面试
勤劳打代码9 小时前
条分缕析 —— 通过 Demo 深入浅出 Provider 原理
flutter·面试·dart
努力学算法的蒟蒻9 小时前
day10(11.7)——leetcode面试经典150
面试
进击的野人10 小时前
JavaScript 中的数组映射方法与面向对象特性深度解析
javascript·面试
南山安10 小时前
以腾讯面试题深度剖析JavaScript:从数组map方法到面向对象本质
javascript·面试
橘颂TA12 小时前
【剑斩OFFER】算法的暴力美学——二分查找
算法·leetcode·面试·职场和发展·c/c++