Message ID | 20230901155812.2696560-9-nsg@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | s390x: CPU Topology | expand |
On 01/09/2023 17.58, Nina Schoetterl-Glausch wrote: > From: Pierre Morel <pmorel@linux.ibm.com> > > The modification of the CPU attributes are done through a monitor > command. > > It allows to move the core inside the topology tree to optimize > the cache usage in the case the host's hypervisor previously > moved the CPU. > > The same command allows to modify the CPU attributes modifiers > like polarization entitlement and the dedicated attribute to notify > the guest if the host admin modified scheduling or dedication of a vCPU. > > With this knowledge the guest has the possibility to optimize the > usage of the vCPUs. > > The command has a feature unstable for the moment. > > 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> > Signed-off-by: Nina Schoetterl-Glausch <nsg@linux.ibm.com> > --- ... > diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c > index 52bfbe12a9..c828538f2a 100644 > --- a/hw/s390x/cpu-topology.c > +++ b/hw/s390x/cpu-topology.c > @@ -23,6 +23,7 @@ > #include "target/s390x/cpu.h" > #include "hw/s390x/s390-virtio-ccw.h" > #include "hw/s390x/cpu-topology.h" > +#include "qapi/qapi-commands-machine-target.h" > > /* > * s390_topology is used to keep the topology information. > @@ -259,6 +260,29 @@ static bool s390_topology_check(uint16_t socket_id, uint16_t book_id, > return true; > } > > +/** > + * s390_topology_need_report > + * @cpu: Current cpu > + * @drawer_id: future drawer ID > + * @book_id: future book ID > + * @socket_id: future socket ID > + * @entitlement: future entitlement > + * @dedicated: future dedicated > + * > + * A modified topology change report is needed if the topology > + * tree or the topology attributes change. > + */ > +static bool s390_topology_need_report(S390CPU *cpu, int drawer_id, > + int book_id, int socket_id, > + uint16_t entitlement, bool dedicated) Nit: Indentation should match the "(" ? > +{ > + return cpu->env.drawer_id != drawer_id || > + cpu->env.book_id != book_id || > + cpu->env.socket_id != socket_id || > + cpu->env.entitlement != entitlement || > + cpu->env.dedicated != dedicated; > +} > + > /** > * s390_update_cpu_props: > * @ms: the machine state > @@ -328,3 +352,114 @@ void s390_topology_setup_cpu(MachineState *ms, S390CPU *cpu, Error **errp) > /* topology tree is reflected in props */ > s390_update_cpu_props(ms, cpu); > } > + > +static void s390_change_topology(uint16_t core_id, > + bool has_socket_id, uint16_t socket_id, > + bool has_book_id, uint16_t book_id, > + bool has_drawer_id, uint16_t drawer_id, > + bool has_entitlement, > + CpuS390Entitlement entitlement, > + bool has_dedicated, bool dedicated, > + Error **errp) > +{ > + MachineState *ms = current_machine; > + int old_socket_entry; > + int new_socket_entry; > + bool report_needed; > + S390CPU *cpu; > + ERRP_GUARD(); > + > + cpu = s390_cpu_addr2state(core_id); > + if (!cpu) { > + error_setg(errp, "Core-id %d does not exist!", core_id); > + return; > + } > + > + /* Get attributes not provided from cpu and verify the new topology */ > + if (!has_socket_id) { > + socket_id = cpu->env.socket_id; > + } > + if (!has_book_id) { > + book_id = cpu->env.book_id; > + } > + if (!has_drawer_id) { > + drawer_id = cpu->env.drawer_id; > + } > + if (!has_dedicated) { > + dedicated = cpu->env.dedicated; > + } > + > + /* > + * When the user specifies the entitlement as 'auto' on the command line, > + * qemu will set the entitlement as: s/qemu/QEMU/ > + * Medium when the CPU is not dedicated. > + * High when dedicated is true. > + */ > + if (!has_entitlement || (entitlement == S390_CPU_ENTITLEMENT_AUTO)) { nit: Remove the parentheses around "entitlement == S390_CPU_ENTITLEMENT_AUTO". > + if (dedicated) { > + entitlement = S390_CPU_ENTITLEMENT_HIGH; > + } else { > + entitlement = S390_CPU_ENTITLEMENT_MEDIUM; > + } > + } > + > + if (!s390_topology_check(socket_id, book_id, drawer_id, > + entitlement, dedicated, errp)) { > + return; > + } > + > + /* Check for space on new socket */ > + old_socket_entry = s390_socket_nb(cpu); > + new_socket_entry = s390_socket_nb_from_ids(drawer_id, book_id, socket_id); > + > + if (new_socket_entry != old_socket_entry) { > + if (s390_topology.cores_per_socket[new_socket_entry] >= > + ms->smp.cores) { > + error_setg(errp, "No more space on this socket"); > + return; > + } > + /* Update the count of cores in sockets */ > + s390_topology.cores_per_socket[new_socket_entry] += 1; > + s390_topology.cores_per_socket[old_socket_entry] -= 1; > + } > + > + /* Check if we will need to report the modified topology */ > + report_needed = s390_topology_need_report(cpu, drawer_id, book_id, > + socket_id, entitlement, > + dedicated); > + > + /* All checks done, report new topology into the vCPU */ > + cpu->env.drawer_id = drawer_id; > + cpu->env.book_id = book_id; > + cpu->env.socket_id = socket_id; > + cpu->env.dedicated = dedicated; > + cpu->env.entitlement = entitlement; > + > + /* topology tree is reflected in props */ > + s390_update_cpu_props(ms, cpu); > + > + /* Advertise the topology change */ > + if (report_needed) { > + s390_cpu_topology_set_changed(true); > + } > +} > + > +void qmp_set_cpu_topology(uint16_t core, > + bool has_socket, uint16_t socket, > + bool has_book, uint16_t book, > + bool has_drawer, uint16_t drawer, > + bool has_entitlement, CpuS390Entitlement entitlement, > + bool has_dedicated, bool dedicated, > + Error **errp) > +{ > + ERRP_GUARD(); No need for ERRP_GUARD here, I think. > + if (!s390_has_topology()) { > + error_setg(errp, "This machine doesn't support topology"); > + return; > + } > + > + s390_change_topology(core, has_socket, socket, has_book, book, > + has_drawer, drawer, has_entitlement, entitlement, > + has_dedicated, dedicated, errp); > +} Thomas
diff --git a/qapi/machine-target.json b/qapi/machine-target.json index 275234a20f..1e7f512477 100644 --- a/qapi/machine-target.json +++ b/qapi/machine-target.json @@ -4,6 +4,8 @@ # 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': 'machine-common.json' } + ## # @CpuModelInfo: # @@ -375,3 +377,38 @@ 'data': [ 'horizontal', 'vertical' ], 'if': { 'all': [ 'TARGET_S390X' , 'CONFIG_KVM' ] } } + +## +# @set-cpu-topology: +# +# @core-id: the vCPU ID to be moved +# @socket-id: optional destination socket where to move the vCPU +# @book-id: optional destination book where to move the vCPU +# @drawer-id: optional destination drawer where to move the vCPU +# @entitlement: optional entitlement +# @dedicated: optional, if the vCPU is dedicated to a real CPU +# +# Features: +# @unstable: This command may still be modified. +# +# Modifies the topology by moving the CPU inside the topology +# tree or by changing a modifier attribute of a CPU. +# Default value for optional parameter is the current value +# used by the CPU. +# +# Returns: Nothing on success, the reason on failure. +# +# Since: 8.2 +## +{ 'command': 'set-cpu-topology', + 'data': { + 'core-id': 'uint16', + '*socket-id': 'uint16', + '*book-id': 'uint16', + '*drawer-id': 'uint16', + '*entitlement': 'CpuS390Entitlement', + '*dedicated': 'bool' + }, + 'features': [ 'unstable' ], + 'if': { 'all': [ 'TARGET_S390X' , 'CONFIG_KVM' ] } +} diff --git a/hw/s390x/cpu-topology.c b/hw/s390x/cpu-topology.c index 52bfbe12a9..c828538f2a 100644 --- a/hw/s390x/cpu-topology.c +++ b/hw/s390x/cpu-topology.c @@ -23,6 +23,7 @@ #include "target/s390x/cpu.h" #include "hw/s390x/s390-virtio-ccw.h" #include "hw/s390x/cpu-topology.h" +#include "qapi/qapi-commands-machine-target.h" /* * s390_topology is used to keep the topology information. @@ -259,6 +260,29 @@ static bool s390_topology_check(uint16_t socket_id, uint16_t book_id, return true; } +/** + * s390_topology_need_report + * @cpu: Current cpu + * @drawer_id: future drawer ID + * @book_id: future book ID + * @socket_id: future socket ID + * @entitlement: future entitlement + * @dedicated: future dedicated + * + * A modified topology change report is needed if the topology + * tree or the topology attributes change. + */ +static bool s390_topology_need_report(S390CPU *cpu, int drawer_id, + int book_id, int socket_id, + uint16_t entitlement, bool dedicated) +{ + return cpu->env.drawer_id != drawer_id || + cpu->env.book_id != book_id || + cpu->env.socket_id != socket_id || + cpu->env.entitlement != entitlement || + cpu->env.dedicated != dedicated; +} + /** * s390_update_cpu_props: * @ms: the machine state @@ -328,3 +352,114 @@ void s390_topology_setup_cpu(MachineState *ms, S390CPU *cpu, Error **errp) /* topology tree is reflected in props */ s390_update_cpu_props(ms, cpu); } + +static void s390_change_topology(uint16_t core_id, + bool has_socket_id, uint16_t socket_id, + bool has_book_id, uint16_t book_id, + bool has_drawer_id, uint16_t drawer_id, + bool has_entitlement, + CpuS390Entitlement entitlement, + bool has_dedicated, bool dedicated, + Error **errp) +{ + MachineState *ms = current_machine; + int old_socket_entry; + int new_socket_entry; + bool report_needed; + S390CPU *cpu; + ERRP_GUARD(); + + cpu = s390_cpu_addr2state(core_id); + if (!cpu) { + error_setg(errp, "Core-id %d does not exist!", core_id); + return; + } + + /* Get attributes not provided from cpu and verify the new topology */ + if (!has_socket_id) { + socket_id = cpu->env.socket_id; + } + if (!has_book_id) { + book_id = cpu->env.book_id; + } + if (!has_drawer_id) { + drawer_id = cpu->env.drawer_id; + } + if (!has_dedicated) { + dedicated = cpu->env.dedicated; + } + + /* + * When the user specifies the entitlement as 'auto' on the command line, + * qemu will set the entitlement as: + * Medium when the CPU is not dedicated. + * High when dedicated is true. + */ + if (!has_entitlement || (entitlement == S390_CPU_ENTITLEMENT_AUTO)) { + if (dedicated) { + entitlement = S390_CPU_ENTITLEMENT_HIGH; + } else { + entitlement = S390_CPU_ENTITLEMENT_MEDIUM; + } + } + + if (!s390_topology_check(socket_id, book_id, drawer_id, + entitlement, dedicated, errp)) { + return; + } + + /* Check for space on new socket */ + old_socket_entry = s390_socket_nb(cpu); + new_socket_entry = s390_socket_nb_from_ids(drawer_id, book_id, socket_id); + + if (new_socket_entry != old_socket_entry) { + if (s390_topology.cores_per_socket[new_socket_entry] >= + ms->smp.cores) { + error_setg(errp, "No more space on this socket"); + return; + } + /* Update the count of cores in sockets */ + s390_topology.cores_per_socket[new_socket_entry] += 1; + s390_topology.cores_per_socket[old_socket_entry] -= 1; + } + + /* Check if we will need to report the modified topology */ + report_needed = s390_topology_need_report(cpu, drawer_id, book_id, + socket_id, entitlement, + dedicated); + + /* All checks done, report new topology into the vCPU */ + cpu->env.drawer_id = drawer_id; + cpu->env.book_id = book_id; + cpu->env.socket_id = socket_id; + cpu->env.dedicated = dedicated; + cpu->env.entitlement = entitlement; + + /* topology tree is reflected in props */ + s390_update_cpu_props(ms, cpu); + + /* Advertise the topology change */ + if (report_needed) { + s390_cpu_topology_set_changed(true); + } +} + +void qmp_set_cpu_topology(uint16_t core, + bool has_socket, uint16_t socket, + bool has_book, uint16_t book, + bool has_drawer, uint16_t drawer, + bool has_entitlement, CpuS390Entitlement entitlement, + bool has_dedicated, bool dedicated, + Error **errp) +{ + ERRP_GUARD(); + + if (!s390_has_topology()) { + error_setg(errp, "This machine doesn't support topology"); + return; + } + + s390_change_topology(core, has_socket, socket, has_book, book, + has_drawer, drawer, has_entitlement, entitlement, + has_dedicated, dedicated, errp); +}