1. 什么是BFS

这里的BFS可不是广度优先算法,本文介绍的BFS是Linux的一个非Linux mainline调度算法。根据作者的描述BFS能够极大的提高低端设备(这里的低端设备的定义为:CPU数量小于16)的执行效率。

2. 原理

Linux默认的调度算法CFS是为了支持多CPU(非常多,4位数!!),那么我们平常的CPU个数一般都是2个,4个。所以CFS……

要知道 BFS 是什么最好先了解一下它的作者,传说中的澳洲猛士 CK。

CK,Con Kolivas,男, 澳大利亚中年男子,资深内核 hacker。众所周知,Linux Kernel 是聚集了一帮天才蠢才和暴君怪胎的地方,CK 貌似最适合这种地方的人。是真的貌似,一张电影里面典型高智商通缉犯的脸。

几年前编译 Linux kernel,ck 补丁集就是系统提速的代名词。当时编译内核的三部曲是下 kernel 源码,打上 ck 补丁集,编译安装。后来上游代码将 ck 补丁集稳定的部分不断吸收,它的影响力也渐渐消失。

真正有几个人用有上千 CPU 的电脑呢?为什么要为这种扩展性牺牲桌面性能。BFS 就在其间做了取舍,仅仅支持最多 16 个 CPU ,把问题外沿做小,让算法更简单精悍高效。作为原理来讲,这足够解释速度的来源。对于其它废问题, CK 专门写了一个 FAQ。在可以预见的将来,BFS 也不会进入 mainline kernel,说白了是取向问题。

A: 经过某些人千百年的努力,最新的 Linux  补丁支持 4096 个 CPU 的电脑了!原来只能支持 1024 个!
B: 全屏 Flash 视频卡不卡啊?
A: 卡。不过谁他丫的看视频啊?

3. BFS 实现原理

调度器是非常复杂的话题,尤其是 CFS 调度器,想要描述清楚,需要一支非凡的笔,我还没有找到。但 BFS 非常简单,所以我才有勇气在这里写点儿 BFS 的实现原理什么的。首先介绍几个关键概念。

3.1 虚拟 Deadline ( Virtual Deadline )

当一个进程被创建时,它被赋予一个固定的时间片,和一个虚拟 Deadline。该虚拟 deadline 的计算公式非常简单:

 Virtual Deadline = jiffies + (user_priority * rr_interval)
公式一

其中 jiffies 是当前时间 , user_priority 是进程的优先级,rr_interval 代表 round-robin interval,近似于一个进程必须被调度的最后期限,所谓 Deadline 么。不过在这个 Deadline 之前还有一个形容词为 Virtual,因此这个 Deadline 只是表达一种愿望而已,并非很多领导们常说的那种 deadline。

虚拟 Deadline 将用于调度器的 picknext 决策,这将在后续章节详细描述。

3.2 进程队列的表示方法和调度策略

在操作系统内部,所有的 Ready 进程都被存放在进程队列中,调度器从进程队列中选取下一个被调度的进程。因此如何设计进程队列是我们研究调度器的一个重要话题。BFS 采用了非常传统的进程队列表示方法,即 bitmap 加 queue。

BFS 将所有进程分成 4 类,分别表示不同的调度策略 :

  • Realtime,实时进程
  • SCHED_ISO,isochronous 进程,用于交互式任务
  • SCHED_NORMAL,普通进程
  • SCHED_IDELPRO,低优先级任务

实时进程总能获得 CPU,采用 Round Robin 或者 FIFO 的方法来选择同样优先级的实时进程。他们需要 superuser 的权限,通常限于那些占用 CPU 时间不多却非常在乎 Latency 的进程。

SCHED_ISO 在主流内核中至今仍未实现,Con 早在 2003 年就提出了这个 patch,但一直无法进入主流内核,这种调度策略是为了那些 near-realtime 的进程设计的。如前所述,实时进程需要用户有 superuser 的权限,这类进程能够独占 CPU,因此只有很少的进程可以被配置为实时进程。对于那些对交互性要求比较高的,又无法成为实时进程的进程,BFS 将采用 SCHED_ISO,这些进程能够抢占 SCHED_NORMAL 进程。他们的优先级比 SCHED_NORMAL 高,但又低于实时进程。此外当 SCHED_ISO 进程占用 CPU 时间达到一定限度后,会被降级为 SCHED_NORMAL,防止其独占整个系统资源。

SCHED_NORMAL 类似于主流调度器 CFS 中的 SCHED_OTHER,是基本的分时调度策略。

SCHED_IDELPRO 类似于 CFS 中的 SCHED_IDLE,即只有当 CPU 即将处于 IDLE 状态时才被调度的进程。

在这些不同的调度策略中,实时进程分成 100 个不同的优先级,加上其他三个调度策略,一共有 103 个不同的进程类型。对于每个进程类型,系统中都有可能有多个进程同时 Ready,比如很可能有两个优先级为 10 的 RT 进程同时 Ready,所以对于每个类型,还需要一个队列来存储属于该类型的 ready 进程。

BFS 用 103 个 bitmap 来表示是否有相应类型的进程准备进行调度。如下图所示:

图 6. BFS 进程队列

当任何一种类型的进程队列非空时,即存在 Ready 进程时,相应的 bitmap 位被设置为 1。

调度器如何在这样一个 bitmap 加 queue 的复杂结构中选择下一个被调度的进程的问题被称为 Task Selection 或者 pick next。

3.3 Task Selection i.e. Pick Next

当调度器决定进行进程调度的时候,BFS 将按照下面的原则来进行任务的选择:

图 7. Task Selection


首先查看 bitmap 是否有置位的比特。比如上图,对应于 SCHED_NORMAL 的 bit 被置位,表明有类型为 SCHED_NORMAL 的进程 ready。如果有 SCHED_ISO 或者 RT task 的比特被置位,则优先处理他们。

选定了相应的 bit 位之后,便需要遍历其相应的子队列。假如是一个 RT 进程的子队列,则选取其中的第一个进程。如果是其他的队列,那么就采用 EEVDF 算法来选取合适的进程。

EEVDF,即 earliest eligible virtual deadline first。BFS 将遍历该子队列,一个双向列表,比较队列中的每一个进程的 Virtual Deadline 值,找到最小的那个。最坏情况下,这是一个 O(n) 的算法,即需要遍历整个双向列表,假如其中有 n 个进程,就需要进行 n 此读取和比较。

但实际上,往往不需要遍历整个 n 个进程,这是因为 BFS 还有这样一个搜索条件:

当某个进程的 Virtual Deadline 小于当前的 jiffies 值时,直接返回该进程。并将其从就绪队列中删除,下次再 insert 时会放到队列的尾部,从而保证每个进程都有可能被选中,而不会出现饥饿现象。

这条规则对应于这样一种情况,即进程已经睡眠了比较长的时间,以至于已经睡过了它的 Virtual Deadline,如下图所示:

图 8. 睡眠和唤醒


T1 本来的 virtual deadline 为 t1,它 sleep 之后,其他的进程比如 T2 开始运行,等到 T1 再次 wakeup 的时候,当时的 jiffies 已经大于 t1,在这种情况下,T1 无需和其他进程的 virtual deadline 相比较,而直接被 BFS 调度器选取。

3.4 基本的调度场景

三个基本的 scenario 可以概括多数的调度情景。系统中发生的每一次调度都属于以下三种情景之一。

(1)进程 wakeup:Task Insertion

睡眠进程 wakeup 时,调度器需要执行 task insertion 的操作,将该进程插入到 run queue 中。BFS 将进程插入相应队列的操作就是执行一个双向队列的插入操作,计算机常用算法结构告诉我们,这个操作是 O(1) 的。不过,BFS 在执行插入操作之前需要首先查看当前进程是否可以抢占当前正在系统中运行的进程。因此它会用新进程的 virtual deadline 值和当前在每个 CPU 上正在运行的进程的 virtual deadline 值进行比较,如果新进程的值小,则直接抢占该 CPU 上正在运行的进程。这个算法是 O(m) 的,其中 m 是 CPU 的个数,假如系统中有 16 个 CPU,那么每次都需要进行 16 次比较。但这个设计却保证了非常好的 low-latency 特性。

(2)进程 Sleep

当前正在运行的进程有可能主动睡眠,此时,调度器需要将该进程从 run queue 中移除,并选择另外一个进程运行。但该进程的 virtual deadline 的值保持不变。

这样该进程 wakeup 时,其 virtual deadline 将相对较小,因为 jiffies 随着时间流逝而不断增加。较小的 Virtual Deadline 可以保证该进程能更快得到调度。

仍然以图 8 为例,系统中有两个进程,T1 和 T2,T1 进入 sleep 状态后其 virtual deadline 仍然为 t1。T2 此时被调度,根据公式一,计算得出其 virtual deadline 为 t2。此后,T1 进程 wakeup 了,此时虽然 T2 的时间片尚未用完,但由于 T1 的 virtual deadline 小于 T2 的,(t1<t2),因此 T1 立即得到调度。

(3)进程用完自己的时间片

每个进程都拥有自己的时间片,即使不被其他进程抢占,假如属于自己的时间片用完时,当前进程也一定会被剥夺 CPU 时间,以便让别的进程有机会执行。

当前进程的时间片用完后就必须让出 CPU, 此时将它的 virtual deadline 按照公式一重新计算。

这保证了一个特性:只有其他就绪进程都获得 CPU 之后,用完当前时间片的进程才可以再次得到运行,这避免了饥饿。

4. 评测

这是某些不够剽悍的读者会挣扎到最后的问题。BFS 原理上讲,机器配置越低,感受会越明显。如果你非要评测的话,Phoronix 这个专业的 Linux 测评狂网站也出了一份。我可以提前剧透结论,区别都很小,BFS 胜出绝大部分测试,然而优势不明显。我只是补充一下绝大多数折腾过的人的感受
——快 !人能感觉到的快!

5. 安装BFS

这里不应该叫做安装,下面叫你怎么使用BFS:

(1)下载kernel 源代码
(2)去:http://ck.kolivas.org/patches/bfs/下一个 patch,现在是 3.0 开头的,表示适用该版本。
(3)解压内核源码,打上 patch,配置以后编译安装。
编译的时候有什么需要配置的?不需要, Scheduler 这东西太底层了,打上补丁就把原来的 CFS 替换掉了,没什么选项给你选。如果你非要问的话,不就图个快么,记着把配置弄到 1000Hz,开 preempt ,禁掉 dynamic ticks。编译重启不用说了,我可以酷酷的扔下一个 have fun 然后去玩 Mac 了,反正你机器启动不了不要找我。虽然我纯净 kernel 单加 BFS Patch 编译成功启动没问题,依然有一位倒霉的推油编译以后不知道怎么折腾的无法启动。可另外被我忽悠成功的推友们反应一致:“快!人能感觉得到的快!”

Linux BFS简介的更多相关文章

  1. linux 文件系统简介

    linux文件系统简介   文件系统是linux的一个十分基础的知识,同时也是学习linux的必备知识. 本文将站在一个较高的视图来了解linux的文件系统,主要包括了linux磁盘分区和目录.挂载基 ...

  2. Linux 内核简介

    Linux内核简介 一.系统架构 (1). Linux系统架构 ##用户空间: 文件系统 C库 ##内核空间: 接口 内核 (2). Linux内核架构 二.Linux内核源代码 下载地址 www.k ...

  3. Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装

    原文:Linux内核分析(一)---linux体系简介|内核源码简介|内核配置编译安装 Linux内核分析(一) 从本篇博文开始我将对linux内核进行学习和分析,整个过程必将十分艰辛,但我会坚持到底 ...

  4. Linux基础学习(1)--Linux系统简介

    第一章——Linux系统简介 1.UNIX和Linux发展史: 1.1 unix发展史: (1)1965年,美国麻省理工学院(MIT).通用电气公司(GE)及AT&T的贝尔实验室联合开发Mul ...

  5. Linux内核分析——第一章 Linux内核简介

    第一章   Linux内核简介 一.Unix的历史 1.Unix系统成为一个强大.健壮和稳定的操作系统的根本原因: (1)简洁 (2)在Unix中,很多东西都被当做文件对待.这种抽象使对数据和对设备的 ...

  6. 2013337朱荟潼 Linux第一章读书笔记——Linux内核简介

    一.Unix历史 二.Linux足迹 类Linux系统.非商业化产品.用途广泛 三.操作系统和Linux内核简介 1.操作系统 (1)是指在整个最基本功能系统中负责完成最基本功能和系统管理的部分. ( ...

  7. 第一节 Linux系统简介

    一.Linux定义 Linux 是一个操作系统,就像你多少已经了解的 Windows(xp,7,8)和 Max OS. 操作系统在整个计算机系统中的角色: Linux 是系统调用和内核那两层,直观的来 ...

  8. Linux学习笔记-Linux系统简介

    Linux学习笔记-Linux系统简介 UNIX与Linux发展史 UNIX是父亲,Linux是儿子. UNIX发行版本 操作系统 公司 硬件平台 AIX IBM PowerPC HP-UX HP P ...

  9. Linux防火墙简介 – iptables配置策略

    Linux防火墙简介 – iptables配置策略 Netfilter/iptables简介 要想真正掌握Linux防火墙体系,首先要搞清楚Netfilter和iptables的关系,Netfilte ...

随机推荐

  1. 一个JAVA代码

    public class HelloJava { public static void main(String[] args) { System.out.println("这"); ...

  2. c++ 11 vs 98

    在求最长子字符串中题中要遍历个上万字符数据 1.使用c++11代码 for (auto ch : s) { auto ss = vsi[ch]; vsi[ch].insert(i); i++; } 2 ...

  3. CSS截取字符串

    /*溢出的字...处理*/ .updatecsssubstring { text-overflow: ellipsis; -o-text-overflow: ellipsis; white-space ...

  4. R与数据分析旧笔记(十七) 主成分分析

    主成分分析 主成分分析 Pearson于1901年提出的,再由Hotelling(1933)加以发展的一种多变量统计方法 通过析取主成分显出最大的个别差异,也用来削减回归分析和聚类分析中变量的数目 可 ...

  5. php数组使用技巧及操作总结

    数组,可以说是PHP的数据应用中较重要的一种方式.PHP的数组函数众多,下面是一些小结,借此记之,便于以后鉴之. 1. 数组定义 数组的定义使用 array()方式定义,可以定义空数组:<?ph ...

  6. 使用Qt 开发图形界面的软件(尘中远)

    3DSlicer, a free open source software for visualization and medical image computing AcetoneISO:镜像文件挂 ...

  7. jquery 使用ajax调用c#后台方法

    $.ajax({                         type: "get",                         cache: false,        ...

  8. Hive索引

    1.        Hive索引概述 Hive的索引目的是提高Hive表指定列的查询速度. 没有索引时.类似'WHERE tab1.col1 = 10' 的查询.Hive会载入整张表或分区.然后处理全 ...

  9. 为客户打造RAC-DG一些遇到的问题汇总

    昨日有建立一个客户RAC-DG物理备用数据库,这里的一般过程中再次列举一下,为了不涉及泄露隐私.的主要参数已被替换名称.详细路径也不一致.因为环境的客户端不与本机连接的网络同意,当故障不能削减各种报警 ...

  10. Linq to Sqlite连接

    本人还是挺喜欢用Sqlite,鼓捣半天终于连上了,赶紧记录一下 1.当然还是新建一个项目,还是winform, 2.Vs2012添加NoGet,点击工具--扩展和更新,搜索NoGet,安装. 3.管理 ...