]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
qemu: Use qom-list-get for checking enabled CPU features
authorJiri Denemark <jdenemar@redhat.com>
Mon, 25 Aug 2025 14:16:49 +0000 (16:16 +0200)
committerJiri Denemark <jdenemar@redhat.com>
Mon, 8 Sep 2025 13:32:47 +0000 (15:32 +0200)
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>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_json.h
src/qemu/qemu_process.c
tests/qemumonitorjsondata/get-guest-cpu-SierraForest-legacy.json [moved from tests/qemumonitorjsondata/get-guest-cpu-SierraForest.json with 100% similarity]
tests/qemumonitorjsondata/get-guest-cpu-SkylakeClient-legacy.json [moved from tests/qemumonitorjsondata/get-guest-cpu-SkylakeClient.json with 100% similarity]
tests/qemumonitorjsontest.c

index 0213bd5af8bdc17487d63e614ec4e8028bdab892..eec6905e9fb1dc41c9fb1f26ac1d737cd16648a9 100644 (file)
@@ -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);
 }
 
 
index 689a587ec66690f879f811d999030c9523e580b7..750e7444fc0d167cc8b142298428e1d81e172cdb 100644 (file)
@@ -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,
index 76118ea6640743a5e8576204e1fc492c26cc8d3a..7ef065ba453a2e5115e4f7d7de691eb022df9386 100644 (file)
@@ -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 (qemuMonitorJSONGetObjectProperty(data->mon, data->cpuQOMPath,
+                                             name, &prop) < 0)
+            return -1;
 
-    if (!prop.val.b)
+        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,28 @@ 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();
+
+        if (virJSONValueArrayAppendString(paths, cpuQOMPath) < 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 +6681,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 +6704,7 @@ qemuMonitorJSONGetCPUProperties(qemuMonitor *mon,
 
 static int
 qemuMonitorJSONGetCPUData(qemuMonitor *mon,
+                          bool qomListGet,
                           const char *cpuQOMPath,
                           qemuMonitorCPUFeatureTranslationCallback translate,
                           virCPUData *data)
@@ -6664,7 +6712,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 +6760,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 +6776,7 @@ qemuMonitorJSONGetCPUDataDisabled(qemuMonitor *mon,
 int
 qemuMonitorJSONGetGuestCPU(qemuMonitor *mon,
                            virArch arch,
+                           bool qomListGet,
                            const char *cpuQOMPath,
                            qemuMonitorCPUFeatureTranslationCallback translate,
                            virCPUData **enabled,
@@ -6738,7 +6789,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 &&
index 62050470e85e16ca42ecc9e9adf018223825b844..f17769f7fe22acaad08b719554f5fa5441bf01a3 100644 (file)
@@ -561,6 +561,7 @@ qemuMonitorJSONGetDeviceAliases(qemuMonitor *mon,
 int
 qemuMonitorJSONGetGuestCPU(qemuMonitor *mon,
                            virArch arch,
+                           bool qomListGet,
                            const char *cpuQOMPath,
                            qemuMonitorCPUFeatureTranslationCallback translate,
                            virCPUData **enabled,
index 2988ffb1578e4b421de1b2d9e2ff933c9b9126f0..ead5bf3e48d1297f47336bbefc8c5c37c6cb8591 100644 (file)
@@ -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);
index c3e83fc7284547bc4304993b2b451eea0fdaf6d2..02684b538dc6944742c81db7bbe2e9f02ea3b3b0 100644 (file)
@@ -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,13 @@ 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=%d)", name, qomListGet); \
+        if (virTestRun(label, \
                        testQemuMonitorJSONGetGuestCPU, \
                        &data) < 0) \
             ret = -1; \
@@ -2984,8 +2989,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) \