Machine core patches
- Clarify qdev_connect_gpio_out() documentation - Rework test-smp-parse tests following QOM style - Introduce CPU cluster topology support (Yanan Wang) - MAINTAINERS updates (Yanan Wang, Li Zhijian, myself) -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+qvnXhKRciHc/Wuy4+MsLN6twN4FAmHO+28ACgkQ4+MsLN6t wN53UhAAt4T6k2g4qiBTdvzU3QREGbpBedXsBQU8REykIBmHHG+9PH9QGOejZu9I a7i9V2FH1TgNsuIo4DdC01p8Pvrpyy6tJc4GNL8wrXHWKyfPn8e/pOgHFtgxLSWD msalW4Q5dQba2qTUXFNT9IBhAnRds56LBnKfseqWFEQyVahbep/MqN41nTJXLmbW W0FPivutMp9eKCMjivnjegrWW1Nht/01pMSCphEAsHjjICXjvzIpRJvJIB+kh/pK zG7hO+eynFlbbIGBgwU51ANEV7c+/8I0sLAI0O6cfswPdVZxY929DElgDjT7YxIl mQBdalEiaHX0cgzY91o/wwJ2lRk5xtVy+hV+PsBIP0RTrcJLAqel7Xsv9eXB1uCr /XtEvQbKDo0oP4z9/huxwJkXSZ4FX/UAyAPZQxYhqv3iVbtBhmUD1WN87WKC53Rk DbJn7jj+xmcA3SfwN8EdEFn87K72w3t1u7SJnP7w3naLTz5mREKB2K6Z2oCdvtAh XTKxIkAOQ9eWQPJYi/2SA8B2xwWfKV7vw2+PT8/eKdKgcmhbcZFqqSSrP7YX3QeW RtwCQB8FSS2kT1WCaNkKtKMZykZVYvX8gzzsGSww60GCqPDR33BRp7lqi/VlDdmV XBuKLm9vuBA+zJawcZKjv7diwlZTy2kaDOyf+wAnGZso/4HOSHU= =gP1z -----END PGP SIGNATURE----- Merge tag 'machine-core-20211231' of https://github.com/philmd/qemu into staging Machine core patches - Clarify qdev_connect_gpio_out() documentation - Rework test-smp-parse tests following QOM style - Introduce CPU cluster topology support (Yanan Wang) - MAINTAINERS updates (Yanan Wang, Li Zhijian, myself) # gpg: Signature made Fri 31 Dec 2021 04:45:35 AM PST # gpg: using RSA key FAABE75E12917221DCFD6BB2E3E32C2CDEADC0DE # gpg: Good signature from "Philippe Mathieu-Daudé (F4BUG) <f4bug@amsat.org>" [full] * tag 'machine-core-20211231' of https://github.com/philmd/qemu: MAINTAINERS: email address change MAINTAINERS: Change philmd's email address MAINTAINERS: Self-recommended as reviewer of "Machine core" tests/unit/test-smp-parse: Keep default MIN/MAX CPUs in machine_base_class_init tests/unit/test-smp-parse: No need to explicitly zero MachineClass members tests/unit/test-smp-parse: Add testcases for CPU clusters hw/core/machine: Introduce CPU cluster topology support qemu-options: Improve readability of SMP related Docs hw/core: Rename smp_parse() -> machine_parse_smp_config() tests/unit/test-smp-parse: Constify some pointer/struct tests/unit/test-smp-parse: Simplify pointer to compound literal use tests/unit/test-smp-parse: Add 'smp-generic-valid' machine type tests/unit/test-smp-parse: Add 'smp-generic-invalid' machine type tests/unit/test-smp-parse: Add 'smp-with-dies' machine type tests/unit/test-smp-parse: Split the 'generic' test in valid / invalid tests/unit/test-smp-parse: Pass machine type as argument to tests hw/qdev: Rename qdev_connect_gpio_out*() 'input_pin' parameter hw/qdev: Correct qdev_connect_gpio_out_named() documentation hw/qdev: Correct qdev_init_gpio_out_named() documentation hw/qdev: Cosmetic around documentation Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
814a050530
@ -3,7 +3,7 @@
|
|||||||
#
|
#
|
||||||
FROM ubuntu:16.04
|
FROM ubuntu:16.04
|
||||||
|
|
||||||
MAINTAINER Philippe Mathieu-Daudé <philmd@redhat.com>
|
MAINTAINER Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||||
|
|
||||||
# Install packages required to build EDK2
|
# Install packages required to build EDK2
|
||||||
RUN apt update \
|
RUN apt update \
|
||||||
|
1
.mailmap
1
.mailmap
@ -63,6 +63,7 @@ Paul Burton <paulburton@kernel.org> <paul.burton@mips.com>
|
|||||||
Paul Burton <paulburton@kernel.org> <paul.burton@imgtec.com>
|
Paul Burton <paulburton@kernel.org> <paul.burton@imgtec.com>
|
||||||
Paul Burton <paulburton@kernel.org> <paul@archlinuxmips.org>
|
Paul Burton <paulburton@kernel.org> <paul@archlinuxmips.org>
|
||||||
Paul Burton <paulburton@kernel.org> <pburton@wavecomp.com>
|
Paul Burton <paulburton@kernel.org> <pburton@wavecomp.com>
|
||||||
|
Philippe Mathieu-Daudé <f4bug@amsat.org> <philmd@redhat.com>
|
||||||
Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
|
Stefan Brankovic <stefan.brankovic@syrmia.com> <stefan.brankovic@rt-rk.com.com>
|
||||||
Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
|
Yongbok Kim <yongbok.kim@mips.com> <yongbok.kim@imgtec.com>
|
||||||
|
|
||||||
|
21
MAINTAINERS
21
MAINTAINERS
@ -1630,7 +1630,8 @@ F: pc-bios/bios-microvm.bin
|
|||||||
Machine core
|
Machine core
|
||||||
M: Eduardo Habkost <eduardo@habkost.net>
|
M: Eduardo Habkost <eduardo@habkost.net>
|
||||||
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
|
M: Marcel Apfelbaum <marcel.apfelbaum@gmail.com>
|
||||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||||
|
R: Yanan Wang <wangyanan55@huawei.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: cpu.c
|
F: cpu.c
|
||||||
F: hw/core/cpu.c
|
F: hw/core/cpu.c
|
||||||
@ -1810,7 +1811,7 @@ F: docs/virtio-net-failover.rst
|
|||||||
T: git https://github.com/jasowang/qemu.git net
|
T: git https://github.com/jasowang/qemu.git net
|
||||||
|
|
||||||
Parallel NOR Flash devices
|
Parallel NOR Flash devices
|
||||||
M: Philippe Mathieu-Daudé <philmd@redhat.com>
|
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||||
T: git https://gitlab.com/philmd/qemu.git pflash-next
|
T: git https://gitlab.com/philmd/qemu.git pflash-next
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: hw/block/pflash_cfi*.c
|
F: hw/block/pflash_cfi*.c
|
||||||
@ -2226,7 +2227,7 @@ F: hw/isa/piix4.c
|
|||||||
F: include/hw/southbridge/piix.h
|
F: include/hw/southbridge/piix.h
|
||||||
|
|
||||||
Firmware configuration (fw_cfg)
|
Firmware configuration (fw_cfg)
|
||||||
M: Philippe Mathieu-Daudé <philmd@redhat.com>
|
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||||
R: Gerd Hoffmann <kraxel@redhat.com>
|
R: Gerd Hoffmann <kraxel@redhat.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: docs/specs/fw_cfg.txt
|
F: docs/specs/fw_cfg.txt
|
||||||
@ -2524,7 +2525,7 @@ F: scripts/coccinelle/errp-guard.cocci
|
|||||||
|
|
||||||
GDB stub
|
GDB stub
|
||||||
M: Alex Bennée <alex.bennee@linaro.org>
|
M: Alex Bennée <alex.bennee@linaro.org>
|
||||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: gdbstub*
|
F: gdbstub*
|
||||||
F: include/exec/gdbstub.h
|
F: include/exec/gdbstub.h
|
||||||
@ -2535,7 +2536,7 @@ Memory API
|
|||||||
M: Paolo Bonzini <pbonzini@redhat.com>
|
M: Paolo Bonzini <pbonzini@redhat.com>
|
||||||
M: Peter Xu <peterx@redhat.com>
|
M: Peter Xu <peterx@redhat.com>
|
||||||
M: David Hildenbrand <david@redhat.com>
|
M: David Hildenbrand <david@redhat.com>
|
||||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: include/exec/ioport.h
|
F: include/exec/ioport.h
|
||||||
F: include/exec/memop.h
|
F: include/exec/memop.h
|
||||||
@ -2981,7 +2982,7 @@ F: docs/COLO-FT.txt
|
|||||||
|
|
||||||
COLO Proxy
|
COLO Proxy
|
||||||
M: Zhang Chen <chen.zhang@intel.com>
|
M: Zhang Chen <chen.zhang@intel.com>
|
||||||
M: Li Zhijian <lizhijian@cn.fujitsu.com>
|
M: Li Zhijian <lizhijian@fujitsu.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: docs/colo-proxy.txt
|
F: docs/colo-proxy.txt
|
||||||
F: net/colo*
|
F: net/colo*
|
||||||
@ -3029,14 +3030,14 @@ F: include/hw/i2c/smbus_slave.h
|
|||||||
F: include/hw/i2c/smbus_eeprom.h
|
F: include/hw/i2c/smbus_eeprom.h
|
||||||
|
|
||||||
Firmware schema specifications
|
Firmware schema specifications
|
||||||
M: Philippe Mathieu-Daudé <philmd@redhat.com>
|
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||||
R: Daniel P. Berrange <berrange@redhat.com>
|
R: Daniel P. Berrange <berrange@redhat.com>
|
||||||
R: Kashyap Chamarthy <kchamart@redhat.com>
|
R: Kashyap Chamarthy <kchamart@redhat.com>
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: docs/interop/firmware.json
|
F: docs/interop/firmware.json
|
||||||
|
|
||||||
EDK2 Firmware
|
EDK2 Firmware
|
||||||
M: Philippe Mathieu-Daudé <philmd@redhat.com>
|
M: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||||
R: Gerd Hoffmann <kraxel@redhat.com>
|
R: Gerd Hoffmann <kraxel@redhat.com>
|
||||||
S: Supported
|
S: Supported
|
||||||
F: hw/i386/*ovmf*
|
F: hw/i386/*ovmf*
|
||||||
@ -3274,7 +3275,7 @@ F: block/null.c
|
|||||||
NVMe Block Driver
|
NVMe Block Driver
|
||||||
M: Stefan Hajnoczi <stefanha@redhat.com>
|
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||||
R: Fam Zheng <fam@euphon.net>
|
R: Fam Zheng <fam@euphon.net>
|
||||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||||
L: qemu-block@nongnu.org
|
L: qemu-block@nongnu.org
|
||||||
S: Supported
|
S: Supported
|
||||||
F: block/nvme*
|
F: block/nvme*
|
||||||
@ -3517,7 +3518,7 @@ F: tests/tcg/Makefile.include
|
|||||||
Integration Testing with the Avocado framework
|
Integration Testing with the Avocado framework
|
||||||
W: https://trello.com/b/6Qi1pxVn/avocado-qemu
|
W: https://trello.com/b/6Qi1pxVn/avocado-qemu
|
||||||
R: Cleber Rosa <crosa@redhat.com>
|
R: Cleber Rosa <crosa@redhat.com>
|
||||||
R: Philippe Mathieu-Daudé <philmd@redhat.com>
|
R: Philippe Mathieu-Daudé <f4bug@amsat.org>
|
||||||
R: Wainer dos Santos Moschetta <wainersm@redhat.com>
|
R: Wainer dos Santos Moschetta <wainersm@redhat.com>
|
||||||
R: Beraldo Leal <bleal@redhat.com>
|
R: Beraldo Leal <bleal@redhat.com>
|
||||||
S: Odd Fixes
|
S: Odd Fixes
|
||||||
|
@ -115,17 +115,18 @@ qemu_irq qdev_get_gpio_in(DeviceState *dev, int n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
||||||
qemu_irq pin)
|
qemu_irq input_pin)
|
||||||
{
|
{
|
||||||
char *propname = g_strdup_printf("%s[%d]",
|
char *propname = g_strdup_printf("%s[%d]",
|
||||||
name ? name : "unnamed-gpio-out", n);
|
name ? name : "unnamed-gpio-out", n);
|
||||||
if (pin && !OBJECT(pin)->parent) {
|
if (input_pin && !OBJECT(input_pin)->parent) {
|
||||||
/* We need a name for object_property_set_link to work */
|
/* We need a name for object_property_set_link to work */
|
||||||
object_property_add_child(container_get(qdev_get_machine(),
|
object_property_add_child(container_get(qdev_get_machine(),
|
||||||
"/unattached"),
|
"/unattached"),
|
||||||
"non-qdev-gpio[*]", OBJECT(pin));
|
"non-qdev-gpio[*]", OBJECT(input_pin));
|
||||||
}
|
}
|
||||||
object_property_set_link(OBJECT(dev), propname, OBJECT(pin), &error_abort);
|
object_property_set_link(OBJECT(dev), propname,
|
||||||
|
OBJECT(input_pin), &error_abort);
|
||||||
g_free(propname);
|
g_free(propname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,9 +166,9 @@ qemu_irq qdev_intercept_gpio_out(DeviceState *dev, qemu_irq icpt,
|
|||||||
return disconnected;
|
return disconnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin)
|
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq input_pin)
|
||||||
{
|
{
|
||||||
qdev_connect_gpio_out_named(dev, NULL, n, pin);
|
qdev_connect_gpio_out_named(dev, NULL, n, input_pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
|
void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
|
||||||
|
@ -37,6 +37,10 @@ static char *cpu_hierarchy_to_string(MachineState *ms)
|
|||||||
g_string_append_printf(s, " * dies (%u)", ms->smp.dies);
|
g_string_append_printf(s, " * dies (%u)", ms->smp.dies);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mc->smp_props.clusters_supported) {
|
||||||
|
g_string_append_printf(s, " * clusters (%u)", ms->smp.clusters);
|
||||||
|
}
|
||||||
|
|
||||||
g_string_append_printf(s, " * cores (%u)", ms->smp.cores);
|
g_string_append_printf(s, " * cores (%u)", ms->smp.cores);
|
||||||
g_string_append_printf(s, " * threads (%u)", ms->smp.threads);
|
g_string_append_printf(s, " * threads (%u)", ms->smp.threads);
|
||||||
|
|
||||||
@ -44,7 +48,8 @@ static char *cpu_hierarchy_to_string(MachineState *ms)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* smp_parse - Generic function used to parse the given SMP configuration
|
* machine_parse_smp_config: Generic function used to parse the given
|
||||||
|
* SMP configuration
|
||||||
*
|
*
|
||||||
* Any missing parameter in "cpus/maxcpus/sockets/cores/threads" will be
|
* Any missing parameter in "cpus/maxcpus/sockets/cores/threads" will be
|
||||||
* automatically computed based on the provided ones.
|
* automatically computed based on the provided ones.
|
||||||
@ -63,12 +68,14 @@ static char *cpu_hierarchy_to_string(MachineState *ms)
|
|||||||
* introduced topology members which are likely to be target specific should
|
* introduced topology members which are likely to be target specific should
|
||||||
* be directly set as 1 if they are omitted (e.g. dies for PC since 4.1).
|
* be directly set as 1 if they are omitted (e.g. dies for PC since 4.1).
|
||||||
*/
|
*/
|
||||||
void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
|
void machine_parse_smp_config(MachineState *ms,
|
||||||
|
const SMPConfiguration *config, Error **errp)
|
||||||
{
|
{
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
MachineClass *mc = MACHINE_GET_CLASS(ms);
|
||||||
unsigned cpus = config->has_cpus ? config->cpus : 0;
|
unsigned cpus = config->has_cpus ? config->cpus : 0;
|
||||||
unsigned sockets = config->has_sockets ? config->sockets : 0;
|
unsigned sockets = config->has_sockets ? config->sockets : 0;
|
||||||
unsigned dies = config->has_dies ? config->dies : 0;
|
unsigned dies = config->has_dies ? config->dies : 0;
|
||||||
|
unsigned clusters = config->has_clusters ? config->clusters : 0;
|
||||||
unsigned cores = config->has_cores ? config->cores : 0;
|
unsigned cores = config->has_cores ? config->cores : 0;
|
||||||
unsigned threads = config->has_threads ? config->threads : 0;
|
unsigned threads = config->has_threads ? config->threads : 0;
|
||||||
unsigned maxcpus = config->has_maxcpus ? config->maxcpus : 0;
|
unsigned maxcpus = config->has_maxcpus ? config->maxcpus : 0;
|
||||||
@ -80,6 +87,7 @@ void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
|
|||||||
if ((config->has_cpus && config->cpus == 0) ||
|
if ((config->has_cpus && config->cpus == 0) ||
|
||||||
(config->has_sockets && config->sockets == 0) ||
|
(config->has_sockets && config->sockets == 0) ||
|
||||||
(config->has_dies && config->dies == 0) ||
|
(config->has_dies && config->dies == 0) ||
|
||||||
|
(config->has_clusters && config->clusters == 0) ||
|
||||||
(config->has_cores && config->cores == 0) ||
|
(config->has_cores && config->cores == 0) ||
|
||||||
(config->has_threads && config->threads == 0) ||
|
(config->has_threads && config->threads == 0) ||
|
||||||
(config->has_maxcpus && config->maxcpus == 0)) {
|
(config->has_maxcpus && config->maxcpus == 0)) {
|
||||||
@ -95,8 +103,13 @@ void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
|
|||||||
error_setg(errp, "dies not supported by this machine's CPU topology");
|
error_setg(errp, "dies not supported by this machine's CPU topology");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!mc->smp_props.clusters_supported && clusters > 1) {
|
||||||
|
error_setg(errp, "clusters not supported by this machine's CPU topology");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
dies = dies > 0 ? dies : 1;
|
dies = dies > 0 ? dies : 1;
|
||||||
|
clusters = clusters > 0 ? clusters : 1;
|
||||||
|
|
||||||
/* compute missing values based on the provided ones */
|
/* compute missing values based on the provided ones */
|
||||||
if (cpus == 0 && maxcpus == 0) {
|
if (cpus == 0 && maxcpus == 0) {
|
||||||
@ -111,41 +124,42 @@ void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp)
|
|||||||
if (sockets == 0) {
|
if (sockets == 0) {
|
||||||
cores = cores > 0 ? cores : 1;
|
cores = cores > 0 ? cores : 1;
|
||||||
threads = threads > 0 ? threads : 1;
|
threads = threads > 0 ? threads : 1;
|
||||||
sockets = maxcpus / (dies * cores * threads);
|
sockets = maxcpus / (dies * clusters * cores * threads);
|
||||||
} else if (cores == 0) {
|
} else if (cores == 0) {
|
||||||
threads = threads > 0 ? threads : 1;
|
threads = threads > 0 ? threads : 1;
|
||||||
cores = maxcpus / (sockets * dies * threads);
|
cores = maxcpus / (sockets * dies * clusters * threads);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* prefer cores over sockets since 6.2 */
|
/* prefer cores over sockets since 6.2 */
|
||||||
if (cores == 0) {
|
if (cores == 0) {
|
||||||
sockets = sockets > 0 ? sockets : 1;
|
sockets = sockets > 0 ? sockets : 1;
|
||||||
threads = threads > 0 ? threads : 1;
|
threads = threads > 0 ? threads : 1;
|
||||||
cores = maxcpus / (sockets * dies * threads);
|
cores = maxcpus / (sockets * dies * clusters * threads);
|
||||||
} else if (sockets == 0) {
|
} else if (sockets == 0) {
|
||||||
threads = threads > 0 ? threads : 1;
|
threads = threads > 0 ? threads : 1;
|
||||||
sockets = maxcpus / (dies * cores * threads);
|
sockets = maxcpus / (dies * clusters * cores * threads);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* try to calculate omitted threads at last */
|
/* try to calculate omitted threads at last */
|
||||||
if (threads == 0) {
|
if (threads == 0) {
|
||||||
threads = maxcpus / (sockets * dies * cores);
|
threads = maxcpus / (sockets * dies * clusters * cores);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
maxcpus = maxcpus > 0 ? maxcpus : sockets * dies * cores * threads;
|
maxcpus = maxcpus > 0 ? maxcpus : sockets * dies * clusters * cores * threads;
|
||||||
cpus = cpus > 0 ? cpus : maxcpus;
|
cpus = cpus > 0 ? cpus : maxcpus;
|
||||||
|
|
||||||
ms->smp.cpus = cpus;
|
ms->smp.cpus = cpus;
|
||||||
ms->smp.sockets = sockets;
|
ms->smp.sockets = sockets;
|
||||||
ms->smp.dies = dies;
|
ms->smp.dies = dies;
|
||||||
|
ms->smp.clusters = clusters;
|
||||||
ms->smp.cores = cores;
|
ms->smp.cores = cores;
|
||||||
ms->smp.threads = threads;
|
ms->smp.threads = threads;
|
||||||
ms->smp.max_cpus = maxcpus;
|
ms->smp.max_cpus = maxcpus;
|
||||||
|
|
||||||
/* sanity-check of the computed topology */
|
/* sanity-check of the computed topology */
|
||||||
if (sockets * dies * cores * threads != maxcpus) {
|
if (sockets * dies * clusters * cores * threads != maxcpus) {
|
||||||
g_autofree char *topo_msg = cpu_hierarchy_to_string(ms);
|
g_autofree char *topo_msg = cpu_hierarchy_to_string(ms);
|
||||||
error_setg(errp, "Invalid CPU topology: "
|
error_setg(errp, "Invalid CPU topology: "
|
||||||
"product of the hierarchy must match maxcpus: "
|
"product of the hierarchy must match maxcpus: "
|
||||||
|
@ -742,10 +742,12 @@ static void machine_get_smp(Object *obj, Visitor *v, const char *name,
|
|||||||
.has_cpus = true, .cpus = ms->smp.cpus,
|
.has_cpus = true, .cpus = ms->smp.cpus,
|
||||||
.has_sockets = true, .sockets = ms->smp.sockets,
|
.has_sockets = true, .sockets = ms->smp.sockets,
|
||||||
.has_dies = true, .dies = ms->smp.dies,
|
.has_dies = true, .dies = ms->smp.dies,
|
||||||
|
.has_clusters = true, .clusters = ms->smp.clusters,
|
||||||
.has_cores = true, .cores = ms->smp.cores,
|
.has_cores = true, .cores = ms->smp.cores,
|
||||||
.has_threads = true, .threads = ms->smp.threads,
|
.has_threads = true, .threads = ms->smp.threads,
|
||||||
.has_maxcpus = true, .maxcpus = ms->smp.max_cpus,
|
.has_maxcpus = true, .maxcpus = ms->smp.max_cpus,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!visit_type_SMPConfiguration(v, name, &config, &error_abort)) {
|
if (!visit_type_SMPConfiguration(v, name, &config, &error_abort)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -761,7 +763,7 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
smp_parse(ms, config, errp);
|
machine_parse_smp_config(ms, config, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void machine_class_init(ObjectClass *oc, void *data)
|
static void machine_class_init(ObjectClass *oc, void *data)
|
||||||
@ -932,6 +934,7 @@ static void machine_initfn(Object *obj)
|
|||||||
ms->smp.max_cpus = mc->default_cpus;
|
ms->smp.max_cpus = mc->default_cpus;
|
||||||
ms->smp.sockets = 1;
|
ms->smp.sockets = 1;
|
||||||
ms->smp.dies = 1;
|
ms->smp.dies = 1;
|
||||||
|
ms->smp.clusters = 1;
|
||||||
ms->smp.cores = 1;
|
ms->smp.cores = 1;
|
||||||
ms->smp.threads = 1;
|
ms->smp.threads = 1;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,8 @@ HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine);
|
|||||||
void machine_set_cpu_numa_node(MachineState *machine,
|
void machine_set_cpu_numa_node(MachineState *machine,
|
||||||
const CpuInstanceProperties *props,
|
const CpuInstanceProperties *props,
|
||||||
Error **errp);
|
Error **errp);
|
||||||
void smp_parse(MachineState *ms, SMPConfiguration *config, Error **errp);
|
void machine_parse_smp_config(MachineState *ms,
|
||||||
|
const SMPConfiguration *config, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* machine_class_allow_dynamic_sysbus_dev: Add type to list of valid devices
|
* machine_class_allow_dynamic_sysbus_dev: Add type to list of valid devices
|
||||||
@ -128,10 +129,12 @@ typedef struct {
|
|||||||
* SMPCompatProps:
|
* SMPCompatProps:
|
||||||
* @prefer_sockets - whether sockets are preferred over cores in smp parsing
|
* @prefer_sockets - whether sockets are preferred over cores in smp parsing
|
||||||
* @dies_supported - whether dies are supported by the machine
|
* @dies_supported - whether dies are supported by the machine
|
||||||
|
* @clusters_supported - whether clusters are supported by the machine
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool prefer_sockets;
|
bool prefer_sockets;
|
||||||
bool dies_supported;
|
bool dies_supported;
|
||||||
|
bool clusters_supported;
|
||||||
} SMPCompatProps;
|
} SMPCompatProps;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -298,7 +301,8 @@ typedef struct DeviceMemoryState {
|
|||||||
* @cpus: the number of present logical processors on the machine
|
* @cpus: the number of present logical processors on the machine
|
||||||
* @sockets: the number of sockets on the machine
|
* @sockets: the number of sockets on the machine
|
||||||
* @dies: the number of dies in one socket
|
* @dies: the number of dies in one socket
|
||||||
* @cores: the number of cores in one die
|
* @clusters: the number of clusters in one die
|
||||||
|
* @cores: the number of cores in one cluster
|
||||||
* @threads: the number of threads in one core
|
* @threads: the number of threads in one core
|
||||||
* @max_cpus: the maximum number of logical processors on the machine
|
* @max_cpus: the maximum number of logical processors on the machine
|
||||||
*/
|
*/
|
||||||
@ -306,6 +310,7 @@ typedef struct CpuTopology {
|
|||||||
unsigned int cpus;
|
unsigned int cpus;
|
||||||
unsigned int sockets;
|
unsigned int sockets;
|
||||||
unsigned int dies;
|
unsigned int dies;
|
||||||
|
unsigned int clusters;
|
||||||
unsigned int cores;
|
unsigned int cores;
|
||||||
unsigned int threads;
|
unsigned int threads;
|
||||||
unsigned int max_cpus;
|
unsigned int max_cpus;
|
||||||
|
@ -321,6 +321,7 @@ compat_props_add(GPtrArray *arr,
|
|||||||
* The returned object has a reference count of 1.
|
* The returned object has a reference count of 1.
|
||||||
*/
|
*/
|
||||||
DeviceState *qdev_new(const char *name);
|
DeviceState *qdev_new(const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_try_new: Try to create a device on the heap
|
* qdev_try_new: Try to create a device on the heap
|
||||||
* @name: device type to create
|
* @name: device type to create
|
||||||
@ -329,6 +330,7 @@ DeviceState *qdev_new(const char *name);
|
|||||||
* does not exist, rather than asserting.
|
* does not exist, rather than asserting.
|
||||||
*/
|
*/
|
||||||
DeviceState *qdev_try_new(const char *name);
|
DeviceState *qdev_try_new(const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_realize: Realize @dev.
|
* qdev_realize: Realize @dev.
|
||||||
* @dev: device to realize
|
* @dev: device to realize
|
||||||
@ -347,6 +349,7 @@ DeviceState *qdev_try_new(const char *name);
|
|||||||
* qdev_realize_and_unref() instead.
|
* qdev_realize_and_unref() instead.
|
||||||
*/
|
*/
|
||||||
bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp);
|
bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_realize_and_unref: Realize @dev and drop a reference
|
* qdev_realize_and_unref: Realize @dev and drop a reference
|
||||||
* @dev: device to realize
|
* @dev: device to realize
|
||||||
@ -372,6 +375,7 @@ bool qdev_realize(DeviceState *dev, BusState *bus, Error **errp);
|
|||||||
* would be incorrect. For that use case you want qdev_realize().
|
* would be incorrect. For that use case you want qdev_realize().
|
||||||
*/
|
*/
|
||||||
bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp);
|
bool qdev_realize_and_unref(DeviceState *dev, BusState *bus, Error **errp);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_unrealize: Unrealize a device
|
* qdev_unrealize: Unrealize a device
|
||||||
* @dev: device to unrealize
|
* @dev: device to unrealize
|
||||||
@ -450,6 +454,7 @@ typedef enum {
|
|||||||
* For named input GPIO lines, use qdev_get_gpio_in_named().
|
* For named input GPIO lines, use qdev_get_gpio_in_named().
|
||||||
*/
|
*/
|
||||||
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
|
qemu_irq qdev_get_gpio_in(DeviceState *dev, int n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_get_gpio_in_named: Get one of a device's named input GPIO lines
|
* qdev_get_gpio_in_named: Get one of a device's named input GPIO lines
|
||||||
* @dev: Device whose GPIO we want
|
* @dev: Device whose GPIO we want
|
||||||
@ -471,7 +476,7 @@ qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n);
|
|||||||
* qdev_connect_gpio_out: Connect one of a device's anonymous output GPIO lines
|
* qdev_connect_gpio_out: Connect one of a device's anonymous output GPIO lines
|
||||||
* @dev: Device whose GPIO to connect
|
* @dev: Device whose GPIO to connect
|
||||||
* @n: Number of the anonymous output GPIO line (which must be in range)
|
* @n: Number of the anonymous output GPIO line (which must be in range)
|
||||||
* @pin: qemu_irq to connect the output line to
|
* @input_pin: qemu_irq to connect the output line to
|
||||||
*
|
*
|
||||||
* This function connects an anonymous output GPIO line on a device
|
* This function connects an anonymous output GPIO line on a device
|
||||||
* up to an arbitrary qemu_irq, so that when the device asserts that
|
* up to an arbitrary qemu_irq, so that when the device asserts that
|
||||||
@ -497,12 +502,14 @@ qemu_irq qdev_get_gpio_in_named(DeviceState *dev, const char *name, int n);
|
|||||||
* For named output GPIO lines, use qdev_connect_gpio_out_named().
|
* For named output GPIO lines, use qdev_connect_gpio_out_named().
|
||||||
*/
|
*/
|
||||||
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
|
void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_connect_gpio_out: Connect one of a device's anonymous output GPIO lines
|
* qdev_connect_gpio_out_named: Connect one of a device's named output
|
||||||
|
* GPIO lines
|
||||||
* @dev: Device whose GPIO to connect
|
* @dev: Device whose GPIO to connect
|
||||||
* @name: Name of the output GPIO array
|
* @name: Name of the output GPIO array
|
||||||
* @n: Number of the anonymous output GPIO line (which must be in range)
|
* @n: Number of the anonymous output GPIO line (which must be in range)
|
||||||
* @pin: qemu_irq to connect the output line to
|
* @input_pin: qemu_irq to connect the output line to
|
||||||
*
|
*
|
||||||
* This function connects an anonymous output GPIO line on a device
|
* This function connects an anonymous output GPIO line on a device
|
||||||
* up to an arbitrary qemu_irq, so that when the device asserts that
|
* up to an arbitrary qemu_irq, so that when the device asserts that
|
||||||
@ -520,10 +527,11 @@ void qdev_connect_gpio_out(DeviceState *dev, int n, qemu_irq pin);
|
|||||||
* qemu_irqs at once, or to connect multiple outbound GPIOs to the
|
* qemu_irqs at once, or to connect multiple outbound GPIOs to the
|
||||||
* same qemu_irq; see qdev_connect_gpio_out() for details.
|
* same qemu_irq; see qdev_connect_gpio_out() for details.
|
||||||
*
|
*
|
||||||
* For named output GPIO lines, use qdev_connect_gpio_out_named().
|
* For anonymous output GPIO lines, use qdev_connect_gpio_out().
|
||||||
*/
|
*/
|
||||||
void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
||||||
qemu_irq pin);
|
qemu_irq input_pin);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_get_gpio_out_connector: Get the qemu_irq connected to an output GPIO
|
* qdev_get_gpio_out_connector: Get the qemu_irq connected to an output GPIO
|
||||||
* @dev: Device whose output GPIO we are interested in
|
* @dev: Device whose output GPIO we are interested in
|
||||||
@ -541,6 +549,7 @@ void qdev_connect_gpio_out_named(DeviceState *dev, const char *name, int n,
|
|||||||
* by the platform-bus subsystem.
|
* by the platform-bus subsystem.
|
||||||
*/
|
*/
|
||||||
qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n);
|
qemu_irq qdev_get_gpio_out_connector(DeviceState *dev, const char *name, int n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_intercept_gpio_out: Intercept an existing GPIO connection
|
* qdev_intercept_gpio_out: Intercept an existing GPIO connection
|
||||||
* @dev: Device to intercept the outbound GPIO line from
|
* @dev: Device to intercept the outbound GPIO line from
|
||||||
@ -582,6 +591,7 @@ BusState *qdev_get_child_bus(DeviceState *dev, const char *name);
|
|||||||
* hold of an input GPIO line to manipulate it.
|
* hold of an input GPIO line to manipulate it.
|
||||||
*/
|
*/
|
||||||
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
|
void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_init_gpio_out: create an array of anonymous output GPIO lines
|
* qdev_init_gpio_out: create an array of anonymous output GPIO lines
|
||||||
* @dev: Device to create output GPIOs for
|
* @dev: Device to create output GPIOs for
|
||||||
@ -610,8 +620,9 @@ void qdev_init_gpio_in(DeviceState *dev, qemu_irq_handler handler, int n);
|
|||||||
* handler.
|
* handler.
|
||||||
*/
|
*/
|
||||||
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
|
void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_init_gpio_out: create an array of named output GPIO lines
|
* qdev_init_gpio_out_named: create an array of named output GPIO lines
|
||||||
* @dev: Device to create output GPIOs for
|
* @dev: Device to create output GPIOs for
|
||||||
* @pins: Pointer to qemu_irq or qemu_irq array for the GPIO lines
|
* @pins: Pointer to qemu_irq or qemu_irq array for the GPIO lines
|
||||||
* @name: Name to give this array of GPIO lines
|
* @name: Name to give this array of GPIO lines
|
||||||
@ -623,6 +634,7 @@ void qdev_init_gpio_out(DeviceState *dev, qemu_irq *pins, int n);
|
|||||||
*/
|
*/
|
||||||
void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
|
void qdev_init_gpio_out_named(DeviceState *dev, qemu_irq *pins,
|
||||||
const char *name, int n);
|
const char *name, int n);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* qdev_init_gpio_in_named_with_opaque: create an array of input GPIO lines
|
* qdev_init_gpio_in_named_with_opaque: create an array of input GPIO lines
|
||||||
* for the specified device
|
* for the specified device
|
||||||
|
@ -1404,7 +1404,9 @@
|
|||||||
#
|
#
|
||||||
# @dies: number of dies per socket in the CPU topology
|
# @dies: number of dies per socket in the CPU topology
|
||||||
#
|
#
|
||||||
# @cores: number of cores per die in the CPU topology
|
# @clusters: number of clusters per die in the CPU topology (since 7.0)
|
||||||
|
#
|
||||||
|
# @cores: number of cores per cluster in the CPU topology
|
||||||
#
|
#
|
||||||
# @threads: number of threads per core in the CPU topology
|
# @threads: number of threads per core in the CPU topology
|
||||||
#
|
#
|
||||||
@ -1416,6 +1418,7 @@
|
|||||||
'*cpus': 'int',
|
'*cpus': 'int',
|
||||||
'*sockets': 'int',
|
'*sockets': 'int',
|
||||||
'*dies': 'int',
|
'*dies': 'int',
|
||||||
|
'*clusters': 'int',
|
||||||
'*cores': 'int',
|
'*cores': 'int',
|
||||||
'*threads': 'int',
|
'*threads': 'int',
|
||||||
'*maxcpus': 'int' } }
|
'*maxcpus': 'int' } }
|
||||||
|
@ -206,17 +206,30 @@ SRST
|
|||||||
ERST
|
ERST
|
||||||
|
|
||||||
DEF("smp", HAS_ARG, QEMU_OPTION_smp,
|
DEF("smp", HAS_ARG, QEMU_OPTION_smp,
|
||||||
"-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]\n"
|
"-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]\n"
|
||||||
" set the number of CPUs to 'n' [default=1]\n"
|
" set the number of initial CPUs to 'n' [default=1]\n"
|
||||||
" maxcpus= maximum number of total CPUs, including\n"
|
" maxcpus= maximum number of total CPUs, including\n"
|
||||||
" offline CPUs for hotplug, etc\n"
|
" offline CPUs for hotplug, etc\n"
|
||||||
" sockets= number of discrete sockets in the system\n"
|
" sockets= number of sockets on the machine board\n"
|
||||||
" dies= number of CPU dies on one socket (for PC only)\n"
|
" dies= number of dies in one socket\n"
|
||||||
" cores= number of CPU cores on one socket (for PC, it's on one die)\n"
|
" clusters= number of clusters in one die\n"
|
||||||
" threads= number of threads on one CPU core\n",
|
" cores= number of cores in one cluster\n"
|
||||||
|
" threads= number of threads in one core\n"
|
||||||
|
"Note: Different machines may have different subsets of the CPU topology\n"
|
||||||
|
" parameters supported, so the actual meaning of the supported parameters\n"
|
||||||
|
" will vary accordingly. For example, for a machine type that supports a\n"
|
||||||
|
" three-level CPU hierarchy of sockets/cores/threads, the parameters will\n"
|
||||||
|
" sequentially mean as below:\n"
|
||||||
|
" sockets means the number of sockets on the machine board\n"
|
||||||
|
" cores means the number of cores in one socket\n"
|
||||||
|
" threads means the number of threads in one core\n"
|
||||||
|
" For a particular machine type board, an expected CPU topology hierarchy\n"
|
||||||
|
" can be defined through the supported sub-option. Unsupported parameters\n"
|
||||||
|
" can also be provided in addition to the sub-option, but their values\n"
|
||||||
|
" must be set as 1 in the purpose of correct parsing.\n",
|
||||||
QEMU_ARCH_ALL)
|
QEMU_ARCH_ALL)
|
||||||
SRST
|
SRST
|
||||||
``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,cores=cores][,threads=threads]``
|
``-smp [[cpus=]n][,maxcpus=maxcpus][,sockets=sockets][,dies=dies][,clusters=clusters][,cores=cores][,threads=threads]``
|
||||||
Simulate a SMP system with '\ ``n``\ ' CPUs initially present on
|
Simulate a SMP system with '\ ``n``\ ' CPUs initially present on
|
||||||
the machine type board. On boards supporting CPU hotplug, the optional
|
the machine type board. On boards supporting CPU hotplug, the optional
|
||||||
'\ ``maxcpus``\ ' parameter can be set to enable further CPUs to be
|
'\ ``maxcpus``\ ' parameter can be set to enable further CPUs to be
|
||||||
@ -225,27 +238,57 @@ SRST
|
|||||||
initial CPU count will match the maximum number. When only one of them
|
initial CPU count will match the maximum number. When only one of them
|
||||||
is given then the omitted one will be set to its counterpart's value.
|
is given then the omitted one will be set to its counterpart's value.
|
||||||
Both parameters may be specified, but the maximum number of CPUs must
|
Both parameters may be specified, but the maximum number of CPUs must
|
||||||
be equal to or greater than the initial CPU count. Both parameters are
|
be equal to or greater than the initial CPU count. Product of the
|
||||||
subject to an upper limit that is determined by the specific machine
|
CPU topology hierarchy must be equal to the maximum number of CPUs.
|
||||||
type chosen.
|
Both parameters are subject to an upper limit that is determined by
|
||||||
|
the specific machine type chosen.
|
||||||
|
|
||||||
To control reporting of CPU topology information, the number of sockets,
|
To control reporting of CPU topology information, values of the topology
|
||||||
dies per socket, cores per die, and threads per core can be specified.
|
parameters can be specified. Machines may only support a subset of the
|
||||||
The sum `` sockets * cores * dies * threads `` must be equal to the
|
parameters and different machines may have different subsets supported
|
||||||
maximum CPU count. CPU targets may only support a subset of the topology
|
which vary depending on capacity of the corresponding CPU targets. So
|
||||||
parameters. Where a CPU target does not support use of a particular
|
for a particular machine type board, an expected topology hierarchy can
|
||||||
topology parameter, its value should be assumed to be 1 for the purpose
|
be defined through the supported sub-option. Unsupported parameters can
|
||||||
of computing the CPU maximum count.
|
also be provided in addition to the sub-option, but their values must be
|
||||||
|
set as 1 in the purpose of correct parsing.
|
||||||
|
|
||||||
Either the initial CPU count, or at least one of the topology parameters
|
Either the initial CPU count, or at least one of the topology parameters
|
||||||
must be specified. The specified parameters must be greater than zero,
|
must be specified. The specified parameters must be greater than zero,
|
||||||
explicit configuration like "cpus=0" is not allowed. Values for any
|
explicit configuration like "cpus=0" is not allowed. Values for any
|
||||||
omitted parameters will be computed from those which are given.
|
omitted parameters will be computed from those which are given.
|
||||||
|
|
||||||
|
For example, the following sub-option defines a CPU topology hierarchy
|
||||||
|
(2 sockets totally on the machine, 2 cores per socket, 2 threads per
|
||||||
|
core) for a machine that only supports sockets/cores/threads.
|
||||||
|
Some members of the option can be omitted but their values will be
|
||||||
|
automatically computed:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-smp 8,sockets=2,cores=2,threads=2,maxcpus=8
|
||||||
|
|
||||||
|
The following sub-option defines a CPU topology hierarchy (2 sockets
|
||||||
|
totally on the machine, 2 dies per socket, 2 cores per die, 2 threads
|
||||||
|
per core) for PC machines which support sockets/dies/cores/threads.
|
||||||
|
Some members of the option can be omitted but their values will be
|
||||||
|
automatically computed:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-smp 16,sockets=2,dies=2,cores=2,threads=2,maxcpus=16
|
||||||
|
|
||||||
Historically preference was given to the coarsest topology parameters
|
Historically preference was given to the coarsest topology parameters
|
||||||
when computing missing values (ie sockets preferred over cores, which
|
when computing missing values (ie sockets preferred over cores, which
|
||||||
were preferred over threads), however, this behaviour is considered
|
were preferred over threads), however, this behaviour is considered
|
||||||
liable to change. Prior to 6.2 the preference was sockets over cores
|
liable to change. Prior to 6.2 the preference was sockets over cores
|
||||||
over threads. Since 6.2 the preference is cores over sockets over threads.
|
over threads. Since 6.2 the preference is cores over sockets over threads.
|
||||||
|
|
||||||
|
For example, the following option defines a machine board with 2 sockets
|
||||||
|
of 1 core before 6.2 and 1 socket of 2 cores after 6.2:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
-smp 2
|
||||||
ERST
|
ERST
|
||||||
|
|
||||||
DEF("numa", HAS_ARG, QEMU_OPTION_numa,
|
DEF("numa", HAS_ARG, QEMU_OPTION_numa,
|
||||||
|
@ -726,6 +726,9 @@ static QemuOptsList qemu_smp_opts = {
|
|||||||
}, {
|
}, {
|
||||||
.name = "dies",
|
.name = "dies",
|
||||||
.type = QEMU_OPT_NUMBER,
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
}, {
|
||||||
|
.name = "clusters",
|
||||||
|
.type = QEMU_OPT_NUMBER,
|
||||||
}, {
|
}, {
|
||||||
.name = "cores",
|
.name = "cores",
|
||||||
.type = QEMU_OPT_NUMBER,
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
@ -61,6 +61,20 @@
|
|||||||
.has_maxcpus = hf, .maxcpus = f, \
|
.has_maxcpus = hf, .maxcpus = f, \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Currently a 4-level topology hierarchy is supported on ARM virt machines
|
||||||
|
* -sockets/clusters/cores/threads
|
||||||
|
*/
|
||||||
|
#define SMP_CONFIG_WITH_CLUSTERS(ha, a, hb, b, hc, c, hd, d, he, e, hf, f) \
|
||||||
|
{ \
|
||||||
|
.has_cpus = ha, .cpus = a, \
|
||||||
|
.has_sockets = hb, .sockets = b, \
|
||||||
|
.has_clusters = hc, .clusters = c, \
|
||||||
|
.has_cores = hd, .cores = d, \
|
||||||
|
.has_threads = he, .threads = e, \
|
||||||
|
.has_maxcpus = hf, .maxcpus = f, \
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @config - the given SMP configuration
|
* @config - the given SMP configuration
|
||||||
* @expect_prefer_sockets - the expected parsing result for the
|
* @expect_prefer_sockets - the expected parsing result for the
|
||||||
@ -83,7 +97,7 @@ typedef struct SMPTestData {
|
|||||||
* then test the automatic calculation algorithm of the missing
|
* then test the automatic calculation algorithm of the missing
|
||||||
* values in the parser.
|
* values in the parser.
|
||||||
*/
|
*/
|
||||||
static struct SMPTestData data_generic_valid[] = {
|
static const struct SMPTestData data_generic_valid[] = {
|
||||||
{
|
{
|
||||||
/* config: no configuration provided
|
/* config: no configuration provided
|
||||||
* expect: cpus=1,sockets=1,cores=1,threads=1,maxcpus=1 */
|
* expect: cpus=1,sockets=1,cores=1,threads=1,maxcpus=1 */
|
||||||
@ -285,11 +299,15 @@ static struct SMPTestData data_generic_valid[] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct SMPTestData data_generic_invalid[] = {
|
static const struct SMPTestData data_generic_invalid[] = {
|
||||||
{
|
{
|
||||||
/* config: -smp 2,dies=2 */
|
/* config: -smp 2,dies=2 */
|
||||||
.config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0),
|
.config = SMP_CONFIG_WITH_DIES(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0),
|
||||||
.expect_error = "dies not supported by this machine's CPU topology",
|
.expect_error = "dies not supported by this machine's CPU topology",
|
||||||
|
}, {
|
||||||
|
/* config: -smp 2,clusters=2 */
|
||||||
|
.config = SMP_CONFIG_WITH_CLUSTERS(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0),
|
||||||
|
.expect_error = "clusters not supported by this machine's CPU topology",
|
||||||
}, {
|
}, {
|
||||||
/* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */
|
/* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */
|
||||||
.config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8),
|
.config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8),
|
||||||
@ -319,7 +337,7 @@ static struct SMPTestData data_generic_invalid[] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct SMPTestData data_with_dies_invalid[] = {
|
static const struct SMPTestData data_with_dies_invalid[] = {
|
||||||
{
|
{
|
||||||
/* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */
|
/* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */
|
||||||
.config = SMP_CONFIG_WITH_DIES(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16),
|
.config = SMP_CONFIG_WITH_DIES(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16),
|
||||||
@ -337,13 +355,32 @@ static struct SMPTestData data_with_dies_invalid[] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *smp_config_to_string(SMPConfiguration *config)
|
static const struct SMPTestData data_with_clusters_invalid[] = {
|
||||||
|
{
|
||||||
|
/* config: -smp 16,sockets=2,clusters=2,cores=4,threads=2,maxcpus=16 */
|
||||||
|
.config = SMP_CONFIG_WITH_CLUSTERS(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16),
|
||||||
|
.expect_error = "Invalid CPU topology: "
|
||||||
|
"product of the hierarchy must match maxcpus: "
|
||||||
|
"sockets (2) * clusters (2) * cores (4) * threads (2) "
|
||||||
|
"!= maxcpus (16)",
|
||||||
|
}, {
|
||||||
|
/* config: -smp 34,sockets=2,clusters=2,cores=4,threads=2,maxcpus=32 */
|
||||||
|
.config = SMP_CONFIG_WITH_CLUSTERS(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32),
|
||||||
|
.expect_error = "Invalid CPU topology: "
|
||||||
|
"maxcpus must be equal to or greater than smp: "
|
||||||
|
"sockets (2) * clusters (2) * cores (4) * threads (2) "
|
||||||
|
"== maxcpus (32) < smp_cpus (34)",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *smp_config_to_string(const SMPConfiguration *config)
|
||||||
{
|
{
|
||||||
return g_strdup_printf(
|
return g_strdup_printf(
|
||||||
"(SMPConfiguration) {\n"
|
"(SMPConfiguration) {\n"
|
||||||
" .has_cpus = %5s, cpus = %" PRId64 ",\n"
|
" .has_cpus = %5s, cpus = %" PRId64 ",\n"
|
||||||
" .has_sockets = %5s, sockets = %" PRId64 ",\n"
|
" .has_sockets = %5s, sockets = %" PRId64 ",\n"
|
||||||
" .has_dies = %5s, dies = %" PRId64 ",\n"
|
" .has_dies = %5s, dies = %" PRId64 ",\n"
|
||||||
|
" .has_clusters = %5s, clusters = %" PRId64 ",\n"
|
||||||
" .has_cores = %5s, cores = %" PRId64 ",\n"
|
" .has_cores = %5s, cores = %" PRId64 ",\n"
|
||||||
" .has_threads = %5s, threads = %" PRId64 ",\n"
|
" .has_threads = %5s, threads = %" PRId64 ",\n"
|
||||||
" .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n"
|
" .has_maxcpus = %5s, maxcpus = %" PRId64 ",\n"
|
||||||
@ -351,28 +388,30 @@ static char *smp_config_to_string(SMPConfiguration *config)
|
|||||||
config->has_cpus ? "true" : "false", config->cpus,
|
config->has_cpus ? "true" : "false", config->cpus,
|
||||||
config->has_sockets ? "true" : "false", config->sockets,
|
config->has_sockets ? "true" : "false", config->sockets,
|
||||||
config->has_dies ? "true" : "false", config->dies,
|
config->has_dies ? "true" : "false", config->dies,
|
||||||
|
config->has_clusters ? "true" : "false", config->clusters,
|
||||||
config->has_cores ? "true" : "false", config->cores,
|
config->has_cores ? "true" : "false", config->cores,
|
||||||
config->has_threads ? "true" : "false", config->threads,
|
config->has_threads ? "true" : "false", config->threads,
|
||||||
config->has_maxcpus ? "true" : "false", config->maxcpus);
|
config->has_maxcpus ? "true" : "false", config->maxcpus);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *cpu_topology_to_string(CpuTopology *topo)
|
static char *cpu_topology_to_string(const CpuTopology *topo)
|
||||||
{
|
{
|
||||||
return g_strdup_printf(
|
return g_strdup_printf(
|
||||||
"(CpuTopology) {\n"
|
"(CpuTopology) {\n"
|
||||||
" .cpus = %u,\n"
|
" .cpus = %u,\n"
|
||||||
" .sockets = %u,\n"
|
" .sockets = %u,\n"
|
||||||
" .dies = %u,\n"
|
" .dies = %u,\n"
|
||||||
|
" .clusters = %u,\n"
|
||||||
" .cores = %u,\n"
|
" .cores = %u,\n"
|
||||||
" .threads = %u,\n"
|
" .threads = %u,\n"
|
||||||
" .max_cpus = %u,\n"
|
" .max_cpus = %u,\n"
|
||||||
"}",
|
"}",
|
||||||
topo->cpus, topo->sockets, topo->dies,
|
topo->cpus, topo->sockets, topo->dies, topo->clusters,
|
||||||
topo->cores, topo->threads, topo->max_cpus);
|
topo->cores, topo->threads, topo->max_cpus);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void check_parse(MachineState *ms, SMPConfiguration *config,
|
static void check_parse(MachineState *ms, const SMPConfiguration *config,
|
||||||
CpuTopology *expect_topo, const char *expect_err,
|
const CpuTopology *expect_topo, const char *expect_err,
|
||||||
bool is_valid)
|
bool is_valid)
|
||||||
{
|
{
|
||||||
g_autofree char *config_str = smp_config_to_string(config);
|
g_autofree char *config_str = smp_config_to_string(config);
|
||||||
@ -380,8 +419,8 @@ static void check_parse(MachineState *ms, SMPConfiguration *config,
|
|||||||
g_autofree char *output_topo_str = NULL;
|
g_autofree char *output_topo_str = NULL;
|
||||||
Error *err = NULL;
|
Error *err = NULL;
|
||||||
|
|
||||||
/* call the generic parser smp_parse() */
|
/* call the generic parser */
|
||||||
smp_parse(ms, config, &err);
|
machine_parse_smp_config(ms, config, &err);
|
||||||
|
|
||||||
output_topo_str = cpu_topology_to_string(&ms->smp);
|
output_topo_str = cpu_topology_to_string(&ms->smp);
|
||||||
|
|
||||||
@ -391,6 +430,7 @@ static void check_parse(MachineState *ms, SMPConfiguration *config,
|
|||||||
(ms->smp.cpus == expect_topo->cpus) &&
|
(ms->smp.cpus == expect_topo->cpus) &&
|
||||||
(ms->smp.sockets == expect_topo->sockets) &&
|
(ms->smp.sockets == expect_topo->sockets) &&
|
||||||
(ms->smp.dies == expect_topo->dies) &&
|
(ms->smp.dies == expect_topo->dies) &&
|
||||||
|
(ms->smp.clusters == expect_topo->clusters) &&
|
||||||
(ms->smp.cores == expect_topo->cores) &&
|
(ms->smp.cores == expect_topo->cores) &&
|
||||||
(ms->smp.threads == expect_topo->threads) &&
|
(ms->smp.threads == expect_topo->threads) &&
|
||||||
(ms->smp.max_cpus == expect_topo->max_cpus)) {
|
(ms->smp.max_cpus == expect_topo->max_cpus)) {
|
||||||
@ -466,12 +506,17 @@ static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_valid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* The parsed results of the unsupported parameters should be 1 */
|
/* The parsed results of the unsupported parameters should be 1 */
|
||||||
static void unsupported_params_init(MachineClass *mc, SMPTestData *data)
|
static void unsupported_params_init(const MachineClass *mc, SMPTestData *data)
|
||||||
{
|
{
|
||||||
if (!mc->smp_props.dies_supported) {
|
if (!mc->smp_props.dies_supported) {
|
||||||
data->expect_prefer_sockets.dies = 1;
|
data->expect_prefer_sockets.dies = 1;
|
||||||
data->expect_prefer_cores.dies = 1;
|
data->expect_prefer_cores.dies = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mc->smp_props.clusters_supported) {
|
||||||
|
data->expect_prefer_sockets.clusters = 1;
|
||||||
|
data->expect_prefer_cores.clusters = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void machine_base_class_init(ObjectClass *oc, void *data)
|
static void machine_base_class_init(ObjectClass *oc, void *data)
|
||||||
@ -481,101 +526,171 @@ static void machine_base_class_init(ObjectClass *oc, void *data)
|
|||||||
mc->min_cpus = MIN_CPUS;
|
mc->min_cpus = MIN_CPUS;
|
||||||
mc->max_cpus = MAX_CPUS;
|
mc->max_cpus = MAX_CPUS;
|
||||||
|
|
||||||
mc->smp_props.prefer_sockets = true;
|
|
||||||
mc->smp_props.dies_supported = false;
|
|
||||||
|
|
||||||
mc->name = g_strdup(SMP_MACHINE_NAME);
|
mc->name = g_strdup(SMP_MACHINE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_generic(void)
|
static void machine_generic_invalid_class_init(ObjectClass *oc, void *data)
|
||||||
{
|
{
|
||||||
Object *obj = object_new(TYPE_MACHINE);
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
MachineState *ms = MACHINE(obj);
|
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(obj);
|
|
||||||
SMPTestData *data = &(SMPTestData){{ }};
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
|
|
||||||
*data = data_generic_valid[i];
|
|
||||||
unsupported_params_init(mc, data);
|
|
||||||
|
|
||||||
smp_parse_test(ms, data, true);
|
|
||||||
|
|
||||||
/* Unsupported parameters can be provided with their values as 1 */
|
|
||||||
data->config.has_dies = true;
|
|
||||||
data->config.dies = 1;
|
|
||||||
smp_parse_test(ms, data, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Force invalid min CPUs and max CPUs */
|
/* Force invalid min CPUs and max CPUs */
|
||||||
mc->min_cpus = 2;
|
mc->min_cpus = 2;
|
||||||
mc->max_cpus = 511;
|
mc->max_cpus = 511;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) {
|
static void machine_with_dies_class_init(ObjectClass *oc, void *data)
|
||||||
*data = data_generic_invalid[i];
|
{
|
||||||
unsupported_params_init(mc, data);
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
|
||||||
smp_parse_test(ms, data, false);
|
mc->smp_props.dies_supported = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void machine_with_clusters_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
MachineClass *mc = MACHINE_CLASS(oc);
|
||||||
|
|
||||||
|
mc->smp_props.clusters_supported = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_generic_valid(const void *opaque)
|
||||||
|
{
|
||||||
|
const char *machine_type = opaque;
|
||||||
|
Object *obj = object_new(machine_type);
|
||||||
|
MachineState *ms = MACHINE(obj);
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(obj);
|
||||||
|
SMPTestData data = {};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
|
||||||
|
data = data_generic_valid[i];
|
||||||
|
unsupported_params_init(mc, &data);
|
||||||
|
|
||||||
|
smp_parse_test(ms, &data, true);
|
||||||
|
|
||||||
|
/* Unsupported parameters can be provided with their values as 1 */
|
||||||
|
data.config.has_dies = true;
|
||||||
|
data.config.dies = 1;
|
||||||
|
smp_parse_test(ms, &data, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the supported min CPUs and max CPUs */
|
|
||||||
mc->min_cpus = MIN_CPUS;
|
|
||||||
mc->max_cpus = MAX_CPUS;
|
|
||||||
|
|
||||||
object_unref(obj);
|
object_unref(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_with_dies(void)
|
static void test_generic_invalid(const void *opaque)
|
||||||
{
|
{
|
||||||
Object *obj = object_new(TYPE_MACHINE);
|
const char *machine_type = opaque;
|
||||||
|
Object *obj = object_new(machine_type);
|
||||||
MachineState *ms = MACHINE(obj);
|
MachineState *ms = MACHINE(obj);
|
||||||
MachineClass *mc = MACHINE_GET_CLASS(obj);
|
MachineClass *mc = MACHINE_GET_CLASS(obj);
|
||||||
SMPTestData *data = &(SMPTestData){{ }};
|
SMPTestData data = {};
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) {
|
||||||
|
data = data_generic_invalid[i];
|
||||||
|
unsupported_params_init(mc, &data);
|
||||||
|
|
||||||
|
smp_parse_test(ms, &data, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
object_unref(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_with_dies(const void *opaque)
|
||||||
|
{
|
||||||
|
const char *machine_type = opaque;
|
||||||
|
Object *obj = object_new(machine_type);
|
||||||
|
MachineState *ms = MACHINE(obj);
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(obj);
|
||||||
|
SMPTestData data = {};
|
||||||
unsigned int num_dies = 2;
|
unsigned int num_dies = 2;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Force the SMP compat properties */
|
|
||||||
mc->smp_props.dies_supported = true;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
|
for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
|
||||||
*data = data_generic_valid[i];
|
data = data_generic_valid[i];
|
||||||
unsupported_params_init(mc, data);
|
unsupported_params_init(mc, &data);
|
||||||
|
|
||||||
/* when dies parameter is omitted, it will be set as 1 */
|
/* when dies parameter is omitted, it will be set as 1 */
|
||||||
data->expect_prefer_sockets.dies = 1;
|
data.expect_prefer_sockets.dies = 1;
|
||||||
data->expect_prefer_cores.dies = 1;
|
data.expect_prefer_cores.dies = 1;
|
||||||
|
|
||||||
smp_parse_test(ms, data, true);
|
smp_parse_test(ms, &data, true);
|
||||||
|
|
||||||
/* when dies parameter is specified */
|
/* when dies parameter is specified */
|
||||||
data->config.has_dies = true;
|
data.config.has_dies = true;
|
||||||
data->config.dies = num_dies;
|
data.config.dies = num_dies;
|
||||||
if (data->config.has_cpus) {
|
if (data.config.has_cpus) {
|
||||||
data->config.cpus *= num_dies;
|
data.config.cpus *= num_dies;
|
||||||
}
|
}
|
||||||
if (data->config.has_maxcpus) {
|
if (data.config.has_maxcpus) {
|
||||||
data->config.maxcpus *= num_dies;
|
data.config.maxcpus *= num_dies;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->expect_prefer_sockets.dies = num_dies;
|
data.expect_prefer_sockets.dies = num_dies;
|
||||||
data->expect_prefer_sockets.cpus *= num_dies;
|
data.expect_prefer_sockets.cpus *= num_dies;
|
||||||
data->expect_prefer_sockets.max_cpus *= num_dies;
|
data.expect_prefer_sockets.max_cpus *= num_dies;
|
||||||
data->expect_prefer_cores.dies = num_dies;
|
data.expect_prefer_cores.dies = num_dies;
|
||||||
data->expect_prefer_cores.cpus *= num_dies;
|
data.expect_prefer_cores.cpus *= num_dies;
|
||||||
data->expect_prefer_cores.max_cpus *= num_dies;
|
data.expect_prefer_cores.max_cpus *= num_dies;
|
||||||
|
|
||||||
smp_parse_test(ms, data, true);
|
smp_parse_test(ms, &data, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) {
|
for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) {
|
||||||
*data = data_with_dies_invalid[i];
|
data = data_with_dies_invalid[i];
|
||||||
unsupported_params_init(mc, data);
|
unsupported_params_init(mc, &data);
|
||||||
|
|
||||||
smp_parse_test(ms, data, false);
|
smp_parse_test(ms, &data, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore the SMP compat properties */
|
object_unref(obj);
|
||||||
mc->smp_props.dies_supported = false;
|
}
|
||||||
|
|
||||||
|
static void test_with_clusters(const void *opaque)
|
||||||
|
{
|
||||||
|
const char *machine_type = opaque;
|
||||||
|
Object *obj = object_new(machine_type);
|
||||||
|
MachineState *ms = MACHINE(obj);
|
||||||
|
MachineClass *mc = MACHINE_GET_CLASS(obj);
|
||||||
|
SMPTestData data = {};
|
||||||
|
unsigned int num_clusters = 2;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
|
||||||
|
data = data_generic_valid[i];
|
||||||
|
unsupported_params_init(mc, &data);
|
||||||
|
|
||||||
|
/* when clusters parameter is omitted, it will be set as 1 */
|
||||||
|
data.expect_prefer_sockets.clusters = 1;
|
||||||
|
data.expect_prefer_cores.clusters = 1;
|
||||||
|
|
||||||
|
smp_parse_test(ms, &data, true);
|
||||||
|
|
||||||
|
/* when clusters parameter is specified */
|
||||||
|
data.config.has_clusters = true;
|
||||||
|
data.config.clusters = num_clusters;
|
||||||
|
if (data.config.has_cpus) {
|
||||||
|
data.config.cpus *= num_clusters;
|
||||||
|
}
|
||||||
|
if (data.config.has_maxcpus) {
|
||||||
|
data.config.maxcpus *= num_clusters;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.expect_prefer_sockets.clusters = num_clusters;
|
||||||
|
data.expect_prefer_sockets.cpus *= num_clusters;
|
||||||
|
data.expect_prefer_sockets.max_cpus *= num_clusters;
|
||||||
|
data.expect_prefer_cores.clusters = num_clusters;
|
||||||
|
data.expect_prefer_cores.cpus *= num_clusters;
|
||||||
|
data.expect_prefer_cores.max_cpus *= num_clusters;
|
||||||
|
|
||||||
|
smp_parse_test(ms, &data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(data_with_clusters_invalid); i++) {
|
||||||
|
data = data_with_clusters_invalid[i];
|
||||||
|
unsupported_params_init(mc, &data);
|
||||||
|
|
||||||
|
smp_parse_test(ms, &data, false);
|
||||||
|
}
|
||||||
|
|
||||||
object_unref(obj);
|
object_unref(obj);
|
||||||
}
|
}
|
||||||
@ -585,9 +700,25 @@ static const TypeInfo smp_machine_types[] = {
|
|||||||
{
|
{
|
||||||
.name = TYPE_MACHINE,
|
.name = TYPE_MACHINE,
|
||||||
.parent = TYPE_OBJECT,
|
.parent = TYPE_OBJECT,
|
||||||
|
.abstract = true,
|
||||||
.class_init = machine_base_class_init,
|
.class_init = machine_base_class_init,
|
||||||
.class_size = sizeof(MachineClass),
|
.class_size = sizeof(MachineClass),
|
||||||
.instance_size = sizeof(MachineState),
|
.instance_size = sizeof(MachineState),
|
||||||
|
}, {
|
||||||
|
.name = MACHINE_TYPE_NAME("smp-generic-valid"),
|
||||||
|
.parent = TYPE_MACHINE,
|
||||||
|
}, {
|
||||||
|
.name = MACHINE_TYPE_NAME("smp-generic-invalid"),
|
||||||
|
.parent = TYPE_MACHINE,
|
||||||
|
.class_init = machine_generic_invalid_class_init,
|
||||||
|
}, {
|
||||||
|
.name = MACHINE_TYPE_NAME("smp-with-dies"),
|
||||||
|
.parent = TYPE_MACHINE,
|
||||||
|
.class_init = machine_with_dies_class_init,
|
||||||
|
}, {
|
||||||
|
.name = MACHINE_TYPE_NAME("smp-with-clusters"),
|
||||||
|
.parent = TYPE_MACHINE,
|
||||||
|
.class_init = machine_with_clusters_class_init,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -599,8 +730,18 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
|
|
||||||
g_test_add_func("/test-smp-parse/generic", test_generic);
|
g_test_add_data_func("/test-smp-parse/generic/valid",
|
||||||
g_test_add_func("/test-smp-parse/with_dies", test_with_dies);
|
MACHINE_TYPE_NAME("smp-generic-valid"),
|
||||||
|
test_generic_valid);
|
||||||
|
g_test_add_data_func("/test-smp-parse/generic/invalid",
|
||||||
|
MACHINE_TYPE_NAME("smp-generic-invalid"),
|
||||||
|
test_generic_invalid);
|
||||||
|
g_test_add_data_func("/test-smp-parse/with_dies",
|
||||||
|
MACHINE_TYPE_NAME("smp-with-dies"),
|
||||||
|
test_with_dies);
|
||||||
|
g_test_add_data_func("/test-smp-parse/with_clusters",
|
||||||
|
MACHINE_TYPE_NAME("smp-with-clusters"),
|
||||||
|
test_with_clusters);
|
||||||
|
|
||||||
g_test_run();
|
g_test_run();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user