1. #ifdef CONFIG_CFS_BANDWIDTH
  2. /*
  3.  * Amount of runtime to allocate from global (tg) to local (per-cfs_rq) pool
  4.  * each time a cfs_rq requests quota.
  5.  *
  6.  * Note: in the case that the slice exceeds the runtime remaining (either due
  7.  * to consumption or the quota being specified to be smaller than the slice)
  8.  * we will always only issue the remaining available time.
  9.  *
  10.  * default: 5 msec, units: microseconds
  11.   */
  12. unsigned int sysctl_sched_cfs_bandwidth_slice = 5000UL;
  13. #endif

  14. /*
  15.  * Replenish runtime according to assigned quota and update expiration time.
  16.  * We use sched_clock_cpu directly instead of rq->clock to avoid adding
  17.  * additional synchronization around rq->lock.
  18.  *
  19.  * requires cfs_b->lock
  20.  */
  21. void __refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b)
  22. {
  23.     u64 now;

  24.     if (cfs_b->quota == RUNTIME_INF)
  25.         return;

  26.     now = sched_clock_cpu(smp_processor_id());
  27.     cfs_b->runtime = cfs_b->quota;
  28.     cfs_b->runtime_expires = now + ktime_to_ns(cfs_b->period);
  29.     // 组调度, 配额, quota
  30.     // 也就是说cfs_b->period这段时间分配给该cfs_b组的runtime配额为cfs_b->quota
  31.     // 不论该组消耗了多少配额, 都会在这里将配额重新填满, 触发接下来的消耗period[2014-11-26]
  32.     // start_bandwidth_timer(&cfs_b->period_timer, cfs_b->period);
  33. }


  34. static inline u64 sched_cfs_bandwidth_slice(void)
  35. {
  36.     return (u64)sysctl_sched_cfs_bandwidth_slice * NSEC_PER_USEC;
  37. }

  38. /* returns 0 on failure to allocate runtime */
  39. // 努力延长本cfs_rq的runtime_remaining时间寿命[gliethttp]
  40. static int assign_cfs_rq_runtime(struct cfs_rq *cfs_rq)
  41. {
  42.     struct task_group *tg = cfs_rq->tg;
  43.     struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(tg);
  44.     u64 amount = 0, min_amount, expires;

  45.     /* note: this is a positive sum as runtime_remaining <= 0 */
  46.     // 5ms + 欠的账(超出配额的部分), 如注释所说cfs_rq->runtime_remaining是一个负数, 欠费了
  47.     min_amount = sched_cfs_bandwidth_slice() - cfs_rq->runtime_remaining;

  48.     raw_spin_lock(&cfs_b->lock);
  49.     if (cfs_b->quota == RUNTIME_INF)
  50.         amount = min_amount; // 如果是infinite的,那么每次都获取5ms
  51.     else {
  52.         /*
  53.          * If the bandwidth pool has become inactive, then at least one
  54.          * period must have elapsed since the last consumption.
  55.          * Refresh the global state and ensure bandwidth timer becomes
  56.          * active.
  57.          */
  58.         if (!cfs_b->timer_active) {
  59.             // 如果带宽timer刚好stop了, 那么重新填充带宽timer的runtime和runtime_expires
  60.             // cfs_b->runtime = cfs_b->quota;
  61.             // cfs_b->runtime_expires = now + ktime_to_ns(cfs_b->period);
  62.             // 进入下一轮以cfs_b->period为间隔的, 有效时长(单位ns纳秒)cfs_b->runtime的带宽period[gliethttp]
  63.             __refill_cfs_bandwidth_runtime(cfs_b);
  64.             __start_cfs_bandwidth(cfs_b);
  65.         }

  66.         if (cfs_b->runtime > 0) {
  67.             amount = min(cfs_b->runtime, min_amount); // 如果剩余的cfs_b->runtime不足5ms(sysctl_sched_cfs_bandwidth_slice)
  68.             // 更甚至与不足-cfs_rq->runtime_remaining, 那么amount将等于2者最小者.
  69.             cfs_b->runtime -= amount; // 被瓜分出去amount
  70.             cfs_b->idle = 0;
  71.         }
  72.     }
  73.     expires = cfs_b->runtime_expires;
  74.     raw_spin_unlock(&cfs_b->lock);

  75.     cfs_rq->runtime_remaining += amount; // 重新为自己充电amount纳秒
  76.     /*
  77.      * we may have advanced our local expiration to account for allowed
  78.      * spread between our sched_clock and the one on which runtime was
  79.      * issued.
  80.      */
  81.     if ((s64)(expires - cfs_rq->runtime_expires) > 0)
  82.         cfs_rq->runtime_expires = expires;

  83.     return cfs_rq->runtime_remaining > 0;
  84. }

  85. // 发红包啦[20141128]! 每个处于trhottled的cfs_rq获得
  86. // 我有些多余的remaining纳秒带宽, 将在expires时到期
  87. // cfs_b你把这些带宽发给你手里饥渴的人吧[20141128]
  88. static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b,
  89.         u64 remaining, u64 expires)
  90. {
  91.     struct cfs_rq *cfs_rq;
  92.     u64 runtime = remaining;

  93.     rcu_read_lock();
  94.     list_for_each_entry_rcu(cfs_rq, &cfs_b->throttled_cfs_rq,
  95.                 throttled_list) {
  96.         struct rq *rq = rq_of(cfs_rq);

  97.         raw_spin_lock(&rq->lock);
  98.         if (!cfs_rq_throttled(cfs_rq))
  99.             goto next;

  100.         runtime = -cfs_rq->runtime_remaining + 1; // 发红包啦[20141128]! 每个处于trhottled获得
  101.         // -cfs_rq->runtime_remaining, 填平到数值0, 同时再额外附送1ns
  102.         // 其实对于当前cfs_rq只获得了可用的1ns,
  103.         // 但是发红包的人,可把这个cfs_rq签得账-cfs_rq->runtime_remaining都给偿还上了
  104.         // 调用这个函数发红包的人, 真是个runtime富裕的大好人[20141128]
  105.         // 不要想太美啦, 世上哪有好事,便宜让你占呀,
  106.         // 其实是do_sched_cfs_period_timer自己欠下的账, 自己在这个时机来还而已[gliethttp]
  107.         if (runtime > remaining)
  108.             runtime = remaining;
  109.         remaining -= runtime; // 红包发出去了runtime, 计算我还剩多少ns红包

  110.         cfs_rq->runtime_remaining += runtime; // 红包给你这个cfs_rq了[20141128]
  111.         cfs_rq->runtime_expires = expires; // 你cfs_rq使用我的expires吧, 我和我富裕出来的红包生命将在expires时刻因过期而终结

  112.         /* we check whether we're throttled above */
  113.         if (cfs_rq->runtime_remaining > 0) // 把自己throttled吧
  114.             unthrottle_cfs_rq(cfs_rq);

  115. next:
  116.         raw_spin_unlock(&rq->lock);

  117.         if (!remaining)
  118.             break;
  119.     }
  120.     rcu_read_unlock();

  121.     return remaining;
  122. }

  123. /*
  124.  * Responsible for refilling a task_group's bandwidth and unthrottling its
  125.  * cfs_rqs as appropriate. If there has been no activity within the last
  126.  * period the timer is deactivated until scheduling resumes; cfs_b->idle is
  127.  * used to track this state.
  128.  */
  129. // 新的cfs_b->period_timer带宽周期到达,
  130. // 带宽数值(单位ns纳秒): cfs_b->runtime (cfs_b->runtime = cfs_b->quota;)
  131. // 带宽有效期(单位ns纳秒): cfs_b->runtime_expires (cfs_b->runtime_expires = now + ktime_to_ns(cfs_b->period);)
  132. static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun)
  133. {
  134.     ......
  135.     /*
  136.      * This check is repeated as we are holding onto the new bandwidth
  137.      * while we unthrottle. This can potentially race with an unthrottled
  138.      * group trying to acquire new bandwidth from the global pool.
  139.      */
  140.     while (throttled && runtime > 0) {
  141.         raw_spin_unlock(&cfs_b->lock);
  142.         /* we can't nest cfs_b->lock while distributing bandwidth */
  143.         runtime = distribute_cfs_runtime(cfs_b, runtime,
  144.                          runtime_expires); // 把自己欠的账还回去
  145.         raw_spin_lock(&cfs_b->lock);

  146.         throttled = !list_empty(&cfs_b->throttled_cfs_rq);
  147.     }

  148.     /* return (any) remaining runtime */
  149.     cfs_b->runtime = runtime;
  150.     ......
  151. }


10-01 03:35