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é 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é 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é 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é 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é 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é 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é 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é 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é 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