Now we can use "query-stats" QMP command to query statistics of
crypto devices. (Originally this was designed to show statistics
by '{"execute": "query-cryptodev"}'. Daniel Berrangé suggested that
querying configuration info by "query-cryptodev", and querying
runtime performance info by "query-stats". This makes sense!)
Example:
~# virsh qemu-monitor-command vm '{"execute": "query-stats", \
   "arguments": {"target": "cryptodev"} }' | jq
{
  "return": [
    {
      "provider": "cryptodev",
      "stats": [
        {
          "name": "asym-verify-bytes",
          "value": 7680
        },
        ...
        {
          "name": "asym-decrypt-ops",
          "value": 32
        },
        {
          "name": "asym-encrypt-ops",
          "value": 48
        }
      ],
      "qom-path": "/objects/cryptodev0" # support asym only
    },
    {
      "provider": "cryptodev",
      "stats": [
        {
          "name": "asym-verify-bytes",
          "value": 0
        },
        ...
        {
          "name": "sym-decrypt-bytes",
          "value": 5376
        },
        ...
      ],
      "qom-path": "/objects/cryptodev1" # support asym/sym
    }
  ],
  "id": "libvirt-422"
}
Suggested-by: Daniel P. Berrangé <berrange@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
Message-Id: <20230301105847.253084-12-pizhenwei@bytedance.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
		
	
			
		
			
				
	
	
		
			165 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * QMP commands related to stats
 | 
						|
 *
 | 
						|
 * This work is licensed under the terms of the GNU GPL, version 2 or
 | 
						|
 * (at your option) any later version.
 | 
						|
 */
 | 
						|
 | 
						|
#include "qemu/osdep.h"
 | 
						|
#include "sysemu/stats.h"
 | 
						|
#include "qapi/qapi-commands-stats.h"
 | 
						|
#include "qemu/queue.h"
 | 
						|
#include "qapi/error.h"
 | 
						|
 | 
						|
typedef struct StatsCallbacks {
 | 
						|
    StatsProvider provider;
 | 
						|
    StatRetrieveFunc *stats_cb;
 | 
						|
    SchemaRetrieveFunc *schemas_cb;
 | 
						|
    QTAILQ_ENTRY(StatsCallbacks) next;
 | 
						|
} StatsCallbacks;
 | 
						|
 | 
						|
static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks =
 | 
						|
    QTAILQ_HEAD_INITIALIZER(stats_callbacks);
 | 
						|
 | 
						|
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 invoke_stats_cb(StatsCallbacks *entry,
 | 
						|
                            StatsResultList **stats_results,
 | 
						|
                            StatsFilter *filter, StatsRequest *request,
 | 
						|
                            Error **errp)
 | 
						|
{
 | 
						|
    ERRP_GUARD();
 | 
						|
    strList *targets = NULL;
 | 
						|
    strList *names = NULL;
 | 
						|
 | 
						|
    if (request) {
 | 
						|
        if (request->provider != entry->provider) {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
        if (request->has_names && !request->names) {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
        names = request->has_names ? request->names : NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    switch (filter->target) {
 | 
						|
    case STATS_TARGET_VM:
 | 
						|
        break;
 | 
						|
    case STATS_TARGET_VCPU:
 | 
						|
        if (filter->u.vcpu.has_vcpus) {
 | 
						|
            if (!filter->u.vcpu.vcpus) {
 | 
						|
                /* No targets allowed?  Return no statistics.  */
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
            targets = filter->u.vcpu.vcpus;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    case STATS_TARGET_CRYPTODEV:
 | 
						|
        break;
 | 
						|
    default:
 | 
						|
        abort();
 | 
						|
    }
 | 
						|
 | 
						|
    entry->stats_cb(stats_results, filter->target, names, targets, errp);
 | 
						|
    if (*errp) {
 | 
						|
        qapi_free_StatsResultList(*stats_results);
 | 
						|
        *stats_results = NULL;
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
    return true;
 | 
						|
}
 | 
						|
 | 
						|
StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp)
 | 
						|
{
 | 
						|
    StatsResultList *stats_results = NULL;
 | 
						|
    StatsCallbacks *entry;
 | 
						|
    StatsRequestList *request;
 | 
						|
 | 
						|
    QTAILQ_FOREACH(entry, &stats_callbacks, next) {
 | 
						|
        if (filter->has_providers) {
 | 
						|
            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;
 | 
						|
}
 | 
						|
 | 
						|
StatsSchemaList *qmp_query_stats_schemas(bool has_provider,
 | 
						|
                                         StatsProvider provider,
 | 
						|
                                         Error **errp)
 | 
						|
{
 | 
						|
    ERRP_GUARD();
 | 
						|
    StatsSchemaList *stats_results = NULL;
 | 
						|
    StatsCallbacks *entry;
 | 
						|
 | 
						|
    QTAILQ_FOREACH(entry, &stats_callbacks, next) {
 | 
						|
        if (!has_provider || provider == entry->provider) {
 | 
						|
            entry->schemas_cb(&stats_results, errp);
 | 
						|
            if (*errp) {
 | 
						|
                qapi_free_StatsSchemaList(stats_results);
 | 
						|
                return NULL;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return stats_results;
 | 
						|
}
 | 
						|
 | 
						|
void add_stats_entry(StatsResultList **stats_results, StatsProvider provider,
 | 
						|
                     const char *qom_path, StatsList *stats_list)
 | 
						|
{
 | 
						|
    StatsResult *entry = g_new0(StatsResult, 1);
 | 
						|
 | 
						|
    entry->provider = provider;
 | 
						|
    entry->qom_path = g_strdup(qom_path);
 | 
						|
    entry->stats = stats_list;
 | 
						|
 | 
						|
    QAPI_LIST_PREPEND(*stats_results, entry);
 | 
						|
}
 | 
						|
 | 
						|
void add_stats_schema(StatsSchemaList **schema_results,
 | 
						|
                      StatsProvider provider, StatsTarget target,
 | 
						|
                      StatsSchemaValueList *stats_list)
 | 
						|
{
 | 
						|
    StatsSchema *entry = g_new0(StatsSchema, 1);
 | 
						|
 | 
						|
    entry->provider = provider;
 | 
						|
    entry->target = target;
 | 
						|
    entry->stats = stats_list;
 | 
						|
    QAPI_LIST_PREPEND(*schema_results, entry);
 | 
						|
}
 | 
						|
 | 
						|
bool apply_str_list_filter(const char *string, strList *list)
 | 
						|
{
 | 
						|
    strList *str_list = NULL;
 | 
						|
 | 
						|
    if (!list) {
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
    for (str_list = list; str_list; str_list = str_list->next) {
 | 
						|
        if (g_str_equal(string, str_list->value)) {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
}
 |