Aaron's Space

Digital TV
posts - 1, comments - 0, trackbacks - 0, articles - 1

2009年4月11日

 

Linux 内核笔记进程调度

关键词 Linux    内核    进程调度                                          

Linux 内核笔记进程调度

原文链接:

http://www.linuxforum.net/forum/showthreaded.php?Cat=&Board=linuxK&Number=294463&page=5&view=collapsed&sb=5&o=all

刘世胜


Linux
内核笔记进程调度

1      前言
2     
调度算法
2.1.1       
常用概念
2.1.2       
进程数据结构中相关内容
2.1.3       
调度算法说明
2.1.4       
相关函数
3     
调度程序的执行
3.1.1       
直接调用
3.1.2       
延迟调用
3.1.3       
相关函数
4     
进程调度示意图
5      SMP
系统的调度
6     
问题与答案
7     
参考文献

1        前言
本文的许可协议遵循GNU Free Document License。协议的具体内容请参见http://www.gnu.org/copyleft/fdl.html。在遵循GNU Free Document License的基础上,可以自由地传播或发行本文,但请保留本文的完整性。
欢迎大家对这篇文章提出意见和指正,我的email是:shisheng_liu@yahoo.com.cn

2        调度算法
2.1.1       
常用概念
2.1.1.1           
定时中断
   
通过硬件的可编程中断控制器8254来实现,定时中断发生的频率由HZ定义,发生的时间间隔被称为tick
2.1.1.2            CPU
节拍(tick
计算机内部时间的一个计数单位,表示发生一次时钟中断的时间间隔。
2.1.1.3            HZ
 
时钟中断发生的频率。在i386机器上,HZ被定义为100,因此时钟中断每10ms一次。
2.1.1.4            CPU
时期
     
调度是以CPU时期为周期的,在一个CPU时期/调度周期内,系统中所有程序都被执行直到用完当前的时间片,然后所有进程的counter值被重新计算,并开始另一个CPU时期。
2.1.1.5           
进程的分类
在调度程序看来,系统中的进程分为两大类,分别是实时进程和普通进程。在任何时候实时进程的执行都高于普通进程。进程数据结构中的policy成员变量表示了进程是哪一类,而sched_set(/get)scheduler提供了控制进程调度policy的用户级编程接口。
2.1.2       
进程数据结构中相关内容
2.1.2.1               1
nice
   
进程的优先级,影响进程获得CPU事件的多少,20为最低,-19为最高。
2.1.2.2            2
counter
 
进程时间片所剩余的CPU节拍数。初始值根据进程的nice值决定,在每次时钟中断发生时,也就是一个CPU节拍(tick)的时候,当前进程的counter值减1,如果counter值变为0则表示当前进程的时间片已经用完,系统会重新调度,决定下一个执行的进程。
2.1.2.3            3
need_resched
 
标志位。该位在从中断和系统调用中返回的时候被检查,need_resched1的时候表示要求启动调度程序,这通常发生在进程的时间片已经用完,或者因为IO事件发生而强行抢占当前进程的时候。
2.1.2.4            4
policy
 
进程的调度策略。如果调度策略为SCHED_RR或者SCHED_FIFO则表示当前进程为实时进程,否则(SCHED_OTHER)为普通进程。
2.1.3       
调度算法说明
Linux
采用相当简单但实际证明效果不错的调度算法。在调度的时候,所有正在运行进程的执行权值(goodness)都被计算,最终权值最高的进程获得执行的机会。假设得到的最大权值为0,就认为本次CPU时期已经执行完毕,会重新计算所有进程的counter值,开始新的CPU时期。调度算法的核心就是goodness的计算,计算的基本思路如下:
如果等待调度的进程是实时进程,它的goodness1000 + 本身的优先级,而普通进程的goodness远小于1000,这就保证了实时进程总是优先于普通进程执行。
 
如果进程剩余的counter0,就认为它已经用光了自己在该时期的CPU时间片,goodness返回0
 
对于其他的情况,用下面的公式来计算goodness:
goodness = counter + 20 – nice

2.1.4       
相关函数
1
schedule()  in kernel/sched.c
主调度函数,选择要运行的进程
2
goodness() in kernel/sched.c
schedule()调用,计算进程的执行权值
3       
调度程序的执行
可以通过两种方式来激活调度程序,分别是直接调用和延迟调用。
3.1.1       
直接调用
  
current进程准备主动放弃CPU的时候,它会直接调用调度程序schedule(),将CPU让给另一个进程。
促使current进程主动放弃CPU的原因有两种,一种情况是current需要睡眠(阻塞)来等待所需的资源准备好,此时current的状态被设置为TASK_INTERRUPTABLETASK_UNINTERRUPTABLE,在调用schedule()后进程进入睡眠状态;另一种情况下进程设置SCHED_YIELD的调度策略,然后用schedule(),此时进程只是短暂的放弃CPU,在下一次schedule()被调用的时候进程会继续参与CPU的竞争。
3.1.2       
延迟调用
通过设置当前进程的need_resched标志来在其后的某个时刻激活调度程序。前面说过,在从中断/异常/系统调用中返回时,need_resched标志被检查,在标志不为0的时候会激活调度程序。例如:当时钟中断发生时,中断处理程序检查到当前进程的时间片已经执行完毕,它就会设置当前进程的need_resched标志;另一个例子是当某个IO中断发生时,中断处理程序发现有进程在等待该IO事件,它会将正在等待的进程的状态变为执行态,并设置当前进程的need_resched标志。当中断处理程序结束[1],系统会重新调度,在这种情况下,新转入执行态的进程很可能会获得执行机会,从而使系统保持对IO事件的快速响应。
[
1]:如果当前进程运行在内核态,即正在执行系统调用过程中,重新调度会延迟到当前进程的系统调用执行完毕才进行。
3.1.3       
相关函数
  1
wake_up_common() in kernel/sched.c
  
激活IO等待队列中的进程,它会顺序调用try_to_wake_up()reschedule_idle()等函数来要求对进程进程重新调度。
  2
do_timer() in kernel/timer.c
  
定时时钟中断程序,减少当前进程的counter值,如果counter已经用完,则设置进程的need_resched域要求重新调度。
  3
ret_from_intr/sys_call/exception   in arch/i386/entry.S
 
汇编语言中的程序点,在从中断/异常/系统调用中返回时都会执行这一段程序,检查当前进程的need_resched域,如果不为0就会激活schedule()重新调度。

4        进程调度示意图
linux
的进程调度如图1所示。

 
5        SMP
系统的调度
SMP
系统中的调度算法的不同主要表现在调度算法的最后,对于被切换出当前CPU运行权的进程调用了schedule_tail函数,目的是看能够将它转移到另一个CPU中运行。

6        问题与答案
Q
.在当前系统下,调度时间片的长度是多少?
A.
2.2.x版的内核相比,kernel2.4.x的时间片长度缩短了,对于最高优先级的进程来说,时间片的长度为100ms,默认优先级进程的时间片长度为60ms,而最低优先级进程的时间片长度为10ms
Q. Linux
如何保证对I/O事件相对比较快的响应速度,这个响应速度是否与调度时间片的长短有关?
A
.当I/O事件发生的是时候,对应的中断处理程序被激活,当它发现有进程在等待这个I/O事件的时候,它会激活等待进程,并且设置当前正在执行进程的need_resched标志,这样在中断处理程序返回的时候,调度程序被激活,原来在等待I/O事件的进程(很可能)获得执行权,从而保证了对I/O事件的相对快速响应(毫秒级)。
   
从上面的说明可以看出,在I/O事件发生的时候,I/O事件的处理进程会抢占当前进程,系统的响应速度与调度时间片的长度无关。
Q
.高优先级(nice)进程和低优先级进程在执行上有何区别?例如一个优先级为-19(最高优先级)的进程和优先级为20(最低)的进程有何区别
A.
进程获得的CPU时间的绝对数目取决于它的初始counter值,初始的counter的计算公式(sched.c in kernel 2.4.14)如下:
p->counter = (p->counter >> 1) + ((20 - p->nice) >> 2) +1)
由公式可以计算出,对于标准进程(p->nice 0), 得到的初始counter6,即进程获得的时间片为60ms
最高优先级进程(nice-19)的初始counter值为10,进程的时间片为100ms
最低优先级进程(nice20)的初始counter值为1,进程时间片为10ms
 
结论是最高优先级进程会获得最低优先级进程10倍的执行时间,普通优先级进程接近两倍的执行时间。当然,这是在进程不进行任何IO操作的时候的数据,在有IO操作的时候,进程会经常被迫睡眠来等待IO操作的完成,真正所占用的CPU时间是很难比较的。
我们可以看到每次重新计算counter的时候,新的counter值都要加上它本身剩余值的一半,这种奖励只适用于通过SCHED_YIELD主动放弃CPU的进程,只有它在重新计算的时候counter值没有用完,所以在计算后counter值会增大,但永远不可能超过20
Q
.进程是否可能在执行系统调用的过程中被抢占?
A
.进程在执行系统调用的过程中不会被抢占。让我们设想进程a正在执行的过程中发生中断,而中断处理程序判断出系统需要被重新调度,它会设置进程aneed_resched标志(need_resched标志的作用参见前面说明),在中断处理程序结束之后(ret_from_intr),系统会检查被中断处理程序中断执行的进程的优先级,如果此时进程a处在用户态,系统会直接激活调度程序完成进程切换;而如果此时进程a处在内核态,系统会不作调度而恢复进程a的执行,只有进程a完成系统调用之后(ret_from_sys_call),它的need_resched标志才会被检查,从而完成进程切换。
进程在内核态不会被抢占的特点减少了单CPU系统中内核设计的复杂性,因为不需要考虑不同进程对内核代码和数据结构的竞争。

7        参考文献
1
  Linux内核源代码版本2.4.14
在任何时候真实的代码总是提供给我们最准确和详细的资料。感谢Linus TorvaldsAlan Cox和其它linux开发者的辛勤劳动。
2
DANIEL P.BOVET & MARCO CESATI
  <> ISBN: 0-596-00002-2  O’REILLY 2001
 
中译版 《深入理解Linux内核》 陈莉君等译 ISBN: 7-5083-0719-4 中国电力出版社 2001
本书是专门介绍linux内核结构的书中最详尽的一本,对代码分析讲解的也比较深入,基于2.2的内核版本
3
W.Richard Stevens
 
UNIX环境高级编程》 尤晋元译 ISBN: 7-111-07579-X   机械工业出版社 2000
  UNIX
编程圣经,程序员手头必备的书籍之一,对所有UNIX开发人员,无论水平高低,都有参考价值。翻译的水准也难得一见的高明。

 

posted @ 2009-04-11 23:20 Aaron@SMiT 阅读(337) | 评论 (0)编辑 收藏