xref: /openbmc/qemu/accel/tcg/tcg-stats.c (revision 8cc04fd9df3b9775eaf0fb1b17d82a1a075aa3ec)
1*8cc04fd9SPhilippe Mathieu-Daudé /*
2*8cc04fd9SPhilippe Mathieu-Daudé  * SPDX-License-Identifier: LGPL-2.1-or-later
3*8cc04fd9SPhilippe Mathieu-Daudé  *
4*8cc04fd9SPhilippe Mathieu-Daudé  *  QEMU TCG statistics
5*8cc04fd9SPhilippe Mathieu-Daudé  *
6*8cc04fd9SPhilippe Mathieu-Daudé  *  Copyright (c) 2003-2005 Fabrice Bellard
7*8cc04fd9SPhilippe Mathieu-Daudé  */
8*8cc04fd9SPhilippe Mathieu-Daudé 
9*8cc04fd9SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
10*8cc04fd9SPhilippe Mathieu-Daudé #include "qemu/accel.h"
11*8cc04fd9SPhilippe Mathieu-Daudé #include "qemu/qht.h"
12*8cc04fd9SPhilippe Mathieu-Daudé #include "qapi/error.h"
13*8cc04fd9SPhilippe Mathieu-Daudé #include "system/cpu-timers.h"
14*8cc04fd9SPhilippe Mathieu-Daudé #include "exec/icount.h"
15*8cc04fd9SPhilippe Mathieu-Daudé #include "hw/core/cpu.h"
16*8cc04fd9SPhilippe Mathieu-Daudé #include "tcg/tcg.h"
17*8cc04fd9SPhilippe Mathieu-Daudé #include "internal-common.h"
18*8cc04fd9SPhilippe Mathieu-Daudé #include "tb-context.h"
19*8cc04fd9SPhilippe Mathieu-Daudé #include <math.h>
20*8cc04fd9SPhilippe Mathieu-Daudé 
21*8cc04fd9SPhilippe Mathieu-Daudé static void dump_drift_info(GString *buf)
22*8cc04fd9SPhilippe Mathieu-Daudé {
23*8cc04fd9SPhilippe Mathieu-Daudé     if (!icount_enabled()) {
24*8cc04fd9SPhilippe Mathieu-Daudé         return;
25*8cc04fd9SPhilippe Mathieu-Daudé     }
26*8cc04fd9SPhilippe Mathieu-Daudé 
27*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "Host - Guest clock  %"PRIi64" ms\n",
28*8cc04fd9SPhilippe Mathieu-Daudé                            (cpu_get_clock() - icount_get()) / SCALE_MS);
29*8cc04fd9SPhilippe Mathieu-Daudé     if (icount_align_option) {
30*8cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest delay     %"PRIi64" ms\n",
31*8cc04fd9SPhilippe Mathieu-Daudé                                -max_delay / SCALE_MS);
32*8cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest advance   %"PRIi64" ms\n",
33*8cc04fd9SPhilippe Mathieu-Daudé                                max_advance / SCALE_MS);
34*8cc04fd9SPhilippe Mathieu-Daudé     } else {
35*8cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest delay     NA\n");
36*8cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest advance   NA\n");
37*8cc04fd9SPhilippe Mathieu-Daudé     }
38*8cc04fd9SPhilippe Mathieu-Daudé }
39*8cc04fd9SPhilippe Mathieu-Daudé 
40*8cc04fd9SPhilippe Mathieu-Daudé static void dump_accel_info(GString *buf)
41*8cc04fd9SPhilippe Mathieu-Daudé {
42*8cc04fd9SPhilippe Mathieu-Daudé     AccelState *accel = current_accel();
43*8cc04fd9SPhilippe Mathieu-Daudé     bool one_insn_per_tb = object_property_get_bool(OBJECT(accel),
44*8cc04fd9SPhilippe Mathieu-Daudé                                                     "one-insn-per-tb",
45*8cc04fd9SPhilippe Mathieu-Daudé                                                     &error_fatal);
46*8cc04fd9SPhilippe Mathieu-Daudé 
47*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "Accelerator settings:\n");
48*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "one-insn-per-tb: %s\n\n",
49*8cc04fd9SPhilippe Mathieu-Daudé                            one_insn_per_tb ? "on" : "off");
50*8cc04fd9SPhilippe Mathieu-Daudé }
51*8cc04fd9SPhilippe Mathieu-Daudé 
52*8cc04fd9SPhilippe Mathieu-Daudé static void print_qht_statistics(struct qht_stats hst, GString *buf)
53*8cc04fd9SPhilippe Mathieu-Daudé {
54*8cc04fd9SPhilippe Mathieu-Daudé     uint32_t hgram_opts;
55*8cc04fd9SPhilippe Mathieu-Daudé     size_t hgram_bins;
56*8cc04fd9SPhilippe Mathieu-Daudé     char *hgram;
57*8cc04fd9SPhilippe Mathieu-Daudé     double avg;
58*8cc04fd9SPhilippe Mathieu-Daudé 
59*8cc04fd9SPhilippe Mathieu-Daudé     if (!hst.head_buckets) {
60*8cc04fd9SPhilippe Mathieu-Daudé         return;
61*8cc04fd9SPhilippe Mathieu-Daudé     }
62*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB hash buckets     %zu/%zu "
63*8cc04fd9SPhilippe Mathieu-Daudé                            "(%0.2f%% head buckets used)\n",
64*8cc04fd9SPhilippe Mathieu-Daudé                            hst.used_head_buckets, hst.head_buckets,
65*8cc04fd9SPhilippe Mathieu-Daudé                            (double)hst.used_head_buckets /
66*8cc04fd9SPhilippe Mathieu-Daudé                            hst.head_buckets * 100);
67*8cc04fd9SPhilippe Mathieu-Daudé 
68*8cc04fd9SPhilippe Mathieu-Daudé     hgram_opts =  QDIST_PR_BORDER | QDIST_PR_LABELS;
69*8cc04fd9SPhilippe Mathieu-Daudé     hgram_opts |= QDIST_PR_100X   | QDIST_PR_PERCENT;
70*8cc04fd9SPhilippe Mathieu-Daudé     if (qdist_xmax(&hst.occupancy) - qdist_xmin(&hst.occupancy) == 1) {
71*8cc04fd9SPhilippe Mathieu-Daudé         hgram_opts |= QDIST_PR_NODECIMAL;
72*8cc04fd9SPhilippe Mathieu-Daudé     }
73*8cc04fd9SPhilippe Mathieu-Daudé     hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
74*8cc04fd9SPhilippe Mathieu-Daudé     avg = qdist_avg(&hst.occupancy);
75*8cc04fd9SPhilippe Mathieu-Daudé     if (!isnan(avg)) {
76*8cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "TB hash occupancy   "
77*8cc04fd9SPhilippe Mathieu-Daudé                                     "%0.2f%% avg chain occ. "
78*8cc04fd9SPhilippe Mathieu-Daudé                                     "Histogram: %s\n",
79*8cc04fd9SPhilippe Mathieu-Daudé                                avg * 100, hgram);
80*8cc04fd9SPhilippe Mathieu-Daudé     }
81*8cc04fd9SPhilippe Mathieu-Daudé     g_free(hgram);
82*8cc04fd9SPhilippe Mathieu-Daudé 
83*8cc04fd9SPhilippe Mathieu-Daudé     hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
84*8cc04fd9SPhilippe Mathieu-Daudé     hgram_bins = qdist_xmax(&hst.chain) - qdist_xmin(&hst.chain);
85*8cc04fd9SPhilippe Mathieu-Daudé     if (hgram_bins > 10) {
86*8cc04fd9SPhilippe Mathieu-Daudé         hgram_bins = 10;
87*8cc04fd9SPhilippe Mathieu-Daudé     } else {
88*8cc04fd9SPhilippe Mathieu-Daudé         hgram_bins = 0;
89*8cc04fd9SPhilippe Mathieu-Daudé         hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
90*8cc04fd9SPhilippe Mathieu-Daudé     }
91*8cc04fd9SPhilippe Mathieu-Daudé     hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
92*8cc04fd9SPhilippe Mathieu-Daudé     avg = qdist_avg(&hst.chain);
93*8cc04fd9SPhilippe Mathieu-Daudé     if (!isnan(avg)) {
94*8cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "TB hash avg chain   %0.3f buckets. "
95*8cc04fd9SPhilippe Mathieu-Daudé                                "Histogram: %s\n",
96*8cc04fd9SPhilippe Mathieu-Daudé                                avg, hgram);
97*8cc04fd9SPhilippe Mathieu-Daudé     }
98*8cc04fd9SPhilippe Mathieu-Daudé     g_free(hgram);
99*8cc04fd9SPhilippe Mathieu-Daudé }
100*8cc04fd9SPhilippe Mathieu-Daudé 
101*8cc04fd9SPhilippe Mathieu-Daudé struct tb_tree_stats {
102*8cc04fd9SPhilippe Mathieu-Daudé     size_t nb_tbs;
103*8cc04fd9SPhilippe Mathieu-Daudé     size_t host_size;
104*8cc04fd9SPhilippe Mathieu-Daudé     size_t target_size;
105*8cc04fd9SPhilippe Mathieu-Daudé     size_t max_target_size;
106*8cc04fd9SPhilippe Mathieu-Daudé     size_t direct_jmp_count;
107*8cc04fd9SPhilippe Mathieu-Daudé     size_t direct_jmp2_count;
108*8cc04fd9SPhilippe Mathieu-Daudé     size_t cross_page;
109*8cc04fd9SPhilippe Mathieu-Daudé };
110*8cc04fd9SPhilippe Mathieu-Daudé 
111*8cc04fd9SPhilippe Mathieu-Daudé static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
112*8cc04fd9SPhilippe Mathieu-Daudé {
113*8cc04fd9SPhilippe Mathieu-Daudé     const TranslationBlock *tb = value;
114*8cc04fd9SPhilippe Mathieu-Daudé     struct tb_tree_stats *tst = data;
115*8cc04fd9SPhilippe Mathieu-Daudé 
116*8cc04fd9SPhilippe Mathieu-Daudé     tst->nb_tbs++;
117*8cc04fd9SPhilippe Mathieu-Daudé     tst->host_size += tb->tc.size;
118*8cc04fd9SPhilippe Mathieu-Daudé     tst->target_size += tb->size;
119*8cc04fd9SPhilippe Mathieu-Daudé     if (tb->size > tst->max_target_size) {
120*8cc04fd9SPhilippe Mathieu-Daudé         tst->max_target_size = tb->size;
121*8cc04fd9SPhilippe Mathieu-Daudé     }
122*8cc04fd9SPhilippe Mathieu-Daudé #ifndef CONFIG_USER_ONLY
123*8cc04fd9SPhilippe Mathieu-Daudé     if (tb->page_addr[1] != -1) {
124*8cc04fd9SPhilippe Mathieu-Daudé         tst->cross_page++;
125*8cc04fd9SPhilippe Mathieu-Daudé     }
126*8cc04fd9SPhilippe Mathieu-Daudé #endif
127*8cc04fd9SPhilippe Mathieu-Daudé     if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) {
128*8cc04fd9SPhilippe Mathieu-Daudé         tst->direct_jmp_count++;
129*8cc04fd9SPhilippe Mathieu-Daudé         if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) {
130*8cc04fd9SPhilippe Mathieu-Daudé             tst->direct_jmp2_count++;
131*8cc04fd9SPhilippe Mathieu-Daudé         }
132*8cc04fd9SPhilippe Mathieu-Daudé     }
133*8cc04fd9SPhilippe Mathieu-Daudé     return false;
134*8cc04fd9SPhilippe Mathieu-Daudé }
135*8cc04fd9SPhilippe Mathieu-Daudé 
136*8cc04fd9SPhilippe Mathieu-Daudé static void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide)
137*8cc04fd9SPhilippe Mathieu-Daudé {
138*8cc04fd9SPhilippe Mathieu-Daudé     CPUState *cpu;
139*8cc04fd9SPhilippe Mathieu-Daudé     size_t full = 0, part = 0, elide = 0;
140*8cc04fd9SPhilippe Mathieu-Daudé 
141*8cc04fd9SPhilippe Mathieu-Daudé     CPU_FOREACH(cpu) {
142*8cc04fd9SPhilippe Mathieu-Daudé         full += qatomic_read(&cpu->neg.tlb.c.full_flush_count);
143*8cc04fd9SPhilippe Mathieu-Daudé         part += qatomic_read(&cpu->neg.tlb.c.part_flush_count);
144*8cc04fd9SPhilippe Mathieu-Daudé         elide += qatomic_read(&cpu->neg.tlb.c.elide_flush_count);
145*8cc04fd9SPhilippe Mathieu-Daudé     }
146*8cc04fd9SPhilippe Mathieu-Daudé     *pfull = full;
147*8cc04fd9SPhilippe Mathieu-Daudé     *ppart = part;
148*8cc04fd9SPhilippe Mathieu-Daudé     *pelide = elide;
149*8cc04fd9SPhilippe Mathieu-Daudé }
150*8cc04fd9SPhilippe Mathieu-Daudé 
151*8cc04fd9SPhilippe Mathieu-Daudé static void tcg_dump_flush_info(GString *buf)
152*8cc04fd9SPhilippe Mathieu-Daudé {
153*8cc04fd9SPhilippe Mathieu-Daudé     size_t flush_full, flush_part, flush_elide;
154*8cc04fd9SPhilippe Mathieu-Daudé 
155*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB flush count      %u\n",
156*8cc04fd9SPhilippe Mathieu-Daudé                            qatomic_read(&tb_ctx.tb_flush_count));
157*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB invalidate count %u\n",
158*8cc04fd9SPhilippe Mathieu-Daudé                            qatomic_read(&tb_ctx.tb_phys_invalidate_count));
159*8cc04fd9SPhilippe Mathieu-Daudé 
160*8cc04fd9SPhilippe Mathieu-Daudé     tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
161*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TLB full flushes    %zu\n", flush_full);
162*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part);
163*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TLB elided flushes  %zu\n", flush_elide);
164*8cc04fd9SPhilippe Mathieu-Daudé }
165*8cc04fd9SPhilippe Mathieu-Daudé 
166*8cc04fd9SPhilippe Mathieu-Daudé static void dump_exec_info(GString *buf)
167*8cc04fd9SPhilippe Mathieu-Daudé {
168*8cc04fd9SPhilippe Mathieu-Daudé     struct tb_tree_stats tst = {};
169*8cc04fd9SPhilippe Mathieu-Daudé     struct qht_stats hst;
170*8cc04fd9SPhilippe Mathieu-Daudé     size_t nb_tbs;
171*8cc04fd9SPhilippe Mathieu-Daudé 
172*8cc04fd9SPhilippe Mathieu-Daudé     tcg_tb_foreach(tb_tree_stats_iter, &tst);
173*8cc04fd9SPhilippe Mathieu-Daudé     nb_tbs = tst.nb_tbs;
174*8cc04fd9SPhilippe Mathieu-Daudé     /* XXX: avoid using doubles ? */
175*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "Translation buffer state:\n");
176*8cc04fd9SPhilippe Mathieu-Daudé     /*
177*8cc04fd9SPhilippe Mathieu-Daudé      * Report total code size including the padding and TB structs;
178*8cc04fd9SPhilippe Mathieu-Daudé      * otherwise users might think "-accel tcg,tb-size" is not honoured.
179*8cc04fd9SPhilippe Mathieu-Daudé      * For avg host size we use the precise numbers from tb_tree_stats though.
180*8cc04fd9SPhilippe Mathieu-Daudé      */
181*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "gen code size       %zu/%zu\n",
182*8cc04fd9SPhilippe Mathieu-Daudé                            tcg_code_size(), tcg_code_capacity());
183*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB count            %zu\n", nb_tbs);
184*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB avg target size  %zu max=%zu bytes\n",
185*8cc04fd9SPhilippe Mathieu-Daudé                            nb_tbs ? tst.target_size / nb_tbs : 0,
186*8cc04fd9SPhilippe Mathieu-Daudé                            tst.max_target_size);
187*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB avg host size    %zu bytes "
188*8cc04fd9SPhilippe Mathieu-Daudé                            "(expansion ratio: %0.1f)\n",
189*8cc04fd9SPhilippe Mathieu-Daudé                            nb_tbs ? tst.host_size / nb_tbs : 0,
190*8cc04fd9SPhilippe Mathieu-Daudé                            tst.target_size ?
191*8cc04fd9SPhilippe Mathieu-Daudé                            (double)tst.host_size / tst.target_size : 0);
192*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n",
193*8cc04fd9SPhilippe Mathieu-Daudé                            tst.cross_page,
194*8cc04fd9SPhilippe Mathieu-Daudé                            nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
195*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "direct jump count   %zu (%zu%%) "
196*8cc04fd9SPhilippe Mathieu-Daudé                            "(2 jumps=%zu %zu%%)\n",
197*8cc04fd9SPhilippe Mathieu-Daudé                            tst.direct_jmp_count,
198*8cc04fd9SPhilippe Mathieu-Daudé                            nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
199*8cc04fd9SPhilippe Mathieu-Daudé                            tst.direct_jmp2_count,
200*8cc04fd9SPhilippe Mathieu-Daudé                            nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
201*8cc04fd9SPhilippe Mathieu-Daudé 
202*8cc04fd9SPhilippe Mathieu-Daudé     qht_statistics_init(&tb_ctx.htable, &hst);
203*8cc04fd9SPhilippe Mathieu-Daudé     print_qht_statistics(hst, buf);
204*8cc04fd9SPhilippe Mathieu-Daudé     qht_statistics_destroy(&hst);
205*8cc04fd9SPhilippe Mathieu-Daudé 
206*8cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "\nStatistics:\n");
207*8cc04fd9SPhilippe Mathieu-Daudé     tcg_dump_flush_info(buf);
208*8cc04fd9SPhilippe Mathieu-Daudé }
209*8cc04fd9SPhilippe Mathieu-Daudé 
210*8cc04fd9SPhilippe Mathieu-Daudé void tcg_dump_stats(GString *buf)
211*8cc04fd9SPhilippe Mathieu-Daudé {
212*8cc04fd9SPhilippe Mathieu-Daudé     dump_accel_info(buf);
213*8cc04fd9SPhilippe Mathieu-Daudé     dump_exec_info(buf);
214*8cc04fd9SPhilippe Mathieu-Daudé     dump_drift_info(buf);
215*8cc04fd9SPhilippe Mathieu-Daudé }
216