diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/sched/core.c | 64 | ||||
| -rw-r--r-- | kernel/sched/fair.c | 5 | ||||
| -rw-r--r-- | kernel/sched/sched.h | 2 |
3 files changed, 61 insertions, 10 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 6546083af3e0..781acb91a50a 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
| @@ -5994,6 +5994,44 @@ struct sched_domain_topology_level { | |||
| 5994 | struct sd_data data; | 5994 | struct sd_data data; |
| 5995 | }; | 5995 | }; |
| 5996 | 5996 | ||
| 5997 | /* | ||
| 5998 | * Build an iteration mask that can exclude certain CPUs from the upwards | ||
| 5999 | * domain traversal. | ||
| 6000 | * | ||
| 6001 | * Asymmetric node setups can result in situations where the domain tree is of | ||
| 6002 | * unequal depth, make sure to skip domains that already cover the entire | ||
| 6003 | * range. | ||
| 6004 | * | ||
| 6005 | * In that case build_sched_domains() will have terminated the iteration early | ||
| 6006 | * and our sibling sd spans will be empty. Domains should always include the | ||
| 6007 | * cpu they're built on, so check that. | ||
| 6008 | * | ||
| 6009 | */ | ||
| 6010 | static void build_group_mask(struct sched_domain *sd, struct sched_group *sg) | ||
| 6011 | { | ||
| 6012 | const struct cpumask *span = sched_domain_span(sd); | ||
| 6013 | struct sd_data *sdd = sd->private; | ||
| 6014 | struct sched_domain *sibling; | ||
| 6015 | int i; | ||
| 6016 | |||
| 6017 | for_each_cpu(i, span) { | ||
| 6018 | sibling = *per_cpu_ptr(sdd->sd, i); | ||
| 6019 | if (!cpumask_test_cpu(i, sched_domain_span(sibling))) | ||
| 6020 | continue; | ||
| 6021 | |||
| 6022 | cpumask_set_cpu(i, sched_group_mask(sg)); | ||
| 6023 | } | ||
| 6024 | } | ||
| 6025 | |||
| 6026 | /* | ||
| 6027 | * Return the canonical balance cpu for this group, this is the first cpu | ||
| 6028 | * of this group that's also in the iteration mask. | ||
| 6029 | */ | ||
| 6030 | int group_balance_cpu(struct sched_group *sg) | ||
| 6031 | { | ||
| 6032 | return cpumask_first_and(sched_group_cpus(sg), sched_group_mask(sg)); | ||
| 6033 | } | ||
| 6034 | |||
| 5997 | static int | 6035 | static int |
| 5998 | build_overlap_sched_groups(struct sched_domain *sd, int cpu) | 6036 | build_overlap_sched_groups(struct sched_domain *sd, int cpu) |
| 5999 | { | 6037 | { |
| @@ -6012,6 +6050,12 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu) | |||
| 6012 | if (cpumask_test_cpu(i, covered)) | 6050 | if (cpumask_test_cpu(i, covered)) |
| 6013 | continue; | 6051 | continue; |
| 6014 | 6052 | ||
| 6053 | child = *per_cpu_ptr(sdd->sd, i); | ||
| 6054 | |||
| 6055 | /* See the comment near build_group_mask(). */ | ||
| 6056 | if (!cpumask_test_cpu(i, sched_domain_span(child))) | ||
| 6057 | continue; | ||
| 6058 | |||
| 6015 | sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(), | 6059 | sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(), |
| 6016 | GFP_KERNEL, cpu_to_node(cpu)); | 6060 | GFP_KERNEL, cpu_to_node(cpu)); |
| 6017 | 6061 | ||
| @@ -6019,8 +6063,6 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu) | |||
| 6019 | goto fail; | 6063 | goto fail; |
| 6020 | 6064 | ||
| 6021 | sg_span = sched_group_cpus(sg); | 6065 | sg_span = sched_group_cpus(sg); |
| 6022 | |||
| 6023 | child = *per_cpu_ptr(sdd->sd, i); | ||
| 6024 | if (child->child) { | 6066 | if (child->child) { |
| 6025 | child = child->child; | 6067 | child = child->child; |
| 6026 | cpumask_copy(sg_span, sched_domain_span(child)); | 6068 | cpumask_copy(sg_span, sched_domain_span(child)); |
| @@ -6030,13 +6072,18 @@ build_overlap_sched_groups(struct sched_domain *sd, int cpu) | |||
| 6030 | cpumask_or(covered, covered, sg_span); | 6072 | cpumask_or(covered, covered, sg_span); |
| 6031 | 6073 | ||
| 6032 | sg->sgp = *per_cpu_ptr(sdd->sgp, i); | 6074 | sg->sgp = *per_cpu_ptr(sdd->sgp, i); |
| 6033 | atomic_inc(&sg->sgp->ref); | 6075 | if (atomic_inc_return(&sg->sgp->ref) == 1) |
| 6076 | build_group_mask(sd, sg); | ||
| 6077 | |||
| 6034 | 6078 | ||
| 6079 | /* | ||
| 6080 | * Make sure the first group of this domain contains the | ||
| 6081 | * canonical balance cpu. Otherwise the sched_domain iteration | ||
| 6082 | * breaks. See update_sg_lb_stats(). | ||
| 6083 | */ | ||
| 6035 | if ((!groups && cpumask_test_cpu(cpu, sg_span)) || | 6084 | if ((!groups && cpumask_test_cpu(cpu, sg_span)) || |
| 6036 | cpumask_first(sg_span) == cpu) { | 6085 | group_balance_cpu(sg) == cpu) |
| 6037 | WARN_ON_ONCE(!cpumask_test_cpu(cpu, sg_span)); | ||
| 6038 | groups = sg; | 6086 | groups = sg; |
| 6039 | } | ||
| 6040 | 6087 | ||
| 6041 | if (!first) | 6088 | if (!first) |
| 6042 | first = sg; | 6089 | first = sg; |
| @@ -6109,6 +6156,7 @@ build_sched_groups(struct sched_domain *sd, int cpu) | |||
| 6109 | 6156 | ||
| 6110 | cpumask_clear(sched_group_cpus(sg)); | 6157 | cpumask_clear(sched_group_cpus(sg)); |
| 6111 | sg->sgp->power = 0; | 6158 | sg->sgp->power = 0; |
| 6159 | cpumask_setall(sched_group_mask(sg)); | ||
| 6112 | 6160 | ||
| 6113 | for_each_cpu(j, span) { | 6161 | for_each_cpu(j, span) { |
| 6114 | if (get_group(j, sdd, NULL) != group) | 6162 | if (get_group(j, sdd, NULL) != group) |
| @@ -6150,7 +6198,7 @@ static void init_sched_groups_power(int cpu, struct sched_domain *sd) | |||
| 6150 | sg = sg->next; | 6198 | sg = sg->next; |
| 6151 | } while (sg != sd->groups); | 6199 | } while (sg != sd->groups); |
| 6152 | 6200 | ||
| 6153 | if (cpu != group_first_cpu(sg)) | 6201 | if (cpu != group_balance_cpu(sg)) |
| 6154 | return; | 6202 | return; |
| 6155 | 6203 | ||
| 6156 | update_group_power(sd, cpu); | 6204 | update_group_power(sd, cpu); |
| @@ -6525,7 +6573,7 @@ static int __sdt_alloc(const struct cpumask *cpu_map) | |||
| 6525 | 6573 | ||
| 6526 | *per_cpu_ptr(sdd->sg, j) = sg; | 6574 | *per_cpu_ptr(sdd->sg, j) = sg; |
| 6527 | 6575 | ||
| 6528 | sgp = kzalloc_node(sizeof(struct sched_group_power), | 6576 | sgp = kzalloc_node(sizeof(struct sched_group_power) + cpumask_size(), |
| 6529 | GFP_KERNEL, cpu_to_node(j)); | 6577 | GFP_KERNEL, cpu_to_node(j)); |
| 6530 | if (!sgp) | 6578 | if (!sgp) |
| 6531 | return -ENOMEM; | 6579 | return -ENOMEM; |
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index b2a2d236f27b..54cbaa4e7b37 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c | |||
| @@ -3652,7 +3652,7 @@ static inline void update_sg_lb_stats(struct lb_env *env, | |||
| 3652 | int i; | 3652 | int i; |
| 3653 | 3653 | ||
| 3654 | if (local_group) | 3654 | if (local_group) |
| 3655 | balance_cpu = group_first_cpu(group); | 3655 | balance_cpu = group_balance_cpu(group); |
| 3656 | 3656 | ||
| 3657 | /* Tally up the load of all CPUs in the group */ | 3657 | /* Tally up the load of all CPUs in the group */ |
| 3658 | max_cpu_load = 0; | 3658 | max_cpu_load = 0; |
| @@ -3667,7 +3667,8 @@ static inline void update_sg_lb_stats(struct lb_env *env, | |||
| 3667 | 3667 | ||
| 3668 | /* Bias balancing toward cpus of our domain */ | 3668 | /* Bias balancing toward cpus of our domain */ |
| 3669 | if (local_group) { | 3669 | if (local_group) { |
| 3670 | if (idle_cpu(i) && !first_idle_cpu) { | 3670 | if (idle_cpu(i) && !first_idle_cpu && |
| 3671 | cpumask_test_cpu(i, sched_group_mask(group))) { | ||
| 3671 | first_idle_cpu = 1; | 3672 | first_idle_cpu = 1; |
| 3672 | balance_cpu = i; | 3673 | balance_cpu = i; |
| 3673 | } | 3674 | } |
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index ba9dccfd24ce..6d52cea7f33d 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h | |||
| @@ -526,6 +526,8 @@ static inline struct sched_domain *highest_flag_domain(int cpu, int flag) | |||
| 526 | DECLARE_PER_CPU(struct sched_domain *, sd_llc); | 526 | DECLARE_PER_CPU(struct sched_domain *, sd_llc); |
| 527 | DECLARE_PER_CPU(int, sd_llc_id); | 527 | DECLARE_PER_CPU(int, sd_llc_id); |
| 528 | 528 | ||
| 529 | extern int group_balance_cpu(struct sched_group *sg); | ||
| 530 | |||
| 529 | #endif /* CONFIG_SMP */ | 531 | #endif /* CONFIG_SMP */ |
| 530 | 532 | ||
| 531 | #include "stats.h" | 533 | #include "stats.h" |
