]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu_monitor: add qemuMonitorQueryStats
authorAmneesh Singh <natto@weirdnatto.in>
Thu, 18 Aug 2022 03:17:18 +0000 (08:47 +0530)
committerMartin Kletzander <mkletzan@redhat.com>
Thu, 18 Aug 2022 13:09:49 +0000 (15:09 +0200)
Related: https://gitlab.com/libvirt/libvirt/-/issues/276

This patch adds an API for the "query-stats" QMP command.

The query returns a JSON containing the statistics based on the target,
which can either be vCPU or VM, and the providers. The API deserializes
the query result into an array of GHashMaps, which can later be used to
extract all the query statistics. GHashMaps are used to avoid traversing
the entire array to find the statistics you are looking for. This would
be a singleton array if the target is a VM since the returned JSON is
also a singleton array in that case.

Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
src/qemu/qemu_monitor.c
src/qemu/qemu_monitor.h
src/qemu/qemu_monitor_json.c
src/qemu/qemu_monitor_json.h

index 4739810c9b0d0d1d6891c5775badec9bb92f1312..c2808c75a355d5bd724dcefbab31be29fb258ea8 100644 (file)
@@ -4297,3 +4297,123 @@ qemuMonitorGetMigrationBlockers(qemuMonitor *mon,
 
     return qemuMonitorJSONGetMigrationBlockers(mon, blockers);
 }
+
+
+VIR_ENUM_IMPL(qemuMonitorQueryStatsTarget,
+              QEMU_MONITOR_QUERY_STATS_TARGET_LAST,
+              "vm",
+              "vcpu",
+);
+
+
+VIR_ENUM_IMPL(qemuMonitorQueryStatsName,
+              QEMU_MONITOR_QUERY_STATS_NAME_LAST,
+              "halt_poll_success_ns",
+              "halt_poll_fail_ns",
+);
+
+
+VIR_ENUM_IMPL(qemuMonitorQueryStatsProvider,
+              QEMU_MONITOR_QUERY_STATS_PROVIDER_LAST,
+              "kvm",
+);
+
+
+void
+qemuMonitorQueryStatsProviderFree(qemuMonitorQueryStatsProvider *provider)
+{
+    virBitmapFree(provider->names);
+    g_free(provider);
+}
+
+
+qemuMonitorQueryStatsProvider *
+qemuMonitorQueryStatsProviderNew(qemuMonitorQueryStatsProviderType provider_type,
+                                 ...)
+{
+    qemuMonitorQueryStatsProvider *provider = g_new0(qemuMonitorQueryStatsProvider, 1);
+    qemuMonitorQueryStatsNameType stat;
+    va_list name_list;
+
+    /*
+     * This can be lowered later in case of the enum getting quite large, hence
+     *  the virBitmapSetExpand below which also incidently makes this function
+     *  non-fallible.
+     */
+    provider->names = virBitmapNew(QEMU_MONITOR_QUERY_STATS_NAME_LAST);
+    provider->type = provider_type;
+
+    va_start(name_list, provider_type);
+
+    while ((stat = va_arg(name_list, qemuMonitorQueryStatsNameType)) !=
+           QEMU_MONITOR_QUERY_STATS_NAME_LAST)
+        virBitmapSetBitExpand(provider->names, stat);
+
+    va_end(name_list);
+
+    return provider;
+}
+
+
+virJSONValue *
+qemuMonitorQueryStats(qemuMonitor *mon,
+                      qemuMonitorQueryStatsTargetType target,
+                      char **vcpus,
+                      GPtrArray *providers)
+{
+    VIR_DEBUG("target=%u vcpus=%p providers=%p", target, vcpus, providers);
+
+    QEMU_CHECK_MONITOR_NULL(mon);
+
+    if (target != QEMU_MONITOR_QUERY_STATS_TARGET_VCPU && vcpus)
+        return NULL;
+
+    return qemuMonitorJSONQueryStats(mon, target, vcpus, providers);
+}
+
+
+/**
+ * qemuMonitorExtractQueryStats:
+ * @info: One of the array members returned by qemuMonitorQueryStat
+ *
+ * Converts all the statistics into a GHashTable similar to virQEMU
+ * except only object with the key "value" is stored as the value i
+ *
+ * Returns NULL on failure.
+ */
+GHashTable *
+qemuMonitorExtractQueryStats(virJSONValue *info)
+{
+    g_autoptr(GHashTable) hash_table = NULL;
+    virJSONValue *stats = NULL;
+    size_t i;
+
+    if (!virJSONValueIsObject(info))
+        return NULL;
+
+    stats = virJSONValueObjectGetArray(info, "stats");
+    if (!stats)
+        return NULL;
+
+    hash_table = virHashNew(virJSONValueHashFree);
+
+    for (i = 0; i < virJSONValueArraySize(stats); i++) {
+        virJSONValue *stat = virJSONValueArrayGet(stats, i);
+        virJSONValue *value = NULL;
+        const char *name = NULL;
+
+        if (!virJSONValueIsObject(stat))
+            continue;
+
+        name = virJSONValueObjectGetString(stat, "name");
+        if (!name)
+            continue;
+
+        if (virJSONValueObjectRemoveKey(stat, "value", &value) < 0)
+            continue;
+
+        virHashAddEntry(hash_table, name, value);
+    }
+
+    return g_steal_pointer(&hash_table);
+}
index 78e2ebf0bd86c5c233460f28e34137590513b628..63269e15bcc56e419305710e90abb799bf726594 100644 (file)
@@ -1481,3 +1481,51 @@ qemuMonitorMigrateRecover(qemuMonitor *mon,
 int
 qemuMonitorGetMigrationBlockers(qemuMonitor *mon,
                                 char ***blockers);
+
+typedef enum {
+    QEMU_MONITOR_QUERY_STATS_TARGET_VM,
+    QEMU_MONITOR_QUERY_STATS_TARGET_VCPU,
+    QEMU_MONITOR_QUERY_STATS_TARGET_LAST,
+} qemuMonitorQueryStatsTargetType;
+
+VIR_ENUM_DECL(qemuMonitorQueryStatsTarget);
+
+typedef enum {
+    QEMU_MONITOR_QUERY_STATS_NAME_HALT_POLL_SUCCESS_NS,
+    QEMU_MONITOR_QUERY_STATS_NAME_HALT_POLL_FAIL_NS,
+    QEMU_MONITOR_QUERY_STATS_NAME_LAST,
+} qemuMonitorQueryStatsNameType;
+
+VIR_ENUM_DECL(qemuMonitorQueryStatsName);
+
+typedef enum {
+    QEMU_MONITOR_QUERY_STATS_PROVIDER_KVM,
+    QEMU_MONITOR_QUERY_STATS_PROVIDER_LAST,
+} qemuMonitorQueryStatsProviderType;
+
+VIR_ENUM_DECL(qemuMonitorQueryStatsProvider);
+
+typedef struct _qemuMonitorQueryStatsProvider qemuMonitorQueryStatsProvider;
+struct _qemuMonitorQueryStatsProvider {
+    qemuMonitorQueryStatsProviderType type;
+    virBitmap *names;
+};
+
+void
+qemuMonitorQueryStatsProviderFree(qemuMonitorQueryStatsProvider *provider);
+
+qemuMonitorQueryStatsProvider *
+qemuMonitorQueryStatsProviderNew(qemuMonitorQueryStatsProviderType provider_type,
+                                 ...);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMonitorQueryStatsProvider,
+                              qemuMonitorQueryStatsProviderFree);
+
+virJSONValue *
+qemuMonitorQueryStats(qemuMonitor *mon,
+                      qemuMonitorQueryStatsTargetType target,
+                      char **vcpus,
+                      GPtrArray *providers);
+
+GHashTable *
+qemuMonitorExtractQueryStats(virJSONValue *info);
index d664e827dd33da2981be4cbe91b78e87560b4dd9..70fba50e6c3d439c96d1a09baa46b6a4604e5b71 100644 (file)
@@ -8574,3 +8574,94 @@ qemuMonitorJSONMigrateRecover(qemuMonitor *mon,
 
     return qemuMonitorJSONCheckError(cmd, reply);
 }
+
+
+/**
+ * qemuMonitorJSONQueryStats:
+ * @mon: monitor object
+ * @target: the target type for the query
+ * @vcpus: a list of vCPU QOM paths for filtering the statistics
+ * @providers: an array of providers to filter statistics
+ *
+ * @vcpus is a NULL terminated array of strings. @providers is a GPtrArray
+ * for qemuMonitorQueryStatsProvider.
+ * @vcpus and @providers are optional and can be NULL.
+ *
+ * Queries for the @target based statistics.
+ * Returns NULL on failure.
+ */
+virJSONValue *
+qemuMonitorJSONQueryStats(qemuMonitor *mon,
+                          qemuMonitorQueryStatsTargetType target,
+                          char **vcpus,
+                          GPtrArray *providers)
+{
+    g_autoptr(virJSONValue) cmd = NULL;
+    g_autoptr(virJSONValue) reply = NULL;
+    g_autoptr(virJSONValue) vcpu_list = NULL;
+    g_autoptr(virJSONValue) provider_list = NULL;
+
+    size_t i;
+
+    if (providers) {
+        provider_list = virJSONValueNewArray();
+
+        for (i = 0; i < providers->len; i++) {
+            g_autoptr(virJSONValue) provider_obj = virJSONValueNewObject();
+            qemuMonitorQueryStatsProvider *provider = providers->pdata[i];
+            const char *type_str = qemuMonitorQueryStatsProviderTypeToString(provider->type);
+            virBitmap *names = provider->names;
+            int rc;
+
+            rc = virJSONValueObjectAppendString(provider_obj, "provider", type_str);
+
+            if (rc < 0)
+                return NULL;
+
+            if (!virBitmapIsAllClear(names)) {
+                g_autoptr(virJSONValue) provider_names = virJSONValueNewArray();
+                ssize_t curBit = -1;
+
+                while ((curBit = virBitmapNextSetBit(names, curBit)) != -1) {
+                    const char *name = qemuMonitorQueryStatsNameTypeToString(curBit);
+
+                    if (virJSONValueArrayAppendString(provider_names, name) < 0)
+                        return NULL;
+                }
+
+                rc = virJSONValueObjectAppend(provider_obj, "names", &provider_names);
+
+                if (rc < 0)
+                    return NULL;
+            }
+
+            if (virJSONValueArrayAppend(provider_list, &provider_obj) < 0)
+                return NULL;
+        }
+    }
+
+    if (vcpus) {
+        vcpu_list = virJSONValueNewArray();
+
+        for (i = 0; vcpus[i]; i++)
+            if (virJSONValueArrayAppendString(vcpu_list, vcpus[i]) < 0)
+                return NULL;
+    }
+
+    cmd = qemuMonitorJSONMakeCommand("query-stats",
+                                     "s:target", qemuMonitorQueryStatsTargetTypeToString(target),
+                                     "A:vcpus", &vcpu_list,
+                                     "A:providers", &provider_list,
+                                     NULL);
+
+    if (!cmd)
+        return NULL;
+
+    if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+        return NULL;
+
+    if (qemuMonitorJSONCheckReply(cmd, reply, VIR_JSON_TYPE_ARRAY) < 0)
+        return NULL;
+
+    return virJSONValueObjectStealArray(reply, "return");
+}
index 5154c195c9b897e98690c7b29580f4ba27bbf4eb..a53e6423df2f208fc47067696a67acf3a5672902 100644 (file)
@@ -812,3 +812,9 @@ qemuMonitorJSONChangeMemoryRequestedSize(qemuMonitor *mon,
 int
 qemuMonitorJSONMigrateRecover(qemuMonitor *mon,
                               const char *uri);
+
+virJSONValue *
+qemuMonitorJSONQueryStats(qemuMonitor *mon,
+                          qemuMonitorQueryStatsTargetType target,
+                          char **vcpus,
+                          GPtrArray *providers);