(2021) 20 [虚拟化] 进程调度

南京大学操作系统课蒋炎岩老师网络课程笔记。

视频:https://www.bilibili.com/video/BV1HN41197Ko?p=20
讲义:http://jyywiki.cn/OS/2021/slides/11.slides#/

背景 — 机制与策略分离

  • 机制:一个通用的、可定制的抽象
  • 策略:在机制上实现的具体
  • 例子:
    • 分页和存储保护(机制) VS. 进程实现(策略)
    • 操作系统API(机制)VS. 应用程序(策略)

中断和虚拟存储为我们提供了进程抽象(机制),操作系统的实现者在中断时获得了 ”选择一个程序执行“ 的权利,但是到底应该选哪个呢?(策略)

本次课内容与目标

理解常见的处理器调度策略

  • 轮转调度(round - robin)
  • 优先级 / 反馈调度
  • 公平调度

了解调度是操作系统领域重要的、未解决的问题。

虚假的(课本上的)处理器调度

一组基本的假设

我们接下来的讨论,基于这样一组基本的假设,这使得我们能够更好地聚焦与调度问题。

  1. 系统中有一个处理器(1970s)
  2. 多个进程共享CPU
    • 包括系统调用(进程的一部分代码在syscall中运行)
    • 偶尔会等待I/O返回,不适用CPU(通常时间较长)
  3. 处理器以固定的频率被中断
  4. 随时有可能有新的进程被创建 / 旧的进程退出

中断机制:在中断 / 系统调用中可以切换到其他进程执行

策略:Round-Robin 轮转

假设档期 TiT_iTi​ 运行,中断之后会试图切换到下一个线程 T(i+1)modnT_{(i+1)\ mod\ n}T(i+1) mod n​ ,如果下一个线程正在等待 I / O返回,就继续尝试下一个,如果所有的线程都不需要 CPU,就调度idle进程执行。

中断之间进程的执行称为时间片 (time-slicing)

没有优先级的处理。

策略:引入优先级

UNIX niceness

  • -20 … 19

    • 越 nice,越被不 nice 的人抢占
    • -20: 极坏; most favorable to the process
    • 19: 极好; least favorable to the process
  • 基于优先级的各种策略
    • 有坏人,永远轮不到好人 (RTOS; 好人流下了悔恨的泪水),除非高优先级的进程在等待IO,否则永远是高优先级先执行
    • nice 相差 10, CPU 获得相差 10 倍 (Linux)(linux实测应为1:9)
  • 不妨试一试: nice/renice
    • taskset -c 0 nice -n 19 ./a.out &
    • taskset -c 0 nice -n 9 ./a.out &
  • top命令除了查看进程的CPU和内存的占用情况之外,也可以查看进程的NICE值,即NI

真实的处理器调度

策略:动态优先级,多级反馈队列调度(MLFQ)

不会设置优先级?能不能让系统自动设定?

  • 交互进程 (vi, vscode, …),大部分时候在等待外界输入,这时这种进程会主动让出CPU

    • 优先调度它们能提升用户体验,减少卡顿 (试想 Round-Robin)
  • 计算进程 (gcc, ld, …),拼命使用 CPU

调度策略

设置若干个 Round-Robin 队列,每个队列对应一个优先级。

如果将时间片用完了,则判定该进程执行大量运算,就下调其的优先级

  • 优先调度高优先级队列
  • 用完时间片 → 坏人,请你变得更好
  • 让出 CPU I/O → 好人,可以变得更坏

详见教科书OSTEP

问题

这种方式在早年间可以很好地工作,但是在现代操作系统中,大量的进程之间会有通信和互动。这时,如果两个进程之间彼此频繁通信,我们的多级反馈调度也会把它们识别成互动进程,提高其优先级。

策略:Complete Fair Scheduling (CFS)

基本策略

随着现代操作系统越来越复杂,操作系统的设计者已经放弃了设计一个完美的调度算法,而是转而使用一种按执行时间完全公平的调度算法。注意其中还有NICE机制来调节优先级,但其他情况下完全公平。

所有复杂系统的调度都是拙劣的 Workaround

试图去模拟一个 “ideal multi-task CPU”

“让系统里的所用进程尽可能公平地分享处理器”。具体来说,它会为每个进程记录精确的运行时间,中断 / 异常发生之后,就切换到运行时间最少的进程来执行,而当下次中断 / 异常之后,当前进程可能就不是运行时间最少的了,这时再选择当前最少运行时间的进程来执行。

CFS实现优先级

让好人的时间变得快一些,坏人的时间变得慢一些……

  • 不再是运行时间,而是 “vruntime” (virtual runtime)
  • vrt[i]/vrt[j]vrt[i]\ /\ vrt[j]vrt[i] / vrt[j] 的增加比例 =wt[j]/wt[i]= wt[j]\ /\ wt[i]=wt[j] / wt[i]
const int sched_prio_to_weight[40] = {/* -20 */ 88761, 71755, 56483, 46273, 36291,/* -15 */ 29154, 23254, 18705, 14949, 11916,/* -10 */  9548,  7620,  6100,  4904,  3906,/*  -5 */  3121,  2501,  1991,  1586,  1277,/*   0 */  1024,   820,   655,   526,   423,/*   5 */   335,   272,   215,   172,   137,/*  10 */   110,    87,    70,    56,    45,/*  15 */    36,    29,    23,    18,    15,
};

CFS 的复杂性

  1. 新进程 / 线程:子进程继承符进程的vruntime

  2. I/O (例如 1 分钟) 以后回来 vruntime 严重落后。为了赶上,CPU 会全部归它所有。

    Linux 的实现:被唤醒的进程获得 “最小” 的 vruntime (可以立即被执行)。

  3. vruntime 有优先级的 “倍数”,如果溢出了 64-bit 整数怎么办?

    假设:系统中最近、最远的时刻差不超过数轴的一半。我们可以比较它们的相对大小,a < b 不再代表 “小于” !

    bool less(u64 a, u64 b) {return (i64)(a - b) < 0;
    }
    

实现CFS的数据结构

用什么数据结构维护所有进程的 vruntime?考虑:我们需要什么操作?

为每个进程维护映射 t↦vt(t)t↦v_t(t)t↦vt​(t)

  • 维护进程的 vruntimevt(t)←vt(t)+Δt/wvruntime v_t(t)←v_t(t)+Δt/wvruntimevt​(t)←vt​(t)+Δt/w
  • 找到 ttt 满足 vt(t)v_t(t)vt​(t) 最小
  • 进程创建/退出/睡眠/唤醒时插入/删除 ttt

Linux内核中的实现:红黑树。

调度与互斥锁

处理器调度:不仅是计算

线程不是 while (1) 的循环,还可能等待互斥锁/信号量/设备 (比一个时间片短很多)。在此情形下,会发生什么?

  • round-robin?

    • 考虑三个进程/线程: producer, consumer, while (1)
    • 主要是因为没有精确的时间统计
  • CFS?
    • (似乎没问题?) 线程有精确的 accounting 信息

优先级反转(priority inversion)

void bad_guy() { // 高优先级mutex_lock(&lk);...mutex_unlock(&lk);
}void nice_guy() { // 中优先级while (1) ;
}void very_nice_guy() { // 最低优先级mutex_lock(&lk);...mutex_unlock(&lk);
}

very nice guy 在持有锁的时候让出了处理器……

  • bad guy 顺便也无法运行了 (nice guy 抢在了它前面 )

解决优先级反转问题

Linux: CFS 凑合用吧;实时系统(RTOS):火星车在 CPU Reset 啊喂??

  • 优先级继承 (Priority Inheritance)/优先级提升 (Priority Ceiling)

    • 持有 mutex 的线程/进程会继承 block 在该 mutex 上的最高优先级
    • 不总是能 work (例如条件变量唤醒)
  • 在系统中动态维护资源依赖关系
    • 优先级继承是它的特例
    • 似乎更困难了……
  • 避免高/低优先级的任务争抢资源
    • 对潜在的优先级反转进行预警 (lockdep)
    • TX-based: 冲突的 TX 发生时,总是低优先级的 abort

由于在现代操作系统中进程 / 线程之间的资源依赖(如互斥锁等)过于复杂,Linux选择躺平。

实际情况下的一些问题

多处理器调度:多用户、多任务

还没完:我们的 CPU 里有多个共享内存的处理器啊!

  • 不能简单地每个处理器上执行 CFS

    • 出现 “一核出力,七核围观”
  • 也不能简单地一个全局 CFS 维护队列
    • 在处理器之间迁移会导致 L1 cache/TLB 全都白给

      • 迁移?可能过一会儿还得移回来
      • 不迁移?造成处理器的浪费

注意L1、L2缓存是每个CPU独立的,L3缓存共享的。

实际情况(1)

  • A 要跑一个任务,因为要调用一个库,只能单线程跑
  • B 跑并行的任务,创建 1000 个线程跑
    • CFS 会发生什么?
    • 提示: CFS 公平地在线程之间共享 CPU

更糟糕的是,优先级解决不了这个问题……

  • B 不能随便提高自己进程的优先级

    • “An unprivileged user can only increase the nice value and such changes are irreversible…”

Linux Control Groups (cgroups)

可以去读一下手册,man 7 cgroups

顺便提一下:cgroups也是docker实现所依赖的机制之一。

实际情况(2):Big.LITTLE/能耗

处理器的计算能力不同

  • 均分 workloads 会让小核上的任务饥饿
  • Linux Kernel EAS (Energy Aware Scheduler)
  • 移动平台的考虑 (能耗 vs. 速度 vs. 吞吐量)。频率越低,IPC (Instruction per Cycle) 和能效都更好

如骁龙888中:Snapdragon 888

  • 1X Prime Cortex-X1 (2.84GHz)
  • 3X Performance Cortex-A78 (2.4GHz)
  • 4X Efficiency Cortex-A55 (1.8GHz)

实际情况(3):Non-Uniform Memory Access

线程看起来在 “共享内存”,但共享内存却是 memory hierarchy 造就的假象,roducer/consumer 位于同一个/不同 module 性能差距可能很大。

实际情况(4):CPU Hot-plug

指CPU的热插拔的情况,就像弹出U盘一样弹出CPU。

总结

本次课内容与目标

  • 理解常见的处理器的调度策略
  • 了解调度是操作系统领域重要的、未解决的问题

Takeaway messages

  • 机制和策略分离
  • “做系统” 的矛盾
    • 必须把问题简单化,才能做 “第一个” 东西出来
    • 但随着需求的增长,复杂系统会失控
  • 所有复杂系统的调度都是拙劣的 Workaround

(2021) 20 [虚拟化] 进程调度相关推荐

  1. FL Studio 2021.20.20中文版补丁win及mac 音乐制作软件

    FL Studio 中文版简称FL,全称Fruity Loops Studio,因此国人习惯叫它"水果".它让你的计算机就像是全功能的录音室,大混音盘,非常先进的制作工具,让你的音 ...

  2. 今日arXiv精选 | 28篇EMNLP 2021最新论文

     关于 #今日arXiv精选  这是「AI 学术前沿」旗下的一档栏目,编辑将每日从arXiv中精选高质量论文,推送给读者. Broaden the Vision: Geo-Diverse Visual ...

  3. 2021 第十二届蓝桥杯大赛软件赛省赛(第二场),C/C++大学B组题解

    第1题 -- 求余 (5分) 直接输出2021%20 答案:1 #include<bits/stdc++.h> using namespace std;int main(){cout< ...

  4. 2021年第十二届蓝桥杯省赛B组(C/C++)第二场题解

    文章目录 2021年第十二届蓝桥杯省赛B组(C/C++)第二场题解 1.求余 2.双阶乘 3.格点 4.整数分解 5.城邦 6.特殊年份 7.小平方 8.完全平方数 9.负载均衡 10.国际象棋 20 ...

  5. 2021年05月09日第十二届蓝桥杯第二场省赛试题及详解(Java本科B组)

    结果填空 (满分5分) 结果填空 (满分5分) 结果填空 (满分10分) 结果填空 (满分10分) 结果填空 (满分15分) 程序设计(满分15分) 程序设计(满分20分) 程序设计(满分20分) 程 ...

  6. Ubuntu 20.04安装Anaconda3

    1.Anaconda安装包下载 清华大学开源软件镜像站,下载 2.安装Anaconda (2)运行安装包 bash Anaconda3-5.3.1-Linux-x86_64.sh (3)回车键,进入注 ...

  7. Linux内核深入理解中断和异常(3):异常处理的实现(X86_TRAP_xx)

    Linux内核深入理解中断和异常(3):异常处理的实现(X86_TRAP_xx) rtoax 2021年3月 /*** start_kernel()->setup_arch()->idt_ ...

  8. 必会Redis单节点、Sentinel和Cluster操作实战

    本篇文章讲述了 Redis 单机环境.主备.哨兵 Sentinel 模式以及 Redis Cluster 集群模式下的操作步骤,关于这些操作我们没必要死记硬背,只需要总结下来,下次使用直接拿出来就好. ...

  9. 视觉传感器:3D感知算法

    作者丨巫婆塔里的工程师@知乎 来源丨https://zhuanlan.zhihu.com/p/426569335 编辑丨 一点人工一点智能 1 前言 之前的一篇文章介绍了基于视觉传感器的2D环境感知, ...

最新文章

  1. undefined reference to 'pthread_create'问题解决(转)
  2. Android 使用NineOldAndroids实现绚丽的ListView左右滑动删除Item效果
  3. Java笔记——Java代码块的执行顺序
  4. bzoj 4598: [Sdoi2016]模式字符串
  5. 【版本控制管理】 深入 001 A successful Git branching model GIT 项目分支策略和释放管理
  6. java web项目请求控制及简单漏洞防范
  7. oracle外部表kup-04023,Oracle外部表学习
  8. SysV和BSD启动风格的比较
  9. php阳历转阴历(农历),阴历转阳历的方法
  10. sklearn 中GBDT的损失函数
  11. hdu3336 Count the string
  12. AppBox v6.0中实现子页面和父页面的复杂交互
  13. 万恶淫为首,此言不虚。举要言之,邪淫者有如下十大不如意果报:
  14. 手机端如何维持登录状态
  15. 计算机桌面壁纸大小怎么设置,电脑桌面背景和大小比例怎么调试?教你调试电脑桌面背景和大小比例的方法...
  16. lol服务器修复失败,LOL客户端BUG遍地,服务器瘫痪长达一天!官方修复后毫无补偿引不满...
  17. ubuntu 18.04下解决网易云音乐打不开的问题
  18. Windows下获取计算机名和当前用户名
  19. Quartz执行逻辑(七)任务的暂停和恢复
  20. 给天空“染个色”?摄影后期时进行的一些思考

热门文章

  1. linux crontab定时任务常用梳理
  2. Element-UI中Cascader 级联选择器使用
  3. vue控制台报错Duplicate keys detected: 'xxxx'. This may cause an update error.解决方案
  4. 服务器漏洞处理_wildfly禁用https和8443端口
  5. VBA MultiPage 循环多页控件
  6. 计算机专业实践试题,计算机专业实践综合试题答案..doc
  7. qtcreator下拉列表怎么制作_设置EXCEL动态下拉菜单,只需要一个组合键,新手也能快速掌握...
  8. python time sleep和wait_Python和硒:driver.implicitly_wait()和time.sleep()之间的区别...
  9. linux创建定时任务命令,linux设置定时任务的方法步骤
  10. qt动态添加窗口到垂直布局