From: Zhao Liu <zhao1.liu@intel.com>
To: "Daniel P . Berrangé" <berrange@redhat.com>,
"Eduardo Habkost" <eduardo@habkost.net>,
"Marcel Apfelbaum" <marcel.apfelbaum@gmail.com>,
"Philippe Mathieu-Daudé" <philmd@linaro.org>,
"Yanan Wang" <wangyanan55@huawei.com>,
"Michael S . Tsirkin" <mst@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Richard Henderson" <richard.henderson@linaro.org>,
"Eric Blake" <eblake@redhat.com>,
"Markus Armbruster" <armbru@redhat.com>,
"Marcelo Tosatti" <mtosatti@redhat.com>,
"Alex Bennée" <alex.bennee@linaro.org>,
"Peter Maydell" <peter.maydell@linaro.org>,
"Jonathan Cameron" <Jonathan.Cameron@huawei.com>,
"Sia Jee Heng" <jeeheng.sia@starfivetech.com>
Cc: qemu-devel@nongnu.org, kvm@vger.kernel.org,
qemu-riscv@nongnu.org, qemu-arm@nongnu.org,
Zhenyu Wang <zhenyu.z.wang@intel.com>,
Dapeng Mi <dapeng1.mi@linux.intel.com>,
Yongwei Ma <yongwei.ma@intel.com>, Zhao Liu <zhao1.liu@intel.com>
Subject: [RFC v2 1/7] hw/core: Make CPU topology enumeration arch-agnostic
Date: Thu, 30 May 2024 18:15:33 +0800 [thread overview]
Message-ID: <20240530101539.768484-2-zhao1.liu@intel.com> (raw)
In-Reply-To: <20240530101539.768484-1-zhao1.liu@intel.com>
Cache topology needs to be defined based on CPU topology levels. Thus,
define CPU topology enumeration in qapi/machine.json to make it generic
for all architectures.
To match the general topology naming style, rename CPU_TOPO_LEVEL_SMT
and CPU_TOPO_LEVEL_PACKAGE to CPU_TOPO_LEVEL_THREAD and
CPU_TOPO_LEVEL_SOCKET.
Also, enumerate additional topology levels for non-i386 arches, and add
helpers for topology enumeration and string conversion.
Signed-off-by: Zhao Liu <zhao1.liu@intel.com>
---
Changes since RFC v1:
* Use QAPI to enumerate CPU topology levels.
* Drop string_to_cpu_topo() since QAPI will help to parse the topo
levels.
---
MAINTAINERS | 2 ++
hw/core/cpu-topology.c | 36 ++++++++++++++++++++++++++++++
hw/core/meson.build | 1 +
include/hw/core/cpu-topology.h | 20 +++++++++++++++++
include/hw/i386/topology.h | 18 +--------------
qapi/machine.json | 40 ++++++++++++++++++++++++++++++++++
target/i386/cpu.c | 30 ++++++++++++-------------
target/i386/cpu.h | 4 ++--
8 files changed, 117 insertions(+), 34 deletions(-)
create mode 100644 hw/core/cpu-topology.c
create mode 100644 include/hw/core/cpu-topology.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 448dc951c509..09173e8c953d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1875,6 +1875,7 @@ R: Yanan Wang <wangyanan55@huawei.com>
S: Supported
F: hw/core/cpu-common.c
F: hw/core/cpu-sysemu.c
+F: hw/core/cpu-topology.c
F: hw/core/machine-qmp-cmds.c
F: hw/core/machine.c
F: hw/core/machine-smp.c
@@ -1886,6 +1887,7 @@ F: qapi/machine-common.json
F: qapi/machine-target.json
F: include/hw/boards.h
F: include/hw/core/cpu.h
+F: include/hw/core/cpu-topology.h
F: include/hw/cpu/cluster.h
F: include/sysemu/numa.h
F: tests/unit/test-smp-parse.c
diff --git a/hw/core/cpu-topology.c b/hw/core/cpu-topology.c
new file mode 100644
index 000000000000..20b5d708cb54
--- /dev/null
+++ b/hw/core/cpu-topology.c
@@ -0,0 +1,36 @@
+/*
+ * QEMU CPU Topology Representation
+ *
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * Authors:
+ * Zhao Liu <zhao1.liu@intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/core/cpu-topology.h"
+
+typedef struct CPUTopoInfo {
+ const char *name;
+} CPUTopoInfo;
+
+CPUTopoInfo cpu_topo_descriptors[] = {
+ [CPU_TOPO_LEVEL_INVALID] = { .name = "invalid", },
+ [CPU_TOPO_LEVEL_THREAD] = { .name = "thread", },
+ [CPU_TOPO_LEVEL_CORE] = { .name = "core", },
+ [CPU_TOPO_LEVEL_MODULE] = { .name = "module", },
+ [CPU_TOPO_LEVEL_CLUSTER] = { .name = "cluster", },
+ [CPU_TOPO_LEVEL_DIE] = { .name = "die", },
+ [CPU_TOPO_LEVEL_SOCKET] = { .name = "socket", },
+ [CPU_TOPO_LEVEL_BOOK] = { .name = "book", },
+ [CPU_TOPO_LEVEL_DRAWER] = { .name = "drawer", },
+ [CPU_TOPO_LEVEL__MAX] = { .name = NULL, },
+};
+
+const char *cpu_topo_to_string(CPUTopoLevel topo)
+{
+ return cpu_topo_descriptors[topo].name;
+}
diff --git a/hw/core/meson.build b/hw/core/meson.build
index a3d9bab9f42a..71dc396e9bfc 100644
--- a/hw/core/meson.build
+++ b/hw/core/meson.build
@@ -13,6 +13,7 @@ hwcore_ss.add(files(
))
common_ss.add(files('cpu-common.c'))
+common_ss.add(files('cpu-topology.c'))
common_ss.add(files('machine-smp.c'))
system_ss.add(when: 'CONFIG_FITLOADER', if_true: files('loader-fit.c'))
system_ss.add(when: 'CONFIG_GENERIC_LOADER', if_true: files('generic-loader.c'))
diff --git a/include/hw/core/cpu-topology.h b/include/hw/core/cpu-topology.h
new file mode 100644
index 000000000000..0e21fe8a9bf8
--- /dev/null
+++ b/include/hw/core/cpu-topology.h
@@ -0,0 +1,20 @@
+/*
+ * QEMU CPU Topology Representation Header
+ *
+ * Copyright (c) 2024 Intel Corporation
+ *
+ * Authors:
+ * Zhao Liu <zhao1.liu@intel.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ */
+
+#ifndef CPU_TOPOLOGY_H
+#define CPU_TOPOLOGY_H
+
+#include "qapi/qapi-types-machine.h"
+
+const char *cpu_topo_to_string(CPUTopoLevel topo);
+
+#endif /* CPU_TOPOLOGY_H */
diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h
index dff49fce1154..c6ff75f23991 100644
--- a/include/hw/i386/topology.h
+++ b/include/hw/i386/topology.h
@@ -39,7 +39,7 @@
* CPUID Fn8000_0008_ECX[ApicIdCoreIdSize[3:0]] is set to apicid_core_width().
*/
-
+#include "hw/core/cpu-topology.h"
#include "qemu/bitops.h"
/*
@@ -62,22 +62,6 @@ typedef struct X86CPUTopoInfo {
unsigned threads_per_core;
} X86CPUTopoInfo;
-/*
- * CPUTopoLevel is the general i386 topology hierarchical representation,
- * ordered by increasing hierarchical relationship.
- * Its enumeration value is not bound to the type value of Intel (CPUID[0x1F])
- * or AMD (CPUID[0x80000026]).
- */
-enum CPUTopoLevel {
- CPU_TOPO_LEVEL_INVALID,
- CPU_TOPO_LEVEL_SMT,
- CPU_TOPO_LEVEL_CORE,
- CPU_TOPO_LEVEL_MODULE,
- CPU_TOPO_LEVEL_DIE,
- CPU_TOPO_LEVEL_PACKAGE,
- CPU_TOPO_LEVEL_MAX,
-};
-
/* Return the bit width needed for 'count' IDs */
static unsigned apicid_bitwidth_for_count(unsigned count)
{
diff --git a/qapi/machine.json b/qapi/machine.json
index bce6e1bbc412..7ac5a05bb9c9 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -1667,6 +1667,46 @@
'*reboot-timeout': 'int',
'*strict': 'bool' } }
+##
+# @CPUTopoLevel:
+#
+# An enumeration of CPU topology levels.
+#
+# @invalid: Invalid topology level, used as a placeholder.
+#
+# @thread: thread level, which would also be called SMT level or logical
+# processor level. The @threads option in -smp is used to configure
+# the topology of this level.
+#
+# @core: core level. The @cores option in -smp is used to configure the
+# topology of this level.
+#
+# @module: module level. The @modules option in -smp is used to
+# configure the topology of this level.
+#
+# @cluster: cluster level. The @clusters option in -smp is used to
+# configure the topology of this level.
+#
+# @die: die level. The @dies option in -smp is used to configure the
+# topology of this level.
+#
+# @socket: socket level, which would also be called package level. The
+# @sockets option in -smp is used to configure the topology of this
+# level.
+#
+# @book: book level. The @books option in -smp is used to configure the
+# topology of this level.
+#
+# @drawer: drawer level. The @drawers option in -smp is used to
+# configure the topology of this level.
+#
+# Since: 9.1
+##
+{ 'enum': 'CPUTopoLevel',
+ 'prefix': 'CPU_TOPO_LEVEL',
+ 'data': [ 'invalid', 'thread', 'core', 'module', 'cluster',
+ 'die', 'socket', 'book', 'drawer' ] }
+
##
# @SMPConfiguration:
#
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index bc2dceb647fa..b11097b5bafd 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -247,12 +247,12 @@ static uint32_t max_thread_ids_for_cache(X86CPUTopoInfo *topo_info,
case CPU_TOPO_LEVEL_DIE:
num_ids = 1 << apicid_die_offset(topo_info);
break;
- case CPU_TOPO_LEVEL_PACKAGE:
+ case CPU_TOPO_LEVEL_SOCKET:
num_ids = 1 << apicid_pkg_offset(topo_info);
break;
default:
/*
- * Currently there is no use case for SMT and MODULE, so use
+ * Currently there is no use case for THREAD and MODULE, so use
* assert directly to facilitate debugging.
*/
g_assert_not_reached();
@@ -304,7 +304,7 @@ static uint32_t num_threads_by_topo_level(X86CPUTopoInfo *topo_info,
enum CPUTopoLevel topo_level)
{
switch (topo_level) {
- case CPU_TOPO_LEVEL_SMT:
+ case CPU_TOPO_LEVEL_THREAD:
return 1;
case CPU_TOPO_LEVEL_CORE:
return topo_info->threads_per_core;
@@ -313,7 +313,7 @@ static uint32_t num_threads_by_topo_level(X86CPUTopoInfo *topo_info,
case CPU_TOPO_LEVEL_DIE:
return topo_info->threads_per_core * topo_info->cores_per_module *
topo_info->modules_per_die;
- case CPU_TOPO_LEVEL_PACKAGE:
+ case CPU_TOPO_LEVEL_SOCKET:
return topo_info->threads_per_core * topo_info->cores_per_module *
topo_info->modules_per_die * topo_info->dies_per_pkg;
default:
@@ -326,7 +326,7 @@ static uint32_t apicid_offset_by_topo_level(X86CPUTopoInfo *topo_info,
enum CPUTopoLevel topo_level)
{
switch (topo_level) {
- case CPU_TOPO_LEVEL_SMT:
+ case CPU_TOPO_LEVEL_THREAD:
return 0;
case CPU_TOPO_LEVEL_CORE:
return apicid_core_offset(topo_info);
@@ -334,7 +334,7 @@ static uint32_t apicid_offset_by_topo_level(X86CPUTopoInfo *topo_info,
return apicid_module_offset(topo_info);
case CPU_TOPO_LEVEL_DIE:
return apicid_die_offset(topo_info);
- case CPU_TOPO_LEVEL_PACKAGE:
+ case CPU_TOPO_LEVEL_SOCKET:
return apicid_pkg_offset(topo_info);
default:
g_assert_not_reached();
@@ -347,7 +347,7 @@ static uint32_t cpuid1f_topo_type(enum CPUTopoLevel topo_level)
switch (topo_level) {
case CPU_TOPO_LEVEL_INVALID:
return CPUID_1F_ECX_TOPO_LEVEL_INVALID;
- case CPU_TOPO_LEVEL_SMT:
+ case CPU_TOPO_LEVEL_THREAD:
return CPUID_1F_ECX_TOPO_LEVEL_SMT;
case CPU_TOPO_LEVEL_CORE:
return CPUID_1F_ECX_TOPO_LEVEL_CORE;
@@ -371,7 +371,7 @@ static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count,
unsigned long level, next_level;
uint32_t num_threads_next_level, offset_next_level;
- assert(count + 1 < CPU_TOPO_LEVEL_MAX);
+ assert(count + 1 < CPU_TOPO_LEVEL__MAX);
/*
* Find the No.(count + 1) topology level in avail_cpu_topo bitmap.
@@ -380,7 +380,7 @@ static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count,
level = CPU_TOPO_LEVEL_INVALID;
for (int i = 0; i <= count; i++) {
level = find_next_bit(env->avail_cpu_topo,
- CPU_TOPO_LEVEL_PACKAGE,
+ CPU_TOPO_LEVEL_SOCKET,
level + 1);
/*
@@ -388,7 +388,7 @@ static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count,
* and it just encodes the invalid level (all fields are 0)
* into the last subleaf of 0x1f.
*/
- if (level == CPU_TOPO_LEVEL_PACKAGE) {
+ if (level == CPU_TOPO_LEVEL_SOCKET) {
level = CPU_TOPO_LEVEL_INVALID;
break;
}
@@ -399,7 +399,7 @@ static void encode_topo_cpuid1f(CPUX86State *env, uint32_t count,
offset_next_level = 0;
} else {
next_level = find_next_bit(env->avail_cpu_topo,
- CPU_TOPO_LEVEL_PACKAGE,
+ CPU_TOPO_LEVEL_SOCKET,
level + 1);
num_threads_next_level = num_threads_by_topo_level(topo_info,
next_level);
@@ -6435,7 +6435,7 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
/* Share the cache at package level. */
*eax |= max_thread_ids_for_cache(&topo_info,
- CPU_TOPO_LEVEL_PACKAGE) << 14;
+ CPU_TOPO_LEVEL_SOCKET) << 14;
}
}
} else if (cpu->vendor_cpuid_only && IS_AMD_CPU(env)) {
@@ -7935,10 +7935,10 @@ static void x86_cpu_init_default_topo(X86CPU *cpu)
env->nr_modules = 1;
env->nr_dies = 1;
- /* SMT, core and package levels are set by default. */
- set_bit(CPU_TOPO_LEVEL_SMT, env->avail_cpu_topo);
+ /* thread, core and socket levels are set by default. */
+ set_bit(CPU_TOPO_LEVEL_THREAD, env->avail_cpu_topo);
set_bit(CPU_TOPO_LEVEL_CORE, env->avail_cpu_topo);
- set_bit(CPU_TOPO_LEVEL_PACKAGE, env->avail_cpu_topo);
+ set_bit(CPU_TOPO_LEVEL_SOCKET, env->avail_cpu_topo);
}
static void x86_cpu_initfn(Object *obj)
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index c64ef0c1a287..c6d07f38a1e8 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -1606,7 +1606,7 @@ typedef struct CPUCacheInfo {
* Used to encode CPUID[4].EAX[bits 25:14] or
* CPUID[0x8000001D].EAX[bits 25:14].
*/
- enum CPUTopoLevel share_level;
+ CPUTopoLevel share_level;
} CPUCacheInfo;
@@ -1921,7 +1921,7 @@ typedef struct CPUArchState {
unsigned nr_modules;
/* Bitmap of available CPU topology levels for this CPU. */
- DECLARE_BITMAP(avail_cpu_topo, CPU_TOPO_LEVEL_MAX);
+ DECLARE_BITMAP(avail_cpu_topo, CPU_TOPO_LEVEL__MAX);
} CPUX86State;
struct kvm_msrs;
--
2.34.1
next prev parent reply other threads:[~2024-05-30 10:02 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-30 10:15 [RFC v2 0/7] Introduce SMP Cache Topology Zhao Liu
2024-05-30 10:15 ` Zhao Liu [this message]
2024-06-03 12:19 ` [RFC v2 1/7] hw/core: Make CPU topology enumeration arch-agnostic Markus Armbruster
2024-06-04 8:39 ` Zhao Liu
2024-06-04 8:44 ` Markus Armbruster
2024-06-03 12:25 ` Markus Armbruster
2024-06-04 8:33 ` Zhao Liu
2024-06-04 8:47 ` Markus Armbruster
2024-06-04 9:06 ` Zhao Liu
2024-05-30 10:15 ` [RFC v2 2/7] hw/core: Define cache topology for machine Zhao Liu
2024-05-30 10:15 ` [RFC v2 3/7] hw/core: Add cache topology options in -smp Zhao Liu
2024-06-04 8:54 ` Markus Armbruster
2024-06-04 9:32 ` Daniel P. Berrangé
2024-06-04 16:08 ` Zhao Liu
2024-05-30 10:15 ` [RFC v2 4/7] i386/cpu: Support thread and module level cache topology Zhao Liu
2024-05-30 10:15 ` [RFC v2 5/7] i386/cpu: Update cache topology with machine's configuration Zhao Liu
2024-05-30 10:15 ` [RFC v2 6/7] i386/pc: Support cache topology in -smp for PC machine Zhao Liu
2024-05-30 10:15 ` [RFC v2 7/7] qemu-options: Add the cache topology description of -smp Zhao Liu
2024-06-04 9:29 ` [RFC v2 0/7] Introduce SMP Cache Topology Daniel P. Berrangé
2024-06-04 15:31 ` Zhao Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240530101539.768484-2-zhao1.liu@intel.com \
--to=zhao1.liu@intel.com \
--cc=Jonathan.Cameron@huawei.com \
--cc=alex.bennee@linaro.org \
--cc=armbru@redhat.com \
--cc=berrange@redhat.com \
--cc=dapeng1.mi@linux.intel.com \
--cc=eblake@redhat.com \
--cc=eduardo@habkost.net \
--cc=jeeheng.sia@starfivetech.com \
--cc=kvm@vger.kernel.org \
--cc=marcel.apfelbaum@gmail.com \
--cc=mst@redhat.com \
--cc=mtosatti@redhat.com \
--cc=pbonzini@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=philmd@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=qemu-riscv@nongnu.org \
--cc=richard.henderson@linaro.org \
--cc=wangyanan55@huawei.com \
--cc=yongwei.ma@intel.com \
--cc=zhenyu.z.wang@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).