xref: /openbmc/qemu/accel/tcg/tcg-stats.c (revision f96b157ebb93f94cd56ebbc99bc20982b8fd86ef)
18cc04fd9SPhilippe Mathieu-Daudé /*
28cc04fd9SPhilippe Mathieu-Daudé  * SPDX-License-Identifier: LGPL-2.1-or-later
38cc04fd9SPhilippe Mathieu-Daudé  *
48cc04fd9SPhilippe Mathieu-Daudé  *  QEMU TCG statistics
58cc04fd9SPhilippe Mathieu-Daudé  *
68cc04fd9SPhilippe Mathieu-Daudé  *  Copyright (c) 2003-2005 Fabrice Bellard
78cc04fd9SPhilippe Mathieu-Daudé  */
88cc04fd9SPhilippe Mathieu-Daudé 
98cc04fd9SPhilippe Mathieu-Daudé #include "qemu/osdep.h"
108cc04fd9SPhilippe Mathieu-Daudé #include "qemu/accel.h"
118cc04fd9SPhilippe Mathieu-Daudé #include "qemu/qht.h"
128cc04fd9SPhilippe Mathieu-Daudé #include "qapi/error.h"
138cc04fd9SPhilippe Mathieu-Daudé #include "system/cpu-timers.h"
148cc04fd9SPhilippe Mathieu-Daudé #include "exec/icount.h"
158cc04fd9SPhilippe Mathieu-Daudé #include "hw/core/cpu.h"
168cc04fd9SPhilippe Mathieu-Daudé #include "tcg/tcg.h"
178cc04fd9SPhilippe Mathieu-Daudé #include "internal-common.h"
188cc04fd9SPhilippe Mathieu-Daudé #include "tb-context.h"
198cc04fd9SPhilippe Mathieu-Daudé #include <math.h>
208cc04fd9SPhilippe Mathieu-Daudé 
dump_drift_info(GString * buf)218cc04fd9SPhilippe Mathieu-Daudé static void dump_drift_info(GString *buf)
228cc04fd9SPhilippe Mathieu-Daudé {
238cc04fd9SPhilippe Mathieu-Daudé     if (!icount_enabled()) {
248cc04fd9SPhilippe Mathieu-Daudé         return;
258cc04fd9SPhilippe Mathieu-Daudé     }
268cc04fd9SPhilippe Mathieu-Daudé 
278cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "Host - Guest clock  %"PRIi64" ms\n",
288cc04fd9SPhilippe Mathieu-Daudé                            (cpu_get_clock() - icount_get()) / SCALE_MS);
298cc04fd9SPhilippe Mathieu-Daudé     if (icount_align_option) {
308cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest delay     %"PRIi64" ms\n",
318cc04fd9SPhilippe Mathieu-Daudé                                -max_delay / SCALE_MS);
328cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest advance   %"PRIi64" ms\n",
338cc04fd9SPhilippe Mathieu-Daudé                                max_advance / SCALE_MS);
348cc04fd9SPhilippe Mathieu-Daudé     } else {
358cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest delay     NA\n");
368cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "Max guest advance   NA\n");
378cc04fd9SPhilippe Mathieu-Daudé     }
388cc04fd9SPhilippe Mathieu-Daudé }
398cc04fd9SPhilippe Mathieu-Daudé 
dump_accel_info(AccelState * accel,GString * buf)4023204530SPhilippe Mathieu-Daudé static void dump_accel_info(AccelState *accel, GString *buf)
418cc04fd9SPhilippe Mathieu-Daudé {
428cc04fd9SPhilippe Mathieu-Daudé     bool one_insn_per_tb = object_property_get_bool(OBJECT(accel),
438cc04fd9SPhilippe Mathieu-Daudé                                                     "one-insn-per-tb",
448cc04fd9SPhilippe Mathieu-Daudé                                                     &error_fatal);
458cc04fd9SPhilippe Mathieu-Daudé 
468cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "Accelerator settings:\n");
478cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "one-insn-per-tb: %s\n\n",
488cc04fd9SPhilippe Mathieu-Daudé                            one_insn_per_tb ? "on" : "off");
498cc04fd9SPhilippe Mathieu-Daudé }
508cc04fd9SPhilippe Mathieu-Daudé 
print_qht_statistics(struct qht_stats hst,GString * buf)518cc04fd9SPhilippe Mathieu-Daudé static void print_qht_statistics(struct qht_stats hst, GString *buf)
528cc04fd9SPhilippe Mathieu-Daudé {
538cc04fd9SPhilippe Mathieu-Daudé     uint32_t hgram_opts;
548cc04fd9SPhilippe Mathieu-Daudé     size_t hgram_bins;
558cc04fd9SPhilippe Mathieu-Daudé     char *hgram;
568cc04fd9SPhilippe Mathieu-Daudé     double avg;
578cc04fd9SPhilippe Mathieu-Daudé 
588cc04fd9SPhilippe Mathieu-Daudé     if (!hst.head_buckets) {
598cc04fd9SPhilippe Mathieu-Daudé         return;
608cc04fd9SPhilippe Mathieu-Daudé     }
618cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB hash buckets     %zu/%zu "
628cc04fd9SPhilippe Mathieu-Daudé                            "(%0.2f%% head buckets used)\n",
638cc04fd9SPhilippe Mathieu-Daudé                            hst.used_head_buckets, hst.head_buckets,
648cc04fd9SPhilippe Mathieu-Daudé                            (double)hst.used_head_buckets /
658cc04fd9SPhilippe Mathieu-Daudé                            hst.head_buckets * 100);
668cc04fd9SPhilippe Mathieu-Daudé 
678cc04fd9SPhilippe Mathieu-Daudé     hgram_opts =  QDIST_PR_BORDER | QDIST_PR_LABELS;
688cc04fd9SPhilippe Mathieu-Daudé     hgram_opts |= QDIST_PR_100X   | QDIST_PR_PERCENT;
698cc04fd9SPhilippe Mathieu-Daudé     if (qdist_xmax(&hst.occupancy) - qdist_xmin(&hst.occupancy) == 1) {
708cc04fd9SPhilippe Mathieu-Daudé         hgram_opts |= QDIST_PR_NODECIMAL;
718cc04fd9SPhilippe Mathieu-Daudé     }
728cc04fd9SPhilippe Mathieu-Daudé     hgram = qdist_pr(&hst.occupancy, 10, hgram_opts);
738cc04fd9SPhilippe Mathieu-Daudé     avg = qdist_avg(&hst.occupancy);
748cc04fd9SPhilippe Mathieu-Daudé     if (!isnan(avg)) {
758cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "TB hash occupancy   "
768cc04fd9SPhilippe Mathieu-Daudé                                     "%0.2f%% avg chain occ. "
778cc04fd9SPhilippe Mathieu-Daudé                                     "Histogram: %s\n",
788cc04fd9SPhilippe Mathieu-Daudé                                avg * 100, hgram);
798cc04fd9SPhilippe Mathieu-Daudé     }
808cc04fd9SPhilippe Mathieu-Daudé     g_free(hgram);
818cc04fd9SPhilippe Mathieu-Daudé 
828cc04fd9SPhilippe Mathieu-Daudé     hgram_opts = QDIST_PR_BORDER | QDIST_PR_LABELS;
838cc04fd9SPhilippe Mathieu-Daudé     hgram_bins = qdist_xmax(&hst.chain) - qdist_xmin(&hst.chain);
848cc04fd9SPhilippe Mathieu-Daudé     if (hgram_bins > 10) {
858cc04fd9SPhilippe Mathieu-Daudé         hgram_bins = 10;
868cc04fd9SPhilippe Mathieu-Daudé     } else {
878cc04fd9SPhilippe Mathieu-Daudé         hgram_bins = 0;
888cc04fd9SPhilippe Mathieu-Daudé         hgram_opts |= QDIST_PR_NODECIMAL | QDIST_PR_NOBINRANGE;
898cc04fd9SPhilippe Mathieu-Daudé     }
908cc04fd9SPhilippe Mathieu-Daudé     hgram = qdist_pr(&hst.chain, hgram_bins, hgram_opts);
918cc04fd9SPhilippe Mathieu-Daudé     avg = qdist_avg(&hst.chain);
928cc04fd9SPhilippe Mathieu-Daudé     if (!isnan(avg)) {
938cc04fd9SPhilippe Mathieu-Daudé         g_string_append_printf(buf, "TB hash avg chain   %0.3f buckets. "
948cc04fd9SPhilippe Mathieu-Daudé                                "Histogram: %s\n",
958cc04fd9SPhilippe Mathieu-Daudé                                avg, hgram);
968cc04fd9SPhilippe Mathieu-Daudé     }
978cc04fd9SPhilippe Mathieu-Daudé     g_free(hgram);
988cc04fd9SPhilippe Mathieu-Daudé }
998cc04fd9SPhilippe Mathieu-Daudé 
1008cc04fd9SPhilippe Mathieu-Daudé struct tb_tree_stats {
1018cc04fd9SPhilippe Mathieu-Daudé     size_t nb_tbs;
1028cc04fd9SPhilippe Mathieu-Daudé     size_t host_size;
1038cc04fd9SPhilippe Mathieu-Daudé     size_t target_size;
1048cc04fd9SPhilippe Mathieu-Daudé     size_t max_target_size;
1058cc04fd9SPhilippe Mathieu-Daudé     size_t direct_jmp_count;
1068cc04fd9SPhilippe Mathieu-Daudé     size_t direct_jmp2_count;
1078cc04fd9SPhilippe Mathieu-Daudé     size_t cross_page;
1088cc04fd9SPhilippe Mathieu-Daudé };
1098cc04fd9SPhilippe Mathieu-Daudé 
tb_tree_stats_iter(gpointer key,gpointer value,gpointer data)1108cc04fd9SPhilippe Mathieu-Daudé static gboolean tb_tree_stats_iter(gpointer key, gpointer value, gpointer data)
1118cc04fd9SPhilippe Mathieu-Daudé {
1128cc04fd9SPhilippe Mathieu-Daudé     const TranslationBlock *tb = value;
1138cc04fd9SPhilippe Mathieu-Daudé     struct tb_tree_stats *tst = data;
1148cc04fd9SPhilippe Mathieu-Daudé 
1158cc04fd9SPhilippe Mathieu-Daudé     tst->nb_tbs++;
1168cc04fd9SPhilippe Mathieu-Daudé     tst->host_size += tb->tc.size;
1178cc04fd9SPhilippe Mathieu-Daudé     tst->target_size += tb->size;
1188cc04fd9SPhilippe Mathieu-Daudé     if (tb->size > tst->max_target_size) {
1198cc04fd9SPhilippe Mathieu-Daudé         tst->max_target_size = tb->size;
1208cc04fd9SPhilippe Mathieu-Daudé     }
1218cc04fd9SPhilippe Mathieu-Daudé #ifndef CONFIG_USER_ONLY
1228cc04fd9SPhilippe Mathieu-Daudé     if (tb->page_addr[1] != -1) {
1238cc04fd9SPhilippe Mathieu-Daudé         tst->cross_page++;
1248cc04fd9SPhilippe Mathieu-Daudé     }
1258cc04fd9SPhilippe Mathieu-Daudé #endif
1268cc04fd9SPhilippe Mathieu-Daudé     if (tb->jmp_reset_offset[0] != TB_JMP_OFFSET_INVALID) {
1278cc04fd9SPhilippe Mathieu-Daudé         tst->direct_jmp_count++;
1288cc04fd9SPhilippe Mathieu-Daudé         if (tb->jmp_reset_offset[1] != TB_JMP_OFFSET_INVALID) {
1298cc04fd9SPhilippe Mathieu-Daudé             tst->direct_jmp2_count++;
1308cc04fd9SPhilippe Mathieu-Daudé         }
1318cc04fd9SPhilippe Mathieu-Daudé     }
1328cc04fd9SPhilippe Mathieu-Daudé     return false;
1338cc04fd9SPhilippe Mathieu-Daudé }
1348cc04fd9SPhilippe Mathieu-Daudé 
tlb_flush_counts(size_t * pfull,size_t * ppart,size_t * pelide)1358cc04fd9SPhilippe Mathieu-Daudé static void tlb_flush_counts(size_t *pfull, size_t *ppart, size_t *pelide)
1368cc04fd9SPhilippe Mathieu-Daudé {
1378cc04fd9SPhilippe Mathieu-Daudé     CPUState *cpu;
1388cc04fd9SPhilippe Mathieu-Daudé     size_t full = 0, part = 0, elide = 0;
1398cc04fd9SPhilippe Mathieu-Daudé 
1408cc04fd9SPhilippe Mathieu-Daudé     CPU_FOREACH(cpu) {
1418cc04fd9SPhilippe Mathieu-Daudé         full += qatomic_read(&cpu->neg.tlb.c.full_flush_count);
1428cc04fd9SPhilippe Mathieu-Daudé         part += qatomic_read(&cpu->neg.tlb.c.part_flush_count);
1438cc04fd9SPhilippe Mathieu-Daudé         elide += qatomic_read(&cpu->neg.tlb.c.elide_flush_count);
1448cc04fd9SPhilippe Mathieu-Daudé     }
1458cc04fd9SPhilippe Mathieu-Daudé     *pfull = full;
1468cc04fd9SPhilippe Mathieu-Daudé     *ppart = part;
1478cc04fd9SPhilippe Mathieu-Daudé     *pelide = elide;
1488cc04fd9SPhilippe Mathieu-Daudé }
1498cc04fd9SPhilippe Mathieu-Daudé 
tcg_dump_flush_info(GString * buf)1508cc04fd9SPhilippe Mathieu-Daudé static void tcg_dump_flush_info(GString *buf)
1518cc04fd9SPhilippe Mathieu-Daudé {
1528cc04fd9SPhilippe Mathieu-Daudé     size_t flush_full, flush_part, flush_elide;
1538cc04fd9SPhilippe Mathieu-Daudé 
1548cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB flush count      %u\n",
1558cc04fd9SPhilippe Mathieu-Daudé                            qatomic_read(&tb_ctx.tb_flush_count));
1568cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB invalidate count %u\n",
1578cc04fd9SPhilippe Mathieu-Daudé                            qatomic_read(&tb_ctx.tb_phys_invalidate_count));
1588cc04fd9SPhilippe Mathieu-Daudé 
1598cc04fd9SPhilippe Mathieu-Daudé     tlb_flush_counts(&flush_full, &flush_part, &flush_elide);
1608cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TLB full flushes    %zu\n", flush_full);
1618cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TLB partial flushes %zu\n", flush_part);
1628cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TLB elided flushes  %zu\n", flush_elide);
1638cc04fd9SPhilippe Mathieu-Daudé }
1648cc04fd9SPhilippe Mathieu-Daudé 
dump_exec_info(GString * buf)1658cc04fd9SPhilippe Mathieu-Daudé static void dump_exec_info(GString *buf)
1668cc04fd9SPhilippe Mathieu-Daudé {
1678cc04fd9SPhilippe Mathieu-Daudé     struct tb_tree_stats tst = {};
1688cc04fd9SPhilippe Mathieu-Daudé     struct qht_stats hst;
1698cc04fd9SPhilippe Mathieu-Daudé     size_t nb_tbs;
1708cc04fd9SPhilippe Mathieu-Daudé 
1718cc04fd9SPhilippe Mathieu-Daudé     tcg_tb_foreach(tb_tree_stats_iter, &tst);
1728cc04fd9SPhilippe Mathieu-Daudé     nb_tbs = tst.nb_tbs;
1738cc04fd9SPhilippe Mathieu-Daudé     /* XXX: avoid using doubles ? */
1748cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "Translation buffer state:\n");
1758cc04fd9SPhilippe Mathieu-Daudé     /*
1768cc04fd9SPhilippe Mathieu-Daudé      * Report total code size including the padding and TB structs;
1778cc04fd9SPhilippe Mathieu-Daudé      * otherwise users might think "-accel tcg,tb-size" is not honoured.
1788cc04fd9SPhilippe Mathieu-Daudé      * For avg host size we use the precise numbers from tb_tree_stats though.
1798cc04fd9SPhilippe Mathieu-Daudé      */
1808cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "gen code size       %zu/%zu\n",
1818cc04fd9SPhilippe Mathieu-Daudé                            tcg_code_size(), tcg_code_capacity());
1828cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB count            %zu\n", nb_tbs);
1838cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB avg target size  %zu max=%zu bytes\n",
1848cc04fd9SPhilippe Mathieu-Daudé                            nb_tbs ? tst.target_size / nb_tbs : 0,
1858cc04fd9SPhilippe Mathieu-Daudé                            tst.max_target_size);
1868cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "TB avg host size    %zu bytes "
1878cc04fd9SPhilippe Mathieu-Daudé                            "(expansion ratio: %0.1f)\n",
1888cc04fd9SPhilippe Mathieu-Daudé                            nb_tbs ? tst.host_size / nb_tbs : 0,
1898cc04fd9SPhilippe Mathieu-Daudé                            tst.target_size ?
1908cc04fd9SPhilippe Mathieu-Daudé                            (double)tst.host_size / tst.target_size : 0);
1918cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "cross page TB count %zu (%zu%%)\n",
1928cc04fd9SPhilippe Mathieu-Daudé                            tst.cross_page,
1938cc04fd9SPhilippe Mathieu-Daudé                            nb_tbs ? (tst.cross_page * 100) / nb_tbs : 0);
1948cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "direct jump count   %zu (%zu%%) "
1958cc04fd9SPhilippe Mathieu-Daudé                            "(2 jumps=%zu %zu%%)\n",
1968cc04fd9SPhilippe Mathieu-Daudé                            tst.direct_jmp_count,
1978cc04fd9SPhilippe Mathieu-Daudé                            nb_tbs ? (tst.direct_jmp_count * 100) / nb_tbs : 0,
1988cc04fd9SPhilippe Mathieu-Daudé                            tst.direct_jmp2_count,
1998cc04fd9SPhilippe Mathieu-Daudé                            nb_tbs ? (tst.direct_jmp2_count * 100) / nb_tbs : 0);
2008cc04fd9SPhilippe Mathieu-Daudé 
2018cc04fd9SPhilippe Mathieu-Daudé     qht_statistics_init(&tb_ctx.htable, &hst);
2028cc04fd9SPhilippe Mathieu-Daudé     print_qht_statistics(hst, buf);
2038cc04fd9SPhilippe Mathieu-Daudé     qht_statistics_destroy(&hst);
2048cc04fd9SPhilippe Mathieu-Daudé 
2058cc04fd9SPhilippe Mathieu-Daudé     g_string_append_printf(buf, "\nStatistics:\n");
2068cc04fd9SPhilippe Mathieu-Daudé     tcg_dump_flush_info(buf);
2078cc04fd9SPhilippe Mathieu-Daudé }
2088cc04fd9SPhilippe Mathieu-Daudé 
tcg_get_stats(AccelState * accel,GString * buf)209*cf4305edSPhilippe Mathieu-Daudé void tcg_get_stats(AccelState *accel, GString *buf)
2108cc04fd9SPhilippe Mathieu-Daudé {
211*cf4305edSPhilippe Mathieu-Daudé     dump_accel_info(accel, buf);
2128cc04fd9SPhilippe Mathieu-Daudé     dump_exec_info(buf);
2138cc04fd9SPhilippe Mathieu-Daudé     dump_drift_info(buf);
2148cc04fd9SPhilippe Mathieu-Daudé }
215*cf4305edSPhilippe Mathieu-Daudé 
tcg_dump_stats(GString * buf)216*cf4305edSPhilippe Mathieu-Daudé void tcg_dump_stats(GString *buf)
217*cf4305edSPhilippe Mathieu-Daudé {
218*cf4305edSPhilippe Mathieu-Daudé     tcg_get_stats(current_accel(), buf);
219*cf4305edSPhilippe Mathieu-Daudé }
220