summaryrefslogtreecommitdiffstats
path: root/kernel/power
diff options
context:
space:
mode:
authorLukasz Luba <lukasz.luba@arm.com>2024-02-08 12:55:49 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2024-02-08 15:00:31 +0100
commit1b600da510735a0f92c8b4140a7e2cb037a6a6c3 (patch)
treeea67df6e89321d69a5ae51acbbc6cc183dc15562 /kernel/power
parentPM: EM: Support late CPUs booting and capacity adjustment (diff)
downloadlinux-1b600da510735a0f92c8b4140a7e2cb037a6a6c3.tar.xz
linux-1b600da510735a0f92c8b4140a7e2cb037a6a6c3.zip
PM: EM: Optimize em_cpu_energy() and remove division
The Energy Model (EM) can be modified at runtime which brings new possibilities. The em_cpu_energy() is called by the Energy Aware Scheduler (EAS) in its hot path. The energy calculation uses power value for a given performance state (ps) and the CPU busy time as percentage for that given frequency. It is possible to avoid the division by 'scale_cpu' at runtime, because EM is updated whenever new max capacity CPU is set in the system. Use that feature and do the needed division during the calculation of the coefficient 'ps->cost'. That enhanced 'ps->cost' value can be then just multiplied simply by utilization: pd_nrg = ps->cost * \Sum cpu_util to get the needed energy for whole Performance Domain (PD). With this optimization and earlier removal of map_util_freq(), the em_cpu_energy() should run faster on the Big CPU by 1.43x and on the Little CPU by 1.69x (RockPi 4B board). Reviewed-by: Dietmar Eggemann <dietmar.eggemann@arm.com> Tested-by: Dietmar Eggemann <dietmar.eggemann@arm.com> Signed-off-by: Lukasz Luba <lukasz.luba@arm.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'kernel/power')
-rw-r--r--kernel/power/energy_model.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/kernel/power/energy_model.c b/kernel/power/energy_model.c
index b192b0ac8c6e..a631d7d52c40 100644
--- a/kernel/power/energy_model.c
+++ b/kernel/power/energy_model.c
@@ -192,11 +192,9 @@ static int em_compute_costs(struct device *dev, struct em_perf_state *table,
unsigned long flags)
{
unsigned long prev_cost = ULONG_MAX;
- u64 fmax;
int i, ret;
/* Compute the cost of each performance state. */
- fmax = (u64) table[nr_states - 1].frequency;
for (i = nr_states - 1; i >= 0; i--) {
unsigned long power_res, cost;
@@ -208,8 +206,9 @@ static int em_compute_costs(struct device *dev, struct em_perf_state *table,
return -EINVAL;
}
} else {
- power_res = table[i].power;
- cost = div64_u64(fmax * power_res, table[i].frequency);
+ /* increase resolution of 'cost' precision */
+ power_res = table[i].power * 10;
+ cost = power_res / table[i].performance;
}
table[i].cost = cost;