|
@@ -5566,17 +5566,6 @@ static int __init isolated_cpu_setup(char *str)
|
|
|
|
|
|
__setup("isolcpus=", isolated_cpu_setup);
|
|
|
|
|
|
-static const struct cpumask *cpu_cpu_mask(int cpu)
|
|
|
-{
|
|
|
- return cpumask_of_node(cpu_to_node(cpu));
|
|
|
-}
|
|
|
-
|
|
|
-struct sd_data {
|
|
|
- struct sched_domain **__percpu sd;
|
|
|
- struct sched_group **__percpu sg;
|
|
|
- struct sched_group_power **__percpu sgp;
|
|
|
-};
|
|
|
-
|
|
|
struct s_data {
|
|
|
struct sched_domain ** __percpu sd;
|
|
|
struct root_domain *rd;
|
|
@@ -5589,21 +5578,6 @@ enum s_alloc {
|
|
|
sa_none,
|
|
|
};
|
|
|
|
|
|
-struct sched_domain_topology_level;
|
|
|
-
|
|
|
-typedef struct sched_domain *(*sched_domain_init_f)(struct sched_domain_topology_level *tl, int cpu);
|
|
|
-typedef const struct cpumask *(*sched_domain_mask_f)(int cpu);
|
|
|
-
|
|
|
-#define SDTL_OVERLAP 0x01
|
|
|
-
|
|
|
-struct sched_domain_topology_level {
|
|
|
- sched_domain_init_f init;
|
|
|
- sched_domain_mask_f mask;
|
|
|
- int flags;
|
|
|
- int numa_level;
|
|
|
- struct sd_data data;
|
|
|
-};
|
|
|
-
|
|
|
/*
|
|
|
* Build an iteration mask that can exclude certain CPUs from the upwards
|
|
|
* domain traversal.
|
|
@@ -5832,34 +5806,6 @@ int __weak arch_sd_sibling_asym_packing(void)
|
|
|
* Non-inlined to reduce accumulated stack pressure in build_sched_domains()
|
|
|
*/
|
|
|
|
|
|
-#ifdef CONFIG_SCHED_DEBUG
|
|
|
-# define SD_INIT_NAME(sd, type) sd->name = #type
|
|
|
-#else
|
|
|
-# define SD_INIT_NAME(sd, type) do { } while (0)
|
|
|
-#endif
|
|
|
-
|
|
|
-#define SD_INIT_FUNC(type) \
|
|
|
-static noinline struct sched_domain * \
|
|
|
-sd_init_##type(struct sched_domain_topology_level *tl, int cpu) \
|
|
|
-{ \
|
|
|
- struct sched_domain *sd = *per_cpu_ptr(tl->data.sd, cpu); \
|
|
|
- *sd = SD_##type##_INIT; \
|
|
|
- SD_INIT_NAME(sd, type); \
|
|
|
- sd->private = &tl->data; \
|
|
|
- return sd; \
|
|
|
-}
|
|
|
-
|
|
|
-SD_INIT_FUNC(CPU)
|
|
|
-#ifdef CONFIG_SCHED_SMT
|
|
|
- SD_INIT_FUNC(SIBLING)
|
|
|
-#endif
|
|
|
-#ifdef CONFIG_SCHED_MC
|
|
|
- SD_INIT_FUNC(MC)
|
|
|
-#endif
|
|
|
-#ifdef CONFIG_SCHED_BOOK
|
|
|
- SD_INIT_FUNC(BOOK)
|
|
|
-#endif
|
|
|
-
|
|
|
static int default_relax_domain_level = -1;
|
|
|
int sched_domain_level_max;
|
|
|
|
|
@@ -5947,99 +5893,156 @@ static void claim_allocations(int cpu, struct sched_domain *sd)
|
|
|
*per_cpu_ptr(sdd->sgp, cpu) = NULL;
|
|
|
}
|
|
|
|
|
|
-#ifdef CONFIG_SCHED_SMT
|
|
|
-static const struct cpumask *cpu_smt_mask(int cpu)
|
|
|
-{
|
|
|
- return topology_thread_cpumask(cpu);
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-/*
|
|
|
- * Topology list, bottom-up.
|
|
|
- */
|
|
|
-static struct sched_domain_topology_level default_topology[] = {
|
|
|
-#ifdef CONFIG_SCHED_SMT
|
|
|
- { sd_init_SIBLING, cpu_smt_mask, },
|
|
|
-#endif
|
|
|
-#ifdef CONFIG_SCHED_MC
|
|
|
- { sd_init_MC, cpu_coregroup_mask, },
|
|
|
-#endif
|
|
|
-#ifdef CONFIG_SCHED_BOOK
|
|
|
- { sd_init_BOOK, cpu_book_mask, },
|
|
|
-#endif
|
|
|
- { sd_init_CPU, cpu_cpu_mask, },
|
|
|
- { NULL, },
|
|
|
-};
|
|
|
-
|
|
|
-static struct sched_domain_topology_level *sched_domain_topology = default_topology;
|
|
|
-
|
|
|
-#define for_each_sd_topology(tl) \
|
|
|
- for (tl = sched_domain_topology; tl->init; tl++)
|
|
|
-
|
|
|
#ifdef CONFIG_NUMA
|
|
|
-
|
|
|
static int sched_domains_numa_levels;
|
|
|
static int *sched_domains_numa_distance;
|
|
|
static struct cpumask ***sched_domains_numa_masks;
|
|
|
static int sched_domains_curr_level;
|
|
|
+#endif
|
|
|
|
|
|
-static inline int sd_local_flags(int level)
|
|
|
-{
|
|
|
- if (sched_domains_numa_distance[level] > RECLAIM_DISTANCE)
|
|
|
- return 0;
|
|
|
-
|
|
|
- return SD_BALANCE_EXEC | SD_BALANCE_FORK | SD_WAKE_AFFINE;
|
|
|
-}
|
|
|
+/*
|
|
|
+ * SD_flags allowed in topology descriptions.
|
|
|
+ *
|
|
|
+ * SD_SHARE_CPUPOWER - describes SMT topologies
|
|
|
+ * SD_SHARE_PKG_RESOURCES - describes shared caches
|
|
|
+ * SD_NUMA - describes NUMA topologies
|
|
|
+ *
|
|
|
+ * Odd one out:
|
|
|
+ * SD_ASYM_PACKING - describes SMT quirks
|
|
|
+ */
|
|
|
+#define TOPOLOGY_SD_FLAGS \
|
|
|
+ (SD_SHARE_CPUPOWER | \
|
|
|
+ SD_SHARE_PKG_RESOURCES | \
|
|
|
+ SD_NUMA | \
|
|
|
+ SD_ASYM_PACKING)
|
|
|
|
|
|
static struct sched_domain *
|
|
|
-sd_numa_init(struct sched_domain_topology_level *tl, int cpu)
|
|
|
+sd_init(struct sched_domain_topology_level *tl, int cpu)
|
|
|
{
|
|
|
struct sched_domain *sd = *per_cpu_ptr(tl->data.sd, cpu);
|
|
|
- int level = tl->numa_level;
|
|
|
- int sd_weight = cpumask_weight(
|
|
|
- sched_domains_numa_masks[level][cpu_to_node(cpu)]);
|
|
|
+ int sd_weight, sd_flags = 0;
|
|
|
+
|
|
|
+#ifdef CONFIG_NUMA
|
|
|
+ /*
|
|
|
+ * Ugly hack to pass state to sd_numa_mask()...
|
|
|
+ */
|
|
|
+ sched_domains_curr_level = tl->numa_level;
|
|
|
+#endif
|
|
|
+
|
|
|
+ sd_weight = cpumask_weight(tl->mask(cpu));
|
|
|
+
|
|
|
+ if (tl->sd_flags)
|
|
|
+ sd_flags = (*tl->sd_flags)();
|
|
|
+ if (WARN_ONCE(sd_flags & ~TOPOLOGY_SD_FLAGS,
|
|
|
+ "wrong sd_flags in topology description\n"))
|
|
|
+ sd_flags &= ~TOPOLOGY_SD_FLAGS;
|
|
|
|
|
|
*sd = (struct sched_domain){
|
|
|
.min_interval = sd_weight,
|
|
|
.max_interval = 2*sd_weight,
|
|
|
.busy_factor = 32,
|
|
|
.imbalance_pct = 125,
|
|
|
- .cache_nice_tries = 2,
|
|
|
- .busy_idx = 3,
|
|
|
- .idle_idx = 2,
|
|
|
+
|
|
|
+ .cache_nice_tries = 0,
|
|
|
+ .busy_idx = 0,
|
|
|
+ .idle_idx = 0,
|
|
|
.newidle_idx = 0,
|
|
|
.wake_idx = 0,
|
|
|
.forkexec_idx = 0,
|
|
|
|
|
|
.flags = 1*SD_LOAD_BALANCE
|
|
|
| 1*SD_BALANCE_NEWIDLE
|
|
|
- | 0*SD_BALANCE_EXEC
|
|
|
- | 0*SD_BALANCE_FORK
|
|
|
+ | 1*SD_BALANCE_EXEC
|
|
|
+ | 1*SD_BALANCE_FORK
|
|
|
| 0*SD_BALANCE_WAKE
|
|
|
- | 0*SD_WAKE_AFFINE
|
|
|
+ | 1*SD_WAKE_AFFINE
|
|
|
| 0*SD_SHARE_CPUPOWER
|
|
|
| 0*SD_SHARE_PKG_RESOURCES
|
|
|
- | 1*SD_SERIALIZE
|
|
|
+ | 0*SD_SERIALIZE
|
|
|
| 0*SD_PREFER_SIBLING
|
|
|
- | 1*SD_NUMA
|
|
|
- | sd_local_flags(level)
|
|
|
+ | 0*SD_NUMA
|
|
|
+ | sd_flags
|
|
|
,
|
|
|
+
|
|
|
.last_balance = jiffies,
|
|
|
.balance_interval = sd_weight,
|
|
|
+ .smt_gain = 0,
|
|
|
.max_newidle_lb_cost = 0,
|
|
|
.next_decay_max_lb_cost = jiffies,
|
|
|
+#ifdef CONFIG_SCHED_DEBUG
|
|
|
+ .name = tl->name,
|
|
|
+#endif
|
|
|
};
|
|
|
- SD_INIT_NAME(sd, NUMA);
|
|
|
- sd->private = &tl->data;
|
|
|
|
|
|
/*
|
|
|
- * Ugly hack to pass state to sd_numa_mask()...
|
|
|
+ * Convert topological properties into behaviour.
|
|
|
*/
|
|
|
- sched_domains_curr_level = tl->numa_level;
|
|
|
+
|
|
|
+ if (sd->flags & SD_SHARE_CPUPOWER) {
|
|
|
+ sd->imbalance_pct = 110;
|
|
|
+ sd->smt_gain = 1178; /* ~15% */
|
|
|
+ sd->flags |= arch_sd_sibling_asym_packing();
|
|
|
+
|
|
|
+ } else if (sd->flags & SD_SHARE_PKG_RESOURCES) {
|
|
|
+ sd->imbalance_pct = 117;
|
|
|
+ sd->cache_nice_tries = 1;
|
|
|
+ sd->busy_idx = 2;
|
|
|
+
|
|
|
+#ifdef CONFIG_NUMA
|
|
|
+ } else if (sd->flags & SD_NUMA) {
|
|
|
+ sd->cache_nice_tries = 2;
|
|
|
+ sd->busy_idx = 3;
|
|
|
+ sd->idle_idx = 2;
|
|
|
+
|
|
|
+ sd->flags |= SD_SERIALIZE;
|
|
|
+ if (sched_domains_numa_distance[tl->numa_level] > RECLAIM_DISTANCE) {
|
|
|
+ sd->flags &= ~(SD_BALANCE_EXEC |
|
|
|
+ SD_BALANCE_FORK |
|
|
|
+ SD_WAKE_AFFINE);
|
|
|
+ }
|
|
|
+
|
|
|
+#endif
|
|
|
+ } else {
|
|
|
+ sd->flags |= SD_PREFER_SIBLING;
|
|
|
+ sd->cache_nice_tries = 1;
|
|
|
+ sd->busy_idx = 2;
|
|
|
+ sd->idle_idx = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ sd->private = &tl->data;
|
|
|
|
|
|
return sd;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Topology list, bottom-up.
|
|
|
+ */
|
|
|
+static struct sched_domain_topology_level default_topology[] = {
|
|
|
+#ifdef CONFIG_SCHED_SMT
|
|
|
+ { cpu_smt_mask, cpu_smt_flags, SD_INIT_NAME(SMT) },
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_SCHED_MC
|
|
|
+ { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) },
|
|
|
+#endif
|
|
|
+#ifdef CONFIG_SCHED_BOOK
|
|
|
+ { cpu_book_mask, SD_INIT_NAME(BOOK) },
|
|
|
+#endif
|
|
|
+ { cpu_cpu_mask, SD_INIT_NAME(DIE) },
|
|
|
+ { NULL, },
|
|
|
+};
|
|
|
+
|
|
|
+struct sched_domain_topology_level *sched_domain_topology = default_topology;
|
|
|
+
|
|
|
+#define for_each_sd_topology(tl) \
|
|
|
+ for (tl = sched_domain_topology; tl->mask; tl++)
|
|
|
+
|
|
|
+void set_sched_topology(struct sched_domain_topology_level *tl)
|
|
|
+{
|
|
|
+ sched_domain_topology = tl;
|
|
|
+}
|
|
|
+
|
|
|
+#ifdef CONFIG_NUMA
|
|
|
+
|
|
|
static const struct cpumask *sd_numa_mask(int cpu)
|
|
|
{
|
|
|
return sched_domains_numa_masks[sched_domains_curr_level][cpu_to_node(cpu)];
|
|
@@ -6183,7 +6186,10 @@ static void sched_init_numa(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- tl = kzalloc((ARRAY_SIZE(default_topology) + level) *
|
|
|
+ /* Compute default topology size */
|
|
|
+ for (i = 0; sched_domain_topology[i].mask; i++);
|
|
|
+
|
|
|
+ tl = kzalloc((i + level) *
|
|
|
sizeof(struct sched_domain_topology_level), GFP_KERNEL);
|
|
|
if (!tl)
|
|
|
return;
|
|
@@ -6191,18 +6197,19 @@ static void sched_init_numa(void)
|
|
|
/*
|
|
|
* Copy the default topology bits..
|
|
|
*/
|
|
|
- for (i = 0; default_topology[i].init; i++)
|
|
|
- tl[i] = default_topology[i];
|
|
|
+ for (i = 0; sched_domain_topology[i].mask; i++)
|
|
|
+ tl[i] = sched_domain_topology[i];
|
|
|
|
|
|
/*
|
|
|
* .. and append 'j' levels of NUMA goodness.
|
|
|
*/
|
|
|
for (j = 0; j < level; i++, j++) {
|
|
|
tl[i] = (struct sched_domain_topology_level){
|
|
|
- .init = sd_numa_init,
|
|
|
.mask = sd_numa_mask,
|
|
|
+ .sd_flags = cpu_numa_flags,
|
|
|
.flags = SDTL_OVERLAP,
|
|
|
.numa_level = j,
|
|
|
+ SD_INIT_NAME(NUMA)
|
|
|
};
|
|
|
}
|
|
|
|
|
@@ -6360,7 +6367,7 @@ struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl,
|
|
|
const struct cpumask *cpu_map, struct sched_domain_attr *attr,
|
|
|
struct sched_domain *child, int cpu)
|
|
|
{
|
|
|
- struct sched_domain *sd = tl->init(tl, cpu);
|
|
|
+ struct sched_domain *sd = sd_init(tl, cpu);
|
|
|
if (!sd)
|
|
|
return child;
|
|
|
|