qmp: add filtering of statistics by provider

Allow retrieving the statistics from a specific provider only.
This can be used in the future by HMP commands such as "info
sync-profile" or "info profile".  The next patch also adds
filter-by-provider capabilities to the HMP equivalent of
query-stats, "info stats".

Example:

{ "execute": "query-stats",
  "arguments": {
    "target": "vm",
    "providers": [
      { "provider": "kvm" } ] } }

The QAPI is a bit more verbose than just a list of StatsProvider,
so that it can be subsequently extended with filtering of statistics
by name.

If a provider is specified more than once in the filter, each request
will be included separately in the output.

Extracted from a patch by Mark Kanda.

Reviewed-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Paolo Bonzini 2022-04-26 11:49:33 +02:00
parent 433815f5bd
commit 068cc51d42
5 changed files with 55 additions and 14 deletions

View File

@ -2644,7 +2644,8 @@ static int kvm_init(MachineState *ms)
} }
if (kvm_check_extension(kvm_state, KVM_CAP_BINARY_STATS_FD)) { if (kvm_check_extension(kvm_state, KVM_CAP_BINARY_STATS_FD)) {
add_stats_callbacks(query_stats_cb, query_stats_schemas_cb); add_stats_callbacks(STATS_PROVIDER_KVM, query_stats_cb,
query_stats_schemas_cb);
} }
return 0; return 0;

View File

@ -17,10 +17,12 @@ typedef void SchemaRetrieveFunc(StatsSchemaList **result, Error **errp);
/* /*
* Register callbacks for the QMP query-stats command. * Register callbacks for the QMP query-stats command.
* *
* @provider: stats provider checked against QMP command arguments
* @stats_fn: routine to query stats: * @stats_fn: routine to query stats:
* @schema_fn: routine to query stat schemas: * @schema_fn: routine to query stat schemas:
*/ */
void add_stats_callbacks(StatRetrieveFunc *stats_fn, void add_stats_callbacks(StatsProvider provider,
StatRetrieveFunc *stats_fn,
SchemaRetrieveFunc *schemas_fn); SchemaRetrieveFunc *schemas_fn);
/* /*

View File

@ -2397,7 +2397,7 @@ void hmp_info_stats(Monitor *mon, const QDict *qdict)
goto exit_no_print; goto exit_no_print;
} }
schema = qmp_query_stats_schemas(&err); schema = qmp_query_stats_schemas(false, STATS_PROVIDER__MAX, &err);
if (err) { if (err) {
goto exit; goto exit;
} }

View File

@ -445,6 +445,7 @@ HumanReadableText *qmp_x_query_irq(Error **errp)
} }
typedef struct StatsCallbacks { typedef struct StatsCallbacks {
StatsProvider provider;
StatRetrieveFunc *stats_cb; StatRetrieveFunc *stats_cb;
SchemaRetrieveFunc *schemas_cb; SchemaRetrieveFunc *schemas_cb;
QTAILQ_ENTRY(StatsCallbacks) next; QTAILQ_ENTRY(StatsCallbacks) next;
@ -453,10 +454,12 @@ typedef struct StatsCallbacks {
static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks = static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks =
QTAILQ_HEAD_INITIALIZER(stats_callbacks); QTAILQ_HEAD_INITIALIZER(stats_callbacks);
void add_stats_callbacks(StatRetrieveFunc *stats_fn, void add_stats_callbacks(StatsProvider provider,
StatRetrieveFunc *stats_fn,
SchemaRetrieveFunc *schemas_fn) SchemaRetrieveFunc *schemas_fn)
{ {
StatsCallbacks *entry = g_new(StatsCallbacks, 1); StatsCallbacks *entry = g_new(StatsCallbacks, 1);
entry->provider = provider;
entry->stats_cb = stats_fn; entry->stats_cb = stats_fn;
entry->schemas_cb = schemas_fn; entry->schemas_cb = schemas_fn;
@ -465,12 +468,18 @@ void add_stats_callbacks(StatRetrieveFunc *stats_fn,
static bool invoke_stats_cb(StatsCallbacks *entry, static bool invoke_stats_cb(StatsCallbacks *entry,
StatsResultList **stats_results, StatsResultList **stats_results,
StatsFilter *filter, StatsFilter *filter, StatsRequest *request,
Error **errp) Error **errp)
{ {
strList *targets = NULL; strList *targets = NULL;
ERRP_GUARD(); ERRP_GUARD();
if (request) {
if (request->provider != entry->provider) {
return true;
}
}
switch (filter->target) { switch (filter->target) {
case STATS_TARGET_VM: case STATS_TARGET_VM:
break; break;
@ -500,27 +509,41 @@ StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp)
{ {
StatsResultList *stats_results = NULL; StatsResultList *stats_results = NULL;
StatsCallbacks *entry; StatsCallbacks *entry;
StatsRequestList *request;
QTAILQ_FOREACH(entry, &stats_callbacks, next) { QTAILQ_FOREACH(entry, &stats_callbacks, next) {
if (!invoke_stats_cb(entry, &stats_results, filter, errp)) { if (filter->has_providers) {
break; for (request = filter->providers; request; request = request->next) {
if (!invoke_stats_cb(entry, &stats_results, filter,
request->value, errp)) {
break;
}
}
} else {
if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) {
break;
}
} }
} }
return stats_results; return stats_results;
} }
StatsSchemaList *qmp_query_stats_schemas(Error **errp) StatsSchemaList *qmp_query_stats_schemas(bool has_provider,
StatsProvider provider,
Error **errp)
{ {
StatsSchemaList *stats_results = NULL; StatsSchemaList *stats_results = NULL;
StatsCallbacks *entry; StatsCallbacks *entry;
ERRP_GUARD(); ERRP_GUARD();
QTAILQ_FOREACH(entry, &stats_callbacks, next) { QTAILQ_FOREACH(entry, &stats_callbacks, next) {
entry->schemas_cb(&stats_results, errp); if (!has_provider || provider == entry->provider) {
if (*errp) { entry->schemas_cb(&stats_results, errp);
qapi_free_StatsSchemaList(stats_results); if (*errp) {
return NULL; qapi_free_StatsSchemaList(stats_results);
return NULL;
}
} }
} }

View File

@ -69,6 +69,18 @@
{ 'enum': 'StatsTarget', { 'enum': 'StatsTarget',
'data': [ 'vm', 'vcpu' ] } 'data': [ 'vm', 'vcpu' ] }
##
# @StatsRequest:
#
# Indicates a set of statistics that should be returned by query-stats.
#
# @provider: provider for which to return statistics.
#
# Since: 7.1
##
{ 'struct': 'StatsRequest',
'data': { 'provider': 'StatsProvider' } }
## ##
# @StatsVCPUFilter: # @StatsVCPUFilter:
# #
@ -86,11 +98,14 @@
# request statistics and optionally the required subset of information for # request statistics and optionally the required subset of information for
# that target: # that target:
# - which vCPUs to request statistics for # - which vCPUs to request statistics for
# - which providers to request statistics from
# #
# Since: 7.1 # Since: 7.1
## ##
{ 'union': 'StatsFilter', { 'union': 'StatsFilter',
'base': { 'target': 'StatsTarget' }, 'base': {
'target': 'StatsTarget',
'*providers': [ 'StatsRequest' ] },
'discriminator': 'target', 'discriminator': 'target',
'data': { 'vcpu': 'StatsVCPUFilter' } } 'data': { 'vcpu': 'StatsVCPUFilter' } }
@ -226,5 +241,5 @@
# Since: 7.1 # Since: 7.1
## ##
{ 'command': 'query-stats-schemas', { 'command': 'query-stats-schemas',
'data': { }, 'data': { '*provider': 'StatsProvider' },
'returns': [ 'StatsSchema' ] } 'returns': [ 'StatsSchema' ] }