diff options
author | Tim Chen <tim.c.chen@linux.intel.com> | 2016-11-22 15:23:53 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-11-24 08:09:46 -0500 |
commit | afe06efdf07c12fd9370d5cce5383398cedf6c90 (patch) | |
tree | 3219592dcafbd67be8cbb5b97315f2f25fb5c617 | |
parent | 2b4d5b2582deffb77b3b4b48a59cd36e9e1e14d9 (diff) |
sched: Extend scheduler's asym packing
We generalize the scheduler's asym packing to provide an ordering
of the cpu beyond just the cpu number. This allows the use of the
ASYM_PACKING scheduler machinery to move loads to preferred CPU in a
sched domain. The preference is defined with the cpu priority
given by arch_asym_cpu_priority(cpu).
We also record the most preferred cpu in a sched group when
we build the cpu's capacity for fast lookup of preferred cpu
during load balancing.
Co-developed-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: linux-pm@vger.kernel.org
Cc: jolsa@redhat.com
Cc: rjw@rjwysocki.net
Cc: linux-acpi@vger.kernel.org
Cc: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Cc: bp@suse.de
Link: http://lkml.kernel.org/r/0e73ae12737dfaafa46c07066cc7c5d3f1675e46.1479844244.git.tim.c.chen@linux.intel.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | include/linux/sched.h | 2 | ||||
-rw-r--r-- | kernel/sched/core.c | 15 | ||||
-rw-r--r-- | kernel/sched/fair.c | 53 | ||||
-rw-r--r-- | kernel/sched/sched.h | 6 |
4 files changed, 59 insertions, 17 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index 19abba04ceca..fe9a499d5aa4 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -1077,6 +1077,8 @@ static inline int cpu_numa_flags(void) | |||
1077 | } | 1077 | } |
1078 | #endif | 1078 | #endif |
1079 | 1079 | ||
1080 | extern int arch_asym_cpu_priority(int cpu); | ||
1081 | |||
1080 | struct sched_domain_attr { | 1082 | struct sched_domain_attr { |
1081 | int relax_domain_level; | 1083 | int relax_domain_level; |
1082 | }; | 1084 | }; |
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index dc64bd71ed2b..393759bd526e 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -6303,7 +6303,22 @@ static void init_sched_groups_capacity(int cpu, struct sched_domain *sd) | |||
6303 | WARN_ON(!sg); | 6303 | WARN_ON(!sg); |
6304 | 6304 | ||
6305 | do { | 6305 | do { |
6306 | int cpu, max_cpu = -1; | ||
6307 | |||
6306 | sg->group_weight = cpumask_weight(sched_group_cpus(sg)); | 6308 | sg->group_weight = cpumask_weight(sched_group_cpus(sg)); |
6309 | |||
6310 | if (!(sd->flags & SD_ASYM_PACKING)) | ||
6311 | goto next; | ||
6312 | |||
6313 | for_each_cpu(cpu, sched_group_cpus(sg)) { | ||
6314 | if (max_cpu < 0) | ||
6315 | max_cpu = cpu; | ||
6316 | else if (sched_asym_prefer(cpu, max_cpu)) | ||
6317 | max_cpu = cpu; | ||
6318 | } | ||
6319 | sg->asym_prefer_cpu = max_cpu; | ||
6320 | |||
6321 | next: | ||
6307 | sg = sg->next; | 6322 | sg = sg->next; |
6308 | } while (sg != sd->groups); | 6323 | } while (sg != sd->groups); |
6309 | 6324 | ||
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index aa475896782d..18d9e75f1f6e 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c | |||
@@ -97,6 +97,16 @@ unsigned int normalized_sysctl_sched_wakeup_granularity = 1000000UL; | |||
97 | 97 | ||
98 | const_debug unsigned int sysctl_sched_migration_cost = 500000UL; | 98 | const_debug unsigned int sysctl_sched_migration_cost = 500000UL; |
99 | 99 | ||
100 | #ifdef CONFIG_SMP | ||
101 | /* | ||
102 | * For asym packing, by default the lower numbered cpu has higher priority. | ||
103 | */ | ||
104 | int __weak arch_asym_cpu_priority(int cpu) | ||
105 | { | ||
106 | return -cpu; | ||
107 | } | ||
108 | #endif | ||
109 | |||
100 | #ifdef CONFIG_CFS_BANDWIDTH | 110 | #ifdef CONFIG_CFS_BANDWIDTH |
101 | /* | 111 | /* |
102 | * Amount of runtime to allocate from global (tg) to local (per-cfs_rq) pool | 112 | * Amount of runtime to allocate from global (tg) to local (per-cfs_rq) pool |
@@ -7388,16 +7398,18 @@ asym_packing: | |||
7388 | if (env->idle == CPU_NOT_IDLE) | 7398 | if (env->idle == CPU_NOT_IDLE) |
7389 | return true; | 7399 | return true; |
7390 | /* | 7400 | /* |
7391 | * ASYM_PACKING needs to move all the work to the lowest | 7401 | * ASYM_PACKING needs to move all the work to the highest |
7392 | * numbered CPUs in the group, therefore mark all groups | 7402 | * prority CPUs in the group, therefore mark all groups |
7393 | * higher than ourself as busy. | 7403 | * of lower priority than ourself as busy. |
7394 | */ | 7404 | */ |
7395 | if (sgs->sum_nr_running && env->dst_cpu < group_first_cpu(sg)) { | 7405 | if (sgs->sum_nr_running && |
7406 | sched_asym_prefer(env->dst_cpu, sg->asym_prefer_cpu)) { | ||
7396 | if (!sds->busiest) | 7407 | if (!sds->busiest) |
7397 | return true; | 7408 | return true; |
7398 | 7409 | ||
7399 | /* Prefer to move from highest possible cpu's work */ | 7410 | /* Prefer to move from lowest priority cpu's work */ |
7400 | if (group_first_cpu(sds->busiest) < group_first_cpu(sg)) | 7411 | if (sched_asym_prefer(sds->busiest->asym_prefer_cpu, |
7412 | sg->asym_prefer_cpu)) | ||
7401 | return true; | 7413 | return true; |
7402 | } | 7414 | } |
7403 | 7415 | ||
@@ -7549,8 +7561,8 @@ static int check_asym_packing(struct lb_env *env, struct sd_lb_stats *sds) | |||
7549 | if (!sds->busiest) | 7561 | if (!sds->busiest) |
7550 | return 0; | 7562 | return 0; |
7551 | 7563 | ||
7552 | busiest_cpu = group_first_cpu(sds->busiest); | 7564 | busiest_cpu = sds->busiest->asym_prefer_cpu; |
7553 | if (env->dst_cpu > busiest_cpu) | 7565 | if (sched_asym_prefer(busiest_cpu, env->dst_cpu)) |
7554 | return 0; | 7566 | return 0; |
7555 | 7567 | ||
7556 | env->imbalance = DIV_ROUND_CLOSEST( | 7568 | env->imbalance = DIV_ROUND_CLOSEST( |
@@ -7888,10 +7900,11 @@ static int need_active_balance(struct lb_env *env) | |||
7888 | 7900 | ||
7889 | /* | 7901 | /* |
7890 | * ASYM_PACKING needs to force migrate tasks from busy but | 7902 | * ASYM_PACKING needs to force migrate tasks from busy but |
7891 | * higher numbered CPUs in order to pack all tasks in the | 7903 | * lower priority CPUs in order to pack all tasks in the |
7892 | * lowest numbered CPUs. | 7904 | * highest priority CPUs. |
7893 | */ | 7905 | */ |
7894 | if ((sd->flags & SD_ASYM_PACKING) && env->src_cpu > env->dst_cpu) | 7906 | if ((sd->flags & SD_ASYM_PACKING) && |
7907 | sched_asym_prefer(env->dst_cpu, env->src_cpu)) | ||
7895 | return 1; | 7908 | return 1; |
7896 | } | 7909 | } |
7897 | 7910 | ||
@@ -8740,7 +8753,7 @@ static inline bool nohz_kick_needed(struct rq *rq) | |||
8740 | unsigned long now = jiffies; | 8753 | unsigned long now = jiffies; |
8741 | struct sched_domain_shared *sds; | 8754 | struct sched_domain_shared *sds; |
8742 | struct sched_domain *sd; | 8755 | struct sched_domain *sd; |
8743 | int nr_busy, cpu = rq->cpu; | 8756 | int nr_busy, i, cpu = rq->cpu; |
8744 | bool kick = false; | 8757 | bool kick = false; |
8745 | 8758 | ||
8746 | if (unlikely(rq->idle_balance)) | 8759 | if (unlikely(rq->idle_balance)) |
@@ -8791,12 +8804,18 @@ static inline bool nohz_kick_needed(struct rq *rq) | |||
8791 | } | 8804 | } |
8792 | 8805 | ||
8793 | sd = rcu_dereference(per_cpu(sd_asym, cpu)); | 8806 | sd = rcu_dereference(per_cpu(sd_asym, cpu)); |
8794 | if (sd && (cpumask_first_and(nohz.idle_cpus_mask, | 8807 | if (sd) { |
8795 | sched_domain_span(sd)) < cpu)) { | 8808 | for_each_cpu(i, sched_domain_span(sd)) { |
8796 | kick = true; | 8809 | if (i == cpu || |
8797 | goto unlock; | 8810 | !cpumask_test_cpu(i, nohz.idle_cpus_mask)) |
8798 | } | 8811 | continue; |
8799 | 8812 | ||
8813 | if (sched_asym_prefer(i, cpu)) { | ||
8814 | kick = true; | ||
8815 | goto unlock; | ||
8816 | } | ||
8817 | } | ||
8818 | } | ||
8800 | unlock: | 8819 | unlock: |
8801 | rcu_read_unlock(); | 8820 | rcu_read_unlock(); |
8802 | return kick; | 8821 | return kick; |
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index d7e39317d688..7b34c7826ca5 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h | |||
@@ -540,6 +540,11 @@ struct dl_rq { | |||
540 | 540 | ||
541 | #ifdef CONFIG_SMP | 541 | #ifdef CONFIG_SMP |
542 | 542 | ||
543 | static inline bool sched_asym_prefer(int a, int b) | ||
544 | { | ||
545 | return arch_asym_cpu_priority(a) > arch_asym_cpu_priority(b); | ||
546 | } | ||
547 | |||
543 | /* | 548 | /* |
544 | * We add the notion of a root-domain which will be used to define per-domain | 549 | * We add the notion of a root-domain which will be used to define per-domain |
545 | * variables. Each exclusive cpuset essentially defines an island domain by | 550 | * variables. Each exclusive cpuset essentially defines an island domain by |
@@ -908,6 +913,7 @@ struct sched_group { | |||
908 | 913 | ||
909 | unsigned int group_weight; | 914 | unsigned int group_weight; |
910 | struct sched_group_capacity *sgc; | 915 | struct sched_group_capacity *sgc; |
916 | int asym_prefer_cpu; /* cpu of highest priority in group */ | ||
911 | 917 | ||
912 | /* | 918 | /* |
913 | * The CPUs this group covers. | 919 | * The CPUs this group covers. |