Linux调度CFS源码分析(四) 负载跟踪和进程选择

PELT任务负载跟踪

为了实现sched entity级别的负载跟踪,pelt将物理时间划分成了1ms(实际为1024us)的序列,在每一个1024us的周期中,sched entity对系统负载的贡献可以根据该entity处于runnable状态(包含在cpu上running和在cfs_rq上waiting的状态)的时间进行计算;假设该周期内,某entity处于runnable状态的时间为x,那么其对系统负载的贡献为(x/1024);pelt还会累积过去周期的负载贡献,但会根据时间乘以相应的衰减系数y,假设Li表示某entity在周期Pi中对系统负载的贡献,那么该entity对系统负载的总贡献如下:

每经过32个周期,entity对系统负载的贡献减半。

Linux调度器负载计算之PELT_accumulate_sum(u64 delta, struct sched_avg *sa, un-CSDN博客 调度实体负载计算方法

Ln = (prev+deltal1)*y^p + 1024(y + y^2 + y^3 + .... + y^p-1) + delta3
s1 = (prev+deltal1)*y^p,
s2 = 1024(y + y^2 + y^3 + .... + y^p-1)
s3 = deltal3

 s2 = 1024*(y^1 + y^2 + ... +y^p-1)
  s2a= (y^0 + y^1+y^2 + ... + y^n)
  s2b = (y^p + y^p+1 + ..... y^n)=s2a*y^p
  s2 = 1024(s2a - s2b - y^0) = 1024(s2a-s2b-1024)= 1024*(s2a - s2a*y^p - 1)
  利用Sn = (a1 *(1-q^n))/(1-q)当前n趋于无穷时等于 1 /(1- Y)
  求s2a的最大值LOAD_AVG_MAX =1024*s2a = 1 /(1- Y) * 1024 = 47742
  在___update_load_avg中使用这个公式进行负载的累积计算;在这个函数中同时更新se和对应的cfs衰减后的值。
 计算后的值更新在se的成员结构体sa中:
struct sched_avg {
        //上一次负载更新的时候,通过这个值和当前值的差,计算delta;对应上图中的last update time
        u64                                last_update_time; 
        //now时间点的负载总和,也就是下一次计算时的prev值;按照weight计算的累加值
        u64                                load_sum;
        // 按照频率最大为1024进行归一化计算的结果。
        u32                                util_sum;
        // 图上1024 -delta1的值
        u32                                period_contrib;
        // load_sum / LOAD_AVG_MAX
        unsigned long                        load_avg;
        // util_sum / LOAD_AVG_MAX
        unsigned long                        util_avg;
};
通过上面的算法计算出当前任务的contrib,然后分别 结算出load_sum和util_sum值。

sa->load_sum += weight * contrib;
sa->util_sum += contrib * scale_cpu;

CPU负载跟踪

基于上面的公平运行队列的加权平均负载,计算5种处理器负载,计算公式如下:

其中i的取值是0~4,load_avg是根任务组的公平运行队列的加权平均负载。

5种负载的区别是,历史负载和当前负载的比例不同,i越大,历史负载占的比例越大,处理器负载曲线越平滑。在处理器不空闲、即将空闲和空闲等不同情况下实现负载均衡时,使用不同的处理器负载。

在find_idlest_group和update_sg_lb_stats的时候会使用到这个值。也就是说这个值在负载均衡的时候用到。

选择下一个进程

停机调度类中用于选择下一个进程的函数是picknext_task_stop,算法是:如果运行队列的成员stop指向某个进程,并且这个进程在运行队列中,那么返回成员stop指向的进程,否则返回空指针。

限期调度类中用于选择下一个进程的函数是pick_next_task_dl,算法是:从限期运行队列选择绝对截止期限最小的进程,就是红黑树中最左边的进程。限期调度类不支持任务组,所以不需要考虑调度实体是任务组的情况。

实时调度类中用于选择下一个进程的函数是pick_nexttaskrt,算法如下。

  1. 如果实时运行队列没有加入运行队列(rt_rq.rt_queued等于0,如果在一个处理器上所有实时进程在一个周期内用完了运行时间,就会把实时运行队列从运行队列中删除),那么返回空指针。
  2. 从根任务组在当前处理器上的实时运行队列开始,选择优先级最高的调度实体。
  3. 如果选中的调度实体是任务组,那么继续从这个任务组在当前处理器上的实时运行队列中选择优先级最高的调度实体,重复这个步骤,直到选中的调度实体是进程为止。

公平调度类中用于选择下一个进程的函数是picknext_task_fair,算法如下。

  1. 从根任务组在当前处理器上的公平运行队列中,选择虚拟运行时间最小的调度实体,就是红黑树中最左边的调度实体。
  2. 如果选中的调度实体是任务组,那么继续从这个任务组在当前处理器上的公平运行队列中选择虚拟运行时间最小的调度实体,重复这个步骤,直到选中的调度实体是进程为止。
  • 18
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值