1. 背景

Linux社区的负载评估算法默认使用pelt算法,研究这个算法的过程中发现有个get_pelt_divider函数初看有些晦涩,其实实现如下:

40  #define PELT_MIN_DIVIDER	(LOAD_AVG_MAX - 1024)
41  
42  static inline u32 get_pelt_divider(struct sched_avg *avg)
43  {
44  	return PELT_MIN_DIVIDER + avg->period_contrib;
45  }
46  

这个函数的目标:计算一个任务连续运行无限个周期之后,最大的负载贡献的机极限值,根据内核的定义PELT_MIN_DIVIDER是:LOAD_AVG_MAX - 1024,而LOAD_AVG_MAX 47742,如果想了解get_pelt_divider函数的计算原理有两个问题需要搞清楚:

  1. LOAD_AVG_MAX 这个数字的含义,以及计算公式
  2. 为什么get_pelt_divider函数要把avg->period_contrib计算在内
2.LOAD_AVG_MAX是怎么来的

我们知道PELT一个小周期是1ms(1024us),如果一个任务持续运行无限个1ms周期其负载贡献值是多少呢?公式如下:

1024 *y^0 + 1024*y^1 + 1024*y^2 + ... + 1024 * y^(n-1) = 1024 (1-y^n)/(1-y)   

由于n趋近无穷大,那么公式可以简化为 1024/ (1-y),由于y^32 = 0.5,所以这个等比数据的值就是47742,即LOAD_AVG_MAX

3.get_pelt_divider函数原理揭秘

上面我们明白了LOAD_AVG_MAX,那么get_pelt_divider直接返回LOAD_AVG_MAX不久好了吗,内核为什么还要考虑period_contrib呢?这就考虑了内核计算的精准,LOAD_AVG_MAX假设的是某个任务运行无限个“完整的” 1ms,但是实际上任务往往不会这么精准运行时间是1ms的整数倍周期,示意图如下:

所以get_pelt_divider实现的时候将B段时间去掉了 

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐