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_
    【微信公众号】 张昺华
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    hdu 4614 线段树 二分
    cf 1066d 思维 二分
    lca 最大生成树 逆向思维 2018 徐州赛区网络预赛j
    rmq学习
    hdu 5692 dfs序 线段树
    dfs序介绍
    poj 3321 dfs序 树状数组 前向星
    cf 1060d 思维贪心
    【PAT甲级】1126 Eulerian Path (25分)
    【PAT甲级】1125 Chain the Ropes (25分)
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/13963903.html
Copyright © 2011-2022 走看看