1 /*
2 * QMP commands related to stats
3 *
4 * This work is licensed under the terms of the GNU GPL, version 2 or
5 * (at your option) any later version.
6 */
7
8 #include "qemu/osdep.h"
9 #include "sysemu/stats.h"
10 #include "qapi/qapi-commands-stats.h"
11 #include "qemu/queue.h"
12 #include "qapi/error.h"
13
14 typedef struct StatsCallbacks {
15 StatsProvider provider;
16 StatRetrieveFunc *stats_cb;
17 SchemaRetrieveFunc *schemas_cb;
18 QTAILQ_ENTRY(StatsCallbacks) next;
19 } StatsCallbacks;
20
21 static QTAILQ_HEAD(, StatsCallbacks) stats_callbacks =
22 QTAILQ_HEAD_INITIALIZER(stats_callbacks);
23
add_stats_callbacks(StatsProvider provider,StatRetrieveFunc * stats_fn,SchemaRetrieveFunc * schemas_fn)24 void add_stats_callbacks(StatsProvider provider,
25 StatRetrieveFunc *stats_fn,
26 SchemaRetrieveFunc *schemas_fn)
27 {
28 StatsCallbacks *entry = g_new(StatsCallbacks, 1);
29 entry->provider = provider;
30 entry->stats_cb = stats_fn;
31 entry->schemas_cb = schemas_fn;
32
33 QTAILQ_INSERT_TAIL(&stats_callbacks, entry, next);
34 }
35
invoke_stats_cb(StatsCallbacks * entry,StatsResultList ** stats_results,StatsFilter * filter,StatsRequest * request,Error ** errp)36 static bool invoke_stats_cb(StatsCallbacks *entry,
37 StatsResultList **stats_results,
38 StatsFilter *filter, StatsRequest *request,
39 Error **errp)
40 {
41 ERRP_GUARD();
42 strList *targets = NULL;
43 strList *names = NULL;
44
45 if (request) {
46 if (request->provider != entry->provider) {
47 return true;
48 }
49 if (request->has_names && !request->names) {
50 return true;
51 }
52 names = request->has_names ? request->names : NULL;
53 }
54
55 switch (filter->target) {
56 case STATS_TARGET_VM:
57 break;
58 case STATS_TARGET_VCPU:
59 if (filter->u.vcpu.has_vcpus) {
60 if (!filter->u.vcpu.vcpus) {
61 /* No targets allowed? Return no statistics. */
62 return true;
63 }
64 targets = filter->u.vcpu.vcpus;
65 }
66 break;
67 case STATS_TARGET_CRYPTODEV:
68 break;
69 default:
70 abort();
71 }
72
73 entry->stats_cb(stats_results, filter->target, names, targets, errp);
74 if (*errp) {
75 qapi_free_StatsResultList(*stats_results);
76 *stats_results = NULL;
77 return false;
78 }
79 return true;
80 }
81
qmp_query_stats(StatsFilter * filter,Error ** errp)82 StatsResultList *qmp_query_stats(StatsFilter *filter, Error **errp)
83 {
84 StatsResultList *stats_results = NULL;
85 StatsCallbacks *entry;
86 StatsRequestList *request;
87
88 QTAILQ_FOREACH(entry, &stats_callbacks, next) {
89 if (filter->has_providers) {
90 for (request = filter->providers; request; request = request->next) {
91 if (!invoke_stats_cb(entry, &stats_results, filter,
92 request->value, errp)) {
93 break;
94 }
95 }
96 } else {
97 if (!invoke_stats_cb(entry, &stats_results, filter, NULL, errp)) {
98 break;
99 }
100 }
101 }
102
103 return stats_results;
104 }
105
qmp_query_stats_schemas(bool has_provider,StatsProvider provider,Error ** errp)106 StatsSchemaList *qmp_query_stats_schemas(bool has_provider,
107 StatsProvider provider,
108 Error **errp)
109 {
110 ERRP_GUARD();
111 StatsSchemaList *stats_results = NULL;
112 StatsCallbacks *entry;
113
114 QTAILQ_FOREACH(entry, &stats_callbacks, next) {
115 if (!has_provider || provider == entry->provider) {
116 entry->schemas_cb(&stats_results, errp);
117 if (*errp) {
118 qapi_free_StatsSchemaList(stats_results);
119 return NULL;
120 }
121 }
122 }
123
124 return stats_results;
125 }
126
add_stats_entry(StatsResultList ** stats_results,StatsProvider provider,const char * qom_path,StatsList * stats_list)127 void add_stats_entry(StatsResultList **stats_results, StatsProvider provider,
128 const char *qom_path, StatsList *stats_list)
129 {
130 StatsResult *entry = g_new0(StatsResult, 1);
131
132 entry->provider = provider;
133 entry->qom_path = g_strdup(qom_path);
134 entry->stats = stats_list;
135
136 QAPI_LIST_PREPEND(*stats_results, entry);
137 }
138
add_stats_schema(StatsSchemaList ** schema_results,StatsProvider provider,StatsTarget target,StatsSchemaValueList * stats_list)139 void add_stats_schema(StatsSchemaList **schema_results,
140 StatsProvider provider, StatsTarget target,
141 StatsSchemaValueList *stats_list)
142 {
143 StatsSchema *entry = g_new0(StatsSchema, 1);
144
145 entry->provider = provider;
146 entry->target = target;
147 entry->stats = stats_list;
148 QAPI_LIST_PREPEND(*schema_results, entry);
149 }
150
apply_str_list_filter(const char * string,strList * list)151 bool apply_str_list_filter(const char *string, strList *list)
152 {
153 strList *str_list = NULL;
154
155 if (!list) {
156 return true;
157 }
158 for (str_list = list; str_list; str_list = str_list->next) {
159 if (g_str_equal(string, str_list->value)) {
160 return true;
161 }
162 }
163 return false;
164 }
165