 f2b901098e
			
		
	
	
		f2b901098e
		
	
	
	
	
		
			
			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;
 | |
| }
 |