xref: /openbmc/qemu/accel/tcg/monitor.c (revision 74949263a54a1382309afba952683255c1c22ef7)
100c9a5c2SPhilippe Mathieu-Daudé /*
200c9a5c2SPhilippe Mathieu-Daudé  * SPDX-License-Identifier: LGPL-2.1-or-later
300c9a5c2SPhilippe Mathieu-Daudé  *
400c9a5c2SPhilippe Mathieu-Daudé  *  QEMU TCG monitor
500c9a5c2SPhilippe Mathieu-Daudé  *
600c9a5c2SPhilippe Mathieu-Daudé  *  Copyright (c) 2003-2005 Fabrice Bellard
700c9a5c2SPhilippe Mathieu-Daudé  */
800c9a5c2SPhilippe Mathieu-Daudé 
900c9a5c2SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
10e726acd5SPeter Maydell #include "qemu/accel.h"
11*24a4d59aSRichard Henderson #include "qemu/qht.h"
1200c9a5c2SPhilippe Mathieu-Daudé #include "qapi/error.h"
1300c9a5c2SPhilippe Mathieu-Daudé #include "qapi/type-helpers.h"
1400c9a5c2SPhilippe Mathieu-Daudé #include "qapi/qapi-commands-machine.h"
1500c9a5c2SPhilippe Mathieu-Daudé #include "monitor/monitor.h"
1600c9a5c2SPhilippe Mathieu-Daudé #include "sysemu/cpus.h"
1700c9a5c2SPhilippe Mathieu-Daudé #include "sysemu/cpu-timers.h"
1800c9a5c2SPhilippe Mathieu-Daudé #include "sysemu/tcg.h"
19e5b49063SRichard Henderson #include "tcg/tcg.h"
205934660fSPhilippe Mathieu-Daudé #include "internal-common.h"
21*24a4d59aSRichard Henderson #include "tb-context.h"
2200c9a5c2SPhilippe Mathieu-Daudé 
2300c9a5c2SPhilippe Mathieu-Daudé 
dump_drift_info(GString * buf)2400c9a5c2SPhilippe Mathieu-Daudé static void dump_drift_info(GString *buf)
2500c9a5c2SPhilippe Mathieu-Daudé {
2600c9a5c2SPhilippe Mathieu-Daudé     if (!icount_enabled()) {
2700c9a5c2SPhilippe Mathieu-Daudé         return;
2800c9a5c2SPhilippe Mathieu-Daudé     }
2900c9a5c2SPhilippe Mathieu-Daudé 
3000c9a5c2SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "Host - Guest clock  %"PRIi64" ms\n",
3100c9a5c2SPhilippe Mathieu-Daudé                            (cpu_get_clock() - icount_get()) / SCALE_MS);
3200c9a5c2SPhilippe Mathieu-Daudé     if (icount_align_option) {
3300c9a5c2SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest delay     %"PRIi64" ms\n",
3400c9a5c2SPhilippe Mathieu-Daudé                                -max_delay / SCALE_MS);
3500c9a5c2SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest advance   %"PRIi64" ms\n",
3600c9a5c2SPhilippe Mathieu-Daudé                                max_advance / SCALE_MS);
3700c9a5c2SPhilippe Mathieu-Daudé     } else {
3800c9a5c2SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest delay     NA\n");
3900c9a5c2SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest advance   NA\n");
4000c9a5c2SPhilippe Mathieu-Daudé     }
4100c9a5c2SPhilippe Mathieu-Daudé }
4200c9a5c2SPhilippe Mathieu-Daudé 
dump_accel_info(GString * buf)43e726acd5SPeter Maydell static void dump_accel_info(GString *buf)
44e726acd5SPeter Maydell {
45e726acd5SPeter Maydell     AccelState *accel = current_accel();
46e726acd5SPeter Maydell     bool one_insn_per_tb = object_property_get_bool(OBJECT(accel),
47e726acd5SPeter Maydell                                                     "one-insn-per-tb",
48e726acd5SPeter Maydell                                                     &error_fatal);
49e726acd5SPeter Maydell 
50e726acd5SPeter Maydell     g_string_append_printf(buf, "Accelerator settings:\n");
51e726acd5SPeter Maydell     g_string_append_printf(buf, "one-insn-per-tb: %s\n\n",
52e726acd5SPeter Maydell                            one_insn_per_tb ? "on" : "off");
53e726acd5SPeter Maydell }
54e726acd5SPeter Maydell 
print_qht_statistics(struct qht_stats hst,GString * buf)55*24a4d59aSRichard Henderson static void print_qht_statistics(struct qht_stats hst, GString *buf)
56*24a4d59aSRichard Henderson {
57*24a4d59aSRichard Henderson     uint32_t hgram_opts;
58*24a4d59aSRichard Henderson     size_t hgram_bins;
59*24a4d59aSRichard Henderson     char *hgram;
60*24a4d59aSRichard Henderson 
61*24a4d59aSRichard Henderson     if (!hst.head_buckets) {
62*24a4d59aSRichard Henderson         return;
63*24a4d59aSRichard Henderson     }
64*24a4d59aSRichard Henderson     g_string_append_printf(buf, "TB hash buckets     %zu/%zu "
65*24a4d59aSRichard Henderson                            "(%0.2f%% head buckets used)\n",
66*24a4d59aSRichard Henderson                            hst.used_head_buckets, hst.head_buckets,
67*24a4d59aSRichard Henderson                            (double)hst.used_head_buckets /
68*24a4d59aSRichard Henderson                            hst.head_buckets * 100);
69*24a4d59aSRichard Henderson 
70*24a4d59aSRichard Henderson     hgram_opts =  QDIST_PR_BORDER | QDIST_PR_LABELS;
71*24a4d59aSRichard Henderson     hgram_opts |= QDIST_PR_100X   | QDIST_PR_PERCENT;
72*24a4d59aSRichard Henderson     if (qdist_xmax(&hst.occupancy) - qdist_xmin(&hst.occupancy) == 1) {
73*24a4d59aSRichard Henderson         hgram_opts |= QDIST_PR_NODECIMAL;
74*24a4d59aSRichard Henderson     }
75*24a4d59aSRichard Henderson     hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
76*24a4d59aSRichard Henderson     g_string_append_printf(buf, "TB hash occupancy   %0.2f%% avg chain occ. "
77*24a4d59aSRichard Henderson                            "Histogram: %s\n",
78*24a4d59aSRichard Henderson                            qdist_avg(&hst.occupancy) * 100, hgram);
79*24a4d59aSRichard Henderson     g_free(hgram);
80*24a4d59aSRichard Henderson 
81*24a4d59aSRichard Henderson     hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
82*24a4d59aSRichard Henderson     hgram_bins = qdist_xmax(&hst.chain) - qdist_xmin(&hst.chain);
83*24a4d59aSRichard Henderson     if (hgram_bins > 10) {
84*24a4d59aSRichard Henderson         hgram_bins = 10;
85*24a4d59aSRichard Henderson     } else {
86*24a4d59aSRichard Henderson         hgram_bins = 0;
87*24a4d59aSRichard Henderson         hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
88*24a4d59aSRichard Henderson     }
89*24a4d59aSRichard Henderson     hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
90*24a4d59aSRichard Henderson     g_string_append_printf(buf, "TB hash avg chain   %0.3f buckets. "
91*24a4d59aSRichard Henderson                            "Histogram: %s\n",
92*24a4d59aSRichard Henderson                            qdist_avg(&hst.chain), hgram);
93*24a4d59aSRichard Henderson     g_free(hgram);
94*24a4d59aSRichard Henderson }
95*24a4d59aSRichard Henderson 
96*24a4d59aSRichard Henderson struct tb_tree_stats {
97*24a4d59aSRichard Henderson     size_t nb_tbs;
98*24a4d59aSRichard Henderson     size_t host_size;
99*24a4d59aSRichard Henderson     size_t target_size;
100*24a4d59aSRichard Henderson     size_t max_target_size;
101*24a4d59aSRichard Henderson     size_t direct_jmp_count;
102*24a4d59aSRichard Henderson     size_t direct_jmp2_count;
103*24a4d59aSRichard Henderson     size_t cross_page;
104*24a4d59aSRichard Henderson };
105*24a4d59aSRichard Henderson 
tb_tree_stats_iter(gpointer key,gpointer value,gpointer data)106*24a4d59aSRichard Henderson static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
107*24a4d59aSRichard Henderson {
108*24a4d59aSRichard Henderson     const TranslationBlock *tb = value;
109*24a4d59aSRichard Henderson     struct tb_tree_stats *tst = data;
110*24a4d59aSRichard Henderson 
111*24a4d59aSRichard Henderson     tst->nb_tbs++;
112*24a4d59aSRichard Henderson     tst->host_size += tb->tc.size;
113*24a4d59aSRichard Henderson     tst->target_size += tb->size;
114*24a4d59aSRichard Henderson     if (tb->size > tst->max_target_size) {
115*24a4d59aSRichard Henderson         tst->max_target_size = tb->size;
116*24a4d59aSRichard Henderson     }
117*24a4d59aSRichard Henderson     if (tb->page_addr[1] != -1) {
118*24a4d59aSRichard Henderson         tst->cross_page++;
119*24a4d59aSRichard Henderson     }
120*24a4d59aSRichard Henderson     if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) {
121*24a4d59aSRichard Henderson         tst->direct_jmp_count++;
122*24a4d59aSRichard Henderson         if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) {
123*24a4d59aSRichard Henderson             tst->direct_jmp2_count++;
124*24a4d59aSRichard Henderson         }
125*24a4d59aSRichard Henderson     }
126*24a4d59aSRichard Henderson     return false;
127*24a4d59aSRichard Henderson }
128*24a4d59aSRichard Henderson 
tlb_flush_counts(size_t * pfull,size_t * ppart,size_t * pelide)129*24a4d59aSRichard Henderson static void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide)
130*24a4d59aSRichard Henderson {
131*24a4d59aSRichard Henderson     CPUState *cpu;
132*24a4d59aSRichard Henderson     size_t full = 0, part = 0, elide = 0;
133*24a4d59aSRichard Henderson 
134*24a4d59aSRichard Henderson     CPU_FOREACH(cpu) {
135*24a4d59aSRichard Henderson         full += qatomic_read(&cpu->neg.tlb.c.full_flush_count);
136*24a4d59aSRichard Henderson         part += qatomic_read(&cpu->neg.tlb.c.part_flush_count);
137*24a4d59aSRichard Henderson         elide += qatomic_read(&cpu->neg.tlb.c.elide_flush_count);
138*24a4d59aSRichard Henderson     }
139*24a4d59aSRichard Henderson     *pfull = full;
140*24a4d59aSRichard Henderson     *ppart = part;
141*24a4d59aSRichard Henderson     *pelide = elide;
142*24a4d59aSRichard Henderson }
143*24a4d59aSRichard Henderson 
tcg_dump_info(GString * buf)144*24a4d59aSRichard Henderson static void tcg_dump_info(GString *buf)
145*24a4d59aSRichard Henderson {
146*24a4d59aSRichard Henderson     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
147*24a4d59aSRichard Henderson }
148*24a4d59aSRichard Henderson 
dump_exec_info(GString * buf)149*24a4d59aSRichard Henderson static void dump_exec_info(GString *buf)
150*24a4d59aSRichard Henderson {
151*24a4d59aSRichard Henderson     struct tb_tree_stats tst = {};
152*24a4d59aSRichard Henderson     struct qht_stats hst;
153*24a4d59aSRichard Henderson     size_t nb_tbs, flush_full, flush_part, flush_elide;
154*24a4d59aSRichard Henderson 
155*24a4d59aSRichard Henderson     tcg_tb_foreach(tb_tree_stats_iter, &tst);
156*24a4d59aSRichard Henderson     nb_tbs = tst.nb_tbs;
157*24a4d59aSRichard Henderson     /* XXX: avoid using doubles ? */
158*24a4d59aSRichard Henderson     g_string_append_printf(buf, "Translation buffer state:\n");
159*24a4d59aSRichard Henderson     /*
160*24a4d59aSRichard Henderson      * Report total code size including the padding and TB structs;
161*24a4d59aSRichard Henderson      * otherwise users might think "-accel tcg,tb-size" is not honoured.
162*24a4d59aSRichard Henderson      * For avg host size we use the precise numbers from tb_tree_stats though.
163*24a4d59aSRichard Henderson      */
164*24a4d59aSRichard Henderson     g_string_append_printf(buf, "gen code size       %zu/%zu\n",
165*24a4d59aSRichard Henderson                            tcg_code_size(), tcg_code_capacity());
166*24a4d59aSRichard Henderson     g_string_append_printf(buf, "TB count            %zu\n", nb_tbs);
167*24a4d59aSRichard Henderson     g_string_append_printf(buf, "TB avg target size  %zu max=%zu bytes\n",
168*24a4d59aSRichard Henderson                            nb_tbs ? tst.target_size / nb_tbs : 0,
169*24a4d59aSRichard Henderson                            tst.max_target_size);
170*24a4d59aSRichard Henderson     g_string_append_printf(buf, "TB avg host size    %zu bytes "
171*24a4d59aSRichard Henderson                            "(expansion ratio: %0.1f)\n",
172*24a4d59aSRichard Henderson                            nb_tbs ? tst.host_size / nb_tbs : 0,
173*24a4d59aSRichard Henderson                            tst.target_size ?
174*24a4d59aSRichard Henderson                            (double)tst.host_size / tst.target_size : 0);
175*24a4d59aSRichard Henderson     g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n",
176*24a4d59aSRichard Henderson                            tst.cross_page,
177*24a4d59aSRichard Henderson                            nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
178*24a4d59aSRichard Henderson     g_string_append_printf(buf, "direct jump count   %zu (%zu%%) "
179*24a4d59aSRichard Henderson                            "(2 jumps=%zu %zu%%)\n",
180*24a4d59aSRichard Henderson                            tst.direct_jmp_count,
181*24a4d59aSRichard Henderson                            nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
182*24a4d59aSRichard Henderson                            tst.direct_jmp2_count,
183*24a4d59aSRichard Henderson                            nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
184*24a4d59aSRichard Henderson 
185*24a4d59aSRichard Henderson     qht_statistics_init(&tb_ctx.htable, &hst);
186*24a4d59aSRichard Henderson     print_qht_statistics(hst, buf);
187*24a4d59aSRichard Henderson     qht_statistics_destroy(&hst);
188*24a4d59aSRichard Henderson 
189*24a4d59aSRichard Henderson     g_string_append_printf(buf, "\nStatistics:\n");
190*24a4d59aSRichard Henderson     g_string_append_printf(buf, "TB flush count      %u\n",
191*24a4d59aSRichard Henderson                            qatomic_read(&tb_ctx.tb_flush_count));
192*24a4d59aSRichard Henderson     g_string_append_printf(buf, "TB invalidate count %u\n",
193*24a4d59aSRichard Henderson                            qatomic_read(&tb_ctx.tb_phys_invalidate_count));
194*24a4d59aSRichard Henderson 
195*24a4d59aSRichard Henderson     tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
196*24a4d59aSRichard Henderson     g_string_append_printf(buf, "TLB full flushes    %zu\n", flush_full);
197*24a4d59aSRichard Henderson     g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part);
198*24a4d59aSRichard Henderson     g_string_append_printf(buf, "TLB elided flushes  %zu\n", flush_elide);
199*24a4d59aSRichard Henderson     tcg_dump_info(buf);
200*24a4d59aSRichard Henderson }
201*24a4d59aSRichard Henderson 
qmp_x_query_jit(Error ** errp)20200c9a5c2SPhilippe Mathieu-Daudé HumanReadableText *qmp_x_query_jit(Error **errp)
20300c9a5c2SPhilippe Mathieu-Daudé {
20400c9a5c2SPhilippe Mathieu-Daudé     g_autoptr(GString) buf = g_string_new("");
20500c9a5c2SPhilippe Mathieu-Daudé 
20600c9a5c2SPhilippe Mathieu-Daudé     if (!tcg_enabled()) {
20700c9a5c2SPhilippe Mathieu-Daudé         error_setg(errp, "JIT information is only available with accel=tcg");
20800c9a5c2SPhilippe Mathieu-Daudé         return NULL;
20900c9a5c2SPhilippe Mathieu-Daudé     }
21000c9a5c2SPhilippe Mathieu-Daudé 
211e726acd5SPeter Maydell     dump_accel_info(buf);
21200c9a5c2SPhilippe Mathieu-Daudé     dump_exec_info(buf);
21300c9a5c2SPhilippe Mathieu-Daudé     dump_drift_info(buf);
21400c9a5c2SPhilippe Mathieu-Daudé 
21500c9a5c2SPhilippe Mathieu-Daudé     return human_readable_text_from_str(buf);
21600c9a5c2SPhilippe Mathieu-Daudé }
21700c9a5c2SPhilippe Mathieu-Daudé 
tcg_dump_op_count(GString * buf)218*24a4d59aSRichard Henderson static void tcg_dump_op_count(GString *buf)
219*24a4d59aSRichard Henderson {
220*24a4d59aSRichard Henderson     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
221*24a4d59aSRichard Henderson }
222*24a4d59aSRichard Henderson 
qmp_x_query_opcount(Error ** errp)22300c9a5c2SPhilippe Mathieu-Daudé HumanReadableText *qmp_x_query_opcount(Error **errp)
22400c9a5c2SPhilippe Mathieu-Daudé {
22500c9a5c2SPhilippe Mathieu-Daudé     g_autoptr(GString) buf = g_string_new("");
22600c9a5c2SPhilippe Mathieu-Daudé 
22700c9a5c2SPhilippe Mathieu-Daudé     if (!tcg_enabled()) {
22800c9a5c2SPhilippe Mathieu-Daudé         error_setg(errp,
22900c9a5c2SPhilippe Mathieu-Daudé                    "Opcode count information is only available with accel=tcg");
23000c9a5c2SPhilippe Mathieu-Daudé         return NULL;
23100c9a5c2SPhilippe Mathieu-Daudé     }
23200c9a5c2SPhilippe Mathieu-Daudé 
23300c9a5c2SPhilippe Mathieu-Daudé     tcg_dump_op_count(buf);
23400c9a5c2SPhilippe Mathieu-Daudé 
23500c9a5c2SPhilippe Mathieu-Daudé     return human_readable_text_from_str(buf);
23600c9a5c2SPhilippe Mathieu-Daudé }
23700c9a5c2SPhilippe Mathieu-Daudé 
hmp_tcg_register(void)23800c9a5c2SPhilippe Mathieu-Daudé static void hmp_tcg_register(void)
23900c9a5c2SPhilippe Mathieu-Daudé {
24000c9a5c2SPhilippe Mathieu-Daudé     monitor_register_hmp_info_hrt("jit", qmp_x_query_jit);
24100c9a5c2SPhilippe Mathieu-Daudé     monitor_register_hmp_info_hrt("opcount", qmp_x_query_opcount);
24200c9a5c2SPhilippe Mathieu-Daudé }
24300c9a5c2SPhilippe Mathieu-Daudé 
24400c9a5c2SPhilippe Mathieu-Daudé type_init(hmp_tcg_register);
245