Inter-revision diff: patch 2

Comparing v4 (message) to v5 (message)

--- v4
+++ v5
@@ -1,142 +1,188 @@
 From: "Gautham R. Shenoy" <ego@linux.vnet.ibm.com>
 
-A pair of IBM POWER9 SMT4 cores can be fused together to form a big-core
-with 8 SMT threads. This can be discovered via the "ibm,thread-groups"
-CPU property in the device tree which will indicate which group of
-threads that share the L1 cache, translation cache and instruction data
-flow. If there are multiple such group of threads, then the core is a
-big-core.
-
-Furthermore, if the thread-ids of the threads of the big-core can be
-obtained by interleaving the thread-ids of the thread-groups
-(component small core), then such a big-core is called an interleaved
-big-core.
-
-Eg: Threads in the pair of component SMT4 cores of an interleaved
-big-core are numbered {0,2,4,6} and {1,3,5,7} respectively.
-
-The SMT4 cores forming a big-core are more or less independent
+Each of the SMT4 cores forming a big-core are more or less independent
 units. Thus when multiple tasks are scheduled to run on the fused
 core, we get the best performance when the tasks are spread across the
 pair of SMT4 cores.
 
-This patch enables CPU_FTR_ASYM_SMT bit in the cpu-features on
-detecting the presence of interleaved big-cores at boot up. This will
-will bias the load-balancing of tasks on smaller numbered threads,
-which will automatically result in spreading the tasks uniformly
-across the associated pair of SMT4 cores.
+This patch achieves this by setting the SMT level mask to correspond
+to the smallcore sibling mask on big-core systems.
+
+With this patch, the SMT sched-domain with SMT=8,4,2 on big-core
+systems are as follows:
+
+1) ppc64_cpu --smt=8
+
+ CPU0 attaching sched-domain(s):
+  domain-0: span=0,2,4,6 level=SMT
+   groups: 0:{ span=0 cap=294 }, 2:{ span=2 cap=294 },
+           4:{ span=4 cap=294 }, 6:{ span=6 cap=294 }
+ CPU1 attaching sched-domain(s):
+  domain-0: span=1,3,5,7 level=SMT
+   groups: 1:{ span=1 cap=294 }, 3:{ span=3 cap=294 },
+           5:{ span=5 cap=294 }, 7:{ span=7 cap=294 }
+
+2) ppc64_cpu --smt=4
+
+ CPU0 attaching sched-domain(s):
+  domain-0: span=0,2 level=SMT
+   groups: 0:{ span=0 cap=589 }, 2:{ span=2 cap=589 }
+ CPU1 attaching sched-domain(s):
+  domain-0: span=1,3 level=SMT
+   groups: 1:{ span=1 cap=589 }, 3:{ span=3 cap=589 }
+
+3) ppc64_cpu --smt=2
+   SMT domain ceases to exist as each domain consists of just one
+   group.
 
 Signed-off-by: Gautham R. Shenoy <ego@linux.vnet.ibm.com>
 ---
- arch/powerpc/kernel/setup-common.c | 75 +++++++++++++++++++++++++++++++++++++-
- 1 file changed, 74 insertions(+), 1 deletion(-)
+ arch/powerpc/include/asm/smp.h |  6 +++++
+ arch/powerpc/kernel/smp.c      | 55 +++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 57 insertions(+), 4 deletions(-)
 
-diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
-index 989edc1..22bc486 100644
---- a/arch/powerpc/kernel/setup-common.c
-+++ b/arch/powerpc/kernel/setup-common.c
-@@ -581,6 +581,69 @@ int get_cpu_thread_group_start(int cpu, struct thread_groups *tg)
- 	return -1;
+diff --git a/arch/powerpc/include/asm/smp.h b/arch/powerpc/include/asm/smp.h
+index 29ffaab..30798c7 100644
+--- a/arch/powerpc/include/asm/smp.h
++++ b/arch/powerpc/include/asm/smp.h
+@@ -99,6 +99,7 @@ static inline void set_hard_smp_processor_id(int cpu, int phys)
+ #endif
+ 
+ DECLARE_PER_CPU(cpumask_var_t, cpu_sibling_map);
++DECLARE_PER_CPU(cpumask_var_t, cpu_smallcore_sibling_map);
+ DECLARE_PER_CPU(cpumask_var_t, cpu_l2_cache_map);
+ DECLARE_PER_CPU(cpumask_var_t, cpu_core_map);
+ 
+@@ -107,6 +108,11 @@ static inline struct cpumask *cpu_sibling_mask(int cpu)
+ 	return per_cpu(cpu_sibling_map, cpu);
  }
  
-+/*
-+ * check_interleaved_big_core - Checks if the thread group tg
-+ * corresponds to a big-core whose threads are interleavings of the
-+ * threads of the component small cores.
-+ *
-+ * @tg: A thread-group struct for the core.
-+ *
-+ * Returns true if the core is a interleaved big-core.
-+ * Returns false otherwise.
-+ */
-+static inline bool check_interleaved_big_core(struct thread_groups *tg)
++static inline struct cpumask *cpu_smallcore_sibling_mask(int cpu)
 +{
-+	int nr_groups;
-+	int threads_per_group;
-+	int cur_cpu, next_cpu, i, j;
-+
-+	nr_groups = tg->nr_groups;
-+	threads_per_group = tg->threads_per_group;
-+
-+	if (tg->property != 1)
-+		return false;
-+
-+	if (nr_groups < 2 || threads_per_group < 2)
-+		return false;
-+
-+	/*
-+	 * In case of an interleaved big-core, the thread-ids of the
-+	 * big-core can be obtained by interleaving the the thread-ids
-+	 * of the component small
-+	 *
-+	 * Eg: On a 8-thread big-core with two SMT4 small cores, the
-+	 * threads of the two component small cores will be
-+	 * {0, 2, 4, 6} and {1, 3, 5, 7}.
-+	 */
-+	for (i = 0; i < nr_groups; i++) {
-+		int group_start = i * threads_per_group;
-+
-+		for (j = 0; j < threads_per_group - 1; j++) {
-+			int cur_idx = group_start + j;
-+
-+			cur_cpu = tg->thread_list[cur_idx];
-+			next_cpu = tg->thread_list[cur_idx + 1];
-+			if (next_cpu != cur_cpu + nr_groups)
-+				return false;
-+		}
-+	}
-+
-+	return true;
++	return per_cpu(cpu_smallcore_sibling_map, cpu);
 +}
 +
-+#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
-+static inline void enable_asym_smt_feature(void)
+ static inline struct cpumask *cpu_core_mask(int cpu)
+ {
+ 	return per_cpu(cpu_core_map, cpu);
+diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
+index 4794d6b..ea3b306 100644
+--- a/arch/powerpc/kernel/smp.c
++++ b/arch/powerpc/kernel/smp.c
+@@ -76,10 +76,12 @@
+ struct thread_info *secondary_ti;
+ 
+ DEFINE_PER_CPU(cpumask_var_t, cpu_sibling_map);
++DEFINE_PER_CPU(cpumask_var_t, cpu_smallcore_sibling_map);
+ DEFINE_PER_CPU(cpumask_var_t, cpu_l2_cache_map);
+ DEFINE_PER_CPU(cpumask_var_t, cpu_core_map);
+ 
+ EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
++EXPORT_PER_CPU_SYMBOL(cpu_smallcore_sibling_map);
+ EXPORT_PER_CPU_SYMBOL(cpu_l2_cache_map);
+ EXPORT_PER_CPU_SYMBOL(cpu_core_map);
+ 
+@@ -689,6 +691,9 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
+ 	for_each_possible_cpu(cpu) {
+ 		zalloc_cpumask_var_node(&per_cpu(cpu_sibling_map, cpu),
+ 					GFP_KERNEL, cpu_to_node(cpu));
++		zalloc_cpumask_var_node(&per_cpu(cpu_smallcore_sibling_map,
++						 cpu),
++					GFP_KERNEL, cpu_to_node(cpu));
+ 		zalloc_cpumask_var_node(&per_cpu(cpu_l2_cache_map, cpu),
+ 					GFP_KERNEL, cpu_to_node(cpu));
+ 		zalloc_cpumask_var_node(&per_cpu(cpu_core_map, cpu),
+@@ -707,6 +712,10 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
+ 	cpumask_set_cpu(boot_cpuid, cpu_sibling_mask(boot_cpuid));
+ 	cpumask_set_cpu(boot_cpuid, cpu_l2_cache_mask(boot_cpuid));
+ 	cpumask_set_cpu(boot_cpuid, cpu_core_mask(boot_cpuid));
++	if (has_big_cores) {
++		cpumask_set_cpu(boot_cpuid,
++				cpu_smallcore_sibling_mask(boot_cpuid));
++	}
+ 
+ 	if (smp_ops && smp_ops->probe)
+ 		smp_ops->probe();
+@@ -991,6 +1000,10 @@ static void remove_cpu_from_masks(int cpu)
+ 		set_cpus_unrelated(cpu, i, cpu_core_mask);
+ 		set_cpus_unrelated(cpu, i, cpu_l2_cache_mask);
+ 		set_cpus_unrelated(cpu, i, cpu_sibling_mask);
++		if (has_big_cores) {
++			set_cpus_unrelated(cpu, i,
++					   cpu_smallcore_sibling_mask);
++		}
+ 	}
+ }
+ #endif
+@@ -999,7 +1012,17 @@ static void add_cpu_to_masks(int cpu)
+ {
+ 	int first_thread = cpu_first_thread_sibling(cpu);
+ 	int chipid = cpu_to_chip_id(cpu);
+-	int i;
++
++	struct thread_groups tg;
++	int i, cpu_group_start = -1;
++
++	if (has_big_cores) {
++		struct device_node *dn = of_get_cpu_node(cpu, NULL);
++
++		parse_thread_groups(dn, &tg);
++		cpu_group_start = get_cpu_thread_group_start(cpu, &tg);
++		cpumask_set_cpu(cpu, cpu_smallcore_sibling_mask(cpu));
++	}
+ 
+ 	/*
+ 	 * This CPU will not be in the online mask yet so we need to manually
+@@ -1007,9 +1030,21 @@ static void add_cpu_to_masks(int cpu)
+ 	 */
+ 	cpumask_set_cpu(cpu, cpu_sibling_mask(cpu));
+ 
+-	for (i = first_thread; i < first_thread + threads_per_core; i++)
+-		if (cpu_online(i))
+-			set_cpus_related(i, cpu, cpu_sibling_mask);
++	for (i = first_thread; i < first_thread + threads_per_core; i++) {
++		int i_group_start;
++
++		if (!cpu_online(i))
++			continue;
++
++		set_cpus_related(i, cpu, cpu_sibling_mask);
++
++		if (!has_big_cores)
++			continue;
++
++		i_group_start = get_cpu_thread_group_start(i, &tg);
++		if (i_group_start == cpu_group_start)
++			set_cpus_related(i, cpu, cpu_smallcore_sibling_mask);
++	}
+ 
+ 	/*
+ 	 * Copy the thread sibling mask into the cache sibling mask
+@@ -1136,6 +1171,11 @@ static const struct cpumask *shared_cache_mask(int cpu)
+ 	return cpu_l2_cache_mask(cpu);
+ }
+ 
++static const struct cpumask *smallcore_smt_mask(int cpu)
 +{
-+	int key = __builtin_ctzl(CPU_FTR_ASYM_SMT);
++	return cpu_smallcore_sibling_mask(cpu);
++}
 +
-+	cur_cpu_spec->cpu_features |= CPU_FTR_ASYM_SMT;
-+	static_branch_enable(&cpu_feature_keys[key]);
-+	pr_info("Enabling ASYM_SMT on interleaved big-cores\n");
-+}
-+#else
-+#define enable_asym_smt_feature()
+ static struct sched_domain_topology_level power9_topology[] = {
+ #ifdef CONFIG_SCHED_SMT
+ 	{ cpu_smt_mask, powerpc_smt_flags, SD_INIT_NAME(SMT) },
+@@ -1158,6 +1198,13 @@ void __init smp_cpus_done(unsigned int max_cpus)
+ 
+ 	dump_numa_cpu_topology();
+ 
++#ifdef CONFIG_SCHED_SMT
++	if (has_big_cores) {
++		pr_info("Using small cores at SMT level\n");
++		power9_topology[0].mask = smallcore_smt_mask;
++		powerpc_topology[0].mask = smallcore_smt_mask;
++	}
 +#endif
-+
- /**
-  * setup_cpu_maps - initialize the following cpu maps:
-  *                  cpu_possible_mask
-@@ -604,6 +667,7 @@ void __init smp_setup_cpu_maps(void)
- 	struct device_node *dn;
- 	int cpu = 0;
- 	int nthreads = 1;
-+	bool has_interleaved_big_cores = true;
- 
- 	has_big_cores = true;
- 	DBG("smp_setup_cpu_maps()\n");
-@@ -657,6 +721,12 @@ void __init smp_setup_cpu_maps(void)
- 
- 		if (has_big_cores && !dt_has_big_core(dn, &tg)) {
- 			has_big_cores = false;
-+			has_interleaved_big_cores = false;
-+		}
-+
-+		if (has_interleaved_big_cores) {
-+			has_interleaved_big_cores =
-+				check_interleaved_big_core(&tg);
- 		}
- 
- 		if (cpu >= nr_cpu_ids) {
-@@ -713,7 +783,10 @@ void __init smp_setup_cpu_maps(void)
- 	vdso_data->processorCount = num_present_cpus();
- #endif /* CONFIG_PPC64 */
- 
--        /* Initialize CPU <=> thread mapping/
-+	if (has_interleaved_big_cores)
-+		enable_asym_smt_feature();
-+
-+	/* Initialize CPU <=> thread mapping/
- 	 *
- 	 * WARNING: We assume that the number of threads is the same for
- 	 * every CPU in the system. If that is not the case, then some code
+ 	/*
+ 	 * If any CPU detects that it's sharing a cache with another CPU then
+ 	 * use the deeper topology that is aware of this sharing.
 -- 
 1.9.4
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help