实时进程不实时(下)

前文说到实时(real-time)进程cmcld在CPU2的运行队列(run queue)中静坐了14.6秒,虽然还有287个CPU处于空闲状态,cmcld却一直未能得到运行机会。我们已经解释了为什么cmcld一开始会进入CPU2的运行队列而未选择其他空闲状态的CPU,今天我们继续分析为什么cmcld未能被migrate到其他CPU上。

进程从一个CPU换到另一个CPU有个术语叫做migration。已经进入运行队列的进程发生migration只能通过负载均衡(load balance)触发。

在多CPU的系统上,使各个CPU之间的负载保持均衡是进程调度器的工作。在我们这个案例中,大量CPU空闲的情况下还有个进程在运行队列中等了14.6秒之久,显然进程调度器的负载均衡算法失灵了。

Linux的进程调度器是以模块化的方式提供的,允许多种调度算法并存,调度模块称为调度类(scheduling class),最常用的是CFS class和real-time class。而CFS类和real-time类的负载均衡算法是不一样的。

CFS的负载均衡发生在以下时刻:

周期性的负载均衡(Active Balancing),通过时钟中断,scheduler_tick()会调用trigger_load_balance()触发SCHED_SOFTIRQ进行负载均衡操作;

空闲时的负载均衡(Idle Balancing),当CPU进入idle状态的时候,会调用idle_balance(),试图从其他CPU的运行队列里pull(拉取)进程。

Real-time的负载均衡算法基于运行队列是否overload,所谓overload就是运行队列中的real-time进程数量超过了1个。发生负载均衡的时刻如下,请注意它并不考虑进程在队列中等待了多长时间,也没有像CFS的负载均衡那样的周期性操作:

当进程进入real-time队列的时候,会检查队列是否overload,如果overload则调用push_rt_task试图从该队列中把进程push(推)到更空闲的CPU队列;

当运行队列中的最高进程优先级降低的时候,会检查其他队列是否overload,如果有overload就调用pull_rt_task试图从其他队列中把优先级更高的进程pull(拉)过来。

回到我们的案例,cmcld是实时进程,归real-time调度器管,由于CPU2的运行队列里只有这一个实时进程,根据real-time的负载均衡算法,不满足overload的条件,所以既不会发生push也不会发生pull,结果cmcld就这么一直在CPU2的运行队列里待着...

设想如果cmcld是CFS进程,它还会在CPU2的运行队列中等那么长时间吗?并不会,因为CFS的负载均衡算法会发现CPU2上有两个进程,会把一个进程migrate到其他的空闲的CPU上去。

这个案例暴露了real-time调度器的不足之处:real-time调度器在选择CPU和进行负载均衡的时候,眼里只有real-time进程,没有考虑CFS等其他类型的进程的影响,比如它认为队列里只有一个real-time进程就不算overload、无论有没有CFS进程,这通常不会有问题,因为CFS优先级低于real-time,对real-time进程造不成影响,然而它没有考虑到特殊情况:在非抢占式内核里,CFS进程可能会因为陷在内核态而造成real-time进程无法抢占。所以说,也许real-time调度器还可以做得更好一点。

(全文完)

赞 赏 码

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180121G0G6NJ00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券