2011-06-16 08:49:16

by Vincent Guittot

[permalink] [raw]
Subject: [RFC] Add Arm cpu topology definition

The affinity between Arm processors is defined in the MPIDR register.
We can identify which processors are in the same cluster,
and which ones have performance interdependency. The cpu topology
of an Arm platform can be set thanks to this register and this topology
is then used by sched_mc and sched_smt.

Signed-off-by: Vincent Guittot <[email protected]>
---
arch/arm/Kconfig | 26 ++++++++
arch/arm/include/asm/topology.h | 33 ++++++++++
arch/arm/kernel/Makefile | 1 +
arch/arm/kernel/smp.c | 6 ++
arch/arm/kernel/topology.c | 133 +++++++++++++++++++++++++++++++++++++++
5 files changed, 199 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/kernel/topology.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9adc278..bacf9af 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -219,6 +219,24 @@ source "kernel/Kconfig.freezer"

menu "System Type"

+config SCHED_MC
+ bool "Multi-core scheduler support"
+ depends on SMP && ARM_CPU_TOPOLOGY
+ default n
+ help
+ Multi-core scheduler support improves the CPU scheduler's decision
+ making when dealing with multi-core CPU chips at a cost of slightly
+ increased overhead in some places. If unsure say N here.
+
+config SCHED_SMT
+ bool "SMT scheduler support"
+ depends on SMP && ARM_CPU_TOPOLOGY
+ default n
+ help
+ Improves the CPU scheduler's decision making when dealing with
+ MultiThreading at a cost of slightly increased overhead in some
+ places. If unsure say N here.
+
config MMU
bool "MMU-based Paged Memory Management Support"
default y
@@ -1062,6 +1080,14 @@ if !MMU
source "arch/arm/Kconfig-nommu"
endif

+config ARM_CPU_TOPOLOGY
+ bool "Support cpu topology definition"
+ depends on SMP && CPU_V7
+ help
+ Support Arm cpu topology definition. The MPIDR register defines
+ affinity between processors which is used to set the cpu
+ topology of an Arm System.
+
config ARM_ERRATA_411920
bool "ARM errata: Invalidation of the Instruction Cache operation can fail"
depends on CPU_V6 || CPU_V6K
diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
index accbd7c..cb90d0a 100644
--- a/arch/arm/include/asm/topology.h
+++ b/arch/arm/include/asm/topology.h
@@ -1,6 +1,39 @@
#ifndef _ASM_ARM_TOPOLOGY_H
#define _ASM_ARM_TOPOLOGY_H

+#ifdef CONFIG_ARM_CPU_TOPOLOGY
+
+#include <linux/cpumask.h>
+
+struct cputopo_arm {
+ int thread_id;
+ int core_id;
+ int socket_id;
+ cpumask_t thread_sibling;
+ cpumask_t core_sibling;
+};
+
+extern struct cputopo_arm cpu_topology[NR_CPUS];
+
+#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
+#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
+#define topology_core_cpumask(cpu) (&(cpu_topology[cpu].core_sibling))
+#define topology_thread_cpumask(cpu) (&(cpu_topology[cpu].thread_sibling))
+
+#define mc_capable() (cpu_topology[0].socket_id != -1)
+#define smt_capable() (cpu_topology[0].thread_id != -1)
+
+void init_cpu_topology(void);
+void store_cpu_topology(unsigned int cpuid);
+const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
+
+#else
+
+#define init_cpu_topology() {};
+#define store_cpu_topology(cpuid) {};
+
+#endif
+
#include <asm-generic/topology.h>

#endif /* _ASM_ARM_TOPOLOGY_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index a5b31af..816a481 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_IWMMXT) += iwmmxt.o
obj-$(CONFIG_CPU_HAS_PMU) += pmu.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
+obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o

ifneq ($(CONFIG_ARCH_EBSA110),y)
obj-y += io.o
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 344e52b..3e8dc3b 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -31,6 +31,7 @@
#include <asm/cacheflush.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
+#include <asm/topology.h>
#include <asm/mmu_context.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
@@ -268,6 +269,9 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);

cpu_info->loops_per_jiffy = loops_per_jiffy;
+
+ store_cpu_topology(cpuid);
+
}

/*
@@ -354,6 +358,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
{
unsigned int ncores = num_possible_cpus();

+ init_cpu_topology();
+
smp_store_cpu_info(smp_processor_id());

/*
diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
new file mode 100644
index 0000000..d61723c
--- /dev/null
+++ b/arch/arm/kernel/topology.c
@@ -0,0 +1,133 @@
+/*
+ * arch/arm/kernel/topology.c
+ *
+ * Copyright (C) 2011 [email protected]
+ *
+ * based on arch/sh/kernel/topology.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/init.h>
+#include <linux/percpu.h>
+#include <linux/node.h>
+#include <linux/nodemask.h>
+#include <linux/sched.h>
+
+#include <asm/cacheflush.h>
+#include <asm/topology.h>
+
+#define hard_smp_mpidr() \
+ ({ \
+ unsigned int cpunum; \
+ __asm__("mrc p15, 0, %0, c0, c0, 5" \
+ : "=r" (cpunum)); \
+ cpunum; \
+ })
+
+struct cputopo_arm cpu_topology[NR_CPUS];
+
+const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
+{
+ return &(cpu_topology[cpu].core_sibling);
+}
+
+/*
+ * store_cpu_topology is called at boot when only one cpu is running
+ * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
+ * which prevents simultaneous write access to cpu_topology array
+ */
+void store_cpu_topology(unsigned int cpuid)
+{
+ struct cputopo_arm *cpuid_topo = &(cpu_topology[cpuid]);
+ unsigned int mpidr;
+ unsigned int cpu;
+
+ /* If the cpu topology has been already set, just return */
+ if (cpuid_topo->core_id != -1)
+ return;
+
+ mpidr = hard_smp_mpidr();
+
+ /* create cpu topology mapping */
+ if (mpidr & (0x3 << 30)) {
+ /*
+ * This is a multiprocessor system
+ * multiprocessor format & multiprocessor mode field are set
+ */
+
+ if (mpidr & (0x1 << 24)) {
+ /* core performance interdependency */
+ cpuid_topo->thread_id = (mpidr & 0x3);
+ cpuid_topo->core_id = ((mpidr >> 8) & 0xF);
+ cpuid_topo->socket_id = ((mpidr >> 16) & 0xFF);
+ } else {
+ /* normal core interdependency */
+ cpuid_topo->thread_id = -1;
+ cpuid_topo->core_id = (mpidr & 0x3);
+ cpuid_topo->socket_id = ((mpidr >> 8) & 0xF);
+ }
+ } else {
+ /*
+ * This is an uniprocessor system
+ * we are in multiprocessor format but uniprocessor system
+ * or in the old uniprocessor format
+ */
+
+ cpuid_topo->thread_id = -1;
+ cpuid_topo->core_id = 0;
+ cpuid_topo->socket_id = -1;
+ }
+
+ /* update core and thread sibling masks */
+ for_each_possible_cpu(cpu) {
+ struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
+
+ if (cpuid_topo->socket_id == cpu_topo->socket_id) {
+ cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu,
+ &cpuid_topo->core_sibling);
+
+ if (cpuid_topo->core_id == cpu_topo->core_id) {
+ cpumask_set_cpu(cpuid,
+ &cpu_topo->thread_sibling);
+ if (cpu != cpuid)
+ cpumask_set_cpu(cpu,
+ &cpuid_topo->thread_sibling);
+ }
+ }
+ }
+ smp_wmb();
+
+ printk(KERN_INFO "cpu %u : thread %d cpu %d, socket %d, mpidr %x\n",
+ cpuid, cpu_topology[cpuid].thread_id,
+ cpu_topology[cpuid].core_id,
+ cpu_topology[cpuid].socket_id, mpidr);
+
+}
+
+/*
+ * init_cpu_topology is called at boot when only one cpu is running
+ * which prevent simultaneous write access to cpu_topology array
+ */
+void init_cpu_topology(void)
+{
+ unsigned int cpu;
+
+ /* init core mask */
+ for_each_possible_cpu(cpu) {
+ struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
+
+ cpu_topo->thread_id = -1;
+ cpu_topo->core_id = -1;
+ cpu_topo->socket_id = -1;
+ cpumask_clear(&cpu_topo->core_sibling);
+ cpumask_clear(&cpu_topo->thread_sibling);
+ }
+ smp_wmb();
+}
--
1.7.4.1


2011-06-16 09:01:57

by Samuel Thibault

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

Hello,

Vincent Guittot, le Thu 16 Jun 2011 10:49:13 +0200, a ?crit :
> The affinity between Arm processors is defined in the MPIDR register.
> We can identify which processors are in the same cluster,
> and which ones have performance interdependency. The cpu topology
> of an Arm platform can be set thanks to this register and this topology
> is then used by sched_mc and sched_smt.

Cool! Could you check that the hwloc tool gets also gets this
information from userland through /sys, and/or send me the output of the
hwloc-gather-topology tool from hwloc so we can add an testcase for
this?

Samuel

2011-06-16 09:44:33

by Vincent Guittot

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 16 June 2011 10:55, Samuel Thibault <[email protected]> wrote:
> Hello,
>
> Vincent Guittot, le Thu 16 Jun 2011 10:49:13 +0200, a ?crit :
>> The affinity between Arm processors is defined in the MPIDR register.
>> We can identify which processors are in the same cluster,
>> and which ones have performance interdependency. The cpu topology
>> ?of an Arm platform can be set thanks to this register and this topology
>> is then used by sched_mc and sched_smt.
>
> Cool! ?Could you check that the hwloc tool gets also gets this
> information from userland through /sys, and/or send me the output of the
> hwloc-gather-topology tool from hwloc so we can add an testcase for
> this?
>

The output of hwloc-gather-topology is :

Machine (phys=0 local=280840KB total=280840KB)
Socket #0 (phys=3)
Core #0 (phys=0)
PU #0 (phys=0)
Core #1 (phys=1)
PU #1 (phys=1)
depth 0: 1 Machine (type #1)
depth 1: 1 Socket (type #3)
depth 2: 2 Cores (type #5)
depth 3: 2 PUs (type #6)
Topology not from this system

let me know if it's what you want

> Samuel
>

2011-06-16 09:47:41

by Samuel Thibault

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

Vincent Guittot, le Thu 16 Jun 2011 11:44:30 +0200, a ?crit :
> The output of hwloc-gather-topology is :
>
> Machine (phys=0 local=280840KB total=280840KB)
> Socket #0 (phys=3)
> Core #0 (phys=0)
> PU #0 (phys=0)
> Core #1 (phys=1)
> PU #1 (phys=1)
> depth 0: 1 Machine (type #1)
> depth 1: 1 Socket (type #3)
> depth 2: 2 Cores (type #5)
> depth 3: 2 PUs (type #6)
> Topology not from this system
>
> let me know if it's what you want

This looks good for a bicore socket, yes. Could you send me the tarball
it created, so we can include it in the hwloc testsuite?

Do you have a example with smt cores?

Samuel

2011-06-16 09:56:07

by Vincent Guittot

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 16 June 2011 11:47, Samuel Thibault <[email protected]> wrote:
> Vincent Guittot, le Thu 16 Jun 2011 11:44:30 +0200, a ?crit :
>> The output of hwloc-gather-topology is :
>>
>> Machine (phys=0 local=280840KB total=280840KB)
>> ? Socket #0 (phys=3)
>> ? ? Core #0 (phys=0)
>> ? ? ? PU #0 (phys=0)
>> ? ? Core #1 (phys=1)
>> ? ? ? PU #1 (phys=1)
>> depth 0: ? ? ? ?1 Machine (type #1)
>> ?depth 1: ? ? ? 1 Socket (type #3)
>> ? depth 2: ? ? ?2 Cores (type #5)
>> ? ?depth 3: ? ? 2 PUs (type #6)
>> Topology not from this system
>>
>> let me know if it's what you want
>
> This looks good for a bicore socket, yes. ?Could you send me the tarball
> it created, so we can include it in the hwloc testsuite?
>

yes, I will send it to you

> Do you have a example with smt cores?

no, I haven't

>
> Samuel
>

2011-06-16 10:49:10

by Daniel Lezcano

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 06/16/2011 10:49 AM, Vincent Guittot wrote:
> The affinity between Arm processors is defined in the MPIDR register.
> We can identify which processors are in the same cluster,
> and which ones have performance interdependency. The cpu topology
> of an Arm platform can be set thanks to this register and this topology
> is then used by sched_mc and sched_smt.
>
> Signed-off-by: Vincent Guittot<[email protected]>
> ---
> arch/arm/Kconfig | 26 ++++++++
> arch/arm/include/asm/topology.h | 33 ++++++++++
> arch/arm/kernel/Makefile | 1 +
> arch/arm/kernel/smp.c | 6 ++
> arch/arm/kernel/topology.c | 133 +++++++++++++++++++++++++++++++++++++++
> 5 files changed, 199 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/kernel/topology.c
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 9adc278..bacf9af 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -219,6 +219,24 @@ source "kernel/Kconfig.freezer"
>
> menu "System Type"
>
> +config SCHED_MC
> + bool "Multi-core scheduler support"
> + depends on SMP&& ARM_CPU_TOPOLOGY

ARM_CPU_TOPOLOGY depends on SMP, so the check can be reduced to

depends on ARM_CPU_TOPOLOGY
> + default n
> + help
> + Multi-core scheduler support improves the CPU scheduler's decision
> + making when dealing with multi-core CPU chips at a cost of slightly
> + increased overhead in some places. If unsure say N here.
> +
> +config SCHED_SMT
> + bool "SMT scheduler support"
> + depends on SMP&& ARM_CPU_TOPOLOGY

depends on SMT && ARM_CPU_TOPOLOGY ?

> + default n
> + help
> + Improves the CPU scheduler's decision making when dealing with
> + MultiThreading at a cost of slightly increased overhead in some
> + places. If unsure say N here.
> +
> config MMU
> bool "MMU-based Paged Memory Management Support"
> default y
> @@ -1062,6 +1080,14 @@ if !MMU
> source "arch/arm/Kconfig-nommu"
> endif
>
> +config ARM_CPU_TOPOLOGY
> + bool "Support cpu topology definition"
> + depends on SMP&& CPU_V7
> + help
> + Support Arm cpu topology definition. The MPIDR register defines
> + affinity between processors which is used to set the cpu
> + topology of an Arm System.
> +
> config ARM_ERRATA_411920
> bool "ARM errata: Invalidation of the Instruction Cache operation can fail"
> depends on CPU_V6 || CPU_V6K
> diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
> index accbd7c..cb90d0a 100644
> --- a/arch/arm/include/asm/topology.h
> +++ b/arch/arm/include/asm/topology.h
> @@ -1,6 +1,39 @@
> #ifndef _ASM_ARM_TOPOLOGY_H
> #define _ASM_ARM_TOPOLOGY_H
>
> +#ifdef CONFIG_ARM_CPU_TOPOLOGY
> +
> +#include<linux/cpumask.h>
> +
> +struct cputopo_arm {
> + int thread_id;
> + int core_id;
> + int socket_id;

I am not sure how that deals with the rest of the functions prototype
but wouldn't u16 be more adequate ?

> + cpumask_t thread_sibling;
> + cpumask_t core_sibling;
> +};
> +
> +extern struct cputopo_arm cpu_topology[NR_CPUS];
> +
> +#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
> +#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
> +#define topology_core_cpumask(cpu) (&(cpu_topology[cpu].core_sibling))
> +#define topology_thread_cpumask(cpu) (&(cpu_topology[cpu].thread_sibling))
> +
> +#define mc_capable() (cpu_topology[0].socket_id != -1)
> +#define smt_capable() (cpu_topology[0].thread_id != -1)
> +
> +void init_cpu_topology(void);
> +void store_cpu_topology(unsigned int cpuid);
> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
> +
> +#else
> +
> +#define init_cpu_topology() {};
> +#define store_cpu_topology(cpuid) {};

AFAIK the convention is to declare static inline noop functions.

static inline void init_cpu_topology(void) { };
static inline void store_cpu_topology(unsigned int cpuid) { };

> +
> +#endif
> +
> #include<asm-generic/topology.h>
>
> #endif /* _ASM_ARM_TOPOLOGY_H */
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index a5b31af..816a481 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -61,6 +61,7 @@ obj-$(CONFIG_IWMMXT) += iwmmxt.o
> obj-$(CONFIG_CPU_HAS_PMU) += pmu.o
> obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
> AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
> +obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
>
> ifneq ($(CONFIG_ARCH_EBSA110),y)
> obj-y += io.o
> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
> index 344e52b..3e8dc3b 100644
> --- a/arch/arm/kernel/smp.c
> +++ b/arch/arm/kernel/smp.c
> @@ -31,6 +31,7 @@
> #include<asm/cacheflush.h>
> #include<asm/cpu.h>
> #include<asm/cputype.h>
> +#include<asm/topology.h>
> #include<asm/mmu_context.h>
> #include<asm/pgtable.h>
> #include<asm/pgalloc.h>
> @@ -268,6 +269,9 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
> struct cpuinfo_arm *cpu_info =&per_cpu(cpu_data, cpuid);
>
> cpu_info->loops_per_jiffy = loops_per_jiffy;
> +
> + store_cpu_topology(cpuid);
> +
> }

If the store_cpu_topology function is called once, can it be changed to
a __cpuinit function, declared as a subsys_initcall and removed from here ?

> /*
> @@ -354,6 +358,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
> {
> unsigned int ncores = num_possible_cpus();
>
> + init_cpu_topology();

Why do you need to call the init function here ?

On the other architecture I see:

static int __init topology_init(void)
{
...
}

subsys_initcall(topology_init);

Isn't possible to use the same way ? (with the benefit to save two
declarations in the header).


[ ... ]

> +
> +struct cputopo_arm cpu_topology[NR_CPUS];

IMO, you can define it static here no ?

> +
> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
> +{
> + return&(cpu_topology[cpu].core_sibling);
> +}
> +
> +/*
> + * store_cpu_topology is called at boot when only one cpu is running
> + * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
> + * which prevents simultaneous write access to cpu_topology array
> + */
> +void store_cpu_topology(unsigned int cpuid)
> +{
> + struct cputopo_arm *cpuid_topo =&(cpu_topology[cpuid]);
> + unsigned int mpidr;
> + unsigned int cpu;
> +
> + /* If the cpu topology has been already set, just return */
> + if (cpuid_topo->core_id != -1)
> + return;

If the code calls store_cpu_topology but with no effect because it was
already called before, that means it shouldn't be called at all, no ?
IMHO, this test should be removed or at least add a WARN_ONCE.

> +
> + mpidr = hard_smp_mpidr();
> +
> + /* create cpu topology mapping */
> + if (mpidr& (0x3<< 30)) {
> + /*
> + * This is a multiprocessor system
> + * multiprocessor format& multiprocessor mode field are set
> + */
> +
> + if (mpidr& (0x1<< 24)) {
> + /* core performance interdependency */
> + cpuid_topo->thread_id = (mpidr& 0x3);
> + cpuid_topo->core_id = ((mpidr>> 8)& 0xF);
> + cpuid_topo->socket_id = ((mpidr>> 16)& 0xFF);
> + } else {
> + /* normal core interdependency */
> + cpuid_topo->thread_id = -1;
> + cpuid_topo->core_id = (mpidr& 0x3);
> + cpuid_topo->socket_id = ((mpidr>> 8)& 0xF);
> + }
> + } else {
> + /*
> + * This is an uniprocessor system
> + * we are in multiprocessor format but uniprocessor system
> + * or in the old uniprocessor format
> + */
> +
> + cpuid_topo->thread_id = -1;
> + cpuid_topo->core_id = 0;
> + cpuid_topo->socket_id = -1;
> + }
> +
> + /* update core and thread sibling masks */
> + for_each_possible_cpu(cpu) {
> + struct cputopo_arm *cpu_topo =&(cpu_topology[cpu]);
> +
> + if (cpuid_topo->socket_id == cpu_topo->socket_id) {
> + cpumask_set_cpu(cpuid,&cpu_topo->core_sibling);
> + if (cpu != cpuid)
> + cpumask_set_cpu(cpu,
> + &cpuid_topo->core_sibling);
> +
> + if (cpuid_topo->core_id == cpu_topo->core_id) {
> + cpumask_set_cpu(cpuid,
> + &cpu_topo->thread_sibling);
> + if (cpu != cpuid)
> + cpumask_set_cpu(cpu,
> + &cpuid_topo->thread_sibling);
> + }
> + }
> + }
> + smp_wmb();
> +
> + printk(KERN_INFO "cpu %u : thread %d cpu %d, socket %d, mpidr %x\n",
> + cpuid, cpu_topology[cpuid].thread_id,
> + cpu_topology[cpuid].core_id,
> + cpu_topology[cpuid].socket_id, mpidr);
> +
> +}
> +
> +/*
> + * init_cpu_topology is called at boot when only one cpu is running
> + * which prevent simultaneous write access to cpu_topology array
> + */
> +void init_cpu_topology(void)
> +{
> + unsigned int cpu;
> +
> + /* init core mask */
> + for_each_possible_cpu(cpu) {
> + struct cputopo_arm *cpu_topo =&(cpu_topology[cpu]);
> +
> + cpu_topo->thread_id = -1;
> + cpu_topo->core_id = -1;
nit : extra space
> + cpu_topo->socket_id = -1;
> + cpumask_clear(&cpu_topo->core_sibling);
> + cpumask_clear(&cpu_topo->thread_sibling);
> + }
> + smp_wmb();
> +}

2011-06-16 11:48:56

by Amit Kucheria

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 11 Jun 16, Vincent Guittot wrote:
> The affinity between Arm processors is defined in the MPIDR register.
> We can identify which processors are in the same cluster,
> and which ones have performance interdependency. The cpu topology
> of an Arm platform can be set thanks to this register and this topology
> is then used by sched_mc and sched_smt.

Probably worth adding a note that sched_mc/sched_smt are disabled by default
and need to be enabled by writing to their respective sysfs files.

> Signed-off-by: Vincent Guittot <[email protected]>
> ---
> arch/arm/Kconfig | 26 ++++++++
> arch/arm/include/asm/topology.h | 33 ++++++++++
> arch/arm/kernel/Makefile | 1 +
> arch/arm/kernel/smp.c | 6 ++
> arch/arm/kernel/topology.c | 133 +++++++++++++++++++++++++++++++++++++++
> 5 files changed, 199 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/kernel/topology.c
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 9adc278..bacf9af 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -219,6 +219,24 @@ source "kernel/Kconfig.freezer"
>
> menu "System Type"
>
> +config SCHED_MC
> + bool "Multi-core scheduler support"
> + depends on SMP && ARM_CPU_TOPOLOGY
> + default n
> + help
> + Multi-core scheduler support improves the CPU scheduler's decision
> + making when dealing with multi-core CPU chips at a cost of slightly
> + increased overhead in some places. If unsure say N here.
> +
> +config SCHED_SMT
> + bool "SMT scheduler support"
> + depends on SMP && ARM_CPU_TOPOLOGY
> + default n
> + help
> + Improves the CPU scheduler's decision making when dealing with
> + MultiThreading at a cost of slightly increased overhead in some
> + places. If unsure say N here.
> +
> config MMU
> bool "MMU-based Paged Memory Management Support"
> default y
> @@ -1062,6 +1080,14 @@ if !MMU
> source "arch/arm/Kconfig-nommu"
> endif
>
> +config ARM_CPU_TOPOLOGY
> + bool "Support cpu topology definition"
> + depends on SMP && CPU_V7
> + help
> + Support Arm cpu topology definition. The MPIDR register defines
> + affinity between processors which is used to set the cpu
> + topology of an Arm System.
> +
> config ARM_ERRATA_411920
> bool "ARM errata: Invalidation of the Instruction Cache operation can fail"
> depends on CPU_V6 || CPU_V6K
> diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
> index accbd7c..cb90d0a 100644
> --- a/arch/arm/include/asm/topology.h
> +++ b/arch/arm/include/asm/topology.h
> @@ -1,6 +1,39 @@
> #ifndef _ASM_ARM_TOPOLOGY_H
> #define _ASM_ARM_TOPOLOGY_H
>
> +#ifdef CONFIG_ARM_CPU_TOPOLOGY
> +
> +#include <linux/cpumask.h>
> +
> +struct cputopo_arm {
> + int thread_id;
> + int core_id;
> + int socket_id;
> + cpumask_t thread_sibling;
> + cpumask_t core_sibling;
> +};
> +
> +extern struct cputopo_arm cpu_topology[NR_CPUS];
> +
> +#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
> +#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
> +#define topology_core_cpumask(cpu) (&(cpu_topology[cpu].core_sibling))
> +#define topology_thread_cpumask(cpu) (&(cpu_topology[cpu].thread_sibling))
> +
> +#define mc_capable() (cpu_topology[0].socket_id != -1)
> +#define smt_capable() (cpu_topology[0].thread_id != -1)
> +
> +void init_cpu_topology(void);
> +void store_cpu_topology(unsigned int cpuid);
> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
> +
> +#else
> +
> +#define init_cpu_topology() {};
> +#define store_cpu_topology(cpuid) {};
> +
> +#endif
> +
> #include <asm-generic/topology.h>
>
> #endif /* _ASM_ARM_TOPOLOGY_H */
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index a5b31af..816a481 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -61,6 +61,7 @@ obj-$(CONFIG_IWMMXT) += iwmmxt.o
> obj-$(CONFIG_CPU_HAS_PMU) += pmu.o
> obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
> AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
> +obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
>
> ifneq ($(CONFIG_ARCH_EBSA110),y)
> obj-y += io.o
> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
> index 344e52b..3e8dc3b 100644
> --- a/arch/arm/kernel/smp.c
> +++ b/arch/arm/kernel/smp.c
> @@ -31,6 +31,7 @@
> #include <asm/cacheflush.h>
> #include <asm/cpu.h>
> #include <asm/cputype.h>
> +#include <asm/topology.h>
> #include <asm/mmu_context.h>
> #include <asm/pgtable.h>
> #include <asm/pgalloc.h>
> @@ -268,6 +269,9 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
> struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);
>
> cpu_info->loops_per_jiffy = loops_per_jiffy;
> +
> + store_cpu_topology(cpuid);
> +
> }
>
> /*
> @@ -354,6 +358,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
> {
> unsigned int ncores = num_possible_cpus();
>
> + init_cpu_topology();
> +
> smp_store_cpu_info(smp_processor_id());
>
> /*
> diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
> new file mode 100644
> index 0000000..d61723c
> --- /dev/null
> +++ b/arch/arm/kernel/topology.c
> @@ -0,0 +1,133 @@
> +/*
> + * arch/arm/kernel/topology.c
> + *
> + * Copyright (C) 2011 [email protected]

This should be

Copyright (C) 2011 Linaro Limited.

Written by: Vincent Guittot

> + *
> + * based on arch/sh/kernel/topology.c
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License. See the file "COPYING" in the main directory of this archive
> + * for more details.
> + */
> +
> +#include <linux/cpu.h>
> +#include <linux/cpumask.h>
> +#include <linux/init.h>
> +#include <linux/percpu.h>
> +#include <linux/node.h>
> +#include <linux/nodemask.h>
> +#include <linux/sched.h>
> +
> +#include <asm/cacheflush.h>
> +#include <asm/topology.h>
> +
> +#define hard_smp_mpidr() \
> + ({ \
> + unsigned int cpunum; \
> + __asm__("mrc p15, 0, %0, c0, c0, 5" \
> + : "=r" (cpunum)); \
> + cpunum; \
> + })
> +
> +struct cputopo_arm cpu_topology[NR_CPUS];
> +
> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
> +{
> + return &(cpu_topology[cpu].core_sibling);
> +}
> +
> +/*
> + * store_cpu_topology is called at boot when only one cpu is running
> + * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
> + * which prevents simultaneous write access to cpu_topology array
> + */
> +void store_cpu_topology(unsigned int cpuid)
> +{
> + struct cputopo_arm *cpuid_topo = &(cpu_topology[cpuid]);
> + unsigned int mpidr;
> + unsigned int cpu;
> +
> + /* If the cpu topology has been already set, just return */
> + if (cpuid_topo->core_id != -1)
> + return;
> +
> + mpidr = hard_smp_mpidr();
> +
> + /* create cpu topology mapping */
> + if (mpidr & (0x3 << 30)) {

Use #defines for the MPIDR bit-fields

#define MPIDR_U_BITMASK (0x3 << 30)

BTW, Bit 31 seems to always be 1, do you really want that in the mask?

> + /*
> + * This is a multiprocessor system
> + * multiprocessor format & multiprocessor mode field are set
> + */
> +
> + if (mpidr & (0x1 << 24)) {

According to
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0388f/CIHCHADB.html

bit 24 is SBZ. Where is this redefined for MT?

> + /* core performance interdependency */
> + cpuid_topo->thread_id = (mpidr & 0x3);
> + cpuid_topo->core_id = ((mpidr >> 8) & 0xF);
> + cpuid_topo->socket_id = ((mpidr >> 16) & 0xFF);

Define BITMASKs for these bits too.

> + } else {
> + /* normal core interdependency */
> + cpuid_topo->thread_id = -1;
> + cpuid_topo->core_id = (mpidr & 0x3);
> + cpuid_topo->socket_id = ((mpidr >> 8) & 0xF);
> + }
> + } else {
> + /*
> + * This is an uniprocessor system
> + * we are in multiprocessor format but uniprocessor system
> + * or in the old uniprocessor format
> + */
> +
> + cpuid_topo->thread_id = -1;
> + cpuid_topo->core_id = 0;
> + cpuid_topo->socket_id = -1;
> + }
> +
> + /* update core and thread sibling masks */
> + for_each_possible_cpu(cpu) {
> + struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
> +
> + if (cpuid_topo->socket_id == cpu_topo->socket_id) {
> + cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
> + if (cpu != cpuid)
> + cpumask_set_cpu(cpu,
> + &cpuid_topo->core_sibling);
> +
> + if (cpuid_topo->core_id == cpu_topo->core_id) {
> + cpumask_set_cpu(cpuid,
> + &cpu_topo->thread_sibling);
> + if (cpu != cpuid)
> + cpumask_set_cpu(cpu,
> + &cpuid_topo->thread_sibling);
> + }
> + }
> + }
> + smp_wmb();
> +
> + printk(KERN_INFO "cpu %u : thread %d cpu %d, socket %d, mpidr %x\n",
> + cpuid, cpu_topology[cpuid].thread_id,
> + cpu_topology[cpuid].core_id,
> + cpu_topology[cpuid].socket_id, mpidr);
> +
> +}
> +
> +/*
> + * init_cpu_topology is called at boot when only one cpu is running
> + * which prevent simultaneous write access to cpu_topology array
> + */
> +void init_cpu_topology(void)
> +{
> + unsigned int cpu;
> +
> + /* init core mask */
> + for_each_possible_cpu(cpu) {
> + struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
> +
> + cpu_topo->thread_id = -1;
> + cpu_topo->core_id = -1;
> + cpu_topo->socket_id = -1;
> + cpumask_clear(&cpu_topo->core_sibling);
> + cpumask_clear(&cpu_topo->thread_sibling);
> + }
> + smp_wmb();
> +}
> --
> 1.7.4.1
>

2011-06-16 11:55:10

by Amit Kachhap

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

I have some doubts about the bit fields of the MPIDR register.
Comments added below.
On 16 June 2011 14:19, Vincent Guittot <[email protected]> wrote:
> The affinity between Arm processors is defined in the MPIDR register.
> We can identify which processors are in the same cluster,
> and which ones have performance interdependency. The cpu topology
> ?of an Arm platform can be set thanks to this register and this topology
> is then used by sched_mc and sched_smt.
>
> Signed-off-by: Vincent Guittot <[email protected]>
> ---
> ?arch/arm/Kconfig ? ? ? ? ? ? ? ?| ? 26 ++++++++
> ?arch/arm/include/asm/topology.h | ? 33 ++++++++++
> ?arch/arm/kernel/Makefile ? ? ? ?| ? ?1 +
> ?arch/arm/kernel/smp.c ? ? ? ? ? | ? ?6 ++
> ?arch/arm/kernel/topology.c ? ? ?| ?133 +++++++++++++++++++++++++++++++++++++++
> ?5 files changed, 199 insertions(+), 0 deletions(-)
> ?create mode 100644 arch/arm/kernel/topology.c
>
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 9adc278..bacf9af 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -219,6 +219,24 @@ source "kernel/Kconfig.freezer"
>
> ?menu "System Type"
>
> +config SCHED_MC
> + ? ? ? bool "Multi-core scheduler support"
> + ? ? ? depends on SMP && ARM_CPU_TOPOLOGY
> + ? ? ? default n
> + ? ? ? help
> + ? ? ? ? Multi-core scheduler support improves the CPU scheduler's decision
> + ? ? ? ? making when dealing with multi-core CPU chips at a cost of slightly
> + ? ? ? ? increased overhead in some places. If unsure say N here.
> +
> +config SCHED_SMT
> + ? ? ? bool "SMT scheduler support"
> + ? ? ? depends on SMP && ARM_CPU_TOPOLOGY
> + ? ? ? default n
> + ? ? ? help
> + ? ? ? ? Improves the CPU scheduler's decision making when dealing with
> + ? ? ? ? MultiThreading at a cost of slightly increased overhead in some
> + ? ? ? ? places. If unsure say N here.
> +
> ?config MMU
> ? ? ? ?bool "MMU-based Paged Memory Management Support"
> ? ? ? ?default y
> @@ -1062,6 +1080,14 @@ if !MMU
> ?source "arch/arm/Kconfig-nommu"
> ?endif
>
> +config ARM_CPU_TOPOLOGY
> + ? ? ? bool "Support cpu topology definition"
> + ? ? ? depends on SMP && CPU_V7
> + ? ? ? help
> + ? ? ? ? Support Arm cpu topology definition. The MPIDR register defines
> + ? ? ? ? affinity between processors which is used to set the cpu
> + ? ? ? ? topology of an Arm System.
> +
> ?config ARM_ERRATA_411920
> ? ? ? ?bool "ARM errata: Invalidation of the Instruction Cache operation can fail"
> ? ? ? ?depends on CPU_V6 || CPU_V6K
> diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
> index accbd7c..cb90d0a 100644
> --- a/arch/arm/include/asm/topology.h
> +++ b/arch/arm/include/asm/topology.h
> @@ -1,6 +1,39 @@
> ?#ifndef _ASM_ARM_TOPOLOGY_H
> ?#define _ASM_ARM_TOPOLOGY_H
>
> +#ifdef CONFIG_ARM_CPU_TOPOLOGY
> +
> +#include <linux/cpumask.h>
> +
> +struct cputopo_arm {
> + ? ? ? int thread_id;
> + ? ? ? int core_id;
> + ? ? ? int socket_id;
> + ? ? ? cpumask_t thread_sibling;
> + ? ? ? cpumask_t core_sibling;
> +};
> +
> +extern struct cputopo_arm cpu_topology[NR_CPUS];
> +
> +#define topology_physical_package_id(cpu) ? ? ?(cpu_topology[cpu].socket_id)
> +#define topology_core_id(cpu) ? ? ? ? ?(cpu_topology[cpu].core_id)
> +#define topology_core_cpumask(cpu) ? ? (&(cpu_topology[cpu].core_sibling))
> +#define topology_thread_cpumask(cpu) ? (&(cpu_topology[cpu].thread_sibling))
> +
> +#define mc_capable() ? (cpu_topology[0].socket_id != -1)
> +#define smt_capable() ?(cpu_topology[0].thread_id != -1)
> +
> +void init_cpu_topology(void);
> +void store_cpu_topology(unsigned int cpuid);
> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
> +
> +#else
> +
> +#define init_cpu_topology() {};
> +#define store_cpu_topology(cpuid) {};
> +
> +#endif
> +
> ?#include <asm-generic/topology.h>
>
> ?#endif /* _ASM_ARM_TOPOLOGY_H */
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index a5b31af..816a481 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -61,6 +61,7 @@ obj-$(CONFIG_IWMMXT) ? ? ? ? ?+= iwmmxt.o
> ?obj-$(CONFIG_CPU_HAS_PMU) ? ? ?+= pmu.o
> ?obj-$(CONFIG_HW_PERF_EVENTS) ? += perf_event.o
> ?AFLAGS_iwmmxt.o ? ? ? ? ? ? ? ? ? ? ? ?:= -Wa,-mcpu=iwmmxt
> +obj-$(CONFIG_ARM_CPU_TOPOLOGY) ?+= topology.o
>
> ?ifneq ($(CONFIG_ARCH_EBSA110),y)
> ? obj-y ? ? ? ? ? ? ? ?+= io.o
> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
> index 344e52b..3e8dc3b 100644
> --- a/arch/arm/kernel/smp.c
> +++ b/arch/arm/kernel/smp.c
> @@ -31,6 +31,7 @@
> ?#include <asm/cacheflush.h>
> ?#include <asm/cpu.h>
> ?#include <asm/cputype.h>
> +#include <asm/topology.h>
> ?#include <asm/mmu_context.h>
> ?#include <asm/pgtable.h>
> ?#include <asm/pgalloc.h>
> @@ -268,6 +269,9 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
> ? ? ? ?struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);
>
> ? ? ? ?cpu_info->loops_per_jiffy = loops_per_jiffy;
> +
> + ? ? ? store_cpu_topology(cpuid);
> +
> ?}
>
> ?/*
> @@ -354,6 +358,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
> ?{
> ? ? ? ?unsigned int ncores = num_possible_cpus();
>
> + ? ? ? init_cpu_topology();
> +
> ? ? ? ?smp_store_cpu_info(smp_processor_id());
>
> ? ? ? ?/*
> diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
> new file mode 100644
> index 0000000..d61723c
> --- /dev/null
> +++ b/arch/arm/kernel/topology.c
> @@ -0,0 +1,133 @@
> +/*
> + * arch/arm/kernel/topology.c
> + *
> + * Copyright (C) 2011 [email protected]
> + *
> + * based on arch/sh/kernel/topology.c
> + *
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License. ?See the file "COPYING" in the main directory of this archive
> + * for more details.
> + */
> +
> +#include <linux/cpu.h>
> +#include <linux/cpumask.h>
> +#include <linux/init.h>
> +#include <linux/percpu.h>
> +#include <linux/node.h>
> +#include <linux/nodemask.h>
> +#include <linux/sched.h>
> +
> +#include <asm/cacheflush.h>
> +#include <asm/topology.h>
> +
> +#define hard_smp_mpidr() \
> + ? ? ? ({ \
> + ? ? ? ? ? ? ? unsigned int cpunum; \
> + ? ? ? ? ? ? ? __asm__("mrc p15, 0, %0, c0, c0, 5" ? ? \
> + ? ? ? ? ? ? ? ? ? ? ? : "=r" (cpunum)); \
> + ? ? ? ? ? ? ? cpunum; \
> + ? ? ? })
> +
> +struct cputopo_arm cpu_topology[NR_CPUS];
> +
> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
> +{
> + ? ? ? return &(cpu_topology[cpu].core_sibling);
> +}
> +
> +/*
> + * store_cpu_topology is called at boot when only one cpu is running
> + * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
> + * which prevents simultaneous write access to cpu_topology array
> + */
> +void store_cpu_topology(unsigned int cpuid)
> +{
> + ? ? ? struct cputopo_arm *cpuid_topo = &(cpu_topology[cpuid]);
> + ? ? ? unsigned int mpidr;
> + ? ? ? unsigned int cpu;
> +
> + ? ? ? /* If the cpu topology has been already set, just return */
> + ? ? ? if (cpuid_topo->core_id != -1)
> + ? ? ? ? ? ? ? return;
> +
> + ? ? ? mpidr = hard_smp_mpidr();
> +
> + ? ? ? /* create cpu topology mapping */
> + ? ? ? if (mpidr & (0x3 << 30)) {

I checked the A9 reference manual. It says bit 30 if 0 denotes that processor is
part of multiprocessor system.


> + ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ?* This is a multiprocessor system
> + ? ? ? ? ? ? ? ?* multiprocessor format & multiprocessor mode field are set
> + ? ? ? ? ? ? ? ?*/
> +
> + ? ? ? ? ? ? ? if (mpidr & (0x1 << 24)) {
> + ? ? ? ? ? ? ? ? ? ? ? /* core performance interdependency */
> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->thread_id = (mpidr & 0x3);
> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->core_id = ?((mpidr >> 8) & 0xF);
> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->socket_id = ((mpidr >> 16) & 0xFF);
> + ? ? ? ? ? ? ? } else {
> + ? ? ? ? ? ? ? ? ? ? ? /* normal core interdependency */
> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->thread_id = -1;
> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->core_id = (mpidr & 0x3);
> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->socket_id = ((mpidr >> 8) & 0xF);
> + ? ? ? ? ? ? ? }
> + ? ? ? } else {
> + ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ?* This is an uniprocessor system
> + ? ? ? ? ? ? ? ?* we are in multiprocessor format but uniprocessor system
> + ? ? ? ? ? ? ? ?* or in the old uniprocessor format
> + ? ? ? ? ? ? ? ?*/
> +
> + ? ? ? ? ? ? ? cpuid_topo->thread_id = -1;
> + ? ? ? ? ? ? ? cpuid_topo->core_id = 0;
> + ? ? ? ? ? ? ? cpuid_topo->socket_id = -1;
> + ? ? ? }
> +
> + ? ? ? /* update core and thread sibling masks */
> + ? ? ? for_each_possible_cpu(cpu) {
> + ? ? ? ? ? ? ? struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
> +
> + ? ? ? ? ? ? ? if (cpuid_topo->socket_id == cpu_topo->socket_id) {
> + ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
> + ? ? ? ? ? ? ? ? ? ? ? if (cpu != cpuid)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpu,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &cpuid_topo->core_sibling);
> +
> + ? ? ? ? ? ? ? ? ? ? ? if (cpuid_topo->core_id == cpu_topo->core_id) {
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpuid,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &cpu_topo->thread_sibling);
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (cpu != cpuid)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpu,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &cpuid_topo->thread_sibling);
> + ? ? ? ? ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? ? }
> + ? ? ? }
> + ? ? ? smp_wmb();
> +
> + ? ? ? printk(KERN_INFO "cpu %u : thread %d cpu %d, socket %d, mpidr %x\n",
> + ? ? ? ? ? ? ? cpuid, cpu_topology[cpuid].thread_id,
> + ? ? ? ? ? ? ? cpu_topology[cpuid].core_id,
> + ? ? ? ? ? ? ? cpu_topology[cpuid].socket_id, mpidr);
> +
> +}
> +
> +/*
> + * init_cpu_topology is called at boot when only one cpu is running
> + * which prevent simultaneous write access to cpu_topology array
> + */
> +void init_cpu_topology(void)
> +{
> + ? ? ? unsigned int cpu;
> +
> + ? ? ? /* init core mask */
> + ? ? ? for_each_possible_cpu(cpu) {
> + ? ? ? ? ? ? ? struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
> +
> + ? ? ? ? ? ? ? cpu_topo->thread_id = -1;
> + ? ? ? ? ? ? ? cpu_topo->core_id = ?-1;
> + ? ? ? ? ? ? ? cpu_topo->socket_id = -1;
> + ? ? ? ? ? ? ? cpumask_clear(&cpu_topo->core_sibling);
> + ? ? ? ? ? ? ? cpumask_clear(&cpu_topo->thread_sibling);
> + ? ? ? }
> + ? ? ? smp_wmb();
> +}
> --
> 1.7.4.1
>
> _______________________________________________
> linaro-dev mailing list
> [email protected]
> http://lists.linaro.org/mailman/listinfo/linaro-dev
>

2011-06-16 12:05:47

by Vincent Guittot

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 16 June 2011 12:49, Daniel Lezcano <[email protected]> wrote:
> On 06/16/2011 10:49 AM, Vincent Guittot wrote:
>>
>> The affinity between Arm processors is defined in the MPIDR register.
>> We can identify which processors are in the same cluster,
>> and which ones have performance interdependency. The cpu topology
>> ?of an Arm platform can be set thanks to this register and this topology
>> is then used by sched_mc and sched_smt.
>>
>> Signed-off-by: Vincent Guittot<[email protected]>
>> ---
>> ?arch/arm/Kconfig ? ? ? ? ? ? ? ?| ? 26 ++++++++
>> ?arch/arm/include/asm/topology.h | ? 33 ++++++++++
>> ?arch/arm/kernel/Makefile ? ? ? ?| ? ?1 +
>> ?arch/arm/kernel/smp.c ? ? ? ? ? | ? ?6 ++
>> ?arch/arm/kernel/topology.c ? ? ?| ?133
>> +++++++++++++++++++++++++++++++++++++++
>> ?5 files changed, 199 insertions(+), 0 deletions(-)
>> ?create mode 100644 arch/arm/kernel/topology.c
>>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index 9adc278..bacf9af 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -219,6 +219,24 @@ source "kernel/Kconfig.freezer"
>>
>> ?menu "System Type"
>>
>> +config SCHED_MC
>> + ? ? ? bool "Multi-core scheduler support"
>> + ? ? ? depends on SMP&& ?ARM_CPU_TOPOLOGY
>
> ARM_CPU_TOPOLOGY depends on SMP, so the check can be reduced to
>
> depends on ARM_CPU_TOPOLOGY

you're right

>>
>> + ? ? ? default n
>> + ? ? ? help
>> + ? ? ? ? Multi-core scheduler support improves the CPU scheduler's
>> decision
>> + ? ? ? ? making when dealing with multi-core CPU chips at a cost of
>> slightly
>> + ? ? ? ? increased overhead in some places. If unsure say N here.
>> +
>> +config SCHED_SMT
>> + ? ? ? bool "SMT scheduler support"
>> + ? ? ? depends on SMP&& ?ARM_CPU_TOPOLOGY
>
> depends on SMT && ARM_CPU_TOPOLOGY ?

SMP is the right one but it can be reduced to : depends on ARM_CPU_TOPOLOGY
like SCHED_MC,

>
>> + ? ? ? default n
>> + ? ? ? help
>> + ? ? ? ? Improves the CPU scheduler's decision making when dealing with
>> + ? ? ? ? MultiThreading at a cost of slightly increased overhead in some
>> + ? ? ? ? places. If unsure say N here.
>> +
>> ?config MMU
>> ? ? ? ?bool "MMU-based Paged Memory Management Support"
>> ? ? ? ?default y
>> @@ -1062,6 +1080,14 @@ if !MMU
>> ?source "arch/arm/Kconfig-nommu"
>> ?endif
>>
>> +config ARM_CPU_TOPOLOGY
>> + ? ? ? bool "Support cpu topology definition"
>> + ? ? ? depends on SMP&& ?CPU_V7
>> + ? ? ? help
>> + ? ? ? ? Support Arm cpu topology definition. The MPIDR register defines
>> + ? ? ? ? affinity between processors which is used to set the cpu
>> + ? ? ? ? topology of an Arm System.
>> +
>> ?config ARM_ERRATA_411920
>> ? ? ? ?bool "ARM errata: Invalidation of the Instruction Cache operation
>> can fail"
>> ? ? ? ?depends on CPU_V6 || CPU_V6K
>> diff --git a/arch/arm/include/asm/topology.h
>> b/arch/arm/include/asm/topology.h
>> index accbd7c..cb90d0a 100644
>> --- a/arch/arm/include/asm/topology.h
>> +++ b/arch/arm/include/asm/topology.h
>> @@ -1,6 +1,39 @@
>> ?#ifndef _ASM_ARM_TOPOLOGY_H
>> ?#define _ASM_ARM_TOPOLOGY_H
>>
>> +#ifdef CONFIG_ARM_CPU_TOPOLOGY
>> +
>> +#include<linux/cpumask.h>
>> +
>> +struct cputopo_arm {
>> + ? ? ? int thread_id;
>> + ? ? ? int core_id;
>> + ? ? ? int socket_id;
>
> I am not sure how that deals with the rest of the functions prototype but
> wouldn't u16 be more adequate ?
>

I have used int to be aligned on register size and minimize register
manipulation

>> + ? ? ? cpumask_t thread_sibling;
>> + ? ? ? cpumask_t core_sibling;
>> +};
>> +
>> +extern struct cputopo_arm cpu_topology[NR_CPUS];
>> +
>> +#define topology_physical_package_id(cpu)
>> ?(cpu_topology[cpu].socket_id)
>> +#define topology_core_id(cpu) ? ? ? ? ?(cpu_topology[cpu].core_id)
>> +#define topology_core_cpumask(cpu)
>> (&(cpu_topology[cpu].core_sibling))
>> +#define topology_thread_cpumask(cpu)
>> (&(cpu_topology[cpu].thread_sibling))
>> +
>> +#define mc_capable() ? (cpu_topology[0].socket_id != -1)
>> +#define smt_capable() ?(cpu_topology[0].thread_id != -1)
>> +
>> +void init_cpu_topology(void);
>> +void store_cpu_topology(unsigned int cpuid);
>> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
>> +
>> +#else
>> +
>> +#define init_cpu_topology() {};
>> +#define store_cpu_topology(cpuid) {};
>
> AFAIK the convention is to declare static inline noop functions.
>
> static inline void init_cpu_topology(void) { };
> static inline void store_cpu_topology(unsigned int cpuid) { };
>

ok

>> +
>> +#endif
>> +
>> ?#include<asm-generic/topology.h>
>>
>> ?#endif /* _ASM_ARM_TOPOLOGY_H */
>> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
>> index a5b31af..816a481 100644
>> --- a/arch/arm/kernel/Makefile
>> +++ b/arch/arm/kernel/Makefile
>> @@ -61,6 +61,7 @@ obj-$(CONFIG_IWMMXT) ? ? ? ? ?+= iwmmxt.o
>> ?obj-$(CONFIG_CPU_HAS_PMU) ? ? += pmu.o
>> ?obj-$(CONFIG_HW_PERF_EVENTS) ?+= perf_event.o
>> ?AFLAGS_iwmmxt.o ? ? ? ? ? ? ? ? ? ? ? := -Wa,-mcpu=iwmmxt
>> +obj-$(CONFIG_ARM_CPU_TOPOLOGY) ?+= topology.o
>>
>> ?ifneq ($(CONFIG_ARCH_EBSA110),y)
>> ? ?obj-y ? ? ? ? ? ? ? += io.o
>> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
>> index 344e52b..3e8dc3b 100644
>> --- a/arch/arm/kernel/smp.c
>> +++ b/arch/arm/kernel/smp.c
>> @@ -31,6 +31,7 @@
>> ?#include<asm/cacheflush.h>
>> ?#include<asm/cpu.h>
>> ?#include<asm/cputype.h>
>> +#include<asm/topology.h>
>> ?#include<asm/mmu_context.h>
>> ?#include<asm/pgtable.h>
>> ?#include<asm/pgalloc.h>
>> @@ -268,6 +269,9 @@ static void __cpuinit smp_store_cpu_info(unsigned int
>> cpuid)
>> ? ? ? ?struct cpuinfo_arm *cpu_info =&per_cpu(cpu_data, cpuid);
>>
>> ? ? ? ?cpu_info->loops_per_jiffy = loops_per_jiffy;
>> +
>> + ? ? ? store_cpu_topology(cpuid);
>> +
>> ?}
>
> If the store_cpu_topology function is called once, can it be changed to a
> __cpuinit function, declared as a subsys_initcall and removed from here ?
>

it must be called once on each cpu before the call of sched_init_smp

>> ?/*
>> @@ -354,6 +358,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
>> ?{
>> ? ? ? ?unsigned int ncores = num_possible_cpus();
>>
>> + ? ? ? init_cpu_topology();
>
> Why do you need to call the init function here ?
>

this function must be called before the 1st call to smp_store_cpu_info

> On the other architecture I see:
>
> static int __init topology_init(void)
> {
> ? ?...
> }
>
> subsys_initcall(topology_init);
>
> Isn't possible to use the same way ? (with the benefit to save two
> declarations in the header).
>
>
> [ ... ]
>
>> +
>> +struct cputopo_arm cpu_topology[NR_CPUS];
>
> IMO, you can define it static here no ?
>

This array is used by "#define topology_xxx" and "#define xx_capable"
which are used by the scheduler and the topology driver

>> +
>> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
>> +{
>> + ? ? ? return&(cpu_topology[cpu].core_sibling);
>> +}
>> +
>> +/*
>> + * store_cpu_topology is called at boot when only one cpu is running
>> + * and with the mutex cpu_hotplug.lock locked, when several cpus have
>> booted,
>> + * which prevents simultaneous write access to cpu_topology array
>> + */
>> +void store_cpu_topology(unsigned int cpuid)
>> +{
>> + ? ? ? struct cputopo_arm *cpuid_topo =&(cpu_topology[cpuid]);
>> + ? ? ? unsigned int mpidr;
>> + ? ? ? unsigned int cpu;
>> +
>> + ? ? ? /* If the cpu topology has been already set, just return */
>> + ? ? ? if (cpuid_topo->core_id != -1)
>> + ? ? ? ? ? ? ? return;
>
> If the code calls store_cpu_topology but with no effect because it was
> already called before, that means it shouldn't be called at all, no ?
> IMHO, this test should be removed or at least add a WARN_ONCE.
>

We will call smp_store_cpu_info each time the cpu will be plugged. But
once set, we don't need to update topology information

>> +
>> + ? ? ? mpidr = hard_smp_mpidr();
>> +
>> + ? ? ? /* create cpu topology mapping */
>> + ? ? ? if (mpidr& ?(0x3<< ?30)) {
>> + ? ? ? ? ? ? ? /*
>> + ? ? ? ? ? ? ? ?* This is a multiprocessor system
>> + ? ? ? ? ? ? ? ?* multiprocessor format& ?multiprocessor mode field are
>> set
>> + ? ? ? ? ? ? ? ?*/
>> +
>> + ? ? ? ? ? ? ? if (mpidr& ?(0x1<< ?24)) {
>> + ? ? ? ? ? ? ? ? ? ? ? /* core performance interdependency */
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->thread_id = (mpidr& ?0x3);
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->core_id = ?((mpidr>> ?8)& ?0xF);
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->socket_id = ((mpidr>> ?16)& ?0xFF);
>> + ? ? ? ? ? ? ? } else {
>> + ? ? ? ? ? ? ? ? ? ? ? /* normal core interdependency */
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->thread_id = -1;
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->core_id = (mpidr& ?0x3);
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->socket_id = ((mpidr>> ?8)& ?0xF);
>> + ? ? ? ? ? ? ? }
>> + ? ? ? } else {
>> + ? ? ? ? ? ? ? /*
>> + ? ? ? ? ? ? ? ?* This is an uniprocessor system
>> + ? ? ? ? ? ? ? ?* we are in multiprocessor format but uniprocessor system
>> + ? ? ? ? ? ? ? ?* or in the old uniprocessor format
>> + ? ? ? ? ? ? ? ?*/
>> +
>> + ? ? ? ? ? ? ? cpuid_topo->thread_id = -1;
>> + ? ? ? ? ? ? ? cpuid_topo->core_id = 0;
>> + ? ? ? ? ? ? ? cpuid_topo->socket_id = -1;
>> + ? ? ? }
>> +
>> + ? ? ? /* update core and thread sibling masks */
>> + ? ? ? for_each_possible_cpu(cpu) {
>> + ? ? ? ? ? ? ? struct cputopo_arm *cpu_topo =&(cpu_topology[cpu]);
>> +
>> + ? ? ? ? ? ? ? if (cpuid_topo->socket_id == cpu_topo->socket_id) {
>> + ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpuid,&cpu_topo->core_sibling);
>> + ? ? ? ? ? ? ? ? ? ? ? if (cpu != cpuid)
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpu,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &cpuid_topo->core_sibling);
>> +
>> + ? ? ? ? ? ? ? ? ? ? ? if (cpuid_topo->core_id == cpu_topo->core_id) {
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpuid,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &cpu_topo->thread_sibling);
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (cpu != cpuid)
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpu,
>> +
>> &cpuid_topo->thread_sibling);
>> + ? ? ? ? ? ? ? ? ? ? ? }
>> + ? ? ? ? ? ? ? }
>> + ? ? ? }
>> + ? ? ? smp_wmb();
>> +
>> + ? ? ? printk(KERN_INFO "cpu %u : thread %d cpu %d, socket %d, mpidr
>> %x\n",
>> + ? ? ? ? ? ? ? cpuid, cpu_topology[cpuid].thread_id,
>> + ? ? ? ? ? ? ? cpu_topology[cpuid].core_id,
>> + ? ? ? ? ? ? ? cpu_topology[cpuid].socket_id, mpidr);
>> +
>> +}
>> +
>> +/*
>> + * init_cpu_topology is called at boot when only one cpu is running
>> + * which prevent simultaneous write access to cpu_topology array
>> + */
>> +void init_cpu_topology(void)
>> +{
>> + ? ? ? unsigned int cpu;
>> +
>> + ? ? ? /* init core mask */
>> + ? ? ? for_each_possible_cpu(cpu) {
>> + ? ? ? ? ? ? ? struct cputopo_arm *cpu_topo =&(cpu_topology[cpu]);
>> +
>> + ? ? ? ? ? ? ? cpu_topo->thread_id = -1;
>> + ? ? ? ? ? ? ? cpu_topo->core_id = ?-1;
>
> nit : extra space

ok

>>
>> + ? ? ? ? ? ? ? cpu_topo->socket_id = -1;
>> + ? ? ? ? ? ? ? cpumask_clear(&cpu_topo->core_sibling);
>> + ? ? ? ? ? ? ? cpumask_clear(&cpu_topo->thread_sibling);
>> + ? ? ? }
>> + ? ? ? smp_wmb();
>> +}
>
>

2011-06-16 12:10:37

by Vincent Guittot

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 16 June 2011 13:55, Amit Kachhap <[email protected]> wrote:
> I have some doubts about the bit fields of the MPIDR register.
> Comments added below.
> On 16 June 2011 14:19, Vincent Guittot <[email protected]> wrote:
>> The affinity between Arm processors is defined in the MPIDR register.
>> We can identify which processors are in the same cluster,
>> and which ones have performance interdependency. The cpu topology
>> ?of an Arm platform can be set thanks to this register and this topology
>> is then used by sched_mc and sched_smt.
>>
>> Signed-off-by: Vincent Guittot <[email protected]>
>> ---
>> ?arch/arm/Kconfig ? ? ? ? ? ? ? ?| ? 26 ++++++++
>> ?arch/arm/include/asm/topology.h | ? 33 ++++++++++
>> ?arch/arm/kernel/Makefile ? ? ? ?| ? ?1 +
>> ?arch/arm/kernel/smp.c ? ? ? ? ? | ? ?6 ++
>> ?arch/arm/kernel/topology.c ? ? ?| ?133 +++++++++++++++++++++++++++++++++++++++
>> ?5 files changed, 199 insertions(+), 0 deletions(-)
>> ?create mode 100644 arch/arm/kernel/topology.c
>>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index 9adc278..bacf9af 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -219,6 +219,24 @@ source "kernel/Kconfig.freezer"
>>
>> ?menu "System Type"
>>
>> +config SCHED_MC
>> + ? ? ? bool "Multi-core scheduler support"
>> + ? ? ? depends on SMP && ARM_CPU_TOPOLOGY
>> + ? ? ? default n
>> + ? ? ? help
>> + ? ? ? ? Multi-core scheduler support improves the CPU scheduler's decision
>> + ? ? ? ? making when dealing with multi-core CPU chips at a cost of slightly
>> + ? ? ? ? increased overhead in some places. If unsure say N here.
>> +
>> +config SCHED_SMT
>> + ? ? ? bool "SMT scheduler support"
>> + ? ? ? depends on SMP && ARM_CPU_TOPOLOGY
>> + ? ? ? default n
>> + ? ? ? help
>> + ? ? ? ? Improves the CPU scheduler's decision making when dealing with
>> + ? ? ? ? MultiThreading at a cost of slightly increased overhead in some
>> + ? ? ? ? places. If unsure say N here.
>> +
>> ?config MMU
>> ? ? ? ?bool "MMU-based Paged Memory Management Support"
>> ? ? ? ?default y
>> @@ -1062,6 +1080,14 @@ if !MMU
>> ?source "arch/arm/Kconfig-nommu"
>> ?endif
>>
>> +config ARM_CPU_TOPOLOGY
>> + ? ? ? bool "Support cpu topology definition"
>> + ? ? ? depends on SMP && CPU_V7
>> + ? ? ? help
>> + ? ? ? ? Support Arm cpu topology definition. The MPIDR register defines
>> + ? ? ? ? affinity between processors which is used to set the cpu
>> + ? ? ? ? topology of an Arm System.
>> +
>> ?config ARM_ERRATA_411920
>> ? ? ? ?bool "ARM errata: Invalidation of the Instruction Cache operation can fail"
>> ? ? ? ?depends on CPU_V6 || CPU_V6K
>> diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
>> index accbd7c..cb90d0a 100644
>> --- a/arch/arm/include/asm/topology.h
>> +++ b/arch/arm/include/asm/topology.h
>> @@ -1,6 +1,39 @@
>> ?#ifndef _ASM_ARM_TOPOLOGY_H
>> ?#define _ASM_ARM_TOPOLOGY_H
>>
>> +#ifdef CONFIG_ARM_CPU_TOPOLOGY
>> +
>> +#include <linux/cpumask.h>
>> +
>> +struct cputopo_arm {
>> + ? ? ? int thread_id;
>> + ? ? ? int core_id;
>> + ? ? ? int socket_id;
>> + ? ? ? cpumask_t thread_sibling;
>> + ? ? ? cpumask_t core_sibling;
>> +};
>> +
>> +extern struct cputopo_arm cpu_topology[NR_CPUS];
>> +
>> +#define topology_physical_package_id(cpu) ? ? ?(cpu_topology[cpu].socket_id)
>> +#define topology_core_id(cpu) ? ? ? ? ?(cpu_topology[cpu].core_id)
>> +#define topology_core_cpumask(cpu) ? ? (&(cpu_topology[cpu].core_sibling))
>> +#define topology_thread_cpumask(cpu) ? (&(cpu_topology[cpu].thread_sibling))
>> +
>> +#define mc_capable() ? (cpu_topology[0].socket_id != -1)
>> +#define smt_capable() ?(cpu_topology[0].thread_id != -1)
>> +
>> +void init_cpu_topology(void);
>> +void store_cpu_topology(unsigned int cpuid);
>> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
>> +
>> +#else
>> +
>> +#define init_cpu_topology() {};
>> +#define store_cpu_topology(cpuid) {};
>> +
>> +#endif
>> +
>> ?#include <asm-generic/topology.h>
>>
>> ?#endif /* _ASM_ARM_TOPOLOGY_H */
>> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
>> index a5b31af..816a481 100644
>> --- a/arch/arm/kernel/Makefile
>> +++ b/arch/arm/kernel/Makefile
>> @@ -61,6 +61,7 @@ obj-$(CONFIG_IWMMXT) ? ? ? ? ?+= iwmmxt.o
>> ?obj-$(CONFIG_CPU_HAS_PMU) ? ? ?+= pmu.o
>> ?obj-$(CONFIG_HW_PERF_EVENTS) ? += perf_event.o
>> ?AFLAGS_iwmmxt.o ? ? ? ? ? ? ? ? ? ? ? ?:= -Wa,-mcpu=iwmmxt
>> +obj-$(CONFIG_ARM_CPU_TOPOLOGY) ?+= topology.o
>>
>> ?ifneq ($(CONFIG_ARCH_EBSA110),y)
>> ? obj-y ? ? ? ? ? ? ? ?+= io.o
>> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
>> index 344e52b..3e8dc3b 100644
>> --- a/arch/arm/kernel/smp.c
>> +++ b/arch/arm/kernel/smp.c
>> @@ -31,6 +31,7 @@
>> ?#include <asm/cacheflush.h>
>> ?#include <asm/cpu.h>
>> ?#include <asm/cputype.h>
>> +#include <asm/topology.h>
>> ?#include <asm/mmu_context.h>
>> ?#include <asm/pgtable.h>
>> ?#include <asm/pgalloc.h>
>> @@ -268,6 +269,9 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
>> ? ? ? ?struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);
>>
>> ? ? ? ?cpu_info->loops_per_jiffy = loops_per_jiffy;
>> +
>> + ? ? ? store_cpu_topology(cpuid);
>> +
>> ?}
>>
>> ?/*
>> @@ -354,6 +358,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
>> ?{
>> ? ? ? ?unsigned int ncores = num_possible_cpus();
>>
>> + ? ? ? init_cpu_topology();
>> +
>> ? ? ? ?smp_store_cpu_info(smp_processor_id());
>>
>> ? ? ? ?/*
>> diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
>> new file mode 100644
>> index 0000000..d61723c
>> --- /dev/null
>> +++ b/arch/arm/kernel/topology.c
>> @@ -0,0 +1,133 @@
>> +/*
>> + * arch/arm/kernel/topology.c
>> + *
>> + * Copyright (C) 2011 [email protected]
>> + *
>> + * based on arch/sh/kernel/topology.c
>> + *
>> + * This file is subject to the terms and conditions of the GNU General Public
>> + * License. ?See the file "COPYING" in the main directory of this archive
>> + * for more details.
>> + */
>> +
>> +#include <linux/cpu.h>
>> +#include <linux/cpumask.h>
>> +#include <linux/init.h>
>> +#include <linux/percpu.h>
>> +#include <linux/node.h>
>> +#include <linux/nodemask.h>
>> +#include <linux/sched.h>
>> +
>> +#include <asm/cacheflush.h>
>> +#include <asm/topology.h>
>> +
>> +#define hard_smp_mpidr() \
>> + ? ? ? ({ \
>> + ? ? ? ? ? ? ? unsigned int cpunum; \
>> + ? ? ? ? ? ? ? __asm__("mrc p15, 0, %0, c0, c0, 5" ? ? \
>> + ? ? ? ? ? ? ? ? ? ? ? : "=r" (cpunum)); \
>> + ? ? ? ? ? ? ? cpunum; \
>> + ? ? ? })
>> +
>> +struct cputopo_arm cpu_topology[NR_CPUS];
>> +
>> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
>> +{
>> + ? ? ? return &(cpu_topology[cpu].core_sibling);
>> +}
>> +
>> +/*
>> + * store_cpu_topology is called at boot when only one cpu is running
>> + * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
>> + * which prevents simultaneous write access to cpu_topology array
>> + */
>> +void store_cpu_topology(unsigned int cpuid)
>> +{
>> + ? ? ? struct cputopo_arm *cpuid_topo = &(cpu_topology[cpuid]);
>> + ? ? ? unsigned int mpidr;
>> + ? ? ? unsigned int cpu;
>> +
>> + ? ? ? /* If the cpu topology has been already set, just return */
>> + ? ? ? if (cpuid_topo->core_id != -1)
>> + ? ? ? ? ? ? ? return;
>> +
>> + ? ? ? mpidr = hard_smp_mpidr();
>> +
>> + ? ? ? /* create cpu topology mapping */
>> + ? ? ? if (mpidr & (0x3 << 30)) {
>
> I checked the A9 reference manual. It says bit 30 if 0 denotes that processor is
> part of multiprocessor system.
>

You're right, i'm going to update my test

>
>> + ? ? ? ? ? ? ? /*
>> + ? ? ? ? ? ? ? ?* This is a multiprocessor system
>> + ? ? ? ? ? ? ? ?* multiprocessor format & multiprocessor mode field are set
>> + ? ? ? ? ? ? ? ?*/
>> +
>> + ? ? ? ? ? ? ? if (mpidr & (0x1 << 24)) {
>> + ? ? ? ? ? ? ? ? ? ? ? /* core performance interdependency */
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->thread_id = (mpidr & 0x3);
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->core_id = ?((mpidr >> 8) & 0xF);
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->socket_id = ((mpidr >> 16) & 0xFF);
>> + ? ? ? ? ? ? ? } else {
>> + ? ? ? ? ? ? ? ? ? ? ? /* normal core interdependency */
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->thread_id = -1;
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->core_id = (mpidr & 0x3);
>> + ? ? ? ? ? ? ? ? ? ? ? cpuid_topo->socket_id = ((mpidr >> 8) & 0xF);
>> + ? ? ? ? ? ? ? }
>> + ? ? ? } else {
>> + ? ? ? ? ? ? ? /*
>> + ? ? ? ? ? ? ? ?* This is an uniprocessor system
>> + ? ? ? ? ? ? ? ?* we are in multiprocessor format but uniprocessor system
>> + ? ? ? ? ? ? ? ?* or in the old uniprocessor format
>> + ? ? ? ? ? ? ? ?*/
>> +
>> + ? ? ? ? ? ? ? cpuid_topo->thread_id = -1;
>> + ? ? ? ? ? ? ? cpuid_topo->core_id = 0;
>> + ? ? ? ? ? ? ? cpuid_topo->socket_id = -1;
>> + ? ? ? }
>> +
>> + ? ? ? /* update core and thread sibling masks */
>> + ? ? ? for_each_possible_cpu(cpu) {
>> + ? ? ? ? ? ? ? struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
>> +
>> + ? ? ? ? ? ? ? if (cpuid_topo->socket_id == cpu_topo->socket_id) {
>> + ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
>> + ? ? ? ? ? ? ? ? ? ? ? if (cpu != cpuid)
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpu,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &cpuid_topo->core_sibling);
>> +
>> + ? ? ? ? ? ? ? ? ? ? ? if (cpuid_topo->core_id == cpu_topo->core_id) {
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpuid,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &cpu_topo->thread_sibling);
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (cpu != cpuid)
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpu,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &cpuid_topo->thread_sibling);
>> + ? ? ? ? ? ? ? ? ? ? ? }
>> + ? ? ? ? ? ? ? }
>> + ? ? ? }
>> + ? ? ? smp_wmb();
>> +
>> + ? ? ? printk(KERN_INFO "cpu %u : thread %d cpu %d, socket %d, mpidr %x\n",
>> + ? ? ? ? ? ? ? cpuid, cpu_topology[cpuid].thread_id,
>> + ? ? ? ? ? ? ? cpu_topology[cpuid].core_id,
>> + ? ? ? ? ? ? ? cpu_topology[cpuid].socket_id, mpidr);
>> +
>> +}
>> +
>> +/*
>> + * init_cpu_topology is called at boot when only one cpu is running
>> + * which prevent simultaneous write access to cpu_topology array
>> + */
>> +void init_cpu_topology(void)
>> +{
>> + ? ? ? unsigned int cpu;
>> +
>> + ? ? ? /* init core mask */
>> + ? ? ? for_each_possible_cpu(cpu) {
>> + ? ? ? ? ? ? ? struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
>> +
>> + ? ? ? ? ? ? ? cpu_topo->thread_id = -1;
>> + ? ? ? ? ? ? ? cpu_topo->core_id = ?-1;
>> + ? ? ? ? ? ? ? cpu_topo->socket_id = -1;
>> + ? ? ? ? ? ? ? cpumask_clear(&cpu_topo->core_sibling);
>> + ? ? ? ? ? ? ? cpumask_clear(&cpu_topo->thread_sibling);
>> + ? ? ? }
>> + ? ? ? smp_wmb();
>> +}
>> --
>> 1.7.4.1
>>
>> _______________________________________________
>> linaro-dev mailing list
>> [email protected]
>> http://lists.linaro.org/mailman/listinfo/linaro-dev
>>
>

2011-06-16 12:30:54

by Vincent Guittot

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 16 June 2011 13:48, Amit Kucheria <[email protected]> wrote:
> On 11 Jun 16, Vincent Guittot wrote:
>> The affinity between Arm processors is defined in the MPIDR register.
>> We can identify which processors are in the same cluster,
>> and which ones have performance interdependency. The cpu topology
>> ?of an Arm platform can be set thanks to this register and this topology
>> is then used by sched_mc and sched_smt.
>
> Probably worth adding a note that sched_mc/sched_smt are disabled by default
> and need to be enabled by writing to their respective sysfs files.
>

ok

>> Signed-off-by: Vincent Guittot <[email protected]>
>> ---
>> ?arch/arm/Kconfig ? ? ? ? ? ? ? ?| ? 26 ++++++++
>> ?arch/arm/include/asm/topology.h | ? 33 ++++++++++
>> ?arch/arm/kernel/Makefile ? ? ? ?| ? ?1 +
>> ?arch/arm/kernel/smp.c ? ? ? ? ? | ? ?6 ++
>> ?arch/arm/kernel/topology.c ? ? ?| ?133 +++++++++++++++++++++++++++++++++++++++
>> ?5 files changed, 199 insertions(+), 0 deletions(-)
>> ?create mode 100644 arch/arm/kernel/topology.c
>>
>> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
>> index 9adc278..bacf9af 100644
>> --- a/arch/arm/Kconfig
>> +++ b/arch/arm/Kconfig
>> @@ -219,6 +219,24 @@ source "kernel/Kconfig.freezer"
>>
>> ?menu "System Type"
>>
>> +config SCHED_MC
>> + ? ? bool "Multi-core scheduler support"
>> + ? ? depends on SMP && ARM_CPU_TOPOLOGY
>> + ? ? default n
>> + ? ? help
>> + ? ? ? Multi-core scheduler support improves the CPU scheduler's decision
>> + ? ? ? making when dealing with multi-core CPU chips at a cost of slightly
>> + ? ? ? increased overhead in some places. If unsure say N here.
>> +
>> +config SCHED_SMT
>> + ? ? bool "SMT scheduler support"
>> + ? ? depends on SMP && ARM_CPU_TOPOLOGY
>> + ? ? default n
>> + ? ? help
>> + ? ? ? Improves the CPU scheduler's decision making when dealing with
>> + ? ? ? MultiThreading at a cost of slightly increased overhead in some
>> + ? ? ? places. If unsure say N here.
>> +
>> ?config MMU
>> ? ? ? bool "MMU-based Paged Memory Management Support"
>> ? ? ? default y
>> @@ -1062,6 +1080,14 @@ if !MMU
>> ?source "arch/arm/Kconfig-nommu"
>> ?endif
>>
>> +config ARM_CPU_TOPOLOGY
>> + ? ? bool "Support cpu topology definition"
>> + ? ? depends on SMP && CPU_V7
>> + ? ? help
>> + ? ? ? Support Arm cpu topology definition. The MPIDR register defines
>> + ? ? ? affinity between processors which is used to set the cpu
>> + ? ? ? topology of an Arm System.
>> +
>> ?config ARM_ERRATA_411920
>> ? ? ? bool "ARM errata: Invalidation of the Instruction Cache operation can fail"
>> ? ? ? depends on CPU_V6 || CPU_V6K
>> diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
>> index accbd7c..cb90d0a 100644
>> --- a/arch/arm/include/asm/topology.h
>> +++ b/arch/arm/include/asm/topology.h
>> @@ -1,6 +1,39 @@
>> ?#ifndef _ASM_ARM_TOPOLOGY_H
>> ?#define _ASM_ARM_TOPOLOGY_H
>>
>> +#ifdef CONFIG_ARM_CPU_TOPOLOGY
>> +
>> +#include <linux/cpumask.h>
>> +
>> +struct cputopo_arm {
>> + ? ? int thread_id;
>> + ? ? int core_id;
>> + ? ? int socket_id;
>> + ? ? cpumask_t thread_sibling;
>> + ? ? cpumask_t core_sibling;
>> +};
>> +
>> +extern struct cputopo_arm cpu_topology[NR_CPUS];
>> +
>> +#define topology_physical_package_id(cpu) ? ?(cpu_topology[cpu].socket_id)
>> +#define topology_core_id(cpu) ? ? ? ? ? ? ? ?(cpu_topology[cpu].core_id)
>> +#define topology_core_cpumask(cpu) ? (&(cpu_topology[cpu].core_sibling))
>> +#define topology_thread_cpumask(cpu) (&(cpu_topology[cpu].thread_sibling))
>> +
>> +#define mc_capable() (cpu_topology[0].socket_id != -1)
>> +#define smt_capable() ? ? ? ?(cpu_topology[0].thread_id != -1)
>> +
>> +void init_cpu_topology(void);
>> +void store_cpu_topology(unsigned int cpuid);
>> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu);
>> +
>> +#else
>> +
>> +#define init_cpu_topology() {};
>> +#define store_cpu_topology(cpuid) {};
>> +
>> +#endif
>> +
>> ?#include <asm-generic/topology.h>
>>
>> ?#endif /* _ASM_ARM_TOPOLOGY_H */
>> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
>> index a5b31af..816a481 100644
>> --- a/arch/arm/kernel/Makefile
>> +++ b/arch/arm/kernel/Makefile
>> @@ -61,6 +61,7 @@ obj-$(CONFIG_IWMMXT) ? ? ? ? ? ? ? ?+= iwmmxt.o
>> ?obj-$(CONFIG_CPU_HAS_PMU) ? ?+= pmu.o
>> ?obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
>> ?AFLAGS_iwmmxt.o ? ? ? ? ? ? ? ? ? ? ?:= -Wa,-mcpu=iwmmxt
>> +obj-$(CONFIG_ARM_CPU_TOPOLOGY) ?+= topology.o
>>
>> ?ifneq ($(CONFIG_ARCH_EBSA110),y)
>> ? ?obj-y ? ? ? ? ? ? ?+= io.o
>> diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
>> index 344e52b..3e8dc3b 100644
>> --- a/arch/arm/kernel/smp.c
>> +++ b/arch/arm/kernel/smp.c
>> @@ -31,6 +31,7 @@
>> ?#include <asm/cacheflush.h>
>> ?#include <asm/cpu.h>
>> ?#include <asm/cputype.h>
>> +#include <asm/topology.h>
>> ?#include <asm/mmu_context.h>
>> ?#include <asm/pgtable.h>
>> ?#include <asm/pgalloc.h>
>> @@ -268,6 +269,9 @@ static void __cpuinit smp_store_cpu_info(unsigned int cpuid)
>> ? ? ? struct cpuinfo_arm *cpu_info = &per_cpu(cpu_data, cpuid);
>>
>> ? ? ? cpu_info->loops_per_jiffy = loops_per_jiffy;
>> +
>> + ? ? store_cpu_topology(cpuid);
>> +
>> ?}
>>
>> ?/*
>> @@ -354,6 +358,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
>> ?{
>> ? ? ? unsigned int ncores = num_possible_cpus();
>>
>> + ? ? init_cpu_topology();
>> +
>> ? ? ? smp_store_cpu_info(smp_processor_id());
>>
>> ? ? ? /*
>> diff --git a/arch/arm/kernel/topology.c b/arch/arm/kernel/topology.c
>> new file mode 100644
>> index 0000000..d61723c
>> --- /dev/null
>> +++ b/arch/arm/kernel/topology.c
>> @@ -0,0 +1,133 @@
>> +/*
>> + * arch/arm/kernel/topology.c
>> + *
>> + * Copyright (C) 2011 [email protected]
>
> This should be
>
> Copyright (C) 2011 Linaro Limited.
>
> Written by: Vincent Guittot
>

ok

>> + *
>> + * based on arch/sh/kernel/topology.c
>> + *
>> + * This file is subject to the terms and conditions of the GNU General Public
>> + * License. ?See the file "COPYING" in the main directory of this archive
>> + * for more details.
>> + */
>> +
>> +#include <linux/cpu.h>
>> +#include <linux/cpumask.h>
>> +#include <linux/init.h>
>> +#include <linux/percpu.h>
>> +#include <linux/node.h>
>> +#include <linux/nodemask.h>
>> +#include <linux/sched.h>
>> +
>> +#include <asm/cacheflush.h>
>> +#include <asm/topology.h>
>> +
>> +#define hard_smp_mpidr() \
>> + ? ? ({ \
>> + ? ? ? ? ? ? unsigned int cpunum; \
>> + ? ? ? ? ? ? __asm__("mrc p15, 0, %0, c0, c0, 5" ? ? \
>> + ? ? ? ? ? ? ? ? ? ? : "=r" (cpunum)); \
>> + ? ? ? ? ? ? cpunum; \
>> + ? ? })
>> +
>> +struct cputopo_arm cpu_topology[NR_CPUS];
>> +
>> +const struct cpumask *cpu_coregroup_mask(unsigned int cpu)
>> +{
>> + ? ? return &(cpu_topology[cpu].core_sibling);
>> +}
>> +
>> +/*
>> + * store_cpu_topology is called at boot when only one cpu is running
>> + * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
>> + * which prevents simultaneous write access to cpu_topology array
>> + */
>> +void store_cpu_topology(unsigned int cpuid)
>> +{
>> + ? ? struct cputopo_arm *cpuid_topo = &(cpu_topology[cpuid]);
>> + ? ? unsigned int mpidr;
>> + ? ? unsigned int cpu;
>> +
>> + ? ? /* If the cpu topology has been already set, just return */
>> + ? ? if (cpuid_topo->core_id != -1)
>> + ? ? ? ? ? ? return;
>> +
>> + ? ? mpidr = hard_smp_mpidr();
>> +
>> + ? ? /* create cpu topology mapping */
>> + ? ? if (mpidr & (0x3 << 30)) {
>
> Use #defines for the MPIDR bit-fields
>
> #define MPIDR_U_BITMASK (0x3 << 30)
>
> BTW, Bit 31 seems to always be 1, do you really want that in the mask?
>

According to
http://infocenter.arm.com/help/topic/com.arm.doc.ddi0406b/index.html

we need to test both bit 31 and bit 24

>> + ? ? ? ? ? ? /*
>> + ? ? ? ? ? ? ?* This is a multiprocessor system
>> + ? ? ? ? ? ? ?* multiprocessor format & multiprocessor mode field are set
>> + ? ? ? ? ? ? ?*/
>> +
>> + ? ? ? ? ? ? if (mpidr & (0x1 << 24)) {
>
> According to
> http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0388f/CIHCHADB.html
>
> bit 24 is SBZ. Where is this redefined for MT?
>
>> + ? ? ? ? ? ? ? ? ? ? /* core performance interdependency */
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->thread_id = (mpidr & 0x3);
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->core_id = ?((mpidr >> 8) & 0xF);
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->socket_id = ((mpidr >> 16) & 0xFF);
>
> Define BITMASKs for these bits too.
>

ok

>> + ? ? ? ? ? ? } else {
>> + ? ? ? ? ? ? ? ? ? ? /* normal core interdependency */
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->thread_id = -1;
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->core_id = (mpidr & 0x3);
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->socket_id = ((mpidr >> 8) & 0xF);
>> + ? ? ? ? ? ? }
>> + ? ? } else {
>> + ? ? ? ? ? ? /*
>> + ? ? ? ? ? ? ?* This is an uniprocessor system
>> + ? ? ? ? ? ? ?* we are in multiprocessor format but uniprocessor system
>> + ? ? ? ? ? ? ?* or in the old uniprocessor format
>> + ? ? ? ? ? ? ?*/
>> +
>> + ? ? ? ? ? ? cpuid_topo->thread_id = -1;
>> + ? ? ? ? ? ? cpuid_topo->core_id = 0;
>> + ? ? ? ? ? ? cpuid_topo->socket_id = -1;
>> + ? ? }
>> +
>> + ? ? /* update core and thread sibling masks */
>> + ? ? for_each_possible_cpu(cpu) {
>> + ? ? ? ? ? ? struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
>> +
>> + ? ? ? ? ? ? if (cpuid_topo->socket_id == cpu_topo->socket_id) {
>> + ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
>> + ? ? ? ? ? ? ? ? ? ? if (cpu != cpuid)
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpu,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &cpuid_topo->core_sibling);
>> +
>> + ? ? ? ? ? ? ? ? ? ? if (cpuid_topo->core_id == cpu_topo->core_id) {
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpuid,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &cpu_topo->thread_sibling);
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (cpu != cpuid)
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? cpumask_set_cpu(cpu,
>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &cpuid_topo->thread_sibling);
>> + ? ? ? ? ? ? ? ? ? ? }
>> + ? ? ? ? ? ? }
>> + ? ? }
>> + ? ? smp_wmb();
>> +
>> + ? ? printk(KERN_INFO "cpu %u : thread %d cpu %d, socket %d, mpidr %x\n",
>> + ? ? ? ? ? ? cpuid, cpu_topology[cpuid].thread_id,
>> + ? ? ? ? ? ? cpu_topology[cpuid].core_id,
>> + ? ? ? ? ? ? cpu_topology[cpuid].socket_id, mpidr);
>> +
>> +}
>> +
>> +/*
>> + * init_cpu_topology is called at boot when only one cpu is running
>> + * which prevent simultaneous write access to cpu_topology array
>> + */
>> +void init_cpu_topology(void)
>> +{
>> + ? ? unsigned int cpu;
>> +
>> + ? ? /* init core mask */
>> + ? ? for_each_possible_cpu(cpu) {
>> + ? ? ? ? ? ? struct cputopo_arm *cpu_topo = &(cpu_topology[cpu]);
>> +
>> + ? ? ? ? ? ? cpu_topo->thread_id = -1;
>> + ? ? ? ? ? ? cpu_topo->core_id = ?-1;
>> + ? ? ? ? ? ? cpu_topo->socket_id = -1;
>> + ? ? ? ? ? ? cpumask_clear(&cpu_topo->core_sibling);
>> + ? ? ? ? ? ? cpumask_clear(&cpu_topo->thread_sibling);
>> + ? ? }
>> + ? ? smp_wmb();
>> +}
>> --
>> 1.7.4.1
>>
>

2011-06-16 13:49:03

by Christian Robottom Reis

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On Thu, Jun 16, 2011 at 10:49:13AM +0200, Vincent Guittot wrote:
> @@ -219,6 +219,24 @@ source "kernel/Kconfig.freezer"
>
> menu "System Type"
>
> +config SCHED_MC
> + bool "Multi-core scheduler support"
> + depends on SMP && ARM_CPU_TOPOLOGY
> + default n
> + help
> + Multi-core scheduler support improves the CPU scheduler's decision
> + making when dealing with multi-core CPU chips at a cost of slightly
> + increased overhead in some places. If unsure say N here.
> +
> +config SCHED_SMT
> + bool "SMT scheduler support"
> + depends on SMP && ARM_CPU_TOPOLOGY
> + default n
> + help
> + Improves the CPU scheduler's decision making when dealing with
> + MultiThreading at a cost of slightly increased overhead in some
> + places. If unsure say N here.
> +

Quick question: the patch doesn't actually seem to use the SCHED_MC and
SCHED_SMT config bits; is that actually correct?
--
Christian Robottom Reis | [+55] 16 9112 6430 | http://launchpad.net/~kiko
Linaro Engineering VP | [ +1] 612 216 4935 | http://async.com.br/~kiko

2011-06-16 13:48:52

by Vincent Guittot

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 16 June 2011 15:24, Christian Robottom Reis <[email protected]> wrote:
> On Thu, Jun 16, 2011 at 10:49:13AM +0200, Vincent Guittot wrote:
>> @@ -219,6 +219,24 @@ source "kernel/Kconfig.freezer"
>>
>> ?menu "System Type"
>>
>> +config SCHED_MC
>> + ? ? bool "Multi-core scheduler support"
>> + ? ? depends on SMP && ARM_CPU_TOPOLOGY
>> + ? ? default n
>> + ? ? help
>> + ? ? ? Multi-core scheduler support improves the CPU scheduler's decision
>> + ? ? ? making when dealing with multi-core CPU chips at a cost of slightly
>> + ? ? ? increased overhead in some places. If unsure say N here.
>> +
>> +config SCHED_SMT
>> + ? ? bool "SMT scheduler support"
>> + ? ? depends on SMP && ARM_CPU_TOPOLOGY
>> + ? ? default n
>> + ? ? help
>> + ? ? ? Improves the CPU scheduler's decision making when dealing with
>> + ? ? ? MultiThreading at a cost of slightly increased overhead in some
>> + ? ? ? places. If unsure say N here.
>> +
>
> Quick question: the patch doesn't actually seem to use the SCHED_MC and
> SCHED_SMT config bits; is that actually correct?

The default config of the patch is to disable sched_mc and sched_smt.
The 1st goal is to let each platform enable and test the feature.
According to feedback, we could then change the default state of the
configuration

> --
> Christian Robottom Reis ? | [+55] 16 9112 6430 | http://launchpad.net/~kiko
> Linaro Engineering VP ? ? | [ +1] 612 216 4935 | http://async.com.br/~kiko
>

2011-06-16 19:40:33

by Stephen Boyd

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 06/16/2011 01:49 AM, Vincent Guittot wrote:
> +config SCHED_MC
> + bool "Multi-core scheduler support"
> + depends on SMP && ARM_CPU_TOPOLOGY
> + default n
> + help
> + Multi-core scheduler support improves the CPU scheduler's decision
> + making when dealing with multi-core CPU chips at a cost of slightly
> + increased overhead in some places. If unsure say N here.
> +
> +config SCHED_SMT
> + bool "SMT scheduler support"
> + depends on SMP && ARM_CPU_TOPOLOGY
> + default n
> + help
> + Improves the CPU scheduler's decision making when dealing with
> + MultiThreading at a cost of slightly increased overhead in some
> + places. If unsure say N here.
> +

The default is already n so you can drop those two lines.

> + * This is a multiprocessor system
> + * multiprocessor format & multiprocessor mode field are set
> + */
> +
> + if (mpidr & (0x1 << 24)) {
> + /* core performance interdependency */
> + cpuid_topo->thread_id = (mpidr & 0x3);
> + cpuid_topo->core_id = ((mpidr >> 8) & 0xF);
> + cpuid_topo->socket_id = ((mpidr >> 16) & 0xFF);
> + } else {
> + /* normal core interdependency */
> + cpuid_topo->thread_id = -1;
> + cpuid_topo->core_id = (mpidr & 0x3);
> + cpuid_topo->socket_id = ((mpidr >> 8) & 0xF);
> + }
> +

The ARM ARM says these fields are IMPLEMENTATION DEFINED meaning that
different vendors may attribute different meaning to these fields if
they wish. Does that mean this should be a platform_*() function?

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

2011-06-16 21:13:55

by Russell King - ARM Linux

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On Thu, Jun 16, 2011 at 10:49:13AM +0200, Vincent Guittot wrote:
> @@ -219,6 +219,24 @@ source "kernel/Kconfig.freezer"
>
> menu "System Type"
>
> +config SCHED_MC
> + bool "Multi-core scheduler support"
> + depends on SMP && ARM_CPU_TOPOLOGY
> + default n
> + help
> + Multi-core scheduler support improves the CPU scheduler's decision
> + making when dealing with multi-core CPU chips at a cost of slightly
> + increased overhead in some places. If unsure say N here.
> +
> +config SCHED_SMT
> + bool "SMT scheduler support"
> + depends on SMP && ARM_CPU_TOPOLOGY
> + default n
> + help
> + Improves the CPU scheduler's decision making when dealing with
> + MultiThreading at a cost of slightly increased overhead in some
> + places. If unsure say N here.

Why place these in the "system type" menu? Wouldn't it be better to
place them along side ARM_CPU_TOPOLOGY, and place that along side
the SMP option too?

> +
> config MMU
> bool "MMU-based Paged Memory Management Support"
> default y
> @@ -1062,6 +1080,14 @@ if !MMU
> source "arch/arm/Kconfig-nommu"
> endif
>
> +config ARM_CPU_TOPOLOGY
> + bool "Support cpu topology definition"
> + depends on SMP && CPU_V7
> + help
> + Support Arm cpu topology definition. The MPIDR register defines
> + affinity between processors which is used to set the cpu
> + topology of an Arm System.

Is there a reason you'd want to disable this?

Please also note that it's "ARM" not "Arm".

> diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
> index accbd7c..cb90d0a 100644
> --- a/arch/arm/include/asm/topology.h
> +++ b/arch/arm/include/asm/topology.h
> @@ -1,6 +1,39 @@
> #ifndef _ASM_ARM_TOPOLOGY_H
> #define _ASM_ARM_TOPOLOGY_H
>
> +#ifdef CONFIG_ARM_CPU_TOPOLOGY
> +
> +#include <linux/cpumask.h>
> +
> +struct cputopo_arm {
> + int thread_id;
> + int core_id;
> + int socket_id;
> + cpumask_t thread_sibling;
> + cpumask_t core_sibling;
> +};
> +
> +extern struct cputopo_arm cpu_topology[NR_CPUS];
> +
> +#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
> +#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
> +#define topology_core_cpumask(cpu) (&(cpu_topology[cpu].core_sibling))
> +#define topology_thread_cpumask(cpu) (&(cpu_topology[cpu].thread_sibling))

The thing which naggs me about this is that its a static array, and we
know from x86 that static arrays of per-cpu data have various issues
(cache line bouncing, as well as limitations when we end up with large
numbers of CPUs.)

Lastly, x86 seems to do this:

#define arch_provides_topology_pointers yes

and the only effect I can find of that define is in drivers/base/topology.c:

#ifdef arch_provides_topology_pointers
...
unsigned int cpu = dev->id; \
return show_cpumap(0, topology_##name(cpu), buf); \
...
#else
...
return show_cpumap(0, topology_##name(dev->id), buf); \
...
#endif

dev->id is type 'u32' which devolves to 'unsigned int' on all supported
arches. So it looks to me like this arch_provides_topology_pointers
define is completely pointless and we just have useless obfuscation for
the hell of it.

That's not a criticism of your patch, it's pointing out a difference
between x86 and our implementation.

> +#include <linux/cpu.h>
> +#include <linux/cpumask.h>
> +#include <linux/init.h>
> +#include <linux/percpu.h>
> +#include <linux/node.h>
> +#include <linux/nodemask.h>
> +#include <linux/sched.h>
> +
> +#include <asm/cacheflush.h>
> +#include <asm/topology.h>
> +
> +#define hard_smp_mpidr() \
> + ({ \
> + unsigned int cpunum; \
> + __asm__("mrc p15, 0, %0, c0, c0, 5" \
> + : "=r" (cpunum)); \
> + cpunum; \
> + })

Please add a definition for CPUID_MPIDR to arch/arm/include/asm/cputype.h
and a read_cpuid_mpidr() function, and use that instead.

2011-06-17 06:54:16

by Vincent Guittot

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 16 June 2011 21:40, Stephen Boyd <[email protected]> wrote:
> On 06/16/2011 01:49 AM, Vincent Guittot wrote:
>> +config SCHED_MC
>> + ? ? bool "Multi-core scheduler support"
>> + ? ? depends on SMP && ARM_CPU_TOPOLOGY
>> + ? ? default n
>> + ? ? help
>> + ? ? ? Multi-core scheduler support improves the CPU scheduler's decision
>> + ? ? ? making when dealing with multi-core CPU chips at a cost of slightly
>> + ? ? ? increased overhead in some places. If unsure say N here.
>> +
>> +config SCHED_SMT
>> + ? ? bool "SMT scheduler support"
>> + ? ? depends on SMP && ARM_CPU_TOPOLOGY
>> + ? ? default n
>> + ? ? help
>> + ? ? ? Improves the CPU scheduler's decision making when dealing with
>> + ? ? ? MultiThreading at a cost of slightly increased overhead in some
>> + ? ? ? places. If unsure say N here.
>> +
>
> The default is already n so you can drop those two lines.
>

ok

>> + ? ? ? ? ? ? ?* This is a multiprocessor system
>> + ? ? ? ? ? ? ?* multiprocessor format & multiprocessor mode field are set
>> + ? ? ? ? ? ? ?*/
>> +
>> + ? ? ? ? ? ? if (mpidr & (0x1 << 24)) {
>> + ? ? ? ? ? ? ? ? ? ? /* core performance interdependency */
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->thread_id = (mpidr & 0x3);
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->core_id = ?((mpidr >> 8) & 0xF);
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->socket_id = ((mpidr >> 16) & 0xFF);
>> + ? ? ? ? ? ? } else {
>> + ? ? ? ? ? ? ? ? ? ? /* normal core interdependency */
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->thread_id = -1;
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->core_id = (mpidr & 0x3);
>> + ? ? ? ? ? ? ? ? ? ? cpuid_topo->socket_id = ((mpidr >> 8) & 0xF);
>> + ? ? ? ? ? ? }
>> +
>
> The ARM ARM says these fields are IMPLEMENTATION DEFINED meaning that
> different vendors may attribute different meaning to these fields if
> they wish. Does that mean this should be a platform_*() function?
>

The ARM ARM also provides a recommended use of the fields of this
register and the TRM of each Cortex adds some details. On the cortex
A9, each platform can only set the value of the Cluster ID with the
CLUSTERID pins. I have tried to consolidate the value of MPIDR across
several platforms and they all match with the description.

Have you got an example of a MPIDR register which doesn't match with
the implementation ?

> --
> Sent by an employee of the Qualcomm Innovation Center, Inc.
> The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
>
>

2011-06-17 07:43:32

by Vincent Guittot

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 16 June 2011 23:13, Russell King - ARM Linux <[email protected]> wrote:
> On Thu, Jun 16, 2011 at 10:49:13AM +0200, Vincent Guittot wrote:
>> @@ -219,6 +219,24 @@ source "kernel/Kconfig.freezer"
>>
>> ?menu "System Type"
>>
>> +config SCHED_MC
>> + ? ? bool "Multi-core scheduler support"
>> + ? ? depends on SMP && ARM_CPU_TOPOLOGY
>> + ? ? default n
>> + ? ? help
>> + ? ? ? Multi-core scheduler support improves the CPU scheduler's decision
>> + ? ? ? making when dealing with multi-core CPU chips at a cost of slightly
>> + ? ? ? increased overhead in some places. If unsure say N here.
>> +
>> +config SCHED_SMT
>> + ? ? bool "SMT scheduler support"
>> + ? ? depends on SMP && ARM_CPU_TOPOLOGY
>> + ? ? default n
>> + ? ? help
>> + ? ? ? Improves the CPU scheduler's decision making when dealing with
>> + ? ? ? MultiThreading at a cost of slightly increased overhead in some
>> + ? ? ? places. If unsure say N here.
>
> Why place these in the "system type" menu? ?Wouldn't it be better to
> place them along side ARM_CPU_TOPOLOGY, and place that along side
> the SMP option too?
>

yes, it's a better place

>> +
>> ?config MMU
>> ? ? ? bool "MMU-based Paged Memory Management Support"
>> ? ? ? default y
>> @@ -1062,6 +1080,14 @@ if !MMU
>> ?source "arch/arm/Kconfig-nommu"
>> ?endif
>>
>> +config ARM_CPU_TOPOLOGY
>> + ? ? bool "Support cpu topology definition"
>> + ? ? depends on SMP && CPU_V7
>> + ? ? help
>> + ? ? ? Support Arm cpu topology definition. The MPIDR register defines
>> + ? ? ? affinity between processors which is used to set the cpu
>> + ? ? ? topology of an Arm System.
>
> Is there a reason you'd want to disable this?
>

In fact, I only want to disable sched_mc and sched_smt. I'm going to
add default y for ARM_CPU_TOPOLOGY

> Please also note that it's "ARM" not "Arm".

OK

>
>> diff --git a/arch/arm/include/asm/topology.h b/arch/arm/include/asm/topology.h
>> index accbd7c..cb90d0a 100644
>> --- a/arch/arm/include/asm/topology.h
>> +++ b/arch/arm/include/asm/topology.h
>> @@ -1,6 +1,39 @@
>> ?#ifndef _ASM_ARM_TOPOLOGY_H
>> ?#define _ASM_ARM_TOPOLOGY_H
>>
>> +#ifdef CONFIG_ARM_CPU_TOPOLOGY
>> +
>> +#include <linux/cpumask.h>
>> +
>> +struct cputopo_arm {
>> + ? ? int thread_id;
>> + ? ? int core_id;
>> + ? ? int socket_id;
>> + ? ? cpumask_t thread_sibling;
>> + ? ? cpumask_t core_sibling;
>> +};
>> +
>> +extern struct cputopo_arm cpu_topology[NR_CPUS];
>> +
>> +#define topology_physical_package_id(cpu) ? ?(cpu_topology[cpu].socket_id)
>> +#define topology_core_id(cpu) ? ? ? ? ? ? ? ?(cpu_topology[cpu].core_id)
>> +#define topology_core_cpumask(cpu) ? (&(cpu_topology[cpu].core_sibling))
>> +#define topology_thread_cpumask(cpu) (&(cpu_topology[cpu].thread_sibling))
>
> The thing which naggs me about this is that its a static array, and we
> know from x86 that static arrays of per-cpu data have various issues
> (cache line bouncing, as well as limitations when we end up with large
> numbers of CPUs.)
>

The array is updated sequentially by each processor during boot. Then,
it should be used by one cpu when building the sched_domain and when
calling the topology sysfs entry.
We should not have so many cases where several cpu are accessing
simultaneously the cells of the array.

> Lastly, x86 seems to do this:
>
> #define arch_provides_topology_pointers ? ? ? ? yes
>
> and the only effect I can find of that define is in drivers/base/topology.c:
>
> #ifdef arch_provides_topology_pointers
> ...
> ? ? ? ?unsigned int cpu = dev->id; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
> ? ? ? ?return show_cpumap(0, topology_##name(cpu), buf); ? ? ? ? ? ? ? \
> ...
> #else
> ...
> ? ? ? ?return show_cpumap(0, topology_##name(dev->id), buf); ? ? ? ? ? \
> ...
> #endif
>
> dev->id is type 'u32' which devolves to 'unsigned int' on all supported
> arches. ?So it looks to me like this arch_provides_topology_pointers
> define is completely pointless and we just have useless obfuscation for
> the hell of it.
>
> That's not a criticism of your patch, it's pointing out a difference
> between x86 and our implementation.
>

I haven't set arch_provides_topology_pointers because I can't find a
difference between setting it or not

>> +#include <linux/cpu.h>
>> +#include <linux/cpumask.h>
>> +#include <linux/init.h>
>> +#include <linux/percpu.h>
>> +#include <linux/node.h>
>> +#include <linux/nodemask.h>
>> +#include <linux/sched.h>
>> +
>> +#include <asm/cacheflush.h>
>> +#include <asm/topology.h>
>> +
>> +#define hard_smp_mpidr() \
>> + ? ? ({ \
>> + ? ? ? ? ? ? unsigned int cpunum; \
>> + ? ? ? ? ? ? __asm__("mrc p15, 0, %0, c0, c0, 5" ? ? \
>> + ? ? ? ? ? ? ? ? ? ? : "=r" (cpunum)); \
>> + ? ? ? ? ? ? cpunum; \
>> + ? ? })
>
> Please add a definition for CPUID_MPIDR to arch/arm/include/asm/cputype.h
> and a read_cpuid_mpidr() function, and use that instead.
>

ok
I can directly use read_cpuid with a definition for CPUID_MPIDR

2011-06-21 20:36:18

by Stephen Boyd

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 06/16/2011 11:54 PM, Vincent Guittot wrote:
> On 16 June 2011 21:40, Stephen Boyd <[email protected]> wrote:
>> The ARM ARM says these fields are IMPLEMENTATION DEFINED meaning that
>> different vendors may attribute different meaning to these fields if
>> they wish. Does that mean this should be a platform_*() function?
>>
> The ARM ARM also provides a recommended use of the fields of this
> register and the TRM of each Cortex adds some details. On the cortex
> A9, each platform can only set the value of the Cluster ID with the
> CLUSTERID pins. I have tried to consolidate the value of MPIDR across
> several platforms and they all match with the description.
>
> Have you got an example of a MPIDR register which doesn't match with
> the implementation ?

Not that I know of. I'm more concerned with how the ARM ARM has two
recommended usages for these fields depending on virtualization or not.
I suppose we can handle that issue when it arises (or does your
implementation already handle that?)

--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

2011-06-22 09:16:32

by Catalin Marinas

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On Tue, Jun 21, 2011 at 01:36:15PM -0700, Stephen Boyd wrote:
> On 06/16/2011 11:54 PM, Vincent Guittot wrote:
> > On 16 June 2011 21:40, Stephen Boyd <[email protected]> wrote:
> >> The ARM ARM says these fields are IMPLEMENTATION DEFINED meaning that
> >> different vendors may attribute different meaning to these fields if
> >> they wish. Does that mean this should be a platform_*() function?
> >>
> > The ARM ARM also provides a recommended use of the fields of this
> > register and the TRM of each Cortex adds some details. On the cortex
> > A9, each platform can only set the value of the Cluster ID with the
> > CLUSTERID pins. I have tried to consolidate the value of MPIDR across
> > several platforms and they all match with the description.
> >
> > Have you got an example of a MPIDR register which doesn't match with
> > the implementation ?
>
> Not that I know of. I'm more concerned with how the ARM ARM has two
> recommended usages for these fields depending on virtualization or not.
> I suppose we can handle that issue when it arises (or does your
> implementation already handle that?)

According to the ARM ARM:

MPIDR provides a mechanism with up to three levels of affinity
information, but the meaning of those levels of affinity is
entirely IMPLEMENTATION DEFINED.

So we can't really tell the meaning of the affinity bits. There are two
recommended ways indeed (with or without virtualisation) which are not
that different with regards to the topology (just introducing another
level for virtual CPUs).

But I think a more general solution would be for the CPU topology to be
provided via the FDT.

--
Catalin

2011-06-22 10:19:09

by Amit Kucheria

[permalink] [raw]
Subject: Re: [RFC] Add Arm cpu topology definition

On 11 Jun 22, Catalin Marinas wrote:
> On Tue, Jun 21, 2011 at 01:36:15PM -0700, Stephen Boyd wrote:
> > On 06/16/2011 11:54 PM, Vincent Guittot wrote:
> > > On 16 June 2011 21:40, Stephen Boyd <[email protected]> wrote:
> > >> The ARM ARM says these fields are IMPLEMENTATION DEFINED meaning that
> > >> different vendors may attribute different meaning to these fields if
> > >> they wish. Does that mean this should be a platform_*() function?
> > >>
> > > The ARM ARM also provides a recommended use of the fields of this
> > > register and the TRM of each Cortex adds some details. On the cortex
> > > A9, each platform can only set the value of the Cluster ID with the
> > > CLUSTERID pins. I have tried to consolidate the value of MPIDR across
> > > several platforms and they all match with the description.
> > >
> > > Have you got an example of a MPIDR register which doesn't match with
> > > the implementation ?
> >
> > Not that I know of. I'm more concerned with how the ARM ARM has two
> > recommended usages for these fields depending on virtualization or not.
> > I suppose we can handle that issue when it arises (or does your
> > implementation already handle that?)
>
> According to the ARM ARM:
>
> MPIDR provides a mechanism with up to three levels of affinity
> information, but the meaning of those levels of affinity is
> entirely IMPLEMENTATION DEFINED.
>
> So we can't really tell the meaning of the affinity bits. There are two
> recommended ways indeed (with or without virtualisation) which are not
> that different with regards to the topology (just introducing another
> level for virtual CPUs).
>
> But I think a more general solution would be for the CPU topology to be
> provided via the FDT.

Agreed. That will be the next step.

We decided on doing it this way to allow non-DT-enabled platforms to be able
to use the feature and to allow DT-enabled platforms to settle down in the
mean time.