From: Jiri Denemark <jdenemar@redhat.com>
qom-list-get is a new QMP command (since QEMU 10.1) that combines
qom-list for listing properties of a specified object with qom-get for
getting a value of a given property. The new command provides an array
of all properties and their values, which allows us to dramatically
reduce the number of QMP commands we have to call when starting a domain
to check which CPU features were actually enabled.
A simple domain with no disk can now be started with only 15 QMP
commands in about 200 ms compared to 485 commands and 400 ms startup
time without this patch.
https://issues.redhat.com/browse/RHEL-7038
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
---
src/qemu/qemu_capabilities.c | 2 +
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_monitor.c | 13 +++-
src/qemu/qemu_monitor.h | 1 +
src/qemu/qemu_monitor_json.c | 73 ++++++++++++++++---
src/qemu/qemu_monitor_json.h | 7 +-
src/qemu/qemu_process.c | 1 +
.../caps_10.1.0_x86_64.xml | 1 +
.../caps_10.2.0_x86_64.xml | 1 +
...=> get-guest-cpu-SierraForest-legacy.json} | 0
...> get-guest-cpu-SkylakeClient-legacy.json} | 0
tests/qemumonitorjsontest.c | 18 +++--
12 files changed, 92 insertions(+), 26 deletions(-)
rename tests/qemumonitorjsondata/{get-guest-cpu-SierraForest.json => get-guest-cpu-SierraForest-legacy.json} (100%)
rename tests/qemumonitorjsondata/{get-guest-cpu-SkylakeClient.json => get-guest-cpu-SkylakeClient-legacy.json} (100%)
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 688d100b01..b7174c657d 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -742,6 +742,7 @@ VIR_ENUM_IMPL(virQEMUCaps,
"amd-iommu.pci-id", /* QEMU_CAPS_AMD_IOMMU_PCI_ID */
"usb-bot", /* QEMU_CAPS_DEVICE_USB_BOT */
"tdx-guest", /* QEMU_CAPS_TDX_GUEST */
+ "qom-list-get", /* QEMU_CAPS_QOM_LIST_GET */
);
@@ -1256,6 +1257,7 @@ struct virQEMUCapsStringFlags virQEMUCapsCommands[] = {
{ "query-stats-schemas", QEMU_CAPS_QUERY_STATS_SCHEMAS },
{ "display-reload", QEMU_CAPS_DISPLAY_RELOAD },
{ "blockdev-set-active", QEMU_CAPS_BLOCKDEV_SET_ACTIVE },
+ { "qom-list-get", QEMU_CAPS_QOM_LIST_GET },
};
struct virQEMUCapsStringFlags virQEMUCapsObjectTypes[] = {
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 8916973364..f50d908b3f 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -723,6 +723,7 @@ typedef enum { /* virQEMUCapsFlags grouping marker for syntax-check */
QEMU_CAPS_AMD_IOMMU_PCI_ID, /* amd-iommu.pci-id */
QEMU_CAPS_DEVICE_USB_BOT, /* -device usb-bot */
QEMU_CAPS_TDX_GUEST, /* -object tdx-guest,... */
+ QEMU_CAPS_QOM_LIST_GET, /* qom-list-get QMP command */
QEMU_CAPS_LAST /* this must always be the last item */
} virQEMUCapsFlags;
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 0213bd5af8..176651eab4 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -3673,6 +3673,8 @@ qemuMonitorSetDomainLog(qemuMonitor *mon,
* qemuMonitorGetGuestCPU:
* @mon: Pointer to the monitor
* @arch: CPU architecture
+ * @qomListGet: QEMU supports getting list of features and their values using
+ * a single qom-list-get QMP command
* @cpuQOMPath: QOM path of a CPU to probe
* @translate: callback for translating CPU feature names from QEMU to libvirt
* @opaque: data for @translate callback
@@ -3687,13 +3689,16 @@ qemuMonitorSetDomainLog(qemuMonitor *mon,
int
qemuMonitorGetGuestCPU(qemuMonitor *mon,
virArch arch,
+ bool qomListGet,
const char *cpuQOMPath,
qemuMonitorCPUFeatureTranslationCallback translate,
virCPUData **enabled,
virCPUData **disabled)
{
- VIR_DEBUG("arch=%s cpuQOMPath=%s translate=%p enabled=%p disabled=%p",
- virArchToString(arch), cpuQOMPath, translate, enabled, disabled);
+ VIR_DEBUG("arch=%s qomListGet%d cpuQOMPath=%s translate=%p "
+ "enabled=%p disabled=%p",
+ virArchToString(arch), qomListGet, cpuQOMPath, translate,
+ enabled, disabled);
QEMU_CHECK_MONITOR(mon);
@@ -3701,8 +3706,8 @@ qemuMonitorGetGuestCPU(qemuMonitor *mon,
if (disabled)
*disabled = NULL;
- return qemuMonitorJSONGetGuestCPU(mon, arch, cpuQOMPath, translate,
- enabled, disabled);
+ return qemuMonitorJSONGetGuestCPU(mon, arch, qomListGet, cpuQOMPath,
+ translate, enabled, disabled);
}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 689a587ec6..750e7444fc 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1268,6 +1268,7 @@ typedef const char *(*qemuMonitorCPUFeatureTranslationCallback)(virArch arch,
int qemuMonitorGetGuestCPU(qemuMonitor *mon,
virArch arch,
+ bool qomListGet,
const char *cpuQOMPath,
qemuMonitorCPUFeatureTranslationCallback translate,
virCPUData **enabled,
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index 76118ea664..8c70279f6d 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -6596,6 +6596,7 @@ qemuMonitorJSONGetDeviceAliases(qemuMonitor *mon,
struct _qemuMonitorJSONCPUPropsFilterData {
qemuMonitor *mon;
+ bool values;
const char *cpuQOMPath;
};
@@ -6604,17 +6605,32 @@ qemuMonitorJSONCPUPropsFilter(const char *name,
virJSONValue *propData,
void *opaque)
{
- qemuMonitorJSONObjectProperty prop = { .type = QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN };
struct _qemuMonitorJSONCPUPropsFilterData *data = opaque;
+ bool enabled = false;
if (STRNEQ_NULLABLE(virJSONValueObjectGetString(propData, "type"), "bool"))
return 1;
- if (qemuMonitorJSONGetObjectProperty(data->mon, data->cpuQOMPath,
- name, &prop) < 0)
- return -1;
+ if (data->values) {
+ if (virJSONValueObjectGetBoolean(propData, "value", &enabled) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("property '%1$s' in reply data was missing value"),
+ name);
+ return -1;
+ }
+ } else {
+ qemuMonitorJSONObjectProperty prop = {
+ .type = QEMU_MONITOR_OBJECT_PROPERTY_BOOLEAN
+ };
- if (!prop.val.b)
+ if (qemuMonitorJSONGetObjectProperty(data->mon, data->cpuQOMPath,
+ name, &prop) < 0)
+ return -1;
+
+ enabled = prop.val.b;
+ }
+
+ if (!enabled)
return 1;
return 0;
@@ -6623,6 +6639,7 @@ qemuMonitorJSONCPUPropsFilter(const char *name,
static int
qemuMonitorJSONGetCPUProperties(qemuMonitor *mon,
+ bool qomListGet,
const char *cpuQOMPath,
char ***props)
{
@@ -6631,14 +6648,29 @@ qemuMonitorJSONGetCPUProperties(qemuMonitor *mon,
virJSONValue *array;
struct _qemuMonitorJSONCPUPropsFilterData filterData = {
.mon = mon,
+ .values = qomListGet,
.cpuQOMPath = cpuQOMPath,
};
*props = NULL;
- if (!(cmd = qemuMonitorJSONMakeCommand("qom-list",
- "s:path", cpuQOMPath,
- NULL)))
+ if (qomListGet) {
+ g_autoptr(virJSONValue) paths = virJSONValueNewArray();
+ g_autoptr(virJSONValue) path = virJSONValueNewString(g_strdup(cpuQOMPath));
+
+ if (virJSONValueArrayAppend(paths, &path) < 0)
+ return -1;
+
+ cmd = qemuMonitorJSONMakeCommand("qom-list-get",
+ "a:paths", &paths,
+ NULL);
+ } else {
+ cmd = qemuMonitorJSONMakeCommand("qom-list",
+ "s:path", cpuQOMPath,
+ NULL);
+ }
+
+ if (!cmd)
return -1;
if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
@@ -6650,6 +6682,22 @@ qemuMonitorJSONGetCPUProperties(qemuMonitor *mon,
if (!(array = qemuMonitorJSONGetReply(cmd, reply, VIR_JSON_TYPE_ARRAY)))
return -1;
+ if (qomListGet) {
+ if (virJSONValueArraySize(array) != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("'qom-list-get' returned unexpected number of paths"));
+ return -1;
+ }
+
+ array = virJSONValueObjectGetArray(virJSONValueArrayGet(array, 0),
+ "properties");
+ if (!array) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("reply data was missing 'properties' array"));
+ return -1;
+ }
+ }
+
return qemuMonitorJSONParsePropsList(array, qemuMonitorJSONCPUPropsFilter,
&filterData, props);
}
@@ -6657,6 +6705,7 @@ qemuMonitorJSONGetCPUProperties(qemuMonitor *mon,
static int
qemuMonitorJSONGetCPUData(qemuMonitor *mon,
+ bool qomListGet,
const char *cpuQOMPath,
qemuMonitorCPUFeatureTranslationCallback translate,
virCPUData *data)
@@ -6664,7 +6713,7 @@ qemuMonitorJSONGetCPUData(qemuMonitor *mon,
g_auto(GStrv) props = NULL;
char **p;
- if (qemuMonitorJSONGetCPUProperties(mon, cpuQOMPath, &props) < 0)
+ if (qemuMonitorJSONGetCPUProperties(mon, qomListGet, cpuQOMPath, &props) < 0)
return -1;
for (p = props; p && *p; p++) {
@@ -6712,6 +6761,8 @@ qemuMonitorJSONGetCPUDataDisabled(qemuMonitor *mon,
* qemuMonitorJSONGetGuestCPU:
* @mon: Pointer to the monitor
* @arch: CPU architecture
+ * @qomListGet: QEMU supports getting list of features and their values using
+ * a single qom-list-get QMP command
* @cpuQOMPath: QOM path of a CPU to probe
* @translate: callback for translating CPU feature names from QEMU to libvirt
* @opaque: data for @translate callback
@@ -6726,6 +6777,7 @@ qemuMonitorJSONGetCPUDataDisabled(qemuMonitor *mon,
int
qemuMonitorJSONGetGuestCPU(qemuMonitor *mon,
virArch arch,
+ bool qomListGet,
const char *cpuQOMPath,
qemuMonitorCPUFeatureTranslationCallback translate,
virCPUData **enabled,
@@ -6738,7 +6790,8 @@ qemuMonitorJSONGetGuestCPU(qemuMonitor *mon,
!(cpuDisabled = virCPUDataNew(arch)))
return -1;
- if (qemuMonitorJSONGetCPUData(mon, cpuQOMPath, translate, cpuEnabled) < 0)
+ if (qemuMonitorJSONGetCPUData(mon, qomListGet, cpuQOMPath,
+ translate, cpuEnabled) < 0)
return -1;
if (disabled &&
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index f076e637ba..f17769f7fe 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -558,15 +558,10 @@ int
qemuMonitorJSONGetDeviceAliases(qemuMonitor *mon,
char ***aliases);
-int
-qemuMonitorJSONGetGuestCPUx86(qemuMonitor *mon,
- const char *cpuQOMPath,
- virCPUData **data,
- virCPUData **disabled);
-
int
qemuMonitorJSONGetGuestCPU(qemuMonitor *mon,
virArch arch,
+ bool qomListGet,
const char *cpuQOMPath,
qemuMonitorCPUFeatureTranslationCallback translate,
virCPUData **enabled,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 2988ffb157..ead5bf3e48 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -4592,6 +4592,7 @@ qemuProcessFetchGuestCPU(virDomainObj *vm,
rc = qemuMonitorGetGuestCPU(priv->mon,
vm->def->os.arch,
+ virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_QOM_LIST_GET),
cpuQOMPath,
virQEMUCapsCPUFeatureFromQEMU,
&dataEnabled, &dataDisabled);
diff --git a/tests/qemucapabilitiesdata/caps_10.1.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_10.1.0_x86_64.xml
index dc3088ba2c..8c53b72b47 100644
--- a/tests/qemucapabilitiesdata/caps_10.1.0_x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_10.1.0_x86_64.xml
@@ -213,6 +213,7 @@
<flag name='amd-iommu.pci-id'/>
<flag name='usb-bot'/>
<flag name='tdx-guest'/>
+ <flag name='qom-list-get'/>
<version>10001000</version>
<microcodeVersion>43100286</microcodeVersion>
<package>v10.1.0</package>
diff --git a/tests/qemucapabilitiesdata/caps_10.2.0_x86_64.xml b/tests/qemucapabilitiesdata/caps_10.2.0_x86_64.xml
index 07826b1a6e..c7452772da 100644
--- a/tests/qemucapabilitiesdata/caps_10.2.0_x86_64.xml
+++ b/tests/qemucapabilitiesdata/caps_10.2.0_x86_64.xml
@@ -213,6 +213,7 @@
<flag name='amd-iommu.pci-id'/>
<flag name='usb-bot'/>
<flag name='tdx-guest'/>
+ <flag name='qom-list-get'/>
<version>10001050</version>
<microcodeVersion>43100287</microcodeVersion>
<package>v10.1.0-1-ge771ba98de</package>
diff --git a/tests/qemumonitorjsondata/get-guest-cpu-SierraForest.json b/tests/qemumonitorjsondata/get-guest-cpu-SierraForest-legacy.json
similarity index 100%
rename from tests/qemumonitorjsondata/get-guest-cpu-SierraForest.json
rename to tests/qemumonitorjsondata/get-guest-cpu-SierraForest-legacy.json
diff --git a/tests/qemumonitorjsondata/get-guest-cpu-SkylakeClient.json b/tests/qemumonitorjsondata/get-guest-cpu-SkylakeClient-legacy.json
similarity index 100%
rename from tests/qemumonitorjsondata/get-guest-cpu-SkylakeClient.json
rename to tests/qemumonitorjsondata/get-guest-cpu-SkylakeClient-legacy.json
diff --git a/tests/qemumonitorjsontest.c b/tests/qemumonitorjsontest.c
index c3e83fc728..9c857a209e 100644
--- a/tests/qemumonitorjsontest.c
+++ b/tests/qemumonitorjsontest.c
@@ -2773,6 +2773,7 @@ testQemuMonitorJSONGetSEVInfo(const void *opaque)
struct testQemuMonitorJSONGetGuestCPUData {
const char *name;
+ bool qomListGet;
virQEMUDriver driver;
GHashTable *schema;
};
@@ -2791,8 +2792,9 @@ testQemuMonitorJSONGetGuestCPU(const void *opaque)
g_autofree char *enabled = NULL;
g_autofree char *disabled = NULL;
bool failed = false;
+ const char *legacy = data->qomListGet ? "" : "-legacy";
- fileJSON = g_strdup_printf("%s-%s.json", base, data->name);
+ fileJSON = g_strdup_printf("%s-%s%s.json", base, data->name, legacy);
fileEnabled = g_strdup_printf("%s-%s-enabled.xml", base, data->name);
fileDisabled = g_strdup_printf("%s-%s-disabled.xml", base, data->name);
@@ -2802,6 +2804,7 @@ testQemuMonitorJSONGetGuestCPU(const void *opaque)
if (qemuMonitorJSONGetGuestCPU(qemuMonitorTestGetMonitor(mon),
VIR_ARCH_X86_64,
+ data->qomListGet,
"/machine/unattached/device[0]",
virQEMUCapsCPUFeatureFromQEMU,
&dataEnabled, &dataDisabled) < 0)
@@ -2884,11 +2887,14 @@ mymain(void)
ret = -1; \
} while (0)
-#define DO_TEST_GET_GUEST_CPU(name) \
+#define DO_TEST_GET_GUEST_CPU(name, qomListGet) \
do { \
struct testQemuMonitorJSONGetGuestCPUData data = { \
- name, driver, qapiData.schema }; \
- if (virTestRun("GetGuestCPU(" name ")", \
+ name, qomListGet, driver, qapiData.schema }; \
+ g_autofree char *label = NULL; \
+ label = g_strdup_printf("GetGuestCPU(%s, legacy=%s)", \
+ name, qomListGet ? "false" : "true"); \
+ if (virTestRun(label, \
testQemuMonitorJSONGetGuestCPU, \
&data) < 0) \
ret = -1; \
@@ -2984,8 +2990,8 @@ mymain(void)
DO_TEST_CPU_INFO("s390", 2);
- DO_TEST_GET_GUEST_CPU("SierraForest");
- DO_TEST_GET_GUEST_CPU("SkylakeClient");
+ DO_TEST_GET_GUEST_CPU("SierraForest", false);
+ DO_TEST_GET_GUEST_CPU("SkylakeClient", false);
#define DO_TEST_QAPI_QUERY(nme, qry, scc, rplobj) \
--
2.51.0
© 2016 - 2025 Red Hat, Inc.