HACK #8 调度策略

本节介绍Linux的调度策略(scheduling policy)。
Linux调度策略的类别大致可以分为TSS(Time Sharing System,分时系统)和实时系统这两种。
一方面,一般的进程是通过分时运行的。也就是说,使用CPU的时间达到分配给进程的时间(时间片)时,就会切换到其他进程。这种分时运行的调度策略称为TSS。
另一方面,在实时制约较严格且要求保证实时的处理中,就需要指定静态的执行优先级,并严格按照执行优先级进行调度。对这种对应答性有要求的进程,可以使用实时调度策略。另外,与TSS调度策略的进程相比,CPU将优先分配给使用实时调度策略的进程。
在Linux中,进程的静态优先级为0~99。TSS调度策略的优先级为0,实时调度策略的优先级可以指定的范围为1~99。
Linux 2.6.23以前一直采用的O(1)调度程序,还会在TSS调度策略中添加动态优先级。长时间持续使用CPU的进程,其调度的动态优先级会渐渐降低。Linux的进程调度程序是按照优先级来分配CPU的,因此长时间占用CPU的进程优先级与其他进程相比就相对较低。与之相对的是,频繁与用户进行交流的shell等对话进程由于CPU使用时间短,其调度的优先级变高,更容易分配到CPU。因此,为等待用户输入而立刻腾出CPU的shell进程的优先级变得比其他进程高,用户的应答性就得到提高。
在Linux 2.6.23导入的CFS(Completely Fair Scheduler)调度程序中,没有之前的O(1)调度程序所进行的经验性优先级变化。CFS通过称为公平的CPU时间分配的结构来运行。
调度策略
RHEL6(Linux 2.6.32)中定义了下列调度策略。

SCHED_OTHER
SCHED_FIFO
SCHED_RR
SCHED_BATCH
SCHED_IDLE

下面将分别对各调度策略进行介绍。

SCHED_OTHER

这是Linux的标准调度策略,也是所谓TSS调度策略。
在RHEL5等Linux 2.6.23之前的内核所使用的以优先级为基础的O(1)调度程序中,还加入了经验性的判断,优先为会话进程赋予执行权。TSS的时间片由优先级决定。
在RHEL6等Linux 2.6.23之后的CFS中,会公平地为所有TSS策略的进程分配CPU时间。其时间片是动态决定的。

SCHED_FIFO

这是实时调度策略,即具有静态优先级的调度策略。Linux内核中能够为实时调度策略的进程指定的优先级为1~99。使用了SCHED_FIFO调度策略的进程,除了等待I/O完成时休眠、自发休眠或优先级更高的实时进程获得优先权以外,不会释放执行权。
使用SCHED_FIFO的实时调度策略时,需要注意的是,它的进程不会自动释放CPU,也就是说执行权不会转移到其他进程。例如,实时调度策略的进程陷入无限循环时,其他所有优先级较低的进程永远不会被赋予执行权,此时系统就会死机。
小贴士:另外,要对进程使用实时调度策略,必须有root权限。

SCHED_RR

这也是实时调度策略。RR是round robin(轮询)的缩写,与SCHED_FIFO不同的是,它具有时间片。时间片使用完时,执行权将转移到其他进程。
在2.6.23以前导入的O(1)调度程序中,时间片是由优先级决定的。
引入CFS时SCHED_RR的调度策略也进行了修改,时间片变为固定值(100毫秒)。

SCHED_BATCH

指定这个调度策略的进程不是会话型,不会根据休眠时间更改优先级。
例如,备份处理等需要进行较大文件或大量文件存取的进程,是通过磁盘I/O来中止的。在TSS调度策略中,因为这个休眠,正在进行备份处理的进程优先级提高,需要应答性的shell等的优先级相对降低。这就会导致系统的应答性降低。
在RHEL5的O(1)调度程序中,使用了这个调度策略的进程被识别为休眠时间为0的CPU bound进程。因此,优先级必然会变成比会话型shell进程低。
对非会话型的进程(即所谓的补丁处理)使用这个调度策略,就可以使会话型进程的优先级保持相对较高,并确保应答性。
在Linux 2.6.23导入的CFS中,对进行补丁处理的进程改变了处理的方法,优先级不会因休眠时间而发生变化。在导入CFS的RHEL6中,SCHED_BATCH和SCHED_OTHER几乎没有区别,因此可以不使用。

SCHED_IDLE

这是由CFS导入的新等级。CPU空闲时,即SCHED_IDLE等级以外处于可执行状态的进程消失时,将被赋予执行权。也就是它将成为优先级最低的进程。
特殊标志:SCHED_RESET_ON_FORK
为了限制实时调度策略的进程运行,而为调度策略添加了标志flag。设置了标志flag的实时调度策略进程,在执行fork()时,新生成的子进程就成为SCHED_OTHER策略的进程。
如下例所示,通过向实时调度策略添加标志flag来设置。

sched_setscheduler(pid, SCHED_FIFO|SCHED_RESET_ON_FORK, &param);

关于调度策略的系统调用
关于调度策略的系统调用如下所示。

sched_setscheduler()

更改调度策略和进程优先级。

sched_getscheduler()

获取当前调度策略与进程优先级。

sched_setparam()

更改调度参数(即进程优先级)。

sched_getparam()

获取当前调度参数。

sched_get_priority_max()
sched_get_priority_min()

获取调度策略的进程的静态优先级范围。

sched_rr_get_interval()

获取当前时间片。
chrt命令
用户使用chrt命令可以很简单地更改调度策略。RHEL5版本的chrt命令中不存在指定SCHED_IDLE的-i选项。
在CentOS5(RHEL5)中chrt的使用方法如下所示。

$ chrt --help
chrt (util-linux 2.13-pre7)
usage: chrt [options] [prio] [pid | cmd [args...]]
manipulate real-time attributes of a process
-b, --batch set policy to SCHED_BATCH
-f, --fifo set policy to SCHED_FF
-p, --pid operate on existing given pid
-m, --max show min and max valid priorities
-o, --other set policy to SCHED_OTHER
-r, --rr set policy to SCHED_RR (default)
-h, --help display this help
-v, --verbose display status information
-V, --version output version information

下面是Fedora 12(RHEL6)中chrt的使用方法。

$ chrt --help

chrt - manipulate real-time attributes of a process.

Set policy:
chrt [options] <policy> <priority> {<pid> | <command> [<arg> ...]} Get policy:
chrt [options] {<pid> | <command> [<arg> ...]} Scheduling policies:
-b | --batch set policy to SCHED_BATCH
-f | --fifo set policy to SCHED_FIFO
-i | --idle set policy to SCHED_IDLE
-o | --other set policy to SCHED_OTHER
-r | --rr set policy to SCHED_RR (default) Options:
-h | --help display this help
-p | --pid operate on existing given pid
-m | --max show min and max valid priorities
-v | --verbose display status information
-V | --version output version information

使用chrt命令,可以更改进程的调度策略和优先级。例如,使用SCHED_IDLE解压缩内核源代码存档时的命令行如下所示。

$ chrt -i o tar jxf linux-2.6.33.tar.bz2

正在运行的进程的调度策略也可以通过指定目的进程的PID来更改。

# chrt -p -r 99 <pid>

另外,使用实时调度策略,必须具有root权限。
小结
本节介绍了可以使用Linux进程调度程序指定的调度策略。可以尝试修改对备份处理和要求实时性的进程的调度策略。
参考文献
CFS
http://www.ibm.com/developerworks/jp/linux/library/l-cfs/?ca=dnj-0208
man sched_setscheduler他
http://www.linux.or.jp/JM/html/LDP_man-pages/man2/sched_setscheduler.2.html
—Hiroshi Shimamoto

精《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #8 调度策略的更多相关文章

  1. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #1 如何获取Linux内核

    HACK #1 如何获取Linux内核 本节介绍获取Linux内核源代码的各种方法.“获取内核”这个说法看似简单,其实Linux内核有很多种衍生版本.要找出自己想要的源代码到底是哪一个,必须首先理解各 ...

  2. 《Linux内核精髓:精通Linux内核必会的75个绝技》目录

    1章 内核入门HACK #1 如何获取Linux内核HACK #2 如何编译Linux内核HACK #3 如何编写内核模块HACK #4 如何使用GitHACK #5 使用checkpatch.pl检 ...

  3. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #15 ramzswap

    HACK #15 ramzswap 本节介绍将一部分内存作为交换设备使用的ramzswap.ramzswap是将一部分内存空间作为交换设备使用的基于RAM的块设备.对要换出(swapout)的页面进行 ...

  4. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #3 如何编写内核模块

    HACK #3 如何编写内核模块 本节将介绍向Linux内核中动态添加功能的结构—内核模块的编写方法.内核模块Linux内核是单内核(monolithic kernel),也就是所有的内核功能都集成在 ...

  5. 精《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #7 Cgroup、Namespace、Linux容器

    HACK #7 Cgroup.Namespace.Linux容器 本节将介绍Cgroup与Namespace以及通过这两个功能实现的容器功能.CgroupCgroup(control group)是将 ...

  6. 精《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #5 使用checkpatch.pl检查补丁的格式

    HACK #5 使用checkpatch.pl检查补丁的格式 本节介绍发布前检查补丁格式的方法.Linux内核是由多个开发者进行开发的.因此,为了保持补丁评估与源代码的可读性,按照统一的规则进行编写是 ...

  7. 精《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #4 如何使用Git

    HACK #4 如何使用Git 本节介绍Git的使用方法.Git是Linux内核等众多OSS(Open Source Software,开源软件)开发中所使用的SCM(Source Code Mana ...

  8. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #21FUSE

    HACK #21FUSE 本节将介绍使用用户进程的文件系统框架—FUSE.FUSE概要FUSE(Filesystem in Userspace,用户空间文件系统),是用来生成用户空间的一般进程的框架. ...

  9. 《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #20 使用fio进行I/O的基准测试

    HACK #20 使用fio进行I/O的基准测试 本节介绍使用fio进行模拟各种情况的I/O基准测试的操作方法.I/O的基准测试中有无数需要考虑的因素.是I/O依次访问还是随机访问?是通过read/w ...

随机推荐

  1. linuxI/O重定向

    假设有这么一段python3程序: import sys ")sys.stderr.write("stderr1 ") 现在想要把程序的输出以及错误信息都存在文件中. 一 ...

  2. [原]visual studio 将(无扩展名)文件以某种(C++)方式阅读(映射)

    工具 选项 文本编辑器 文件扩展名 选择“将无扩展····”后面设置一下就可以

  3. C# 字符串与字节数组相互转换

    https://www.cnblogs.com/xiaoqingshe/p/5882601.html

  4. UVA-307 Sticks (DFS+剪枝)

    题目大意:用n根长度未必相等的木棒匹配出最多数量的等长木棒. 题目分析:枚举所有可能的等长木棒的长度,通过DFS的方式逐根匹配,在此过程中要剪枝.先将木棒长度按从大到小排序,也就是说匹配每一根等长木棒 ...

  5. ASP.NET常用的指令

    指令的类型 指令 说明 Application 配置全局应用程序类 Assembly 注册用在Web窗体中的程序集.建议不使用此指令.而是NuGet. Control 配置用户控件 Implement ...

  6. java并发编程:线程安全管理类--原子操作类--AtomicIntegerFieldUpdater<T>

    1.类 AtomicIntegerFieldUpdater<T> public abstract class AtomicIntegerFieldUpdater<T> exte ...

  7. 条件查询、SQL、JPQL、HQL比较

    一.什么是JPQL 在 Java EE 中,JPQL( Java 持久性查询语言)是专门为Java 应用程序访问和导航实体实例设计的.JPQL是EJB2使用的查询语言EJB QL的扩展,它继承了EJB ...

  8. Python3 条件控制(九)

    Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. 可以通过下图来简单了解条件语句的执行过程: if 语句 Python中if语句的一般形式如下所示: i ...

  9. javascript: 数据类型深入理解

    1.基本类型(值类型或者原始类型): Number.Boolean.String.NULL.Undefined以及ES6的Symbol2.引用类型:Object.Array.Function.Date ...

  10. 代码控制 textarea 控件是否为KindEditor 编辑框

    <script charset="utf-8" src="<%:Url.Content("~/UI/Scripts/KindEditor/kinde ...