diff mbox

[RFC,2/2] cpufreq: arm_big_little: provide cpu capacity

Message ID 1412749572-29449-3-git-send-email-mturquette@linaro.org
State New
Headers show

Commit Message

Mike Turquette Oct. 8, 2014, 6:26 a.m. UTC
Move the cpu capacity bits out of arch/arm/ and into the CPUfreq driver.
Not all ARM devices will use CPUfreq and it is unsafe to assume as such
in topology.c.

Instead, use the new capacity_ops introduced into CFS. If this code is
generic enough then it could be factored and shared via a header to make
it easier for other CPUfreq drivers to take advantage of it.

Signed-off-by: Mike Turquette <mturquette@linaro.org>
---
This approach simply builds on top of Morten's series. I am not sure
that the per-cpu method is the best way to go in the future. And if so I
imagine that the CPUfreq core could provide everything except for the
cpu_eff part.

In general I think that the overlap between CPUfreq drivers and
arch/arm/kernel/topology.c is something that needs to addresssed soon,
as both pieces of code are re-inventing parts of each other.

 arch/arm/include/asm/topology.h  |  2 ++
 arch/arm/kernel/topology.c       | 42 ++-------------------------------
 drivers/cpufreq/arm_big_little.c | 51 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 40 deletions(-)

Comments

Morten Rasmussen Oct. 8, 2014, 3:48 p.m. UTC | #1
On Wed, Oct 08, 2014 at 07:26:12AM +0100, Mike Turquette wrote:
> Move the cpu capacity bits out of arch/arm/ and into the CPUfreq driver.
> Not all ARM devices will use CPUfreq and it is unsafe to assume as such
> in topology.c.
> 
> Instead, use the new capacity_ops introduced into CFS. If this code is
> generic enough then it could be factored and shared via a header to make
> it easier for other CPUfreq drivers to take advantage of it.
> 
> Signed-off-by: Mike Turquette <mturquette@linaro.org>
> ---
> This approach simply builds on top of Morten's series. I am not sure
> that the per-cpu method is the best way to go in the future. And if so I
> imagine that the CPUfreq core could provide everything except for the
> cpu_eff part.
> 
> In general I think that the overlap between CPUfreq drivers and
> arch/arm/kernel/topology.c is something that needs to addresssed soon,
> as both pieces of code are re-inventing parts of each other.

I think it would be easier to deal with the capacity scaling if we split
it into two scaling factors (like Vincent proposed by using the existing
arch_scale_{cpu,freq}_capacity() functions). Then whatever handles
frequency scaling doesn't have to coordinate with uarch scaling. Both
would be factors in the range 0..1024. We would just multiply the two
scaling factors in fair.c when needed (and shift as necessary).

Wouldn't that make it simple enough that we can implement it in a
generic way in arch/*/topology.c with a bit of help from the cpufreq
framework without involving any drivers directly? Or is that just
wishful thinking? :)
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Peter Zijlstra Oct. 9, 2014, 9:02 a.m. UTC | #2
On Wed, Oct 08, 2014 at 03:37:32PM -0700, Mike Turquette wrote:
> It creates a dependency such that any ARM platform that wants to have
> frequency-invariant load must use CPUfreq. I don't think we want that
> dependency. CPUfreq is a likely back-end for many devices, but not all.
> 
> Consider near-future ARM devices that support ACPI for power management
> with no corresponding CPUfreq driver. For example if the CPPC driver is
> not hooked up to CPUfreq, platforms using CPPC will not jive with the
> ARM arch hook that depends on CPUfreq.

Oh crap no, CPPC will not add yet another interface to cpu frequency
stuff.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
Peter Zijlstra Oct. 9, 2014, 5:38 p.m. UTC | #3
On Thu, Oct 09, 2014 at 10:25:13AM -0700, Mike Turquette wrote:
> Quoting Peter Zijlstra (2014-10-09 02:02:52)
> > On Wed, Oct 08, 2014 at 03:37:32PM -0700, Mike Turquette wrote:
> > > It creates a dependency such that any ARM platform that wants to have
> > > frequency-invariant load must use CPUfreq. I don't think we want that
> > > dependency. CPUfreq is a likely back-end for many devices, but not all.
> > > 
> > > Consider near-future ARM devices that support ACPI for power management
> > > with no corresponding CPUfreq driver. For example if the CPPC driver is
> > > not hooked up to CPUfreq, platforms using CPPC will not jive with the
> > > ARM arch hook that depends on CPUfreq.
> > 
> > Oh crap no, CPPC will not add yet another interface to cpu frequency
> > stuff.
> 
> Right.
> 
> So let's say the ARM arch hook creates a dependency on CPUfreq to scale
> capacity as a function of cpu frequency (as it does in the ARM scale
> invariance series).
> 
> Then let's say that a hypothetical ARM platform named "foo" uses CPPC
> and not CPUfreq to scale frequency. Foo's implementation of CPPC does
> not use any of the full-auto or hw-auto stuff. It allows the OS to
> request minimum performance levels and the like.
> 
> In this case, how can foo take advantage of the scale invariant stuff?
> 
> Also, feel free to replace "CPPC" with "anything other than CPUfreq".
> The problem is a general one and not specific to CPPC or ACPI.

Well answer #1 is that you simply should not ever bypass cpufreq for
setting cpu frequencies (be this the existing cpufreq or the future
integrated cpufreq).

Answer #2 is that if you were allowed to create a second infrastructure
and you're not calling the right scheduler hooks right along with it,
you're buggy.

In short, your problem, not mine.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/
diff mbox

Patch

diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
index 2fe85ff..3951232 100644
--- a/arch/arm/include/asm/topology.h
+++ b/arch/arm/include/asm/topology.h
@@ -14,6 +14,8 @@  struct cputopo_arm {
 };
 
 extern struct cputopo_arm cpu_topology[NR_CPUS];
+extern unsigned long max_raw_capacity;
+DECLARE_PER_CPU(unsigned long, cpu_raw_capacity);
 
 #define topology_physical_package_id(cpu)	(cpu_topology[cpu].socket_id)
 #define topology_core_id(cpu)		(cpu_topology[cpu].core_id)
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
index 5f049ec..a2c9b5f 100644
--- a/arch/arm/kernel/topology.c
+++ b/arch/arm/kernel/topology.c
@@ -79,8 +79,8 @@  static unsigned long *__cpu_capacity;
 
 static unsigned long middle_capacity = 1;
 
-static unsigned long max_raw_capacity = 1;
-static DEFINE_PER_CPU(unsigned long, cpu_raw_capacity);
+unsigned long max_raw_capacity = 1;
+DEFINE_PER_CPU(unsigned long, cpu_raw_capacity);
 
 /*
  * Iterate all CPUs' descriptor in DT and compute the efficiency
@@ -175,44 +175,6 @@  static void update_cpu_capacity(unsigned int cpu)
 		cpu, arch_scale_freq_capacity(NULL, cpu));
 }
 
-/*
- * Scheduler load-tracking scale-invariance
- *
- * Provides the scheduler with a scale-invariance correction factor that
- * compensates for frequency scaling and micro-architecture differences between
- * cpus.
- */
-
-static DEFINE_PER_CPU(atomic_long_t, cpu_curr_freq);
-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)
-{
-	atomic_long_set(&per_cpu(cpu_curr_freq, cpu), freq);
-}
-
-/* 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);
-}
-
-unsigned long arch_scale_load_capacity(int cpu)
-{
-	unsigned long curr = atomic_long_read(&per_cpu(cpu_curr_freq, cpu));
-	unsigned long max = atomic_long_read(&per_cpu(cpu_max_freq, cpu));
-	unsigned long ret;
-
-	if (!max || !per_cpu(cpu_raw_capacity, cpu))
-		return SCHED_CAPACITY_SCALE;
-
-	ret = (curr * SCHED_CAPACITY_SCALE) / max;
-	ret = (ret * per_cpu(cpu_raw_capacity, cpu)) / max_raw_capacity;
-
-	return ret;
-}
-
 #else
 static inline void parse_dt_topology(void) {}
 static inline void update_cpu_capacity(unsigned int cpuid) {}
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index a46c223..5baffbd 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -31,7 +31,10 @@ 
 #include <linux/slab.h>
 #include <linux/topology.h>
 #include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/rcupdate.h>
 #include <asm/bL_switcher.h>
+#include <asm/topology.h>
 
 #include "arm_big_little.h"
 
@@ -533,9 +536,52 @@  static struct notifier_block bL_switcher_notifier = {
 	.notifier_call = bL_cpufreq_switcher_notifier,
 };
 
+/*
+ * Scheduler load-tracking scale-invariance
+ *
+ * Provides the scheduler with a scale-invariance correction factor that
+ * compensates for frequency scaling and micro-architecture differences between
+ * cpus.
+ */
+
+static DEFINE_PER_CPU(atomic_long_t, cpu_curr_freq);
+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)
+{
+	atomic_long_set(&per_cpu(cpu_curr_freq, cpu), freq);
+}
+
+/* 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);
+}
+
+/*
+ * scale_load_capacity returns the current capacity for a given cpu, adjusted
+ * for micro-architectural differences and taking into accout cpu frequency
+ */
+unsigned long scale_load_capacity(int cpu)
+{
+	unsigned long curr = atomic_long_read(&per_cpu(cpu_curr_freq, cpu));
+	unsigned long max = atomic_long_read(&per_cpu(cpu_max_freq, cpu));
+	unsigned long ret;
+
+	if (!max || !per_cpu(cpu_raw_capacity, cpu))
+		return SCHED_CAPACITY_SCALE;
+
+	ret = (curr * SCHED_CAPACITY_SCALE) / max;
+	ret = (ret * per_cpu(cpu_raw_capacity, cpu)) / max_raw_capacity;
+
+	return ret;
+}
+
 int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
 {
 	int ret, i;
+	unsigned long flags;
 
 	if (arm_bL_ops) {
 		pr_debug("%s: Already registered: %s, exiting\n", __func__,
@@ -550,6 +596,11 @@  int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops)
 
 	arm_bL_ops = ops;
 
+	spin_lock_irqsave(&cfs_capacity_ops.lock, flags);
+	cfs_capacity_ops.get_capacity = scale_load_capacity;
+	spin_unlock_irqrestore(&cfs_capacity_ops.lock, flags);
+	synchronize_rcu();
+
 	ret = bL_switcher_get_enabled();
 	set_switching_enabled(ret);