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

时间:2021-09-08 23:46:16

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