内核配置参数, 参见3.10/linaro/configs/big-LITTLE-MP.conf
CONFIG_CGROUPS=y
CONFIG_CGROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
CONFIG_NO_HZ=y
CONFIG_SCHED_MC=y
CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE=y #禁止内核自带的SMP负载均衡
CONFIG_SCHED_HMP=y
CONFIG_HMP_FAST_CPU_MASK=""
CONFIG_HMP_SLOW_CPU_MASK=""
CONFIG_HMP_VARIABLE_SCALE=y # 运行动态修改负载计算的比率
CONFIG_HMP_FREQUENCY_INVARIANT_SCALE=y # 设置cpufreq频率
CONFIG_SCHED_HMP_LITTLE_PACKING=y # 小任务封包服务
HMP 调度器的实现可以简单概况为:
- 把小核调度域上“大活”迁移到大核调度域的空闲 CPU 上(向上迁移 up migration)
- 把每个大核 CPU 上“小活”迁移到小核调度域的空闲 CPU 上(向下迁移 down migration)
大活就是负载比较重的进程,小活就是负载比较轻的进程
如何判断进程是大活还是小活呢?
HMP 采用 load_avg_ratio 来比较,load_avg_ratio 的计算公式之前已经描述过,它并没有像内核中采用的 load_avg_contrib 一样考虑进程的可运行时间比重(runnable_sum/unable_period)和实际权重,在 HMP 调度器眼里只考虑进程的可运行时间比重
那么 CPU 密集型的进程以及长时间运行的进程容易理解为大活,那些间隙性运行的进程就变成小活了,即便它优先级很高。比如一个优先级很高的进程,它只是间歇性的运行,那么它是没机会在大核上遛弯的
另外 HMP 调度器还定义了 hmp_up_threshold(700)和 hmp_down_threshold(512),
那么也就是说可运行时间比重(runnable_sum/unable_period)小于 50%就认为是小活,大于68.3%就认为是大活
HMP 调度器的实现比内核中自带的 CPU 负载均衡要简单的多,首先 HMP 调度器只定义了两个调度域,没有调度组和调度能力的概念,而且调度域没有层次. 内核自带的负载均衡调度器可以根据 CPU 的物理属性来定义调度域的层次关系
另外 HMP 调度器没有考虑调度域内以及调度域之间的负载均衡. HMP 调度器寄托在调度域中有空闲 CPU。假设小核上有进程突然持续的在使用 CPU,那么 load_avg_ratio 变大表示这个是大活,可是大核上暂时没有空闲 CPU 啊,那怎么办?
假设大小核调度域都没有空闲 CPU,那么谁来保证他们之间的负载均衡呢?有人说用系统默认的 CPU 负载均衡调度器啊. Linaro 上实现的 HMP 调度器是默认关闭了系统自带的SMP 负载均衡的,即关闭 CONFIG_DISABLE_CPU_SCHED_DOMAIN_BALANCE 这个宏. 如果开启的话会出现什么情况,那么 SMP 调度器就会考虑大小核调度域之间的负载均衡了,他们要负载大致相等喔(假设不考虑大小核之间的能力系数 capacity),那相当于小核调度域也要和大核调度域干一样的活,那这样的话 big.LITTLE 模型就失去意义。另外两套调度器一起运行是否会冲突,即 HMP 迁移了进程,又被 SMP 调度器给迁移回来,