On Thu, Sep 04, 2025 at 16:46:55 +0200, Jiri Denemark via Devel wrote:
> From: Jiri Denemark <jdene...@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 <jdene...@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;

Preferrably introduce new capabilities in separate patch.



> 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 "

qomListGet=%d instead of qomListGet%d

> +              "enabled=%p disabled=%p",
> +              virArchToString(arch), qomListGet, cpuQOMPath, translate,
> +              enabled, disabled);
>  
>      QEMU_CHECK_MONITOR(mon);
>  

[...]


> @@ -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;

How about 'virJSONValueArrayAppendString'? instead of the manual
construction?


> +
> +        cmd = qemuMonitorJSONMakeCommand("qom-list-get",
> +                                         "a:paths", &paths,
> +                                         NULL);
> +    } else {
> +        cmd = qemuMonitorJSONMakeCommand("qom-list",
> +                                         "s:path", cpuQOMPath,
> +                                         NULL);
> +    }


[...]

> 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);
> -

Leftover from 1/15?


>  int
>  qemuMonitorJSONGetGuestCPU(qemuMonitor *mon,
>                             virArch arch,
> +                           bool qomListGet,
>                             const char *cpuQOMPath,
>                             qemuMonitorCPUFeatureTranslationCallback 
> translate,
>                             virCPUData **enabled,


[...]

> --- 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"); \

Not converting it to a string can save you the ternary use.

With the caps separated and the nits addressed:

Reviewed-by: Peter Krempa <pkre...@redhat.com>

Reply via email to