Skip to content

Commit

Permalink
CPU topology: extend with s390 specifics
Browse files Browse the repository at this point in the history
S390 adds two new SMP levels, drawers and books to the CPU
topology.
S390 CPUs have specific topology features like dedication and
entitlement. These indicate to the guest information on host
vCPU scheduling and help the guest make better scheduling decisions.

Add the new levels to the relevant QAPI structs.
Add all the supported topology levels, dedication and entitlement
as properties to S390 CPUs.
Create machine-common.json so we can later include it in
machine-target.json also.

Signed-off-by: Pierre Morel <pmorel@linux.ibm.com>
Reviewed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Co-developed-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com>
Message-ID: <20231016183925.2384704-3-nsg@linux.ibm.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
  • Loading branch information
Pierre Morel authored and huth committed Oct 20, 2023
1 parent 3da4aef commit 5de1aff
Show file tree
Hide file tree
Showing 15 changed files with 141 additions and 13 deletions.
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -1793,6 +1793,7 @@ F: hw/core/null-machine.c
F: hw/core/numa.c
F: hw/cpu/cluster.c
F: qapi/machine.json
F: qapi/machine-common.json
F: qapi/machine-target.json
F: include/hw/boards.h
F: include/hw/core/cpu.h
Expand Down
48 changes: 41 additions & 7 deletions hw/core/machine-smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ static char *cpu_hierarchy_to_string(MachineState *ms)
MachineClass *mc = MACHINE_GET_CLASS(ms);
GString *s = g_string_new(NULL);

if (mc->smp_props.drawers_supported) {
g_string_append_printf(s, "drawers (%u) * ", ms->smp.drawers);
}

if (mc->smp_props.books_supported) {
g_string_append_printf(s, "books (%u) * ", ms->smp.books);
}

g_string_append_printf(s, "sockets (%u)", ms->smp.sockets);

if (mc->smp_props.dies_supported) {
Expand Down Expand Up @@ -75,6 +83,8 @@ void machine_parse_smp_config(MachineState *ms,
{
MachineClass *mc = MACHINE_GET_CLASS(ms);
unsigned cpus = config->has_cpus ? config->cpus : 0;
unsigned drawers = config->has_drawers ? config->drawers : 0;
unsigned books = config->has_books ? config->books : 0;
unsigned sockets = config->has_sockets ? config->sockets : 0;
unsigned dies = config->has_dies ? config->dies : 0;
unsigned clusters = config->has_clusters ? config->clusters : 0;
Expand All @@ -87,6 +97,8 @@ void machine_parse_smp_config(MachineState *ms,
* explicit configuration like "cpus=0" is not allowed.
*/
if ((config->has_cpus && config->cpus == 0) ||
(config->has_drawers && config->drawers == 0) ||
(config->has_books && config->books == 0) ||
(config->has_sockets && config->sockets == 0) ||
(config->has_dies && config->dies == 0) ||
(config->has_clusters && config->clusters == 0) ||
Expand All @@ -113,6 +125,19 @@ void machine_parse_smp_config(MachineState *ms,
dies = dies > 0 ? dies : 1;
clusters = clusters > 0 ? clusters : 1;

if (!mc->smp_props.books_supported && books > 1) {
error_setg(errp, "books not supported by this machine's CPU topology");
return;
}
books = books > 0 ? books : 1;

if (!mc->smp_props.drawers_supported && drawers > 1) {
error_setg(errp,
"drawers not supported by this machine's CPU topology");
return;
}
drawers = drawers > 0 ? drawers : 1;

/* compute missing values based on the provided ones */
if (cpus == 0 && maxcpus == 0) {
sockets = sockets > 0 ? sockets : 1;
Expand All @@ -126,33 +151,41 @@ void machine_parse_smp_config(MachineState *ms,
if (sockets == 0) {
cores = cores > 0 ? cores : 1;
threads = threads > 0 ? threads : 1;
sockets = maxcpus / (dies * clusters * cores * threads);
sockets = maxcpus /
(drawers * books * dies * clusters * cores * threads);
} else if (cores == 0) {
threads = threads > 0 ? threads : 1;
cores = maxcpus / (sockets * dies * clusters * threads);
cores = maxcpus /
(drawers * books * sockets * dies * clusters * threads);
}
} else {
/* prefer cores over sockets since 6.2 */
if (cores == 0) {
sockets = sockets > 0 ? sockets : 1;
threads = threads > 0 ? threads : 1;
cores = maxcpus / (sockets * dies * clusters * threads);
cores = maxcpus /
(drawers * books * sockets * dies * clusters * threads);
} else if (sockets == 0) {
threads = threads > 0 ? threads : 1;
sockets = maxcpus / (dies * clusters * cores * threads);
sockets = maxcpus /
(drawers * books * dies * clusters * cores * threads);
}
}

/* try to calculate omitted threads at last */
if (threads == 0) {
threads = maxcpus / (sockets * dies * clusters * cores);
threads = maxcpus /
(drawers * books * sockets * dies * clusters * cores);
}
}

maxcpus = maxcpus > 0 ? maxcpus : sockets * dies * clusters * cores * threads;
maxcpus = maxcpus > 0 ? maxcpus : drawers * books * sockets * dies *
clusters * cores * threads;
cpus = cpus > 0 ? cpus : maxcpus;

ms->smp.cpus = cpus;
ms->smp.drawers = drawers;
ms->smp.books = books;
ms->smp.sockets = sockets;
ms->smp.dies = dies;
ms->smp.clusters = clusters;
Expand All @@ -163,7 +196,8 @@ void machine_parse_smp_config(MachineState *ms,
mc->smp_props.has_clusters = config->has_clusters;

/* sanity-check of the computed topology */
if (sockets * dies * clusters * cores * threads != maxcpus) {
if (drawers * books * sockets * dies * clusters * cores * threads !=
maxcpus) {
g_autofree char *topo_msg = cpu_hierarchy_to_string(ms);
error_setg(errp, "Invalid CPU topology: "
"product of the hierarchy must match maxcpus: "
Expand Down
4 changes: 4 additions & 0 deletions hw/core/machine.c
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,8 @@ static void machine_get_smp(Object *obj, Visitor *v, const char *name,
MachineState *ms = MACHINE(obj);
SMPConfiguration *config = &(SMPConfiguration){
.has_cpus = true, .cpus = ms->smp.cpus,
.has_drawers = true, .drawers = ms->smp.drawers,
.has_books = true, .books = ms->smp.books,
.has_sockets = true, .sockets = ms->smp.sockets,
.has_dies = true, .dies = ms->smp.dies,
.has_clusters = true, .clusters = ms->smp.clusters,
Expand Down Expand Up @@ -1137,6 +1139,8 @@ static void machine_initfn(Object *obj)
/* default to mc->default_cpus */
ms->smp.cpus = mc->default_cpus;
ms->smp.max_cpus = mc->default_cpus;
ms->smp.drawers = 1;
ms->smp.books = 1;
ms->smp.sockets = 1;
ms->smp.dies = 1;
ms->smp.clusters = 1;
Expand Down
13 changes: 13 additions & 0 deletions hw/core/qdev-properties-system.c
Original file line number Diff line number Diff line change
Expand Up @@ -1139,3 +1139,16 @@ const PropertyInfo qdev_prop_uuid = {
.set = set_uuid,
.set_default_value = set_default_uuid_auto,
};

/* --- s390 cpu entitlement policy --- */

QEMU_BUILD_BUG_ON(sizeof(CpuS390Entitlement) != sizeof(int));

const PropertyInfo qdev_prop_cpus390entitlement = {
.name = "CpuS390Entitlement",
.description = "low/medium (default)/high",
.enum_table = &CpuS390Entitlement_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
4 changes: 4 additions & 0 deletions hw/s390x/s390-virtio-ccw.c
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,8 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
mc->no_sdcard = 1;
mc->max_cpus = S390_MAX_CPUS;
mc->has_hotpluggable_cpus = true;
mc->smp_props.books_supported = true;
mc->smp_props.drawers_supported = true;
assert(!mc->get_hotplug_handler);
mc->get_hotplug_handler = s390_get_hotplug_handler;
mc->cpu_index_to_instance_props = s390_cpu_index_to_props;
Expand Down Expand Up @@ -853,6 +855,8 @@ static void ccw_machine_8_1_class_options(MachineClass *mc)
{
ccw_machine_8_2_class_options(mc);
compat_props_add(mc->compat_props, hw_compat_8_1, hw_compat_8_1_len);
mc->smp_props.drawers_supported = false;
mc->smp_props.books_supported = false;
}
DEFINE_CCW_MACHINE(8_1, "8.1", false);

Expand Down
10 changes: 9 additions & 1 deletion include/hw/boards.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,16 @@ typedef struct {
* @clusters_supported - whether clusters are supported by the machine
* @has_clusters - whether clusters are explicitly specified in the user
* provided SMP configuration
* @books_supported - whether books are supported by the machine
* @drawers_supported - whether drawers are supported by the machine
*/
typedef struct {
bool prefer_sockets;
bool dies_supported;
bool clusters_supported;
bool has_clusters;
bool books_supported;
bool drawers_supported;
} SMPCompatProps;

/**
Expand Down Expand Up @@ -323,7 +327,9 @@ typedef struct DeviceMemoryState {
/**
* CpuTopology:
* @cpus: the number of present logical processors on the machine
* @sockets: the number of sockets on the machine
* @drawers: the number of drawers on the machine
* @books: the number of books in one drawer
* @sockets: the number of sockets in one book
* @dies: the number of dies in one socket
* @clusters: the number of clusters in one die
* @cores: the number of cores in one cluster
Expand All @@ -332,6 +338,8 @@ typedef struct DeviceMemoryState {
*/
typedef struct CpuTopology {
unsigned int cpus;
unsigned int drawers;
unsigned int books;
unsigned int sockets;
unsigned int dies;
unsigned int clusters;
Expand Down
4 changes: 4 additions & 0 deletions include/hw/qdev-properties-system.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extern const PropertyInfo qdev_prop_audiodev;
extern const PropertyInfo qdev_prop_off_auto_pcibar;
extern const PropertyInfo qdev_prop_pcie_link_speed;
extern const PropertyInfo qdev_prop_pcie_link_width;
extern const PropertyInfo qdev_prop_cpus390entitlement;

#define DEFINE_PROP_PCI_DEVFN(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_pci_devfn, int32_t)
Expand Down Expand Up @@ -73,5 +74,8 @@ extern const PropertyInfo qdev_prop_pcie_link_width;
#define DEFINE_PROP_UUID_NODEFAULT(_name, _state, _field) \
DEFINE_PROP(_name, _state, _field, qdev_prop_uuid, QemuUUID)

#define DEFINE_PROP_CPUS390ENTITLEMENT(_n, _s, _f, _d) \
DEFINE_PROP_SIGNED(_n, _s, _f, _d, qdev_prop_cpus390entitlement, \
CpuS390Entitlement)

#endif
21 changes: 21 additions & 0 deletions qapi/machine-common.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- Mode: Python -*-
# vim: filetype=python
#
# This work is licensed under the terms of the GNU GPL, version 2 or later.
# See the COPYING file in the top-level directory.

##
# = Machines S390 data types
##

##
# @CpuS390Entitlement:
#
# An enumeration of CPU entitlements that can be assumed by a virtual
# S390 CPU
#
# Since: 8.2
##
{ 'enum': 'CpuS390Entitlement',
'prefix': 'S390_CPU_ENTITLEMENT',
'data': [ 'auto', 'low', 'medium', 'high' ] }
21 changes: 18 additions & 3 deletions qapi/machine.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
##

{ 'include': 'common.json' }
{ 'include': 'machine-common.json' }

##
# @SysEmuTarget:
Expand Down Expand Up @@ -907,7 +908,13 @@
#
# @node-id: NUMA node ID the CPU belongs to
#
# @socket-id: socket number within CPU topology the CPU belongs to
# @drawer-id: drawer number within CPU topology the CPU belongs to
# (since 8.2)
#
# @book-id: book number within parent container the CPU belongs to
# (since 8.2)
#
# @socket-id: socket number within parent container the CPU belongs to
#
# @die-id: die number within the parent container the CPU belongs to
# (since 4.1)
Expand All @@ -928,6 +935,8 @@
{ 'struct': 'CpuInstanceProperties',
# Keep these in sync with the properties device_add accepts
'data': { '*node-id': 'int',
'*drawer-id': 'int',
'*book-id': 'int',
'*socket-id': 'int',
'*die-id': 'int',
'*cluster-id': 'int',
Expand Down Expand Up @@ -1488,7 +1497,7 @@
# containers.
#
# The ordering from highest/coarsest to lowest/finest is:
# @sockets, @dies, @clusters, @cores, @threads.
# @drawers, @books, @sockets, @dies, @clusters, @cores, @threads.
#
# Different architectures support different subsets of topology
# containers.
Expand All @@ -1501,7 +1510,11 @@
# @maxcpus: maximum number of hotpluggable virtual CPUs in the virtual
# machine
#
# @sockets: number of sockets in the CPU topology
# @drawers: number of drawers in the CPU topology (since 8.2)
#
# @books: number of books in the CPU topology (since 8.2)
#
# @sockets: number of sockets per parent container
#
# @dies: number of dies per parent container
#
Expand All @@ -1515,6 +1528,8 @@
##
{ 'struct': 'SMPConfiguration', 'data': {
'*cpus': 'int',
'*drawers': 'int',
'*books': 'int',
'*sockets': 'int',
'*dies': 'int',
'*clusters': 'int',
Expand Down
1 change: 1 addition & 0 deletions qapi/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ qapi_all_modules = [
'error',
'introspect',
'job',
'machine-common',
'machine',
'machine-target',
'migration',
Expand Down
1 change: 1 addition & 0 deletions qapi/qapi-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
{ 'include': 'introspect.json' }
{ 'include': 'qom.json' }
{ 'include': 'qdev.json' }
{ 'include': 'machine-common.json' }
{ 'include': 'machine.json' }
{ 'include': 'machine-target.json' }
{ 'include': 'replay.json' }
Expand Down
7 changes: 5 additions & 2 deletions qemu-options.hx
Original file line number Diff line number Diff line change
Expand Up @@ -272,11 +272,14 @@ SRST
ERST

DEF("smp", HAS_ARG, QEMU_OPTION_smp,
"-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]\n"
"-smp [[cpus=]n][,maxcpus=maxcpus][,drawers=drawers][,books=books][,sockets=sockets]\n"
" [,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]\n"
" set the number of initial CPUs to 'n' [default=1]\n"
" maxcpus= maximum number of total CPUs, including\n"
" offline CPUs for hotplug, etc\n"
" sockets= number of sockets on the machine board\n"
" drawers= number of drawers on the machine board\n"
" books= number of books in one drawer\n"
" sockets= number of sockets in one book\n"
" dies= number of dies in one socket\n"
" clusters= number of clusters in one die\n"
" cores= number of cores in one cluster\n"
Expand Down
6 changes: 6 additions & 0 deletions system/vl.c
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,12 @@ static QemuOptsList qemu_smp_opts = {
{
.name = "cpus",
.type = QEMU_OPT_NUMBER,
}, {
.name = "drawers",
.type = QEMU_OPT_NUMBER,
}, {
.name = "books",
.type = QEMU_OPT_NUMBER,
}, {
.name = "sockets",
.type = QEMU_OPT_NUMBER,
Expand Down
7 changes: 7 additions & 0 deletions target/s390x/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "qapi/qapi-types-machine.h"
#include "sysemu/hw_accel.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "fpu/softfloat-helpers.h"
#include "disas/capstone.h"
#include "sysemu/tcg.h"
Expand Down Expand Up @@ -290,6 +291,12 @@ static const gchar *s390_gdb_arch_name(CPUState *cs)
static Property s390x_cpu_properties[] = {
#if !defined(CONFIG_USER_ONLY)
DEFINE_PROP_UINT32("core-id", S390CPU, env.core_id, 0),
DEFINE_PROP_INT32("socket-id", S390CPU, env.socket_id, -1),
DEFINE_PROP_INT32("book-id", S390CPU, env.book_id, -1),
DEFINE_PROP_INT32("drawer-id", S390CPU, env.drawer_id, -1),
DEFINE_PROP_BOOL("dedicated", S390CPU, env.dedicated, false),
DEFINE_PROP_CPUS390ENTITLEMENT("entitlement", S390CPU, env.entitlement,
S390_CPU_ENTITLEMENT_AUTO),
#endif
DEFINE_PROP_END_OF_LIST()
};
Expand Down
6 changes: 6 additions & 0 deletions target/s390x/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "exec/cpu-defs.h"
#include "qemu/cpu-float.h"
#include "tcg/tcg_s390x.h"
#include "qapi/qapi-types-machine-common.h"

#define ELF_MACHINE_UNAME "S390X"

Expand Down Expand Up @@ -132,6 +133,11 @@ struct CPUArchState {

#if !defined(CONFIG_USER_ONLY)
uint32_t core_id; /* PoP "CPU address", same as cpu_index */
int32_t socket_id;
int32_t book_id;
int32_t drawer_id;
bool dedicated;
CpuS390Entitlement entitlement; /* Used only for vertical polarization */
uint64_t cpuid;
#endif

Expand Down

0 comments on commit 5de1aff

Please sign in to comment.