2 * HMP commands related to stats
4 * This work is licensed under the terms of the GNU GPL, version 2 or
5 * (at your option) any later version.
8 #include "qemu/osdep.h"
9 #include "qapi/qapi-commands-stats.h"
10 #include "monitor/hmp.h"
11 #include "monitor/monitor.h"
12 #include "qemu/cutils.h"
13 #include "hw/core/cpu.h"
14 #include "qapi/qmp/qdict.h"
15 #include "qapi/error.h"
17 static void print_stats_schema_value(Monitor
*mon
, StatsSchemaValue
*value
)
19 const char *unit
= NULL
;
20 monitor_printf(mon
, " %s (%s%s", value
->name
, StatsType_str(value
->type
),
21 value
->has_unit
|| value
->exponent
? ", " : "");
23 if (value
->has_unit
) {
24 if (value
->unit
== STATS_UNIT_SECONDS
) {
26 } else if (value
->unit
== STATS_UNIT_BYTES
) {
31 if (unit
&& value
->base
== 10 &&
32 value
->exponent
>= -18 && value
->exponent
<= 18 &&
33 value
->exponent
% 3 == 0) {
34 monitor_puts(mon
, si_prefix(value
->exponent
));
35 } else if (unit
&& value
->base
== 2 &&
36 value
->exponent
>= 0 && value
->exponent
<= 60 &&
37 value
->exponent
% 10 == 0) {
39 monitor_puts(mon
, iec_binary_prefix(value
->exponent
));
40 } else if (value
->exponent
) {
41 /* Use exponential notation and write the unit's English name */
42 monitor_printf(mon
, "* %d^%d%s",
43 value
->base
, value
->exponent
,
44 value
->has_unit
? " " : "");
48 if (value
->has_unit
) {
49 monitor_puts(mon
, unit
? unit
: StatsUnit_str(value
->unit
));
52 /* Print bucket size for linear histograms */
53 if (value
->type
== STATS_TYPE_LINEAR_HISTOGRAM
&& value
->has_bucket_size
) {
54 monitor_printf(mon
, ", bucket size=%d", value
->bucket_size
);
56 monitor_printf(mon
, ")");
59 static StatsSchemaValueList
*find_schema_value_list(
60 StatsSchemaList
*list
, StatsProvider provider
,
63 StatsSchemaList
*node
;
65 for (node
= list
; node
; node
= node
->next
) {
66 if (node
->value
->provider
== provider
&&
67 node
->value
->target
== target
) {
68 return node
->value
->stats
;
74 static void print_stats_results(Monitor
*mon
, StatsTarget target
,
77 StatsSchemaList
*schema
)
79 /* Find provider schema */
80 StatsSchemaValueList
*schema_value_list
=
81 find_schema_value_list(schema
, result
->provider
, target
);
82 StatsList
*stats_list
;
84 if (!schema_value_list
) {
85 monitor_printf(mon
, "failed to find schema list for %s\n",
86 StatsProvider_str(result
->provider
));
91 monitor_printf(mon
, "provider: %s\n",
92 StatsProvider_str(result
->provider
));
95 for (stats_list
= result
->stats
; stats_list
;
96 stats_list
= stats_list
->next
,
97 schema_value_list
= schema_value_list
->next
) {
99 Stats
*stats
= stats_list
->value
;
100 StatsValue
*stats_value
= stats
->value
;
101 StatsSchemaValue
*schema_value
= schema_value_list
->value
;
103 /* Find schema entry */
104 while (!g_str_equal(stats
->name
, schema_value
->name
)) {
105 if (!schema_value_list
->next
) {
106 monitor_printf(mon
, "failed to find schema entry for %s\n",
110 schema_value_list
= schema_value_list
->next
;
111 schema_value
= schema_value_list
->value
;
114 print_stats_schema_value(mon
, schema_value
);
116 if (stats_value
->type
== QTYPE_QNUM
) {
117 monitor_printf(mon
, ": %" PRId64
"\n", stats_value
->u
.scalar
);
118 } else if (stats_value
->type
== QTYPE_QBOOL
) {
119 monitor_printf(mon
, ": %s\n", stats_value
->u
.boolean
? "yes" : "no");
120 } else if (stats_value
->type
== QTYPE_QLIST
) {
124 monitor_printf(mon
, ": ");
125 for (list
= stats_value
->u
.list
, i
= 1;
127 list
= list
->next
, i
++) {
128 monitor_printf(mon
, "[%d]=%" PRId64
" ", i
, list
->value
);
130 monitor_printf(mon
, "\n");
135 /* Create the StatsFilter that is needed for an "info stats" invocation. */
136 static StatsFilter
*stats_filter(StatsTarget target
, const char *names
,
137 int cpu_index
, StatsProvider provider
)
139 StatsFilter
*filter
= g_malloc0(sizeof(*filter
));
140 StatsProvider provider_idx
;
141 StatsRequestList
*request_list
= NULL
;
143 filter
->target
= target
;
145 case STATS_TARGET_VM
:
147 case STATS_TARGET_VCPU
:
149 strList
*vcpu_list
= NULL
;
150 CPUState
*cpu
= qemu_get_cpu(cpu_index
);
151 char *canonical_path
= object_get_canonical_path(OBJECT(cpu
));
153 QAPI_LIST_PREPEND(vcpu_list
, canonical_path
);
154 filter
->u
.vcpu
.has_vcpus
= true;
155 filter
->u
.vcpu
.vcpus
= vcpu_list
;
158 case STATS_TARGET_CRYPTODEV
:
164 if (!names
&& provider
== STATS_PROVIDER__MAX
) {
169 * "info stats" can only query either one or all the providers. Querying
170 * by name, but not by provider, requires the creation of one filter per
173 for (provider_idx
= 0; provider_idx
< STATS_PROVIDER__MAX
; provider_idx
++) {
174 if (provider
== STATS_PROVIDER__MAX
|| provider
== provider_idx
) {
175 StatsRequest
*request
= g_new0(StatsRequest
, 1);
176 request
->provider
= provider_idx
;
177 if (names
&& !g_str_equal(names
, "*")) {
178 request
->has_names
= true;
179 request
->names
= hmp_split_at_comma(names
);
181 QAPI_LIST_PREPEND(request_list
, request
);
185 filter
->has_providers
= true;
186 filter
->providers
= request_list
;
190 void hmp_info_stats(Monitor
*mon
, const QDict
*qdict
)
192 const char *target_str
= qdict_get_str(qdict
, "target");
193 const char *provider_str
= qdict_get_try_str(qdict
, "provider");
194 const char *names
= qdict_get_try_str(qdict
, "names");
196 StatsProvider provider
= STATS_PROVIDER__MAX
;
199 g_autoptr(StatsSchemaList
) schema
= NULL
;
200 g_autoptr(StatsResultList
) stats
= NULL
;
201 g_autoptr(StatsFilter
) filter
= NULL
;
202 StatsResultList
*entry
;
204 target
= qapi_enum_parse(&StatsTarget_lookup
, target_str
, -1, &err
);
206 monitor_printf(mon
, "invalid stats target %s\n", target_str
);
210 provider
= qapi_enum_parse(&StatsProvider_lookup
, provider_str
, -1, &err
);
212 monitor_printf(mon
, "invalid stats provider %s\n", provider_str
);
217 schema
= qmp_query_stats_schemas(provider_str
? true : false,
224 case STATS_TARGET_VM
:
225 filter
= stats_filter(target
, names
, -1, provider
);
227 case STATS_TARGET_VCPU
: {}
228 int cpu_index
= monitor_get_cpu_index(mon
);
229 filter
= stats_filter(target
, names
, cpu_index
, provider
);
231 case STATS_TARGET_CRYPTODEV
:
232 filter
= stats_filter(target
, names
, -1, provider
);
238 stats
= qmp_query_stats(filter
, &err
);
242 for (entry
= stats
; entry
; entry
= entry
->next
) {
243 print_stats_results(mon
, target
, provider_str
== NULL
, entry
->value
, schema
);
248 monitor_printf(mon
, "%s\n", error_get_pretty(err
));