Paolo Bonzini <pbonz...@redhat.com> writes: > 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. > > Extracted from a patch by Mark Kanda. > > Signed-off-by: Paolo Bonzini <pbonz...@redhat.com> > --- > accel/kvm/kvm-all.c | 3 ++- > include/monitor/stats.h | 4 +++- > monitor/hmp-cmds.c | 2 +- > monitor/qmp-cmds.c | 45 ++++++++++++++++++++++++++++++++--------- > qapi/stats.json | 17 ++++++++++++++-- > 5 files changed, 56 insertions(+), 15 deletions(-) > > diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c > index 3ee431a431..461b6cf927 100644 > --- a/accel/kvm/kvm-all.c > +++ b/accel/kvm/kvm-all.c > @@ -2644,7 +2644,8 @@ static int kvm_init(MachineState *ms) > } > > 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; > diff --git a/include/monitor/stats.h b/include/monitor/stats.h > index 8c50feeaa9..840c4ed08e 100644 > --- a/include/monitor/stats.h > +++ b/include/monitor/stats.h > @@ -17,10 +17,12 @@ typedef void SchemaRetrieveFunc(StatsSchemaList **result, > Error **errp); > /* > * Register callbacks for the QMP query-stats command. > * > + * @provider: stats provider
Argument documentation that merely paraphrases the type is redundant. May I have a proper contract? > * @stats_fn: routine to query stats: > * @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); > > /* > diff --git a/monitor/hmp-cmds.c b/monitor/hmp-cmds.c > index c0cb440902..8d2c4792d5 100644 > --- a/monitor/hmp-cmds.c > +++ b/monitor/hmp-cmds.c > @@ -2394,7 +2394,7 @@ void hmp_info_stats(Monitor *mon, const QDict *qdict) > goto exit_no_print; > } > > - schema = qmp_query_stats_schemas(&err); > + schema = qmp_query_stats_schemas(false, 0, &err); NULL instead of 0 please. > if (err) { > goto exit; > } > diff --git a/monitor/qmp-cmds.c b/monitor/qmp-cmds.c > index ebf6f49446..7be0e7414a 100644 > --- a/monitor/qmp-cmds.c > +++ b/monitor/qmp-cmds.c > @@ -445,6 +445,7 @@ HumanReadableText *qmp_x_query_irq(Error **errp) > } > > typedef struct StatsCallbacks { > + StatsProvider provider; > StatRetrieveFunc *stats_cb; > SchemaRetrieveFunc *schemas_cb; > QTAILQ_ENTRY(StatsCallbacks) next; > @@ -453,16 +454,34 @@ typedef struct StatsCallbacks { > static QTAILQ_HEAD(, StatsCallbacks) 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) > { > StatsCallbacks *entry = g_new(StatsCallbacks, 1); > + entry->provider = provider; > entry->stats_cb = stats_fn; > entry->schemas_cb = schemas_fn; > > QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next); > } > > +static bool stats_provider_requested(StatsProvider provider, > + StatsFilter *filter) > +{ > + StatsRequestList *request; > + > + if (!filter->has_providers) { > + return true; > + } > + for (request = filter->providers; request; request = request->next) { > + if (request->value->provider == provider) { > + return true; > + } > + } > + return false; > +} > + This is just like apply_str_list_filter(). Good! Could we make the two names similar, too? > StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp) > { > StatsResultList *stats_results = NULL; > @@ -487,27 +506,33 @@ StatsResultList *qmp_query_stats(StatsFilter *filter, > Error **errp) > } > > QTAILQ_FOREACH(entry, &stats_callbacks, next) { > - entry->stats_cb(&stats_results, filter->target, targets, errp); > - if (*errp) { > - qapi_free_StatsResultList(stats_results); > - return NULL; > + if (stats_provider_requested(entry->provider, filter)) { > + entry->stats_cb(&stats_results, filter->target, targets, errp); > + if (*errp) { > + qapi_free_StatsResultList(stats_results); > + return NULL; > + } I like if (!wanted) continue in such loops for less nesting. Clearly a matter of taste. > } > } > > 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; > StatsCallbacks *entry; > ERRP_GUARD(); > > QTAILQ_FOREACH(entry, &stats_callbacks, next) { > - entry->schemas_cb(&stats_results, errp); > - if (*errp) { > - qapi_free_StatsSchemaList(stats_results); > - return NULL; > + if (!has_provider || provider == entry->provider) { > + entry->schemas_cb(&stats_results, errp); > + if (*errp) { > + qapi_free_StatsSchemaList(stats_results); > + return NULL; > + } Likewise. > } > } > > diff --git a/qapi/stats.json b/qapi/stats.json > index e8ed907793..b75bb86124 100644 > --- a/qapi/stats.json > +++ b/qapi/stats.json > @@ -68,6 +68,18 @@ > { 'enum': 'StatsTarget', > '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: > # > @@ -85,11 +97,12 @@ > # request statistics and optionally the required subset of information for > # that target: > # - which vCPUs to request statistics for > +# - which provider to request statistics from > # > # Since: 7.1 > ## > { 'union': 'StatsFilter', > - 'base': { 'target': 'StatsTarget' }, > + 'base': { 'target': 'StatsTarget', '*providers': [ 'StatsRequest' ] > }, Easier to read, I think: 'base': { 'target': 'StatsTarget', '*providers': [ 'StatsRequest' ] }, > 'discriminator': 'target', > 'data': { 'vcpu': 'StatsVCPUFilter' } } > > @@ -225,5 +238,5 @@ > # Since: 7.1 > ## > { 'command': 'query-stats-schemas', > - 'data': { }, > + 'data': { '*provider': 'StatsProvider' }, > 'returns': [ 'StatsSchema' ] } Only the "NULL instead of 0" is a request, the remainder suggestions. So, with that request addressed Reviewed-by: Markus Armbruster <arm...@redhat.com> PS: Consider adding [diff] orderFile = scripts/git.orderfile to your .git/config.