1 前言
本文基于v5.0浅谈一下sched_group_capacity结构体关键字段的计算过程。v5.0是个相对老旧的内核版本(2019年3月3日发布),诸多相关内容与当前v6.x系列内核多有不同之处,文中内容仅供参考。
2 关于sched_group_capacity
sched_group结构体在Linux负载均衡机制中起着非常重要的作用,其数据结构定义如下:
可以看到sched_group结构体包含一个名为sgc的字段,类型是sched_group_capacity结构体。该结构体定义为:
关键字段capacity在负载均衡的相关计算中非常重要,本文重点分析capacity,min_capacity和max_capacity的计算过程。
3 CPU拓扑的相关概念
CPU的sched_domain(调度域,笔者认为直接使用英文名称更有利于阅读的流畅性,后文不进行翻译)可能有DIE,MC和SMT三层。SMT在移动计算平台上并不常见,因为需要CPU支持超线程技术。所以对于常见的移动计算平台,DIE和MC更为常见。
对于DIE层的sched domain,其结构组成可能是这样的:
而对于MC层级的sched domain,其结构可能是这样的:
显然,每个层级的sched group都要对其sgc字段内数值进行计算。事实上,每次负载均衡都要重新对sgc结构体的数值进行更新。其调用过程为:
load_balance
find_busiest_group
update_sd_lb_stats
update_group_capacity
4 update_group_capacity
对sched_group_capacity的更新是从MC这个层级的sched domain开始的。
update_cpu_capacity函数的功能是通过简单的计算得到可以用于CFS调度类的capacity数值。其计算过程可以用公式描述为:
其中,max是CPU核心的capacity。通过arch_scale_cpu_capacity函数计算。
used,是rt和deadline调度类相关进程的util_avg之和,相关计算过程在scale_rt_capacity函数中。
irq指的是在使能了CONFIG_HAVE_SCHED_AVG_IRQ配置项的情况下,IRQ带来的负载。
因为在没有超线程技术的CPU上,MC这一层的sched group每个sched group只有一颗核心。所以max_capacity和min_capacity直接复制capacity的数值就好。相关逻辑在update_cpu_capacity函数中。
再看DIE这个层级的sched group capacity计算。
本质上是依托与MC层级计算的数据,对MC层级的数据进行累加:
当然,如果在NUMA架构的计算机上可能会出现SD_OVERLAP标记的“重叠”现象,计算过程与上面的累加过程不同。这种情况笔者没有遇到过,暂不分析。
5 总结
在负载均衡相关的数据结构与计算过程中,capacity的各种相关计算很多。但是本质上都是基于arch_scale_cpu_capacity函数为CPU设定的定值进行的。一颗CPU的capacity(比如1024)可以拆分成很多成分,这些成分经过计算筛选会在各种不同的计算场景下发挥作用。