zoukankan      html  css  js  c++  java
  • CFS完全公平调度算法

    转自:https://blog.csdn.net/helloanthea/article/details/30081627?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param

    kernel/sched/fair.c 

    负载衰减计算函数decay_load()
    1.  
      /*
    2.  
      * We choose a half-life close to 1 scheduling period.
    3.  
      * Note: The tables below are dependent on this value.
    4.  
      */
    5.  
      #define LOAD_AVG_PERIOD 32
    6.  
      #define LOAD_AVG_MAX 47742 /* maximum possible load avg */
    7.  
      #define LOAD_AVG_MAX_N 345 /* number of full periods to produce LOAD_MAX_AVG */
    8.  
       
    9.  
      /* Precomputed fixed inverse multiplies for multiplication by y^n */
    10.  
      static const u32 runnable_avg_yN_inv[] = {
    11.  
      0xffffffff, 0xfa83b2da, 0xf5257d14, 0xefe4b99a, 0xeac0c6e6, 0xe5b906e6,
    12.  
      0xe0ccdeeb, 0xdbfbb796, 0xd744fcc9, 0xd2a81d91, 0xce248c14, 0xc9b9bd85,
    13.  
      0xc5672a10, 0xc12c4cc9, 0xbd08a39e, 0xb8fbaf46, 0xb504f333, 0xb123f581,
    14.  
      0xad583ee9, 0xa9a15ab4, 0xa5fed6a9, 0xa2704302, 0x9ef5325f, 0x9b8d39b9,
    15.  
      0x9837f050, 0x94f4efa8, 0x91c3d373, 0x8ea4398a, 0x8b95c1e3, 0x88980e80,
    16.  
      0x85aac367, 0x82cd8698,
    17.  
      };
    18.  
       
    19.  
      /*
    20.  
      * Approximate:
    21.  
      * val * y^n, where y^32 ~= 0.5 (~1 scheduling period)
    22.  
      */
    23.  
      //负载衰减计算,val * y^n, 将val的值衰减n次并返回(其中y^32 ~= 0.5,也就是约定了32ms之前调度实体的负载,对调度实体的累计负载的影响因子为0.5)
    24.  
      static __always_inline u64 decay_load(u64 val, u64 n)
    25.  
      {
    26.  
      unsigned int local_n;
    27.  
       
    28.  
      if (!n)
    29.  
      return val;
    30.  
      else if (unlikely(n > LOAD_AVG_PERIOD * 63))
    31.  
      return 0;
    32.  
       
    33.  
      /* after bounds checking we can collapse to 32-bit */
    34.  
      local_n = n;
    35.  
       
    36.  
      /*
    37.  
      * As y^PERIOD = 1/2, we can combine
    38.  
      * y^n = 1/2^(n/PERIOD) * k^(n%PERIOD)
    39.  
      * With a look-up table which covers k^n (n<PERIOD)
    40.  
      *
    41.  
      * To achieve constant time decay_load.
    42.  
      */
    43.  
      if (unlikely(local_n >= LOAD_AVG_PERIOD)) {
    44.  
      val >>= local_n / LOAD_AVG_PERIOD;
    45.  
      local_n %= LOAD_AVG_PERIOD;
    46.  
      }
    47.  
       
    48.  
      val *= runnable_avg_yN_inv[local_n];
    49.  
      /* We don't use SRR here since we always want to round down. */
    50.  
      return val >> 32;
    51.  
      }
    连续n个整周期的负载累计贡献值__compute_runnable_contrib()
    1.  
      /*
    2.  
      * Precomputed Sum y^k { 1<=k<=n }. These are floor(true_value) to prevent
    3.  
      * over-estimates when re-combining.
    4.  
      */
    5.  
      static const u32 runnable_avg_yN_sum[] = {
    6.  
      0, 1002, 1982, 2941, 3880, 4798, 5697, 6576, 7437, 8279, 9103,
    7.  
      9909,10698,11470,12226,12966,13690,14398,15091,15769,16433,17082,
    8.  
      17718,18340,18949,19545,20128,20698,21256,21802,22336,22859,23371,
    9.  
      };
    10.  
       
    11.  
      /*
    12.  
      * For updates fully spanning n periods, the contribution to runnable
    13.  
      * average will be: Sum 1024*y^n
    14.  
      *
    15.  
      * We can compute this reasonably efficiently by combining:
    16.  
      * y^PERIOD = 1/2 with precomputed Sum 1024*y^n {for n <PERIOD}
    17.  
      */
    18.  
      //为了方便计算连续n个整周期的负载累计贡献值,封装了该函数,计算1024*(y + y^2 + y^3 + …… +y^n)
    19.  
      static u32 __compute_runnable_contrib(u64 n)
    20.  
      {
    21.  
      u32 contrib = 0;
    22.  
       
    23.  
      if (likely(n <= LOAD_AVG_PERIOD)) //如果n<=32,直接从表runnable_avg_yN_sum中取已经计算好的1024*(y + y^2 + y^3 + …… +y^n)
    24.  
      return runnable_avg_yN_sum[n];
    25.  
      else if (unlikely(n >= LOAD_AVG_MAX_N)) //如果n>=345,直接返回1024*(y + y^2 + y^3 + …… +y^n)的极限值47742。
    26.  
      return LOAD_AVG_MAX;
    27.  
       
    28.  
      /* Compute Sum k^n combining precomputed values for k^i, Sum k^j */
    29.  
      //如果32<=n<=345,每递进32个衰减周期,负载贡献值衰减一半(y^32 = 1/2),并累加。
    30.  
      do {
    31.  
      contrib /= 2; /* y^LOAD_AVG_PERIOD = 1/2 */
    32.  
      contrib += runnable_avg_yN_sum[LOAD_AVG_PERIOD];
    33.  
       
    34.  
      n -= LOAD_AVG_PERIOD;
    35.  
      } while (n > LOAD_AVG_PERIOD);
    36.  
       
    37.  
      contrib = decay_load(contrib, n);// 最后衰减n中不能凑成32个衰减周期的剩余周期数
    38.  
      return contrib + runnable_avg_yN_sum[n];// n中不能凑成32个衰减周期的剩余周期数,单独计算衰减,并累加
    39.  
      }



    更新调度实体的累计负载平均值__update_entity_runnable_avg()

      1.  
        /*
      2.  
        * We can represent the historical contribution to runnable average as the
      3.  
        * coefficients of a geometric series. To do this we sub-divide our runnable
      4.  
        * history into segments of approximately 1ms (1024us); label the segment that
      5.  
        * occurred N-ms ago p_N, with p_0 corresponding to the current period, e.g.
      6.  
        * [<- 1024us ->|<- 1024us ->|<- 1024us ->| ...
      7.  
        * p0 p1 p2
      8.  
        * (now) (~1ms ago) (~2ms ago)
      9.  
        *
      10.  
        * Let u_i denote the fraction of p_i that the entity was runnable.
      11.  
        *
      12.  
        * We then designate the fractions u_i as our co-efficients, yielding the
      13.  
        * following representation of historical load:
      14.  
        * u_0 + u_1*y + u_2*y^2 + u_3*y^3 + ...
      15.  
        *
      16.  
        * We choose y based on the with of a reasonably scheduling period, fixing:
      17.  
        * y^32 = 0.5
      18.  
        *
      19.  
        * This means that the contribution to load ~32ms ago (u_32) will be weighted
      20.  
        * approximately half as much as the contribution to load within the last ms
      21.  
        * (u_0).
      22.  
        *
      23.  
        * When a period "rolls over" and we have new u_0`, multiplying the previous
      24.  
        * sum again by y is sufficient to update:
      25.  
        * load_avg = u_0` + y*(u_0 + u_1*y + u_2*y^2 + ... )
      26.  
        * = u_0 + u_1*y + u_2*y^2 + ... [re-labeling u_i --> u_{i+1}]
      27.  
        */
      28.  
        //更新调度实体的累计负载平均值
      29.  
        static __always_inline int __update_entity_runnable_avg(u64 now,
      30.  
        struct sched_avg *sa,
      31.  
        int runnable)
      32.  
        {
      33.  
        u64 delta, periods;
      34.  
        u32 runnable_contrib;
      35.  
        int delta_w, decayed = 0;
      36.  
         
      37.  
        delta = now - sa->last_runnable_update;//delta,本次更新累计负载与上次更新累计负载的时间差,单位ns。
      38.  
        /*
      39.  
        * This should only happen when time goes backwards, which it
      40.  
        * unfortunately does during sched clock init when we swap over to TSC.
      41.  
        */
      42.  
        if ((s64)delta < 0) {//如果delta为负,不需要更新累计负载,将累计负载更新时间刷新成最新时间,并返回0
      43.  
        sa->last_runnable_update = now;
      44.  
        return 0;
      45.  
        }
      46.  
         
      47.  
        /*
      48.  
        * Use 1024ns as the unit of measurement since it's a reasonable
      49.  
        * approximation of 1us and fast to compute.
      50.  
        */
      51.  
        delta >>= 10;//delta除以1024,将ns换算为us,用右移是为了提高效率。
      52.  
        if (!delta)//如果delta为0us,时间太短,则直接返回0,且不需要刷新累计负载更新时间。
      53.  
        return 0;
      54.  
        sa->last_runnable_update = now;//将累计负载更新时间刷新成最新时间。
      55.  
         
      56.  
        /* delta_w is the amount already accumulated against our next period */
      57.  
        delta_w = sa->runnable_avg_period % 1024;//delta_w为上次更新调度实体的累计负载runnable_avg_period时,不能凑成1024us的剩余us,对应图二的红色部分,该部分已经被计算过累计负载。
      58.  
        if (delta + delta_w >= 1024) {//如果delta与delta_w的和大于等于1024us,说明至少一个周期(1024us)已经过去了
      59.  
        /* period roll-over */
      60.  
        decayed = 1; //将衰减标志decayed置位
      61.  
         
      62.  
        /*
      63.  
        * Now that we know we're crossing a period boundary, figure
      64.  
        * out how much from delta we need to complete the current
      65.  
        * period and accrue it.
      66.  
        */
      67.  
        delta_w = 1024 - delta_w; //这里是计算上次更新累计负载时,未被计算的剩余部分的累计负载,也就是(1024-delta_w),对应图二的黄色部分
      68.  
        if (runnable)
      69.  
        sa->runnable_avg_sum += delta_w;//如果是可运行的调度实体,才累加runnable_avg_sum
      70.  
        sa->runnable_avg_period += delta_w;//累加runnable_avg_period
      71.  
         
      72.  
        delta -= delta_w;//计算除了(1024-delta_w)以外的剩余的delta
      73.  
         
      74.  
        /* Figure out how many additional periods this update spans */
      75.  
        periods = delta / 1024;//计算本次更新与上次更新之间,总共跨越了几个周期,也就是有多少个周期(1024us)调度实体是一直运行的,对应图二的蓝色部分。
      76.  
        delta %= 1024;//本次更新中不能凑成1024us的剩余us,类似于上次更新中的delta_w,对应图二的绿色部分。
      77.  
         
      78.  
        //分别对调度实体的runnable_avg_sum和runnable_avg_period执行衰减计算,即分别乘以y^(periods+1)
      79.  
        sa->runnable_avg_sum = decay_load(sa->runnable_avg_sum,
      80.  
        periods + 1);
      81.  
        sa->runnable_avg_period = decay_load(sa->runnable_avg_period,
      82.  
        periods + 1);
      83.  
         
      84.  
        /* Efficiently calculate sum (1..n_period) 1024*y^i */
      85.  
        runnable_contrib = __compute_runnable_contrib(periods);//调度实体在periods个周期(1024us)是一直运行的(u_i=1),所以直接计算y+y^2+y^3+……+y^period的累加值。
      86.  
        if (runnable)
      87.  
        sa->runnable_avg_sum += runnable_contrib;
      88.  
        sa->runnable_avg_period += runnable_contrib;
      89.  
        }
      90.  
         
      91.  
        //如果delta与delta_w的和小于1024us,说明上次更新和这次更新还在同一个衰减周期(1024us)内,不需要执行衰减计算,直接将时间差加到runnable_avg_sum和runnable_avg_period即可。
      92.  
        /* Remainder of delta accrued against u_0` */
      93.  
        if (runnable)
      94.  
        sa->runnable_avg_sum += delta;//如果是可运行的调度实体,才累加runnable_avg_sum
      95.  
        sa->runnable_avg_period += delta;//累加runnable_avg_period
      96.  
         
      97.  
        return decayed;//返回衰减标志
      98.  
    【作者】张昺华
    【大饼教你学系列】https://edu.csdn.net/course/detail/10393
    【新浪微博】 张昺华--sky
    【twitter】 @sky2030_
    【微信公众号】 张昺华
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    关于医学的一点想法
    我的ArcGis9.3 到Arcgis10.0 升级步骤
    最近一月的娱乐生活:看电影,玩游戏
    最近一月的娱乐生活:看电影,玩游戏
    5年技术学习历程的回顾
    5年技术学习历程的回顾
    网站开发的技术选型问题
    网站开发的技术选型问题
    学技术真累
    Java实现 LeetCode 200 岛屿数量
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/13963903.html
Copyright © 2011-2022 走看看