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值哪个好值?

相关推荐
nameofworld2 小时前
前端面试笔试(二)
前端·javascript·面试·学习方法·数组去重
摇光932 小时前
promise
前端·面试·promise
喔喔咿哈哈5 小时前
【手撕 Spring】 -- Bean 的创建以及获取
java·后端·spring·面试·开源·github
理想不理想v5 小时前
使用JS实现文件流转换excel?
java·前端·javascript·css·vue.js·spring·面试
Xiao Fei Xiangζั͡ޓއއ8 小时前
一觉睡醒,全世界计算机水平下降100倍,而我却精通C语言——scanf函数
c语言·开发语言·笔记·程序人生·面试·蓝桥杯·学习方法
NMBG228 小时前
[JAVAEE] 面试题(四) - 多线程下使用ArrayList涉及到的线程安全问题及解决
java·开发语言·面试·java-ee·intellij-idea
刘艳兵的学习博客14 小时前
刘艳兵-DBA033-如下那种应用场景符合Oracle ROWID存储规则?
服务器·数据库·oracle·面试·刘艳兵
用户3157476081351 天前
成为程序员的必经之路” Git “,你学会了吗?
面试·github·全栈
布川ku子1 天前
[2024最新] java八股文实用版(附带原理)---Mysql篇
java·mysql·面试
有趣的杰克1 天前
移动端【01】面试系统的MVVM重构实践
面试·职场和发展·重构