Commit c5e22fef authored by Jonathan Cameron's avatar Jonathan Cameron Committed by Peter Zijlstra
Browse files

topology: Represent clusters of CPUs within a die

Both ACPI and DT provide the ability to describe additional layers of
topology between that of individual cores and higher level constructs
such as the level at which the last level cache is shared.
In ACPI this can be represented in PPTT as a Processor Hierarchy
Node Structure [1] that is the parent of the CPU cores and in turn
has a parent Processor Hierarchy Nodes Structure representing
a higher level of topology.

For example Kunpeng 920 has 6 or 8 clusters in each NUMA node, and each
cluster has 4 cpus. All clusters share L3 cache data, but each cluster
has local L3 tag. On the other hand, each clusters will share some
internal system bus.

+-----------------------------------+                          +---------+
|  +------+    +------+             +--------------------------+         |
|  | CPU0 |    | cpu1 |             |    +-----------+         |         |
|  +------+    +------+             |    |           |         |         |
|                                   +----+    L3     |         |         |
|  +------+    +------+   cluster   |    |    tag    |         |         |
|  | CPU2 |    | CPU3 |             |    |           |         |         |
|  +------+    +------+             |    +-----------+         |         |
|                                   |                          |         |
+-----------------------------------+                          |         |
+-----------------------------------+                          |         |
|  +------+    +------+             +--------------------------+         |
|  |      |    |      |             |    +-----------+         |         |
|  +------+    +------+             |    |           |         |         |
|                                   |    |    L3     |         |         |
|  +------+    +------+             +----+    tag    |         |         |
|  |      |    |      |             |    |           |         |         |
|  +------+    +------+             |    +-----------+         |         |
|                                   |                          |         |
+-----------------------------------+                          |   L3    |
                                                               |   data  |
+-----------------------------------+                          |         |
|  +------+    +------+             |    +-----------+         |         |
|  |      |    |      |             |    |           |         |         |
|  +------+    +------+             +----+    L3     |         |         |
|                                   |    |    tag    |         |         |
|  +------+    +------+             |    |           |         |         |
|  |      |    |      |             |    +-----------+         |         |
|  +------+    +------+             +--------------------------+         |
+-----------------------------------|                          |         |
+-----------------------------------|                          |         |
|  +------+    +------+             +--------------------------+         |
|  |      |    |      |             |    +-----------+         |         |
|  +------+    +------+             |    |           |         |         |
|                                   +----+    L3     |         |         |
|  +------+    +------+             |    |    tag    |         |         |
|  |      |    |      |             |    |           |         |         |
|  +------+    +------+             |    +-----------+         |         |
|                                   |                          |         |
+-----------------------------------+                          |         |
+-----------------------------------+                          |         |
|  +------+    +------+             +--------------------------+         |
|  |      |    |      |             |   +-----------+          |         |
|  +------+    +------+             |   |           |          |         |
|                                   |   |    L3     |          |         |
|  +------+    +------+             +---+    tag    |          |         |
|  |      |    |      |             |   |           |          |         |
|  +------+    +------+             |   +-----------+          |         |
|                                   |                          |         |
+-----------------------------------+                          |         |
+-----------------------------------+                          |         |
|  +------+    +------+             +--------------------------+         |
|  |      |    |      |             |  +-----------+           |         |
|  +------+    +------+             |  |           |           |         |
|                                   |  |    L3     |           |         |
|  +------+    +------+             +--+    tag    |           |         |
|  |      |    |      |             |  |           |           |         |
|  +------+    +------+             |  +-----------+           |         |
|                                   |                          +---------+
+-----------------------------------+

That means spreading tasks among clusters will bring more bandwidth
while packing tasks within one cluster will lead to smaller cache
synchronization latency. So both kernel and userspace will have
a chance to leverage this topology to deploy tasks accordingly to
achieve either smaller cache latency within one cluster or an even
distribution of load among clusters for higher throughput.

This patch exposes cluster topology to both kernel and userspace.
Libraried like hwloc will know cluster by cluster_cpus and related
sysfs attributes. PoC of HWLOC support at [2].

Note this patch only handle the ACPI case.

Special consideration is needed for SMT processors, where it is
necessary to move 2 levels up the hierarchy from the leaf nodes
(thus skipping the processor core level).

Note that arm64 / ACPI does not provide any means of identifying
a die level in the topology but that may be unrelate to the cluster
level.

[1] ACPI Specification 6.3 - section 5.2.29.1 processor hierarchy node
    structure (Type 0)
[2] https://github.com/hisilicon/hwloc/tree/linux-cluster



Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: default avatarTian Tao <tiantao6@hisilicon.com>
Signed-off-by: default avatarBarry Song <song.bao.hua@hisilicon.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210924085104.44806-2-21cnbao@gmail.com
parent 37b47298
Loading
Loading
Loading
Loading
+15 −0
Original line number Original line Diff line number Diff line
@@ -42,6 +42,12 @@ Description: the CPU core ID of cpuX. Typically it is the hardware platform's
                architecture and platform dependent.
                architecture and platform dependent.
Values:         integer
Values:         integer


What:           /sys/devices/system/cpu/cpuX/topology/cluster_id
Description:    the cluster ID of cpuX.  Typically it is the hardware platform's
                identifier (rather than the kernel's). The actual value is
                architecture and platform dependent.
Values:         integer

What:           /sys/devices/system/cpu/cpuX/topology/book_id
What:           /sys/devices/system/cpu/cpuX/topology/book_id
Description:    the book ID of cpuX. Typically it is the hardware platform's
Description:    the book ID of cpuX. Typically it is the hardware platform's
                identifier (rather than the kernel's). The actual value is
                identifier (rather than the kernel's). The actual value is
@@ -85,6 +91,15 @@ Description: human-readable list of CPUs within the same die.
                The format is like 0-3, 8-11, 14,17.
                The format is like 0-3, 8-11, 14,17.
Values:         decimal list.
Values:         decimal list.


What:           /sys/devices/system/cpu/cpuX/topology/cluster_cpus
Description:    internal kernel map of CPUs within the same cluster.
Values:         hexadecimal bitmask.

What:           /sys/devices/system/cpu/cpuX/topology/cluster_cpus_list
Description:    human-readable list of CPUs within the same cluster.
                The format is like 0-3, 8-11, 14,17.
Values:         decimal list.

What:           /sys/devices/system/cpu/cpuX/topology/book_siblings
What:           /sys/devices/system/cpu/cpuX/topology/book_siblings
Description:    internal kernel map of cpuX's hardware threads within the same
Description:    internal kernel map of cpuX's hardware threads within the same
                book_id. it's only used on s390.
                book_id. it's only used on s390.
+8 −4
Original line number Original line Diff line number Diff line
@@ -19,11 +19,13 @@ these macros in include/asm-XXX/topology.h::


	#define topology_physical_package_id(cpu)
	#define topology_physical_package_id(cpu)
	#define topology_die_id(cpu)
	#define topology_die_id(cpu)
	#define topology_cluster_id(cpu)
	#define topology_core_id(cpu)
	#define topology_core_id(cpu)
	#define topology_book_id(cpu)
	#define topology_book_id(cpu)
	#define topology_drawer_id(cpu)
	#define topology_drawer_id(cpu)
	#define topology_sibling_cpumask(cpu)
	#define topology_sibling_cpumask(cpu)
	#define topology_core_cpumask(cpu)
	#define topology_core_cpumask(cpu)
	#define topology_cluster_cpumask(cpu)
	#define topology_die_cpumask(cpu)
	#define topology_die_cpumask(cpu)
	#define topology_book_cpumask(cpu)
	#define topology_book_cpumask(cpu)
	#define topology_drawer_cpumask(cpu)
	#define topology_drawer_cpumask(cpu)
@@ -39,10 +41,12 @@ not defined by include/asm-XXX/topology.h:


1) topology_physical_package_id: -1
1) topology_physical_package_id: -1
2) topology_die_id: -1
2) topology_die_id: -1
3) topology_core_id: 0
3) topology_cluster_id: -1
4) topology_sibling_cpumask: just the given CPU
4) topology_core_id: 0
5) topology_core_cpumask: just the given CPU
5) topology_sibling_cpumask: just the given CPU
6) topology_die_cpumask: just the given CPU
6) topology_core_cpumask: just the given CPU
7) topology_cluster_cpumask: just the given CPU
8) topology_die_cpumask: just the given CPU


For architectures that don't support books (CONFIG_SCHED_BOOK) there are no
For architectures that don't support books (CONFIG_SCHED_BOOK) there are no
default definitions for topology_book_id() and topology_book_cpumask().
default definitions for topology_book_id() and topology_book_cpumask().
+2 −0
Original line number Original line Diff line number Diff line
@@ -103,6 +103,8 @@ int __init parse_acpi_topology(void)
			cpu_topology[cpu].thread_id  = -1;
			cpu_topology[cpu].thread_id  = -1;
			cpu_topology[cpu].core_id    = topology_id;
			cpu_topology[cpu].core_id    = topology_id;
		}
		}
		topology_id = find_acpi_cpu_topology_cluster(cpu);
		cpu_topology[cpu].cluster_id = topology_id;
		topology_id = find_acpi_cpu_topology_package(cpu);
		topology_id = find_acpi_cpu_topology_package(cpu);
		cpu_topology[cpu].package_id = topology_id;
		cpu_topology[cpu].package_id = topology_id;


+67 −0
Original line number Original line Diff line number Diff line
@@ -746,6 +746,73 @@ int find_acpi_cpu_topology_package(unsigned int cpu)
					  ACPI_PPTT_PHYSICAL_PACKAGE);
					  ACPI_PPTT_PHYSICAL_PACKAGE);
}
}


/**
 * find_acpi_cpu_topology_cluster() - Determine a unique CPU cluster value
 * @cpu: Kernel logical CPU number
 *
 * Determine a topology unique cluster ID for the given CPU/thread.
 * This ID can then be used to group peers, which will have matching ids.
 *
 * The cluster, if present is the level of topology above CPUs. In a
 * multi-thread CPU, it will be the level above the CPU, not the thread.
 * It may not exist in single CPU systems. In simple multi-CPU systems,
 * it may be equal to the package topology level.
 *
 * Return: -ENOENT if the PPTT doesn't exist, the CPU cannot be found
 * or there is no toplogy level above the CPU..
 * Otherwise returns a value which represents the package for this CPU.
 */

int find_acpi_cpu_topology_cluster(unsigned int cpu)
{
	struct acpi_table_header *table;
	acpi_status status;
	struct acpi_pptt_processor *cpu_node, *cluster_node;
	u32 acpi_cpu_id;
	int retval;
	int is_thread;

	status = acpi_get_table(ACPI_SIG_PPTT, 0, &table);
	if (ACPI_FAILURE(status)) {
		acpi_pptt_warn_missing();
		return -ENOENT;
	}

	acpi_cpu_id = get_acpi_id_for_cpu(cpu);
	cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
	if (cpu_node == NULL || !cpu_node->parent) {
		retval = -ENOENT;
		goto put_table;
	}

	is_thread = cpu_node->flags & ACPI_PPTT_ACPI_PROCESSOR_IS_THREAD;
	cluster_node = fetch_pptt_node(table, cpu_node->parent);
	if (cluster_node == NULL) {
		retval = -ENOENT;
		goto put_table;
	}
	if (is_thread) {
		if (!cluster_node->parent) {
			retval = -ENOENT;
			goto put_table;
		}
		cluster_node = fetch_pptt_node(table, cluster_node->parent);
		if (cluster_node == NULL) {
			retval = -ENOENT;
			goto put_table;
		}
	}
	if (cluster_node->flags & ACPI_PPTT_ACPI_PROCESSOR_ID_VALID)
		retval = cluster_node->acpi_processor_id;
	else
		retval = ACPI_PTR_DIFF(cluster_node, table);

put_table:
	acpi_put_table(table);

	return retval;
}

/**
/**
 * find_acpi_cpu_topology_hetero_id() - Get a core architecture tag
 * find_acpi_cpu_topology_hetero_id() - Get a core architecture tag
 * @cpu: Kernel logical CPU number
 * @cpu: Kernel logical CPU number
+15 −0
Original line number Original line Diff line number Diff line
@@ -600,6 +600,11 @@ const struct cpumask *cpu_coregroup_mask(int cpu)
	return core_mask;
	return core_mask;
}
}


const struct cpumask *cpu_clustergroup_mask(int cpu)
{
	return &cpu_topology[cpu].cluster_sibling;
}

void update_siblings_masks(unsigned int cpuid)
void update_siblings_masks(unsigned int cpuid)
{
{
	struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
	struct cpu_topology *cpu_topo, *cpuid_topo = &cpu_topology[cpuid];
@@ -617,6 +622,12 @@ void update_siblings_masks(unsigned int cpuid)
		if (cpuid_topo->package_id != cpu_topo->package_id)
		if (cpuid_topo->package_id != cpu_topo->package_id)
			continue;
			continue;


		if (cpuid_topo->cluster_id == cpu_topo->cluster_id &&
		    cpuid_topo->cluster_id != -1) {
			cpumask_set_cpu(cpu, &cpuid_topo->cluster_sibling);
			cpumask_set_cpu(cpuid, &cpu_topo->cluster_sibling);
		}

		cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
		cpumask_set_cpu(cpuid, &cpu_topo->core_sibling);
		cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);
		cpumask_set_cpu(cpu, &cpuid_topo->core_sibling);


@@ -635,6 +646,9 @@ static void clear_cpu_topology(int cpu)
	cpumask_clear(&cpu_topo->llc_sibling);
	cpumask_clear(&cpu_topo->llc_sibling);
	cpumask_set_cpu(cpu, &cpu_topo->llc_sibling);
	cpumask_set_cpu(cpu, &cpu_topo->llc_sibling);


	cpumask_clear(&cpu_topo->cluster_sibling);
	cpumask_set_cpu(cpu, &cpu_topo->cluster_sibling);

	cpumask_clear(&cpu_topo->core_sibling);
	cpumask_clear(&cpu_topo->core_sibling);
	cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
	cpumask_set_cpu(cpu, &cpu_topo->core_sibling);
	cpumask_clear(&cpu_topo->thread_sibling);
	cpumask_clear(&cpu_topo->thread_sibling);
@@ -650,6 +664,7 @@ void __init reset_cpu_topology(void)


		cpu_topo->thread_id = -1;
		cpu_topo->thread_id = -1;
		cpu_topo->core_id = -1;
		cpu_topo->core_id = -1;
		cpu_topo->cluster_id = -1;
		cpu_topo->package_id = -1;
		cpu_topo->package_id = -1;
		cpu_topo->llc_id = -1;
		cpu_topo->llc_id = -1;


Loading