Skip to content

Commit 9942cb2

Browse files
vingu-linaroingomolnar
authored andcommitted
sched/topology: Add a new arch_scale_freq_ref() method
Create a new method to get a unique and fixed max frequency. Currently cpuinfo.max_freq or the highest (or last) state of performance domain are used as the max frequency when computing the frequency for a level of utilization, but: - cpuinfo_max_freq can change at runtime. boost is one example of such change. - cpuinfo.max_freq and last item of the PD can be different leading to different results between cpufreq and energy model. We need to save the reference frequency that has been used when computing the CPUs capacity and use this fixed and coherent value to convert between frequency and CPU's capacity. In fact, we already save the frequency that has been used when computing the capacity of each CPU. We extend the precision to save kHz instead of MHz currently and we modify the type to be aligned with other variables used when converting frequency to capacity and the other way. [ mingo: Minor edits. ] Signed-off-by: Vincent Guittot <vincent.guittot@linaro.org> Signed-off-by: Ingo Molnar <mingo@kernel.org> Tested-by: Lukasz Luba <lukasz.luba@arm.com> Reviewed-by: Lukasz Luba <lukasz.luba@arm.com> Acked-by: Sudeep Holla <sudeep.holla@arm.com> Link: https://lore.kernel.org/r/20231211104855.558096-2-vincent.guittot@linaro.org
1 parent d2e9f53 commit 9942cb2

6 files changed

Lines changed: 32 additions & 15 deletions

File tree

arch/arm/include/asm/topology.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#define arch_set_freq_scale topology_set_freq_scale
1414
#define arch_scale_freq_capacity topology_get_freq_scale
1515
#define arch_scale_freq_invariant topology_scale_freq_invariant
16+
#define arch_scale_freq_ref topology_get_freq_ref
1617
#endif
1718

1819
/* Replace task scheduler's default cpu-invariant accounting */

arch/arm64/include/asm/topology.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ void update_freq_counters_refs(void);
2323
#define arch_set_freq_scale topology_set_freq_scale
2424
#define arch_scale_freq_capacity topology_get_freq_scale
2525
#define arch_scale_freq_invariant topology_scale_freq_invariant
26+
#define arch_scale_freq_ref topology_get_freq_ref
2627

2728
#ifdef CONFIG_ACPI_CPPC_LIB
2829
#define arch_init_invariance_cppc topology_init_cpu_capacity_cppc

arch/riscv/include/asm/topology.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#define arch_set_freq_scale topology_set_freq_scale
1010
#define arch_scale_freq_capacity topology_get_freq_scale
1111
#define arch_scale_freq_invariant topology_scale_freq_invariant
12+
#define arch_scale_freq_ref topology_get_freq_ref
1213

1314
/* Replace task scheduler's default cpu-invariant accounting */
1415
#define arch_scale_cpu_capacity topology_get_cpu_scale

drivers/base/arch_topology.c

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,16 @@
1919
#include <linux/init.h>
2020
#include <linux/rcupdate.h>
2121
#include <linux/sched.h>
22+
#include <linux/units.h>
2223

2324
#define CREATE_TRACE_POINTS
2425
#include <trace/events/thermal_pressure.h>
2526

2627
static DEFINE_PER_CPU(struct scale_freq_data __rcu *, sft_data);
2728
static struct cpumask scale_freq_counters_mask;
2829
static bool scale_freq_invariant;
29-
static DEFINE_PER_CPU(u32, freq_factor) = 1;
30+
DEFINE_PER_CPU(unsigned long, capacity_freq_ref) = 1;
31+
EXPORT_PER_CPU_SYMBOL_GPL(capacity_freq_ref);
3032

3133
static bool supports_scale_freq_counters(const struct cpumask *cpus)
3234
{
@@ -170,9 +172,9 @@ DEFINE_PER_CPU(unsigned long, thermal_pressure);
170172
* operating on stale data when hot-plug is used for some CPUs. The
171173
* @capped_freq reflects the currently allowed max CPUs frequency due to
172174
* thermal capping. It might be also a boost frequency value, which is bigger
173-
* than the internal 'freq_factor' max frequency. In such case the pressure
174-
* value should simply be removed, since this is an indication that there is
175-
* no thermal throttling. The @capped_freq must be provided in kHz.
175+
* than the internal 'capacity_freq_ref' max frequency. In such case the
176+
* pressure value should simply be removed, since this is an indication that
177+
* there is no thermal throttling. The @capped_freq must be provided in kHz.
176178
*/
177179
void topology_update_thermal_pressure(const struct cpumask *cpus,
178180
unsigned long capped_freq)
@@ -183,10 +185,7 @@ void topology_update_thermal_pressure(const struct cpumask *cpus,
183185

184186
cpu = cpumask_first(cpus);
185187
max_capacity = arch_scale_cpu_capacity(cpu);
186-
max_freq = per_cpu(freq_factor, cpu);
187-
188-
/* Convert to MHz scale which is used in 'freq_factor' */
189-
capped_freq /= 1000;
188+
max_freq = arch_scale_freq_ref(cpu);
190189

191190
/*
192191
* Handle properly the boost frequencies, which should simply clean
@@ -279,13 +278,13 @@ void topology_normalize_cpu_scale(void)
279278

280279
capacity_scale = 1;
281280
for_each_possible_cpu(cpu) {
282-
capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu);
281+
capacity = raw_capacity[cpu] * per_cpu(capacity_freq_ref, cpu);
283282
capacity_scale = max(capacity, capacity_scale);
284283
}
285284

286285
pr_debug("cpu_capacity: capacity_scale=%llu\n", capacity_scale);
287286
for_each_possible_cpu(cpu) {
288-
capacity = raw_capacity[cpu] * per_cpu(freq_factor, cpu);
287+
capacity = raw_capacity[cpu] * per_cpu(capacity_freq_ref, cpu);
289288
capacity = div64_u64(capacity << SCHED_CAPACITY_SHIFT,
290289
capacity_scale);
291290
topology_set_cpu_scale(cpu, capacity);
@@ -321,15 +320,15 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
321320
cpu_node, raw_capacity[cpu]);
322321

323322
/*
324-
* Update freq_factor for calculating early boot cpu capacities.
323+
* Update capacity_freq_ref for calculating early boot CPU capacities.
325324
* For non-clk CPU DVFS mechanism, there's no way to get the
326325
* frequency value now, assuming they are running at the same
327-
* frequency (by keeping the initial freq_factor value).
326+
* frequency (by keeping the initial capacity_freq_ref value).
328327
*/
329328
cpu_clk = of_clk_get(cpu_node, 0);
330329
if (!PTR_ERR_OR_ZERO(cpu_clk)) {
331-
per_cpu(freq_factor, cpu) =
332-
clk_get_rate(cpu_clk) / 1000;
330+
per_cpu(capacity_freq_ref, cpu) =
331+
clk_get_rate(cpu_clk) / HZ_PER_KHZ;
333332
clk_put(cpu_clk);
334333
}
335334
} else {
@@ -411,7 +410,7 @@ init_cpu_capacity_callback(struct notifier_block *nb,
411410
cpumask_andnot(cpus_to_visit, cpus_to_visit, policy->related_cpus);
412411

413412
for_each_cpu(cpu, policy->related_cpus)
414-
per_cpu(freq_factor, cpu) = policy->cpuinfo.max_freq / 1000;
413+
per_cpu(capacity_freq_ref, cpu) = policy->cpuinfo.max_freq;
415414

416415
if (cpumask_empty(cpus_to_visit)) {
417416
topology_normalize_cpu_scale();

include/linux/arch_topology.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ static inline unsigned long topology_get_cpu_scale(int cpu)
2727

2828
void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity);
2929

30+
DECLARE_PER_CPU(unsigned long, capacity_freq_ref);
31+
32+
static inline unsigned long topology_get_freq_ref(int cpu)
33+
{
34+
return per_cpu(capacity_freq_ref, cpu);
35+
}
36+
3037
DECLARE_PER_CPU(unsigned long, arch_freq_scale);
3138

3239
static inline unsigned long topology_get_freq_scale(int cpu)

include/linux/sched/topology.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ void arch_update_thermal_pressure(const struct cpumask *cpus,
279279
{ }
280280
#endif
281281

282+
#ifndef arch_scale_freq_ref
283+
static __always_inline
284+
unsigned int arch_scale_freq_ref(int cpu)
285+
{
286+
return 0;
287+
}
288+
#endif
289+
282290
static inline int task_node(const struct task_struct *p)
283291
{
284292
return cpu_to_node(task_cpu(p));

0 commit comments

Comments
 (0)