EAS全称是Energy Aware Scheduling,主要目标就是降低功耗同时兼顾性能,专门针对异构CPU,比如Arm大小核架构。

EAS利用task load(PELT or WALT) 和 Engery Model (EM) 找到engergy-efficient CPU。

这里的PELT是per-entity load tracking,上游Linux使用。

QCOM认为PELT有缺陷,提出了一个新的WALT(Window Assited Loading Track)机制。

对于一些轻中度utilization场景,EAS帮助很多,但是对于high utilization场景(over-utilization), 就不用EAS,调度回退到load balancing了。

Engery Model

就是提供各种设备的power消耗到上层子系统(EAS/thermal)供他们做出一些相关决策。

配置选项是CONFIG_ENERGY_MODEL, code在kernel/power/energy_model.c。

  +---------------+  +-----------------+  +---------------+
  | Thermal (IPA) |  | Scheduler (EAS) |  |     Other     |
  +---------------+  +-----------------+  +---------------+
          |                   | em_cpu_energy()   |
          |                   | em_cpu_get()      |
          +---------+         |         +---------+
                    |         |         |
                    v         v         v
                   +---------------------+
                   |    Energy Model     |
                   |     Framework       |
                   +---------------------+
                      ^       ^       ^
                      |       |       | em_dev_register_perf_domain()
           +----------+       |       +---------+
           |                  |                 |
   +---------------+  +---------------+  +--------------+
   |  cpufreq-dt   |  |   arm_scmi    |  |    Other     |
   +---------------+  +---------------+  +--------------+
           ^                  ^                 ^
           |                  |                 |
   +--------------+   +---------------+  +--------------+
   | Device Tree  |   |   Firmware    |  |      ?       |
   +--------------+   +---------------+  +--------------+

两个关键API:

  • em_cpu_get(): 访问power const tables。
  • em_pd_energy(): 估计一个performance domain的能耗。

PELT

想法就是当下non-runnable entities/tasks也会对load产生影响(via decay来实现)

一个entity的load计算是:

L = L0 + L1*y + L2*y*y + ...

y是decay factor,当前代码实现 y^32 = 0.5。

代码在kernel/sched/pelt.c。

WALT

相比PELT,WALT只考虑当前运行的任务,waiting不算,但是一旦变成可运行的,它之前的load会纳入考虑。

task placement

目的就是找到每一个performance domain里的engery efficient CPU, 有个计算公式:

CPU spare capacity = CPU capatity - CPU utilization

CPU spare capcity最多的那些CPUs就是第一步筛选出来的, 然后根据任务(比如此时在CPU0上)迁移到这些CPUs包括prev_cpu(CPU0)的去向,分别计算得到power消耗,消耗最低的就是最终人选。

需要注意的是,小核不总是比大核更省电,比如下面的模型:

   Energy Model
+-----------+-------------+
| Little | Big |
+-----+-----+------+------+
| Cap | Pwr | Cap | Pwr |
+-----+-----+------+------+
| 170 | 50 | 512 | 300 |
| 341 | 150 | 768 | 800 |
| 512 | 400 | 1024 | 1700 |
+-----+-----+------+------+

小核最大Cap的Pwr(400)比大核最小Cap其实要耗电。

代码入口:find_energy_efficient_cpu()

over-utilization

static inline bool cpu_overutilized(int cpu)
{
return !fits_capacity(cpu_util(cpu), capacity_of(cpu));
}
/*
* The margin used when comparing utilization with CPU capacity.
*
* (default: ~20%)
*/
#define fits_capacity(cap, max) ((cap) * 1280 < (max) * 1024)

fits_capacity的条件是cap/max < 80%(1024/1280), 也就是说80%以上的utilization就是non fit了。

refer doc

  • Documentation/scheduler/sched-energy.rst