Chinaunix首页 | 论坛 | 博客
  • 博客访问: 712165
  • 博文数量: 31
  • 博客积分: 330
  • 博客等级: 一等列兵
  • 技术积分: 3004
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-05 22:38
个人简介

java开发工程师,专注于内核源码,算法,数据结构。 qq:630501400

文章分类
文章存档

2014年(2)

2013年(22)

2012年(7)

分类: C/C++

2013-03-13 23:35:15


     CFS调度器选择vruntime最小的任务来进行调度,在更新vruntime的时候一个是要考虑当前时间和上次更新vruntime的时间差,二是要加权计算sched_entityloadload的值依赖于当前sched_entitynice值,在内核中这个niceload的对应关系事先已经被计算好。

           

  1. static const int prio_to_weight[40] = {
  2.     /* -20 */ 88761, 71755, 56483, 46273, 36291,
  3.     /* -15 */ 29154, 23254, 18705, 14949, 11916,
  4.     /* -10 */ 9548, 7620, 6100, 4904, 3906,
  5.     /* -5 */ 3121, 2501, 1991, 1586, 1277,
  6.     /* 0 */ 1024, 820, 655, 526, 423,
  7.     /* 5 */ 335, 272, 215, 172, 137,
  8.     /* 10 */ 110, 87, 70, 56, 45,
  9.     /* 15 */ 36, 29, 23, 18, 15,
  10. };



这些值的取值原因自己也没有搞清楚,看了注释大概明白。


  1. /*
  2. * Nice levels are multiplicative, with a gentle 10% change for every
  3. * nice level changed. I.e. when a CPU-bound task goes from nice 0 to
  4. * nice 1, it will get ~10% less CPU time than another CPU-bound task
  5. * that remained on nice 0.
  6. *
  7. * The "10% effect" is relative and cumulative: from _any_ nice level,
  8. * if you go up 1 level, it's -10% CPU usage, if you go down 1 level
  9. * it's +10% CPU usage. (to achieve that we use a multiplier of 1.25.
  10. * If a task goes up by ~10% and another task goes down by ~10% then
  11. the relative distance between them is ~25%.)



     大概的意思就是nice值的上升1级(越小执行优先级越高),也就意味着sched_entity的运行时间会减少。规定这个减少的幅度是10%,这个差距导致了两个sched_entityload大概差了1.25倍,例子:两个sched_entity具有相同的nice,也就是各占50%cpu时间,其中一个nice上升,导致了这个sched_entity cpu时间比之前少了10%,也就是一个sched_entity55%,一个是45%,所以这个时候5545大概差了1.25倍。

这样就有了 prio_to_weight数组。

还有数组,每个元素的值是1>>32/prio_to_weight每个元素的值。

            

  1. /*
  2. * Nice levels are multiplicative, with a gentle 10% change for every
  3. * nice level changed. I.e. when a CPU-bound task goes from nice 0 to
  4. * nice 1, it will get ~10% less CPU time than another CPU-bound task
  5. * that remained on nice 0.
  6. *
  7. * The "10% effect" is relative and cumulative: from _any_ nice level,
  8. * if you go up 1 level, it's -10% CPU usage, if you go down 1 level
  9. * it's +10% CPU usage. (to achieve that we use a multiplier of 1.25.
  10. * If a task goes up by ~10% and another task goes down by ~10% then
  11. the relative distance between them is ~25%.)


      这个数组的存在的意义很大,因为在更新vruntime的时候,时间差需要加权load,当nice=0表示不需要加权load计算。如果nice=0那么需要按照当前的loadnice=0loadnice=0load=1024)的比例进行等比例缩减或者增加vruntime

公式如下:

delta vruntime= deltaTime*1024/load (1024nice=0的时候)


      这里delta vruntimevruntime的差值。deltaTime就是当前时间和上次计算的load的时间差,load就是当前sched_entityload值,通过上面的公式可以看出,如果load越大,vruntime越小,cfs会通过红黑树选择出最需要调度的sched_entity,也就是vruntime最小的。

      但是内核中会频繁统计这个delta vruntime,我们知道运算中,除法的运行周期十分长,这样就导致了计算delta vruntime会很慢。那么这个除法可以用乘法和位移运算来代替。

      可以看出公式中,利用到了inv_load数组,这个数组事先缓存好了的值,然后最后结果在右移32位就是结果。

代码中,我想了很久才明白的一行代码:

      

  1. /*
  2.         * Shift right and round:
  3.         */
  4.         #define SRR(x, y) (((x) + (1UL << ((y) - 1))) >> (y))


     注释的意思是,x右移y位,相当于然后结果,四舍五入。

     可以知道1UL<<(y-1)相当于1<的一半,对于一个位移操作,相当于除法取整的操作。话语很难表述清楚这个x+1UL << ((y) – 1))的作用,举例说明一下:

     SRR (10,2) 也就是10/41010+0010=1100 >>2=0011=3

     SRR (9,2) 就是9/41001+0010=1010>>2=0010=2

     看了上面的例子也就清楚了,1UL<<(y-1)作用于y-1位(右边第一位是0位),如果为y-1位为1,就是产生了5入的情况,需要1UL<<(y-1)来帮助它进位,不被位移操作抵销掉。如果y-1位为0,那么也就是产生了4舍的情况,1UL<<(y-1)对它来说都是没有任何作用的,因为不会产生进位操作。

     所以这个(1UL << ((y) – 1))SRR操作能四舍五入的根本原因。

     看下代码:

 

  1. static unsigned long calc_delta_mine(unsigned long delta_exec, unsigned long weight,struct load_weight *lw){
  2.         u64 tmp;
  3.         
  4.         if (!lw->inv_weight) { //如果inv_load为0,设置一个最小的inv_load为1,因为weight超过了1>>32,那么按原有逻辑得到的inv_load肯定是0,后面的乘法没有意义了。
  5.                 if (BITS_PER_LONG > 32 && unlikely(lw->weight >= WMULT_CONST))
  6.                         lw->inv_weight = 1;
  7.                 else
  8.                         lw->inv_weight = 1 + (WMULT_CONST-lw->weight/2) / (lw->weight+1);//这个逻辑不太清楚
  9.         }

  10.         tmp = (u64)delta_exec * weight;
  11.     /*
  12.     * Check whether we'd overflow the 64-bit multiplication:
  13.     */

  14.         if (unlikely(tmp > WMULT_CONST)) //如果tmp结果大于了32位整数的限制,那么在乘以inv_load会产生overflow,那么处理逻辑可以先位移一半16位,再位移后一半16位
  15.                 tmp = SRR(SRR(tmp, WMULT_SHIFT/2) * lw->inv_weight,WMULT_SHIFT/2);
  16.         else
  17.                 tmp = SRR(tmp * lw->inv_weight, WMULT_SHIFT);

  18.         return (unsigned long)min(tmp, (u64)(unsigned long)LONG_MAX);


     不明白的问题:在sched_entity更新weight的时候(update_load_addupdate_load_sub)会把inv_weight置为0,导致在计算delta_vruntime的时候重新计算inv_weight,公式中的

lw->inv_weight = 1 + (WMULT_CONST-lw->weight/2)/ (lw->weight+1) 是我不理解的,尤其是那个 lw->weight/2,有什么特殊的用意。希望看懂这行代码的同学能指点我一下。



阅读(10371) | 评论(6) | 转发(0) |
给主人留下些什么吧!~~

djjsindy2013-04-23 14:01:23

nobodythere:1 + (WMULT_CONST-lw->weight/2)/ (lw->weight+1)
这个公式中,(lw->weight+1)如果是lw->weight的话,就好理解了,也是为了四舍五入。WMULT_CONST减去lw->weight的一半,如果原来除以lw->weight需要五入,那么除法的结果不变,除法结果再加1正好等于五入后的结果,如果需要四舍,结果必然比原结果小一,则正好加1进行补偿。
不过不知道(lw->weight+1)加1是为什么

确实,有道理那个四舍五入,,那个lw->weight+1,我觉得是因为在update_load_set和update_load_sub的时候,如果更新完weight为0了,那么到了这个地方的除法,肯定是出错的,发现在函数init_tg_cfs_entry函数中有这么一行代码:update_load_set(&se->load, 0);具体这个函数的作用我还不了解,还没看到,可以看到的是这个地方把se的load更新成了0,那么在计算新的load和invload 的时候就需要在你说的那个地方加1了,不加1除法出错。多亏了你的提醒,原来那段代码是四舍五入的意思。以后多多交流。

回复 | 举报

nobodythere2013-04-22 21:18:46

1 + (WMULT_CONST-lw->weight/2)/ (lw->weight+1)
这个公式中,(lw->weight+1)如果是lw->weight的话,就好理解了,也是为了四舍五入。WMULT_CONST减去lw->weight的一半,如果原来除以lw->weight需要五入,那么除法的结果不变,除法结果再加1正好等于五入后的结果,如果需要四舍,结果必然比原结果小一,则正好加1进行补偿。
不过不知道(lw->weight+1)加1是为什么

djjsindy2013-03-14 10:44:15

Bean_lee:兄弟,没有对你不敬的意思。只是感慨下时不我待。 能把自己的理解分享,然后看自己成长的轨迹,挺好的。共同努力。

误会啦,我也是没有别的意思,有时总是觉得看别人的分享总是看不大懂,还是自己直接看代码比较直观一些;分享出来,一起讨论,共同进步

回复 | 举报

Bean_lee2013-03-14 10:37:21

djjsindy:虽说阿里已经把n多领域写得比较透彻了,但他们写的终归是他们的理解,我只是说一下对一些代码自己的理解。这个1 + (WMULT_CONST-lw->weight/2)/ (lw->weight+1) ,一直不明白是为什么要这么写,尤其是那个lw->weight/2

兄弟,没有对你不敬的意思。只是感慨下时不我待。 能把自己的理解分享,然后看自己成长的轨迹,挺好的。共同努力。

回复 | 举报

djjsindy2013-03-14 10:19:07

Bean_lee:唉,去年想写一个关于CFS的系列,当时自己犯懒,没写,留作今日悔恨啊。
这个调度领域有好多几个magic number,都比较难懂。
另外Linux领域,阿里系的人太厉害,好多领域都被他们写的很透彻了。

虽说阿里已经把n多领域写得比较透彻了,但他们写的终归是他们的理解,我只是说一下对一些代码自己的理解。这个1 + (WMULT_CONST-lw->weight/2)/ (lw->weight+1) ,一直不明白是为什么要这么写,尤其是那个lw->weight/2

回复 | 举报