设为首页 收藏本站
查看: 895|回复: 0

[经验分享] linux进程调度之 FIFO 和 RR 调度策略

[复制链接]
发表于 2015-12-9 15:51:26 | 显示全部楼层 |阅读模式
    作者:manuscola.bean@gmail.com

int sched_setscheduler (pid_t pid,
                        int policy,
                        const struct sched_param *sp);



     sched_setscheduler函数的第二个参数调度方法 :



  • #define SCHED_OTHER 0

  • #define SCHED_FIFO 1
  • #define SCHED_RR 2
  • #ifdef __USE_GNU
  • # define SCHED_BATCH 3
  • #endif
    SCHED_OTHER表示普通进程,对于普通进程,第三个参数sp->sched_priority只能是0
   SCHED_FIFO 和SCHED_RR表示实时进程的调度策略,第三个参数的取值范围为[1,99]。
   如果sched_setscheduler 优先级设置的值和调度策略不符合的话,会返回失败的。


   内核中有这么一段注释:


  • /*

  •      * Valid priorities for SCHED_FIFO and SCHED_RR are
  •      * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL,
  •      * SCHED_BATCH and SCHED_IDLE is 0.
  •      */
    LINUX系统提供了其他的系统调用来获取不同策略优先级的取值范围



  • #include

  • int sched_get_priority_min (int policy);
  • int sched_get_priority_max (int policy);



    另外需要指出的一点是,应用层和内核层的优先级含义是不同的:
   首先说实时进程:实时进程的优先级设置可以通过sched_setsheduler设置,也可以通过sched_setparam设置优先级的大小。

  • int sched_setparam (pid_t pid, const struct sched_param *sp);
    在用户层或者应用层,1表示优先级最低,99表示优先级最高。但是在内核中,[0,99]表示的实时进程的优先级,0最高,99最低。[100,139]是普通进程折腾的范围。应用层比较天真率直,就看大小,数字大,则优先级高。ps查看进程的优先级也是如此。有意思的是,应用层实时进程最高优先级的99,在ps看进程优先级的时候,输出的是139.


    下面是ps -C test -o pid,pri,cmd,time,psr 的输出:

  • PID   PRI  CMD             TIME     PSR

  • 6303 139 ./test 1 99  00:00:04       1
    虽说本文主要讲的是实时进程,但是需要插句话。对于普通进程,是通过nice系统调用来调整优先级的。从内核角度讲[100,139]是普通进程的优先级的范围,100最高,139最低,默认是120。普通进程的优先级的作用和实时进程不同,普通进程优先级表示的是占的CPU时间。深入linux内核架构中提到,普通优先级越高(100最高,139最低),享受的CPU time越多,相邻的两个优先级,高一级的进程比低一级的进程多占用10%的CPU,比如内核优先级数值为120的进程要比数值是121的进程多占用10%的CPU。


    内核中有一个数组:prio_to_weight[20]表示的是默认优先级120的权重,数值为1024,prio_to_weight[21]表示nice值为1,优先级为121的进程的权重,数值为820。这就到了CFS的原理了




  • static const int 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,
  • };

    假如有1台电脑,10个人玩,怎么才公平。
    1 约定好时间片,每人玩1小时,玩完后记账,张XX 1小时,谁玩的时间短,谁去玩
    2 引入优先级的概念,李四有紧急情况,需要提高他玩电脑的时间,怎么办,玩1个小时,记账半小时,那么同等情况下,李四会比其他人被选中玩电脑的频率要高,就体现了这个优先级的概念。
    3  王五也有紧急情况,但是以考察,不如李四的紧急,好吧,玩1个小时,记账45分钟。
    4  情况有变化,听说这里有电脑,突然又来了10个人,如果按照每人玩1小时的时间片,排在最后的那哥们早就开始骂人了,怎么办?时间片动态变化,根据人数来确定时间片。人越多,每个人玩的时间越少,防止哥们老捞不着玩,耐心耗尽,开始骂人。


    这个记账就是我们prio_to_weight的作用。我就不多说了,prio_to_weight[20]就是基准,玩一小时,记账一小时,数组20以前的值是特权一级,玩1小时记账20分钟之类的享有特权的,数组20之后是倒霉蛋,玩1小时,记账1.5小时之类的倒霉蛋。 CFS这种调度好在大家都能捞着玩。


    扯到优先级多说了几句,现在回到正题。我将上面的C程序编译成可执行程序test,然后写了一个脚本comp.sh。



  • [iyunv@localhost sched]# cat comp.sh
  • #/bin/sh


  • ./test $1 99 &
  • usleep 1000;
  • ./test $1 70 &
  • usleep 1000;

  • ./test $1 70 &
  • usleep 1000;

  • ./test $1 70 &
  • usleep 1000;

  • ./test $1 50 &
  • usleep 1000;
  • ./test $1 30 &
  • usleep 1000;
  • ./test $1 10 &
       因为test进程有sleep 2秒,所以可以给comp.sh启动其他test的机会。可以看到有 99级(最高优先级)的实时进程,3个70级的实时进程,50级,30级,10级的各一个。
      对于FIFO而言,一旦sleep过后,高优先级运行,低优先级是没戏运行的,同等优先级的进程,先运行的不运行完,后运行的也没戏。
     对于RR而言,高优先级的先运行,同等优先级的进程过家家,你玩完,我玩,我玩完你再玩,每个进程耗费一个时间片的时间。对于Linux,RR时间片是100ms:



  • #define DEF_TIMESLICE        (100 * HZ / 1000)
  
    下面我们验证: 我写了两个观察脚本,来观察实时进程的调度情况:


    第一个脚本比较简单,观察进程的CPU 占用的time,用ps工具就可以了:


  • [iyunv@localhost sched]# cat getpsinfo.sh
  • #!/bin/sh

  • for((i = 0; i < 40; i++))
  • do
  •     ps -C test -o pid,pri,cmd,time,psr >>psinfo.log 2>&1
  •     sleep 2;
  • done
    第二个脚本比较复杂是systemtap脚本,观察名字为test的进程相关的上下文切换,谁替换了test,或者test替换了谁,同时记录下test进程的退出:




  • [root@localhost sched]# cat cswmon_spec.stp


  • global time_offset
  • probe begin { time_offset = gettimeofday_us() }

  • probe scheduler.ctxswitch {
  •     if(next_task_name == "test" ||prev_task_name == "test")
  •     {
  •          t = gettimeofday_us()
  •          printf(" time_off (%8d )%20s(%6d)(pri=%4d)(state=%d)->%20s(%6d)(pri=%4d)(state=%d)\n",
  •                   t-time_offset,
  •                   prev_task_name,
  •                   prev_pid,
  •                   prev_priority,
  •                   (prevtsk_state),
  •                   next_task_name,
  •                   next_pid,
  •                   next_priority,
  •                   (nexttsk_state))
  •     }
  • }


  • probe scheduler.process_exit
  • {
  •     if(execname() == "test")
  •     printf("task :%s PID(%d) PRI(%d) EXIT\n",execname(),pid,priority);
  • }

  • probe timer.s($1) {
  •     printf("--------------------------------------------------------------\n")
  •         exit();
  • }
   


A)    FIFO调度策略的输出:


  • 终端1 :
  • stap ./cswmon_spec.stp 70

  • 终端2 :
  • ./getpsinfo.sh

  • 终端3
  • ./comp.sh 1
输出结果如下:
DSC0000.png



    99优先级跑完了,才轮到70优先级,但是虽说有3个70优先级,但是先跑的那个进程跑完了,第二个优先级为70的才能跑。因为输出结果用代码无法漂亮的展示,所以我截了图,截图又不能把这个输出都截下来,所以我很蛋疼。有需要结果的,我以附件形式附在最后。


    看下第二个脚本的输出:


  • time_off (  689546 )                test(  6305)(pri= 120)(state=0)->         migration/2(    11)(pri=   0)(state=0)
  • time_off (  689977 )                stap(  5895)(pri= 120)(state=0)->                test(  6305)(pri= 120)(state=0)
  • time_off (  690067 )                test(  6305)(pri=  29)(state=1)->                stap(  5895)(pri= 120)(state=0)
  • time_off (  697899 )                test(  6303)(pri= 120)(state=0)->         migration/2(    11)(pri=   0)(state=0)
  • time_off (  698042 )                test(  6307)(pri= 120)(state=0)->         migration/0(     3)(pri=   0)(state=0)
  • time_off (  699114 )                stap(  5895)(pri= 120)(state=0)->                test(  6303)(pri= 120)(state=0)
  • time_off (  699307 )                test(  6303)(pri=   0)(state=1)->                test(  6307)(pri= 120)(state=0)
  • time_off (  699371 )                test(  6307)(pri=  29)(state=1)->                stap(  5895)(pri= 120)(state=0)
  • time_off (  699392 )                test(  6309)(pri= 120)(state=0)->         migration/3(    15)(pri=   0)(state=0)
  • time_off (  699966 )            events/1(    20)(pri= 120)(state=1)->                test(  6309)(pri= 120)(state=0)
  • time_off (  700034 )                test(  6309)(pri=  29)(state=1)->                stap(  5895)(pri= 120)(state=0)
  • time_off (  707379 )                test(  6311)(pri= 120)(state=0)->         migration/3(    15)(pri=   0)(state=0)
  • time_off (  707587 )                test(  6313)(pri= 120)(state=0)->         migration/0(     3)(pri=   0)(state=0)
  • time_off (  712021 )                stap(  5895)(pri= 120)(state=0)->                test(  6311)(pri= 120)(state=0)
  • time_off (  712145 )                test(  6311)(pri=  49)(state=1)->                test(  6313)(pri= 120)(state=0)
  • time_off (  712252 )                test(  6313)(pri=  69)(state=1)->                stap(  5895)(pri= 120)(state=0)
  • time_off (  727057 )                test(  6315)(pri= 120)(state=0)->         migration/0(     3)(pri=   0)(state=0)
  • time_off (  727952 )                stap(  5895)(pri= 120)(state=0)->                test(  6315)(pri= 120)(state=0)
  • time_off (  728047 )                test(  6315)(pri=  89)(state=1)->                stap(  5895)(pri= 120)(state=0)
  • time_off ( 2690181 )                stap(  5895)(pri= 120)(state=0)->                test(  6305)(pri=  29)(state=0)
  • time_off ( 2699316 )                test(  6305)(pri=  29)(state=0)->                test(  6303)(pri=   0)(state=0)
  • task :test PID(6303) PRI(0) EXIT
  • time_off (13057854 )                test(  6303)(pri=   0)(state=64)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (13057864 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6305)(pri=  29)(state=0)
  • time_off (15333340 )                test(  6305)(pri=  29)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (15333354 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6305)(pri=  29)(state=0)
  • time_off (18743409 )                test(  6305)(pri=  29)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (18743422 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6305)(pri=  29)(state=0)
  • time_off (22154757 )                test(  6305)(pri=  29)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (22154771 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6305)(pri=  29)(state=0)
  • task :test PID(6305) PRI(29) EXIT
  • time_off (22466855 )                test(  6305)(pri=  29)(state=64)->                test(  6307)(pri=  29)(state=0)
  • time_off (25563548 )                test(  6307)(pri=  29)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (25563566 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6307)(pri=  29)(state=0)
  • time_off (28973602 )                test(  6307)(pri=  29)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (28973616 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6307)(pri=  29)(state=0)
  • task :test PID(6307) PRI(29) EXIT
  • time_off (31846121 )                test(  6307)(pri=  29)(state=64)->                test(  6309)(pri=  29)(state=0)
  • time_off (32383671 )                test(  6309)(pri=  29)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (32383683 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6309)(pri=  29)(state=0)
  • time_off (35793735 )                test(  6309)(pri=  29)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (35793747 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6309)(pri=  29)(state=0)
  • time_off (39203797 )                test(  6309)(pri=  29)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (39203809 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6309)(pri=  29)(state=0)
  • task :test PID(6309) PRI(29) EXIT
  • time_off (41200440 )                test(  6309)(pri=  29)(state=64)->                test(  6311)(pri=  49)(state=0)
  • time_off (42613866 )                test(  6311)(pri=  49)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (42613898 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6311)(pri=  49)(state=0)
  • time_off (46024070 )                test(  6311)(pri=  49)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (46024082 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6311)(pri=  49)(state=0)
  • time_off (49434004 )                test(  6311)(pri=  49)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (49434017 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6311)(pri=  49)(state=0)
  • task :test PID(6311) PRI(49) EXIT
    可以清楚的可到,同样是70优先级(内核态是29),6305退出以前,6307根本就捞不着跑。同样6307退出一样,6309根本就捞不着跑。这就是FIFO。


B) RR的情况



  • 终端1 :
  • stap ./cswmon_spec.stp 70

  • 终端2 :
  • ./getpsinfo.sh

  • 终端3
  • ./comp.sh 1
DSC0001.png




    实时优先级是70的三个进程齐头并进。再看第二个脚本的输出:



  • time_off ( 4188015 )                test(  6428)(pri=   0)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off ( 4188025 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6428)(pri=   0)(state=0)
  • time_off ( 7612014 )                test(  6428)(pri=   0)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off ( 7612024 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6428)(pri=   0)(state=0)
  • task :test PID(6428) PRI(0) EXIT
  • time_off (10679062 )                test(  6428)(pri=   0)(state=64)->                test(  6430)(pri=  29)(state=0)
  • time_off (10964413 )                test(  6430)(pri=  29)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (10964422 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6430)(pri=  29)(state=0)
  • time_off (11709024 )                test(  6430)(pri=  29)(state=0)->                test(  6432)(pri=  29)(state=0)
  • time_off (12736030 )                test(  6432)(pri=  29)(state=0)->                test(  6434)(pri=  29)(state=0)
  • time_off (13779022 )                test(  6434)(pri=  29)(state=0)->                test(  6430)(pri=  29)(state=0)
  • time_off (13879021 )                test(  6430)(pri=  29)(state=0)->                test(  6432)(pri=  29)(state=0)
  • time_off (13984075 )                test(  6432)(pri=  29)(state=0)->                test(  6434)(pri=  29)(state=0)
  • time_off (14084020 )                test(  6434)(pri=  29)(state=0)->                test(  6430)(pri=  29)(state=0)
  • time_off (14184023 )                test(  6430)(pri=  29)(state=0)->                test(  6432)(pri=  29)(state=0)
  • time_off (14284024 )                test(  6432)(pri=  29)(state=0)->                test(  6434)(pri=  29)(state=0)
  • time_off (14374486 )                test(  6434)(pri=  29)(state=0)->          watchdog/1(    10)(pri=   0)(state=0)
  • time_off (14374502 )          watchdog/1(    10)(pri=   0)(state=1)->                test(  6434)(pri=  29)(state=0)
  • time_off (14384097 )                test(  6434)(pri=  29)(state=0)->                test(  6430)(pri=  29)(state=0)
  • time_off (14484066 )                test(  6430)(pri=  29)(state=0)->                test(  6432)(pri=  29)(state=0)
  • time_off (14584023 )                test(  6432)(pri=  29)(state=0)->                test(  6434)(pri=  29)(state=0)
  • time_off (14684020 )                test(  6434)(pri=  29)(state=0)->                test(  6430)(pri=  29)(state=0)
  • time_off (14786032 )                test(  6430)(pri=  29)(state=0)->                test(  6432)(pri=  29)(state=0)
  • time_off (14886020 )                test(  6432)(pri=  29)(state=0)->                test(  6434)(pri=  29)(state=0)
  • time_off (14986026 )                test(  6434)(pri=  29)(state=0)->                test(  6430)(pri=  29)(state=0)
  • time_off (15089023 )                test(  6430)(pri=  29)(state=0)->                test(  6432)(pri=  29)(state=0)
  • time_off (15192030 )                test(  6432)(pri=  29)(state=0)->                test(  6434)(pri=  29)(state=0)
  • time_off (15292026 )                test(  6434)(pri=  29)(state=0)->                test(  6430)(pri=  29)(state=0)
  • time_off (15396085 )                test(  6430)(pri=  29)(state=0)->                test(  6432)(pri=  29)(state=0)
  • time_off (15496022 )                test(  6432)(pri=  29)(state=0)->                test(  6434)(pri=  29)(state=0)
  • time_off (15596027 )                test(  6434)(pri=  29)(state=0)->                test(  6430)(pri=  29)(state=0)
  • time_off (15696153 )                test(  6430)(pri=  29)(state=0)->                test(  6432)(pri=  29)(state=0)
  • time_off (15796022 )                test(  6432)(pri=  29)(state=0)->                test(  6434)(pri=  29)(state=0)
    用户态实时优先级为99,内核态优先级为0的进程6428退出后,3个用户态实时优先级为70的进程6430,6432,6434你方唱罢我登场,每个人都"唱"多久呢?看相邻2条记录的时间差,基本都在100ms左右,这就是时间片。


    后记:如果放开绑定到一个CPU的限制,同时加大实时进程的个数,多个实时进程在CPU之间PULL和PUSH,是更复杂的情况,呵呵,希望抛砖引玉,能有人模拟下这种情况。


    附件为测试代码及输出:
    study_sched.txt   




参考文献
1 深入linux 内核架构
2 linux system program
3 systemtap example

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-148877-1-1.html 上篇帖子: linux内核模块之间互相调用对方模块的变量的问题 下篇帖子: linux 音频编程
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表