Message ID | 20230425161456.21031-9-pmorel@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | s390x: CPU Topology | expand |
On Tue, 2023-04-25 at 18:14 +0200, Pierre Morel wrote: > 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> Logic is sound, minor stuff below. > --- > qapi/machine-target.json | 37 +++++++++++ > hw/s390x/cpu-topology.c | 136 +++++++++++++++++++++++++++++++++++++++ > 2 files changed, 173 insertions(+) > > diff --git a/qapi/machine-target.json b/qapi/machine-target.json > index 42a6a40333..3b7a0b77f4 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: > # > @@ -354,3 +356,38 @@ > { 'enum': 'CpuS390Polarization', > 'prefix': 'S390_CPU_POLARIZATION', > 'data': [ 'horizontal', 'vertical' ] } > + > +## > +# @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.1 > +## > +{ '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 d9cd3dc3ce..e5fb976594 100644 > --- a/hw/s390x/cpu-topology.c > +++ b/hw/s390x/cpu-topology.c > @@ -16,6 +16,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. > @@ -261,6 +262,27 @@ 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 and dedicated are missing here. > + * > + * A modified topology change report is needed if the topology > + * tree or the topology attributes change. > + */ > +static int s390_topology_need_report(S390CPU *cpu, int drawer_id, I'd prefer a bool return type. > + 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 > @@ -330,3 +352,117 @@ 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, uint16_t entitlement, I would keep the enum type for entitlement. > + bool has_dedicated, bool dedicated, > + Error **errp) > +{ > + MachineState *ms = current_machine; > + int old_socket_entry; > + int new_socket_entry; > + int report_needed; > + S390CPU *cpu; > + ERRP_GUARD(); > + > + if (core_id >= ms->smp.max_cpus) { > + error_setg(errp, "Core-id %d out of range!", core_id); > + return; > + } > + > + cpu = (S390CPU *)ms->possible_cpus->cpus[core_id].cpu; You can replace this with cpu = s390_cpu_addr2state(core_id); and get rid of the if above that checks for out of range. > + 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(drawer_id, book_id, socket_id); > + > + if (new_socket_entry != old_socket_entry) { > + if (s390_topology.cores_per_socket[new_socket_entry] >= > + s390_topology.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); > +}
On 5/8/23 21:42, Nina Schoetterl-Glausch wrote: > On Tue, 2023-04-25 at 18:14 +0200, Pierre Morel wrote: >> 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> > Logic is sound, minor stuff below. > >> --- >> qapi/machine-target.json | 37 +++++++++++ >> hw/s390x/cpu-topology.c | 136 +++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 173 insertions(+) >> >> diff --git a/qapi/machine-target.json b/qapi/machine-target.json >> index 42a6a40333..3b7a0b77f4 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: >> # >> @@ -354,3 +356,38 @@ >> { 'enum': 'CpuS390Polarization', >> 'prefix': 'S390_CPU_POLARIZATION', >> 'data': [ 'horizontal', 'vertical' ] } >> + >> +## >> +# @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.1 >> +## >> +{ '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 d9cd3dc3ce..e5fb976594 100644 >> --- a/hw/s390x/cpu-topology.c >> +++ b/hw/s390x/cpu-topology.c >> @@ -16,6 +16,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. >> @@ -261,6 +262,27 @@ 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 and dedicated are missing here. Yes, thx > >> + * >> + * A modified topology change report is needed if the topology >> + * tree or the topology attributes change. >> + */ >> +static int s390_topology_need_report(S390CPU *cpu, int drawer_id, > I'd prefer a bool return type. ok > >> + 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 >> @@ -330,3 +352,117 @@ 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, uint16_t entitlement, > I would keep the enum type for entitlement. ok > >> + bool has_dedicated, bool dedicated, >> + Error **errp) >> +{ >> + MachineState *ms = current_machine; >> + int old_socket_entry; >> + int new_socket_entry; >> + int report_needed; >> + S390CPU *cpu; >> + ERRP_GUARD(); >> + >> + if (core_id >= ms->smp.max_cpus) { >> + error_setg(errp, "Core-id %d out of range!", core_id); >> + return; >> + } >> + >> + cpu = (S390CPU *)ms->possible_cpus->cpus[core_id].cpu; > You can replace this with > > cpu = s390_cpu_addr2state(core_id); > > and get rid of the if above that checks for out of range. yes, ok > >> + 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(drawer_id, book_id, socket_id); >> + >> + if (new_socket_entry != old_socket_entry) { >> + if (s390_topology.cores_per_socket[new_socket_entry] >= >> + s390_topology.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); >> +} Thanks I change this. regards, Pierre
diff --git a/qapi/machine-target.json b/qapi/machine-target.json index 42a6a40333..3b7a0b77f4 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: # @@ -354,3 +356,38 @@ { 'enum': 'CpuS390Polarization', 'prefix': 'S390_CPU_POLARIZATION', 'data': [ 'horizontal', 'vertical' ] } + +## +# @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.1 +## +{ '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 d9cd3dc3ce..e5fb976594 100644 --- a/hw/s390x/cpu-topology.c +++ b/hw/s390x/cpu-topology.c @@ -16,6 +16,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. @@ -261,6 +262,27 @@ 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 + * + * A modified topology change report is needed if the topology + * tree or the topology attributes change. + */ +static int 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 @@ -330,3 +352,117 @@ 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, uint16_t entitlement, + bool has_dedicated, bool dedicated, + Error **errp) +{ + MachineState *ms = current_machine; + int old_socket_entry; + int new_socket_entry; + int report_needed; + S390CPU *cpu; + ERRP_GUARD(); + + if (core_id >= ms->smp.max_cpus) { + error_setg(errp, "Core-id %d out of range!", core_id); + return; + } + + cpu = (S390CPU *)ms->possible_cpus->cpus[core_id].cpu; + 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(drawer_id, book_id, socket_id); + + if (new_socket_entry != old_socket_entry) { + if (s390_topology.cores_per_socket[new_socket_entry] >= + s390_topology.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); +}
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> --- qapi/machine-target.json | 37 +++++++++++ hw/s390x/cpu-topology.c | 136 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+)