summaryrefslogtreecommitdiffstats
path: root/meta-eas/recipes-kernel/linux/linux-renesas/0053-sched-Calculate-energy-consumption-of-sched_group.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-eas/recipes-kernel/linux/linux-renesas/0053-sched-Calculate-energy-consumption-of-sched_group.patch')
-rw-r--r--meta-eas/recipes-kernel/linux/linux-renesas/0053-sched-Calculate-energy-consumption-of-sched_group.patch229
1 files changed, 229 insertions, 0 deletions
diff --git a/meta-eas/recipes-kernel/linux/linux-renesas/0053-sched-Calculate-energy-consumption-of-sched_group.patch b/meta-eas/recipes-kernel/linux/linux-renesas/0053-sched-Calculate-energy-consumption-of-sched_group.patch
new file mode 100644
index 0000000..2f82044
--- /dev/null
+++ b/meta-eas/recipes-kernel/linux/linux-renesas/0053-sched-Calculate-energy-consumption-of-sched_group.patch
@@ -0,0 +1,229 @@
+From 1e9ffadc70a89ede023b79139debe4f6a17c5c7f Mon Sep 17 00:00:00 2001
+From: Morten Rasmussen <morten.rasmussen@arm.com>
+Date: Thu, 18 Dec 2014 14:47:18 +0000
+Subject: [PATCH 53/92] sched: Calculate energy consumption of sched_group
+
+For energy-aware load-balancing decisions it is necessary to know the
+energy consumption estimates of groups of cpus. This patch introduces a
+basic function, sched_group_energy(), which estimates the energy
+consumption of the cpus in the group and any resources shared by the
+members of the group.
+
+NOTE: The function has five levels of identation and breaks the 80
+character limit. Refactoring is necessary.
+
+cc: Ingo Molnar <mingo@redhat.com>
+cc: Peter Zijlstra <peterz@infradead.org>
+Signed-off-by: Morten Rasmussen <morten.rasmussen@arm.com>
+(cherry picked from commit 1e09b216da57376d8321459eda52699cef8f7e1a)
+Signed-off-by: Gaku Inami <gaku.inami.xw@bp.renesas.com>
+---
+ kernel/sched/core.c | 4 ++
+ kernel/sched/fair.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ kernel/sched/sched.h | 1 +
+ 3 files changed, 161 insertions(+)
+
+diff --git a/kernel/sched/core.c b/kernel/sched/core.c
+index f2642d4..431c7e0 100644
+--- a/kernel/sched/core.c
++++ b/kernel/sched/core.c
+@@ -6002,6 +6002,7 @@ static void destroy_sched_domains(struct sched_domain *sd)
+ DEFINE_PER_CPU(struct sched_domain *, sd_numa);
+ DEFINE_PER_CPU(struct sched_domain *, sd_asym);
+ DEFINE_PER_CPU(struct sched_domain *, sd_ea);
++DEFINE_PER_CPU(struct sched_domain *, sd_scs);
+
+ static void update_top_cache_domain(int cpu)
+ {
+@@ -6036,6 +6037,9 @@ static void update_top_cache_domain(int cpu)
+ break;
+ }
+ rcu_assign_pointer(per_cpu(sd_ea, cpu), ea_sd);
++
++ sd = highest_flag_domain(cpu, SD_SHARE_CAP_STATES);
++ rcu_assign_pointer(per_cpu(sd_scs, cpu), sd);
+ }
+
+ /*
+diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
+index 0085d4f..1b8dca7 100644
+--- a/kernel/sched/fair.c
++++ b/kernel/sched/fair.c
+@@ -5331,6 +5331,162 @@ static inline bool energy_aware(void)
+ }
+
+ /*
++ * cpu_norm_util() returns the cpu util relative to a specific capacity,
++ * i.e. it's busy ratio, in the range [0..SCHED_CAPACITY_SCALE] which is useful
++ * for energy calculations. Using the scale-invariant util returned by
++ * cpu_util() and approximating scale-invariant util by:
++ *
++ * util ~ (curr_freq/max_freq)*1024 * capacity_orig/1024 * running_time/time
++ *
++ * the normalized util can be found using the specific capacity.
++ *
++ * capacity = capacity_orig * curr_freq/max_freq
++ *
++ * norm_util = running_time/time ~ util/capacity
++ */
++static unsigned long cpu_norm_util(int cpu, unsigned long capacity)
++{
++ int util = cpu_util(cpu);
++
++ if (util >= capacity)
++ return SCHED_CAPACITY_SCALE;
++
++ return (util << SCHED_CAPACITY_SHIFT)/capacity;
++}
++
++static unsigned long group_max_util(struct sched_group *sg)
++{
++ int i;
++ unsigned long max_util = 0;
++
++ for_each_cpu(i, sched_group_cpus(sg))
++ max_util = max(max_util, cpu_util(i));
++
++ return max_util;
++}
++
++/*
++ * group_norm_util() returns the approximated group util relative to it's
++ * current capacity (busy ratio) in the range [0..SCHED_CAPACITY_SCALE] for use
++ * in energy calculations. Since task executions may or may not overlap in time
++ * in the group the true normalized util is between max(cpu_norm_util(i)) and
++ * sum(cpu_norm_util(i)) when iterating over all cpus in the group, i. The
++ * latter is used as the estimate as it leads to a more pessimistic energy
++ * estimate (more busy).
++ */
++static unsigned long group_norm_util(struct sched_group *sg, int cap_idx)
++{
++ int i;
++ unsigned long util_sum = 0;
++ unsigned long capacity = sg->sge->cap_states[cap_idx].cap;
++
++ for_each_cpu(i, sched_group_cpus(sg))
++ util_sum += cpu_norm_util(i, capacity);
++
++ if (util_sum > SCHED_CAPACITY_SCALE)
++ return SCHED_CAPACITY_SCALE;
++ return util_sum;
++}
++
++static int find_new_capacity(struct sched_group *sg,
++ const struct sched_group_energy const *sge)
++{
++ int idx;
++ unsigned long util = group_max_util(sg);
++
++ for (idx = 0; idx < sge->nr_cap_states; idx++) {
++ if (sge->cap_states[idx].cap >= util)
++ return idx;
++ }
++
++ return idx;
++}
++
++/*
++ * sched_group_energy(): Computes the absolute energy consumption of cpus
++ * belonging to the sched_group including shared resources shared only by
++ * members of the group. Iterates over all cpus in the hierarchy below the
++ * sched_group starting from the bottom working it's way up before going to
++ * the next cpu until all cpus are covered at all levels. The current
++ * implementation is likely to gather the same util statistics multiple times.
++ * This can probably be done in a faster but more complex way.
++ * Note: sched_group_energy() may fail when racing with sched_domain updates.
++ */
++static int sched_group_energy(struct sched_group *sg_top)
++{
++ struct sched_domain *sd;
++ int cpu, total_energy = 0;
++ struct cpumask visit_cpus;
++ struct sched_group *sg;
++
++ WARN_ON(!sg_top->sge);
++
++ cpumask_copy(&visit_cpus, sched_group_cpus(sg_top));
++
++ while (!cpumask_empty(&visit_cpus)) {
++ struct sched_group *sg_shared_cap = NULL;
++
++ cpu = cpumask_first(&visit_cpus);
++
++ /*
++ * Is the group utilization affected by cpus outside this
++ * sched_group?
++ */
++ sd = rcu_dereference(per_cpu(sd_scs, cpu));
++
++ if (!sd)
++ /*
++ * We most probably raced with hotplug; returning a
++ * wrong energy estimation is better than entering an
++ * infinite loop.
++ */
++ return -EINVAL;
++
++ if (sd->parent)
++ sg_shared_cap = sd->parent->groups;
++
++ for_each_domain(cpu, sd) {
++ sg = sd->groups;
++
++ /* Has this sched_domain already been visited? */
++ if (sd->child && group_first_cpu(sg) != cpu)
++ break;
++
++ do {
++ struct sched_group *sg_cap_util;
++ unsigned long group_util;
++ int sg_busy_energy, sg_idle_energy, cap_idx;
++
++ if (sg_shared_cap && sg_shared_cap->group_weight >= sg->group_weight)
++ sg_cap_util = sg_shared_cap;
++ else
++ sg_cap_util = sg;
++
++ cap_idx = find_new_capacity(sg_cap_util, sg->sge);
++ group_util = group_norm_util(sg, cap_idx);
++ sg_busy_energy = (group_util * sg->sge->cap_states[cap_idx].power)
++ >> SCHED_CAPACITY_SHIFT;
++ sg_idle_energy = ((SCHED_CAPACITY_SCALE-group_util) * sg->sge->idle_states[0].power)
++ >> SCHED_CAPACITY_SHIFT;
++
++ total_energy += sg_busy_energy + sg_idle_energy;
++
++ if (!sd->child)
++ cpumask_xor(&visit_cpus, &visit_cpus, sched_group_cpus(sg));
++
++ if (cpumask_equal(sched_group_cpus(sg), sched_group_cpus(sg_top)))
++ goto next_cpu;
++
++ } while (sg = sg->next, sg != sd->groups);
++ }
++next_cpu:
++ continue;
++ }
++
++ return total_energy;
++}
++
++/*
+ * Detect M:N waker/wakee relationships via a switching-frequency heuristic.
+ *
+ * A waker of many should wake a different task than the one last awakened
+diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
+index 22b7cfd..75dcd85 100644
+--- a/kernel/sched/sched.h
++++ b/kernel/sched/sched.h
+@@ -893,6 +893,7 @@ static inline struct sched_domain *lowest_flag_domain(int cpu, int flag)
+ DECLARE_PER_CPU(struct sched_domain *, sd_numa);
+ DECLARE_PER_CPU(struct sched_domain *, sd_asym);
+ DECLARE_PER_CPU(struct sched_domain *, sd_ea);
++DECLARE_PER_CPU(struct sched_domain *, sd_scs);
+
+ struct sched_group_capacity {
+ atomic_t ref;
+--
+1.9.1
+