On Wed, Apr 22, 2015 at 05:20:07PM +0100, Vincent Guittot wrote:
On 16 April 2015 at 07:29, Michael Turquette mturquette@linaro.org wrote:
From: Morten Rasmussen Morten.Rasmussen@arm.com
Implements arch-specific function to provide the scheduler with a frequency scaling correction factor for more accurate load-tracking. The factor is:
current_freq(cpu) * SCHED_CAPACITY_SCALE / max_freq(cpu)
This implementation only provides frequency invariance. No micro-architecture invariance yet.
Cc: Russell King linux@arm.linux.org.uk Signed-off-by: Morten Rasmussen morten.rasmussen@arm.com
arch/arm/include/asm/topology.h | 4 ++++ arch/arm/kernel/topology.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+)
diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h index 2fe85ff..86acd06 100644 --- a/arch/arm/include/asm/topology.h +++ b/arch/arm/include/asm/topology.h @@ -24,6 +24,10 @@ void init_cpu_topology(void); void store_cpu_topology(unsigned int cpuid); const struct cpumask *cpu_coregroup_mask(int cpu);
+#define arch_scale_freq_capacity arm_arch_scale_freq_capacity +struct sched_domain; +extern unsigned long arm_arch_scale_freq_capacity(struct sched_domain *sd, int cpu);
#else
static inline void init_cpu_topology(void) { } diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c index 08b7847..eccc634 100644 --- a/arch/arm/kernel/topology.c +++ b/arch/arm/kernel/topology.c @@ -169,6 +169,47 @@ static void update_cpu_capacity(unsigned int cpu) cpu, arch_scale_cpu_capacity(NULL, cpu)); }
+/*
- Scheduler load-tracking scale-invariance
- Provides the scheduler with a scale-invariance correction factor that
- compensates for frequency scaling.
- */
+static DEFINE_PER_CPU(atomic_long_t, cpu_freq_capacity); +static DEFINE_PER_CPU(atomic_long_t, cpu_max_freq);
+/* cpufreq callback function setting current cpu frequency */ +void arch_scale_set_curr_freq(int cpu, unsigned long freq) +{
unsigned long max = atomic_long_read(&per_cpu(cpu_max_freq, cpu));
unsigned long curr;
if (!max)
return;
curr = (freq * SCHED_CAPACITY_SCALE) / max;
atomic_long_set(&per_cpu(cpu_freq_capacity, cpu), curr);
+}
+/* cpufreq callback function setting max cpu frequency */ +void arch_scale_set_max_freq(int cpu, unsigned long freq) +{
atomic_long_set(&per_cpu(cpu_max_freq, cpu), freq);
You should update per_cpu(cpu_freq_capacity, cpu) too
Right. I made the assumption that we wouldn't change max very often. But I guess we could do something like:
unsigned long curr, old_max;
if (!freq) return;
old_max = atomic_long_read(&per_cpu(cpu_max_freq, cpu)); curr = atomic_long_read(&per_cpu(cpu_freq_capacity, cpu)); curr = (curr * old_max)/freq;
atomic_long_set(&per_cpu(cpu_max_freq, cpu), freq); atomic_long_set(&per_cpu(cpu_freq_capacity, cpu), curr);
We would get some rounding errors though if we change max. For example:
curr max capacity 200 1000 204 200 800 255 (as proposed for arch_scale_set_max_freq()) 200 800 256 (if computed by arch_scale_set_curr_freq())
This can only be avoided by having another per_cpu variable storing the curr freq too. It shouldn't be a big deal. I can fix that.
Thanks, Morten