[PATCH 1/3] qemu_monitor: add qemuMonitorQueryStats
Michal Prívozník
mprivozn at redhat.com
Tue Jun 28 15:23:09 UTC 2022
On 6/24/22 10:14, Amneesh Singh wrote:
> 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 at weirdnatto.in>
> ---
> src/qemu/qemu_monitor.c | 46 +++++++++++++
> src/qemu/qemu_monitor.h | 36 ++++++++++
> src/qemu/qemu_monitor_json.c | 128 +++++++++++++++++++++++++++++++++++
> src/qemu/qemu_monitor_json.h | 6 ++
> 4 files changed, 216 insertions(+)
>
> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index fda5d2f3..bedb5308 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -4541,3 +4541,49 @@ qemuMonitorMigrateRecover(qemuMonitor *mon,
>
> return qemuMonitorJSONMigrateRecover(mon, uri);
> }
> +
> +VIR_ENUM_IMPL(qemuMonitorQueryStatsTarget,
> + QEMU_MONITOR_QUERY_STATS_TARGET_LAST,
> + "vm",
> + "vcpu",
> +);
> +
> +VIR_ENUM_IMPL(qemuMonitorQueryStatsProvider,
> + QEMU_MONITOR_QUERY_STATS_PROVIDER_LAST,
> + "kvm",
> +);
> +
> +void
> +qemuMonitorQueryStatsProviderFree(qemuMonitorQueryStatsProvider *provider)
> +{
> + g_strfreev(provider->names);
> + g_free(provider);
> +}
> +
> +qemuMonitorQueryStatsProvider *
> +qemuMonitorQueryStatsProviderNew(qemuMonitorQueryStatsProviderType provider_type)
> +{
> + g_autoptr(qemuMonitorQueryStatsProvider) provider = NULL;
> +
> + provider = g_new0(qemuMonitorQueryStatsProvider, 1);
> + provider->provider = provider_type;
> + provider->names = NULL;
> +
> + return g_steal_pointer(&provider);
> +}
> +
> +GPtrArray *
> +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);
> +}
> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index 95267ec6..ddfdb526 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -1554,3 +1554,39 @@ qemuMonitorChangeMemoryRequestedSize(qemuMonitor *mon,
> int
> qemuMonitorMigrateRecover(qemuMonitor *mon,
> const char *uri);
> +
> +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_PROVIDER_KVM,
> + QEMU_MONITOR_QUERY_STATS_PROVIDER_LAST,
> +} qemuMonitorQueryStatsProviderType;
> +
> +VIR_ENUM_DECL(qemuMonitorQueryStatsProvider);
> +
> +typedef struct _qemuMonitorQueryStatsProvider qemuMonitorQueryStatsProvider;
> +struct _qemuMonitorQueryStatsProvider {
> + qemuMonitorQueryStatsProviderType provider;
> + GStrv names;
> +};
> +
> +void
> +qemuMonitorQueryStatsProviderFree(qemuMonitorQueryStatsProvider *provider);
> +
> +qemuMonitorQueryStatsProvider *
> +qemuMonitorQueryStatsProviderNew(qemuMonitorQueryStatsProviderType provider_type);
> +
> +G_DEFINE_AUTOPTR_CLEANUP_FUNC(qemuMonitorQueryStatsProvider,
> + qemuMonitorQueryStatsProviderFree);
> +
> +GPtrArray *
> +qemuMonitorQueryStats(qemuMonitor *mon,
> + qemuMonitorQueryStatsTargetType target,
> + char **vcpus,
> + GPtrArray *providers);
> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
> index 3aad2ab2..d6757042 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -9006,3 +9006,131 @@ qemuMonitorJSONMigrateRecover(qemuMonitor *mon,
>
> return qemuMonitorJSONCheckError(cmd, reply);
> }
> +
> +static GPtrArray *
> +qemuMonitorJSONExtractQueryStats(virJSONValue *arr)
> +{
> + g_autoptr(GPtrArray) queried_stats = NULL;
> + size_t nstats = virJSONValueArraySize(arr);
> + size_t i;
> +
> + /* Create a GPtrArray for GHashTables */
> + queried_stats = g_ptr_array_new_full(nstats, (GDestroyNotify) g_hash_table_destroy);
> +
> + for (i = 0; i < nstats; i++) {
> + virJSONValue *obj = virJSONValueArrayGet(arr, i);
> + virJSONValue *stats = virJSONValueObjectGetArray(obj, "stats");
> + size_t j;
> +
> + /* Create a GHashTable for virJSONValues */
> + GHashTable *hash_table = virHashNew((GDestroyNotify) virJSONValueFree);
> +
> + for (j = 0; j < virJSONValueArraySize(stats); j++) {
> + virJSONValue *stat = virJSONValueArrayGet(stats, j);
> +
> + g_hash_table_insert(hash_table,
> + g_strdup(virJSONValueObjectGetString(stat, "name")),
> + virJSONValueObjectGet(stat, "value"));
> + }
> +
> + g_ptr_array_add(queried_stats, hash_table);
> + }
> +
> + return g_steal_pointer(&queried_stats);
> +}
> +
> +
> +/**
> + * 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 a GPtrArray of GHashTables containing the statistics on success or
> + * NULL on failure.
> + */
> +
> +GPtrArray *
> +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;
> + virJSONValue *rv = NULL;
> +
> + size_t i;
> +
> + if (providers) {
> + provider_list = virJSONValueNewArray();
> +
> + for (i = 0; i < providers->len; i++) {
> + int rc;
> + g_autoptr(virJSONValue) provider_obj = virJSONValueNewObject();
> + qemuMonitorQueryStatsProvider *provider = providers->pdata[i];
> + const char *type_str = qemuMonitorQueryStatsProviderTypeToString(provider->provider);
Nit pick, I think this block would look a bit better if @rc was declared
at its end.
> +
> + rc = virJSONValueObjectAppendString(provider_obj, "provider", type_str);
> +
> + if (rc < 0)
> + return NULL;
> +
> + if (provider->names) {
> + g_autoptr(virJSONValue) providerNames = virJSONValueNewArray();
> + size_t j = 0;
> + const char *name = provider->names[j];
Another nitpick: here I'd prefer names[0] instead if names[j]. While it
may not matter now, @j and @name are declared next to each other, that
may not be always the case and I have to remember one thing less when
reading the code.
> +
> + while (name) {
> + if (virJSONValueArrayAppendString(providerNames, name) < 0)
> + return NULL;
> +
> + name = provider->names[++j];
> + }
> +
> + rc = virJSONValueObjectAppend(provider_obj, "names", &providerNames);
> +
> + if (rc < 0)
> + return NULL;
> + }
Misleading alignment.
> +
> + 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 (qemuMonitorJSONCheckError(cmd, reply) < 0)
> + return NULL;
> +
> + rv = virJSONValueObjectStealArray(reply, "return");
> +
> + return qemuMonitorJSONExtractQueryStats(rv);
> +}
Michal
More information about the libvir-list
mailing list