All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v15 00/10] TCG code quality tracking
@ 2023-06-07 12:24 Fei Wu
  2023-06-07 12:24 ` [PATCH v15 01/10] accel/tcg: remove CONFIG_PROFILER Fei Wu
                   ` (11 more replies)
  0 siblings, 12 replies; 17+ messages in thread
From: Fei Wu @ 2023-06-07 12:24 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel; +Cc: Fei Wu

v15
---
This is a large change:
* remove all time related stuffs, including cmd 'info profile'
* remove the per-TB flag, use global flag instead
* remove tb_stats pause/filter, but add status
* remove qemu_log changes, and use monitor_printf
* use array instead of list for sorting
* remove async_safe_run_on_cpu for cmd info tb-list & tb
* use monitor_disas instead of regenerate TB, but **doesn't work yet**
* other cleanups


Alex Bennée (1):
  tb-stats: reset the tracked TBs on a tb_flush

Fei Wu (5):
  accel/tcg: remove CONFIG_PROFILER
  accel/tcg: add jit stats to TBStatistics
  debug: add -d tb_stats to control TBStatistics
  tb-stats: dump hot TBs at the end of the execution
  docs: add tb-stats how to

Vanderson M. do Rosario (4):
  accel/tcg: introduce TBStatistics structure
  accel: collecting TB execution count
  monitor: adding tb_stats hmp command
  tb-stats: Adding info [tb-list|tb] commands to HMP (WIP)

 MAINTAINERS                   |   1 +
 accel/tcg/cpu-exec.c          |   6 +
 accel/tcg/meson.build         |   1 +
 accel/tcg/monitor.c           | 184 +++++++++++++++--
 accel/tcg/tb-context.h        |   1 +
 accel/tcg/tb-hash.h           |   7 +
 accel/tcg/tb-maint.c          |  20 ++
 accel/tcg/tb-stats.c          | 365 ++++++++++++++++++++++++++++++++++
 accel/tcg/tcg-accel-ops.c     |  10 -
 accel/tcg/tcg-runtime.c       |   1 +
 accel/tcg/translate-all.c     | 110 ++++++----
 accel/tcg/translator.c        |  30 +++
 disas/disas.c                 |   2 +
 docs/devel/tcg-tbstats.rst    |  97 +++++++++
 hmp-commands-info.hx          |  31 +--
 hmp-commands.hx               |  16 ++
 include/exec/exec-all.h       |   3 +
 include/exec/gen-icount.h     |   1 +
 include/exec/tb-stats-dump.h  |  21 ++
 include/exec/tb-stats-flags.h |  29 +++
 include/exec/tb-stats.h       | 130 ++++++++++++
 include/monitor/hmp.h         |   3 +
 include/qemu/log.h            |   1 +
 include/qemu/timer.h          |   9 -
 include/tcg/tcg.h             |  26 +--
 linux-user/exit.c             |   2 +
 meson.build                   |   2 -
 meson_options.txt             |   2 -
 qapi/machine.json             |  18 --
 scripts/meson-buildoptions.sh |   3 -
 softmmu/runstate.c            |  11 +-
 stubs/meson.build             |   1 +
 stubs/tb-stats.c              |  36 ++++
 tcg/tcg.c                     | 237 +++-------------------
 tests/qtest/qmp-cmd-test.c    |   3 -
 util/log.c                    |  26 +++
 36 files changed, 1093 insertions(+), 353 deletions(-)
 create mode 100644 accel/tcg/tb-stats.c
 create mode 100644 docs/devel/tcg-tbstats.rst
 create mode 100644 include/exec/tb-stats-dump.h
 create mode 100644 include/exec/tb-stats-flags.h
 create mode 100644 include/exec/tb-stats.h
 create mode 100644 stubs/tb-stats.c

-- 
2.25.1



^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v15 01/10] accel/tcg: remove CONFIG_PROFILER
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
@ 2023-06-07 12:24 ` Fei Wu
  2023-06-07 12:24 ` [PATCH v15 02/10] accel/tcg: introduce TBStatistics structure Fei Wu
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Fei Wu @ 2023-06-07 12:24 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel
  Cc: Fei Wu, Vanderson M . do Rosario, Paolo Bonzini,
	Dr. David Alan Gilbert, Marc-André Lureau,
	Daniel P. Berrangé, Thomas Huth, Philippe Mathieu-Daudé,
	Eduardo Habkost, Marcel Apfelbaum, Yanan Wang, Eric Blake,
	Markus Armbruster, Laurent Vivier

TBStats will be introduced to replace CONFIG_PROFILER totally, here
remove all CONFIG_PROFILER related stuffs first.

Signed-off-by: Vanderson M. do Rosario <vandersonmr2@gmail.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Fei Wu <fei2.wu@intel.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
---
 accel/tcg/monitor.c           |  31 -----
 accel/tcg/tcg-accel-ops.c     |  10 --
 accel/tcg/translate-all.c     |  33 ------
 hmp-commands-info.hx          |  15 ---
 include/qemu/timer.h          |   9 --
 include/tcg/tcg.h             |  26 -----
 meson.build                   |   2 -
 meson_options.txt             |   2 -
 qapi/machine.json             |  18 ---
 scripts/meson-buildoptions.sh |   3 -
 softmmu/runstate.c            |   9 --
 tcg/tcg.c                     | 214 ----------------------------------
 tests/qtest/qmp-cmd-test.c    |   3 -
 13 files changed, 375 deletions(-)

diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c
index 92fce580f1..39d8260428 100644
--- a/accel/tcg/monitor.c
+++ b/accel/tcg/monitor.c
@@ -80,37 +80,6 @@ HumanReadableText *qmp_x_query_opcount(Error **errp)
     return human_readable_text_from_str(buf);
 }
 
-#ifdef CONFIG_PROFILER
-
-int64_t dev_time;
-
-HumanReadableText *qmp_x_query_profile(Error **errp)
-{
-    g_autoptr(GString) buf = g_string_new("");
-    static int64_t last_cpu_exec_time;
-    int64_t cpu_exec_time;
-    int64_t delta;
-
-    cpu_exec_time = tcg_cpu_exec_time();
-    delta = cpu_exec_time - last_cpu_exec_time;
-
-    g_string_append_printf(buf, "async time  %" PRId64 " (%0.3f)\n",
-                           dev_time, dev_time / (double)NANOSECONDS_PER_SECOND);
-    g_string_append_printf(buf, "qemu time   %" PRId64 " (%0.3f)\n",
-                           delta, delta / (double)NANOSECONDS_PER_SECOND);
-    last_cpu_exec_time = cpu_exec_time;
-    dev_time = 0;
-
-    return human_readable_text_from_str(buf);
-}
-#else
-HumanReadableText *qmp_x_query_profile(Error **errp)
-{
-    error_setg(errp, "Internal profiler not compiled");
-    return NULL;
-}
-#endif
-
 static void hmp_tcg_register(void)
 {
     monitor_register_hmp_info_hrt("jit", qmp_x_query_jit);
diff --git a/accel/tcg/tcg-accel-ops.c b/accel/tcg/tcg-accel-ops.c
index 58c8e64096..3973591508 100644
--- a/accel/tcg/tcg-accel-ops.c
+++ b/accel/tcg/tcg-accel-ops.c
@@ -70,20 +70,10 @@ void tcg_cpus_destroy(CPUState *cpu)
 int tcg_cpus_exec(CPUState *cpu)
 {
     int ret;
-#ifdef CONFIG_PROFILER
-    int64_t ti;
-#endif
     assert(tcg_enabled());
-#ifdef CONFIG_PROFILER
-    ti = profile_getclock();
-#endif
     cpu_exec_start(cpu);
     ret = cpu_exec(cpu);
     cpu_exec_end(cpu);
-#ifdef CONFIG_PROFILER
-    qatomic_set(&tcg_ctx->prof.cpu_exec_time,
-                tcg_ctx->prof.cpu_exec_time + profile_getclock() - ti);
-#endif
     return ret;
 }
 
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index c87648b99e..4e035e0f79 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -203,10 +203,6 @@ void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
                                uintptr_t host_pc)
 {
     uint64_t data[TARGET_INSN_START_WORDS];
-#ifdef CONFIG_PROFILER
-    TCGProfile *prof = &tcg_ctx->prof;
-    int64_t ti = profile_getclock();
-#endif
     int insns_left = cpu_unwind_data_from_tb(tb, host_pc, data);
 
     if (insns_left < 0) {
@@ -223,12 +219,6 @@ void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
     }
 
     cpu->cc->tcg_ops->restore_state_to_opc(cpu, tb, data);
-
-#ifdef CONFIG_PROFILER
-    qatomic_set(&prof->restore_time,
-                prof->restore_time + profile_getclock() - ti);
-    qatomic_set(&prof->restore_count, prof->restore_count + 1);
-#endif
 }
 
 bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc)
@@ -291,13 +281,6 @@ static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb,
     tcg_ctx->cpu = NULL;
     *max_insns = tb->icount;
 
-#ifdef CONFIG_PROFILER
-    qatomic_set(&tcg_ctx->prof.tb_count, tcg_ctx->prof.tb_count + 1);
-    qatomic_set(&tcg_ctx->prof.interm_time,
-                tcg_ctx->prof.interm_time + profile_getclock() - *ti);
-    *ti = profile_getclock();
-#endif
-
     return tcg_gen_code(tcg_ctx, tb, pc);
 }
 
@@ -311,9 +294,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
     tb_page_addr_t phys_pc;
     tcg_insn_unit *gen_code_buf;
     int gen_code_size, search_size, max_insns;
-#ifdef CONFIG_PROFILER
-    TCGProfile *prof = &tcg_ctx->prof;
-#endif
     int64_t ti;
     void *host_pc;
 
@@ -365,12 +345,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
 
  tb_overflow:
 
-#ifdef CONFIG_PROFILER
-    /* includes aborted translations because of exceptions */
-    qatomic_set(&prof->tb_count1, prof->tb_count1 + 1);
-    ti = profile_getclock();
-#endif
-
     trace_translate_block(tb, pc, tb->tc.ptr);
 
     gen_code_size = setjmp_gen_code(env, tb, pc, host_pc, &max_insns, &ti);
@@ -425,13 +399,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
      */
     perf_report_code(pc, tb, tcg_splitwx_to_rx(gen_code_buf));
 
-#ifdef CONFIG_PROFILER
-    qatomic_set(&prof->code_time, prof->code_time + profile_getclock() - ti);
-    qatomic_set(&prof->code_in_len, prof->code_in_len + tb->size);
-    qatomic_set(&prof->code_out_len, prof->code_out_len + gen_code_size);
-    qatomic_set(&prof->search_out_len, prof->search_out_len + search_size);
-#endif
-
     if (qemu_loglevel_mask(CPU_LOG_TB_OUT_ASM) &&
         qemu_log_in_addr_range(pc)) {
         FILE *logfile = qemu_log_trylock();
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 47d63d26db..f5b37eb74a 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -360,21 +360,6 @@ SRST
     Show host USB devices.
 ERST
 
-#if defined(CONFIG_TCG)
-    {
-        .name       = "profile",
-        .args_type  = "",
-        .params     = "",
-        .help       = "show profiling information",
-        .cmd_info_hrt = qmp_x_query_profile,
-    },
-#endif
-
-SRST
-  ``info profile``
-    Show profiling information.
-ERST
-
     {
         .name       = "capture",
         .args_type  = "",
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index ee071e07d1..9a91cb1248 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -989,13 +989,4 @@ static inline int64_t cpu_get_host_ticks(void)
 }
 #endif
 
-#ifdef CONFIG_PROFILER
-static inline int64_t profile_getclock(void)
-{
-    return get_clock();
-}
-
-extern int64_t dev_time;
-#endif
-
 #endif
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index 072c35f7f5..da1c8fa3b5 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -522,27 +522,6 @@ static inline TCGRegSet output_pref(const TCGOp *op, unsigned i)
     return i < ARRAY_SIZE(op->output_pref) ? op->output_pref[i] : 0;
 }
 
-typedef struct TCGProfile {
-    int64_t cpu_exec_time;
-    int64_t tb_count1;
-    int64_t tb_count;
-    int64_t op_count; /* total insn count */
-    int op_count_max; /* max insn per TB */
-    int temp_count_max;
-    int64_t temp_count;
-    int64_t del_op_count;
-    int64_t code_in_len;
-    int64_t code_out_len;
-    int64_t search_out_len;
-    int64_t interm_time;
-    int64_t code_time;
-    int64_t la_time;
-    int64_t opt_time;
-    int64_t restore_count;
-    int64_t restore_time;
-    int64_t table_op_count[NB_OPS];
-} TCGProfile;
-
 struct TCGContext {
     uint8_t *pool_cur, *pool_end;
     TCGPool *pool_first, *pool_current, *pool_first_large;
@@ -569,10 +548,6 @@ struct TCGContext {
     tcg_insn_unit *code_buf;      /* pointer for start of tb */
     tcg_insn_unit *code_ptr;      /* pointer for running end of tb */
 
-#ifdef CONFIG_PROFILER
-    TCGProfile prof;
-#endif
-
 #ifdef CONFIG_DEBUG_TCG
     int goto_tb_issue_mask;
     const TCGOpcode *vecop_list;
@@ -910,7 +885,6 @@ static inline TCGv_ptr tcg_temp_new_ptr(void)
     return temp_tcgv_ptr(t);
 }
 
-int64_t tcg_cpu_exec_time(void);
 void tcg_dump_info(GString *buf);
 void tcg_dump_op_count(GString *buf);
 
diff --git a/meson.build b/meson.build
index ef181ff2df..7da252cc81 100644
--- a/meson.build
+++ b/meson.build
@@ -2134,7 +2134,6 @@ if numa.found()
                                        dependencies: numa))
 endif
 config_host_data.set('CONFIG_OPENGL', opengl.found())
-config_host_data.set('CONFIG_PROFILER', get_option('profiler'))
 config_host_data.set('CONFIG_RBD', rbd.found())
 config_host_data.set('CONFIG_RDMA', rdma.found())
 config_host_data.set('CONFIG_SAFESTACK', get_option('safe_stack'))
@@ -4117,7 +4116,6 @@ if 'objc' in all_languages
   summary_info += {'QEMU_OBJCFLAGS':    ' '.join(qemu_common_flags)}
 endif
 summary_info += {'QEMU_LDFLAGS':      ' '.join(qemu_ldflags)}
-summary_info += {'profiler':          get_option('profiler')}
 summary_info += {'link-time optimization (LTO)': get_option('b_lto')}
 summary_info += {'PIE':               get_option('b_pie')}
 summary_info += {'static build':      config_host.has_key('CONFIG_STATIC')}
diff --git a/meson_options.txt b/meson_options.txt
index 90237389e2..bbb5c7e886 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -345,8 +345,6 @@ option('qom_cast_debug', type: 'boolean', value: true,
 option('gprof', type: 'boolean', value: false,
        description: 'QEMU profiling with gprof',
        deprecated: true)
-option('profiler', type: 'boolean', value: false,
-       description: 'profiler support')
 option('slirp_smbd', type : 'feature', value : 'auto',
        description: 'use smbd (at path --smbd=*) in slirp networking')
 
diff --git a/qapi/machine.json b/qapi/machine.json
index 37660d8f2a..a08b6576ca 100644
--- a/qapi/machine.json
+++ b/qapi/machine.json
@@ -1575,24 +1575,6 @@
   'if': 'CONFIG_TCG',
   'features': [ 'unstable' ] }
 
-##
-# @x-query-profile:
-#
-# Query TCG profiling information
-#
-# Features:
-#
-# @unstable: This command is meant for debugging.
-#
-# Returns: profile information
-#
-# Since: 6.2
-##
-{ 'command': 'x-query-profile',
-  'returns': 'HumanReadableText',
-  'if': 'CONFIG_TCG',
-  'features': [ 'unstable' ] }
-
 ##
 # @x-query-ramblock:
 #
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 5714fd93d9..7dd5709ef4 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -39,7 +39,6 @@ meson_options_help() {
   printf "%s\n" '                           jemalloc/system/tcmalloc)'
   printf "%s\n" '  --enable-module-upgrades try to load modules from alternate paths for'
   printf "%s\n" '                           upgrades'
-  printf "%s\n" '  --enable-profiler        profiler support'
   printf "%s\n" '  --enable-rng-none        dummy RNG, avoid using /dev/(u)random and'
   printf "%s\n" '                           getrandom()'
   printf "%s\n" '  --enable-safe-stack      SafeStack Stack Smash Protection (requires'
@@ -401,8 +400,6 @@ _meson_option_parse() {
     --with-pkgversion=*) quote_sh "-Dpkgversion=$2" ;;
     --enable-png) printf "%s" -Dpng=enabled ;;
     --disable-png) printf "%s" -Dpng=disabled ;;
-    --enable-profiler) printf "%s" -Dprofiler=true ;;
-    --disable-profiler) printf "%s" -Dprofiler=false ;;
     --enable-pvrdma) printf "%s" -Dpvrdma=enabled ;;
     --disable-pvrdma) printf "%s" -Dpvrdma=disabled ;;
     --enable-qcow1) printf "%s" -Dqcow1=enabled ;;
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
index 2f2396c819..bd50062ed0 100644
--- a/softmmu/runstate.c
+++ b/softmmu/runstate.c
@@ -728,18 +728,9 @@ static bool main_loop_should_exit(int *status)
 int qemu_main_loop(void)
 {
     int status = EXIT_SUCCESS;
-#ifdef CONFIG_PROFILER
-    int64_t ti;
-#endif
 
     while (!main_loop_should_exit(&status)) {
-#ifdef CONFIG_PROFILER
-        ti = profile_getclock();
-#endif
         main_loop_wait(false);
-#ifdef CONFIG_PROFILER
-        dev_time += profile_getclock() - ti;
-#endif
     }
 
     return status;
diff --git a/tcg/tcg.c b/tcg/tcg.c
index ac30d484f5..4c569294db 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2983,10 +2983,6 @@ void tcg_op_remove(TCGContext *s, TCGOp *op)
     QTAILQ_REMOVE(&s->ops, op, link);
     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
     s->nb_ops--;
-
-#ifdef CONFIG_PROFILER
-    qatomic_set(&s->prof.del_op_count, s->prof.del_op_count + 1);
-#endif
 }
 
 void tcg_remove_ops_after(TCGOp *op)
@@ -5856,143 +5852,16 @@ static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
     tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
 }
 
-#ifdef CONFIG_PROFILER
-
-/* avoid copy/paste errors */
-#define PROF_ADD(to, from, field)                       \
-    do {                                                \
-        (to)->field += qatomic_read(&((from)->field));  \
-    } while (0)
-
-#define PROF_MAX(to, from, field)                                       \
-    do {                                                                \
-        typeof((from)->field) val__ = qatomic_read(&((from)->field));   \
-        if (val__ > (to)->field) {                                      \
-            (to)->field = val__;                                        \
-        }                                                               \
-    } while (0)
-
-/* Pass in a zero'ed @prof */
-static inline
-void tcg_profile_snapshot(TCGProfile *prof, bool counters, bool table)
-{
-    unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
-    unsigned int i;
-
-    for (i = 0; i < n_ctxs; i++) {
-        TCGContext *s = qatomic_read(&tcg_ctxs[i]);
-        const TCGProfile *orig = &s->prof;
-
-        if (counters) {
-            PROF_ADD(prof, orig, cpu_exec_time);
-            PROF_ADD(prof, orig, tb_count1);
-            PROF_ADD(prof, orig, tb_count);
-            PROF_ADD(prof, orig, op_count);
-            PROF_MAX(prof, orig, op_count_max);
-            PROF_ADD(prof, orig, temp_count);
-            PROF_MAX(prof, orig, temp_count_max);
-            PROF_ADD(prof, orig, del_op_count);
-            PROF_ADD(prof, orig, code_in_len);
-            PROF_ADD(prof, orig, code_out_len);
-            PROF_ADD(prof, orig, search_out_len);
-            PROF_ADD(prof, orig, interm_time);
-            PROF_ADD(prof, orig, code_time);
-            PROF_ADD(prof, orig, la_time);
-            PROF_ADD(prof, orig, opt_time);
-            PROF_ADD(prof, orig, restore_count);
-            PROF_ADD(prof, orig, restore_time);
-        }
-        if (table) {
-            int i;
-
-            for (i = 0; i < NB_OPS; i++) {
-                PROF_ADD(prof, orig, table_op_count[i]);
-            }
-        }
-    }
-}
-
-#undef PROF_ADD
-#undef PROF_MAX
-
-static void tcg_profile_snapshot_counters(TCGProfile *prof)
-{
-    tcg_profile_snapshot(prof, true, false);
-}
-
-static void tcg_profile_snapshot_table(TCGProfile *prof)
-{
-    tcg_profile_snapshot(prof, false, true);
-}
-
-void tcg_dump_op_count(GString *buf)
-{
-    TCGProfile prof = {};
-    int i;
-
-    tcg_profile_snapshot_table(&prof);
-    for (i = 0; i < NB_OPS; i++) {
-        g_string_append_printf(buf, "%s %" PRId64 "\n", tcg_op_defs[i].name,
-                               prof.table_op_count[i]);
-    }
-}
-
-int64_t tcg_cpu_exec_time(void)
-{
-    unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
-    unsigned int i;
-    int64_t ret = 0;
-
-    for (i = 0; i < n_ctxs; i++) {
-        const TCGContext *s = qatomic_read(&tcg_ctxs[i]);
-        const TCGProfile *prof = &s->prof;
-
-        ret += qatomic_read(&prof->cpu_exec_time);
-    }
-    return ret;
-}
-#else
 void tcg_dump_op_count(GString *buf)
 {
     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
 }
 
-int64_t tcg_cpu_exec_time(void)
-{
-    error_report("%s: TCG profiler not compiled", __func__);
-    exit(EXIT_FAILURE);
-}
-#endif
-
-
 int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
 {
-#ifdef CONFIG_PROFILER
-    TCGProfile *prof = &s->prof;
-#endif
     int i, num_insns;
     TCGOp *op;
 
-#ifdef CONFIG_PROFILER
-    {
-        int n = 0;
-
-        QTAILQ_FOREACH(op, &s->ops, link) {
-            n++;
-        }
-        qatomic_set(&prof->op_count, prof->op_count + n);
-        if (n > prof->op_count_max) {
-            qatomic_set(&prof->op_count_max, n);
-        }
-
-        n = s->nb_temps;
-        qatomic_set(&prof->temp_count, prof->temp_count + n);
-        if (n > prof->temp_count_max) {
-            qatomic_set(&prof->temp_count_max, n);
-        }
-    }
-#endif
-
     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
                  && qemu_log_in_addr_range(pc_start))) {
         FILE *logfile = qemu_log_trylock();
@@ -6021,17 +5890,8 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
     }
 #endif
 
-#ifdef CONFIG_PROFILER
-    qatomic_set(&prof->opt_time, prof->opt_time - profile_getclock());
-#endif
-
     tcg_optimize(s);
 
-#ifdef CONFIG_PROFILER
-    qatomic_set(&prof->opt_time, prof->opt_time + profile_getclock());
-    qatomic_set(&prof->la_time, prof->la_time - profile_getclock());
-#endif
-
     reachable_code_pass(s);
     liveness_pass_0(s);
     liveness_pass_1(s);
@@ -6055,10 +5915,6 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
         }
     }
 
-#ifdef CONFIG_PROFILER
-    qatomic_set(&prof->la_time, prof->la_time + profile_getclock());
-#endif
-
     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP_OPT)
                  && qemu_log_in_addr_range(pc_start))) {
         FILE *logfile = qemu_log_trylock();
@@ -6097,10 +5953,6 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
     QTAILQ_FOREACH(op, &s->ops, link) {
         TCGOpcode opc = op->opc;
 
-#ifdef CONFIG_PROFILER
-        qatomic_set(&prof->table_op_count[opc], prof->table_op_count[opc] + 1);
-#endif
-
         switch (opc) {
         case INDEX_op_mov_i32:
         case INDEX_op_mov_i64:
@@ -6195,76 +6047,10 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
     return tcg_current_code_size(s);
 }
 
-#ifdef CONFIG_PROFILER
-void tcg_dump_info(GString *buf)
-{
-    TCGProfile prof = {};
-    const TCGProfile *s;
-    int64_t tb_count;
-    int64_t tb_div_count;
-    int64_t tot;
-
-    tcg_profile_snapshot_counters(&prof);
-    s = &prof;
-    tb_count = s->tb_count;
-    tb_div_count = tb_count ? tb_count : 1;
-    tot = s->interm_time + s->code_time;
-
-    g_string_append_printf(buf, "JIT cycles          %" PRId64
-                           " (%0.3f s at 2.4 GHz)\n",
-                           tot, tot / 2.4e9);
-    g_string_append_printf(buf, "translated TBs      %" PRId64
-                           " (aborted=%" PRId64 " %0.1f%%)\n",
-                           tb_count, s->tb_count1 - tb_count,
-                           (double)(s->tb_count1 - s->tb_count)
-                           / (s->tb_count1 ? s->tb_count1 : 1) * 100.0);
-    g_string_append_printf(buf, "avg ops/TB          %0.1f max=%d\n",
-                           (double)s->op_count / tb_div_count, s->op_count_max);
-    g_string_append_printf(buf, "deleted ops/TB      %0.2f\n",
-                           (double)s->del_op_count / tb_div_count);
-    g_string_append_printf(buf, "avg temps/TB        %0.2f max=%d\n",
-                           (double)s->temp_count / tb_div_count,
-                           s->temp_count_max);
-    g_string_append_printf(buf, "avg host code/TB    %0.1f\n",
-                           (double)s->code_out_len / tb_div_count);
-    g_string_append_printf(buf, "avg search data/TB  %0.1f\n",
-                           (double)s->search_out_len / tb_div_count);
-
-    g_string_append_printf(buf, "cycles/op           %0.1f\n",
-                           s->op_count ? (double)tot / s->op_count : 0);
-    g_string_append_printf(buf, "cycles/in byte      %0.1f\n",
-                           s->code_in_len ? (double)tot / s->code_in_len : 0);
-    g_string_append_printf(buf, "cycles/out byte     %0.1f\n",
-                           s->code_out_len ? (double)tot / s->code_out_len : 0);
-    g_string_append_printf(buf, "cycles/search byte     %0.1f\n",
-                           s->search_out_len ?
-                           (double)tot / s->search_out_len : 0);
-    if (tot == 0) {
-        tot = 1;
-    }
-    g_string_append_printf(buf, "  gen_interm time   %0.1f%%\n",
-                           (double)s->interm_time / tot * 100.0);
-    g_string_append_printf(buf, "  gen_code time     %0.1f%%\n",
-                           (double)s->code_time / tot * 100.0);
-    g_string_append_printf(buf, "optim./code time    %0.1f%%\n",
-                           (double)s->opt_time / (s->code_time ?
-                                                  s->code_time : 1)
-                           * 100.0);
-    g_string_append_printf(buf, "liveness/code time  %0.1f%%\n",
-                           (double)s->la_time / (s->code_time ?
-                                                 s->code_time : 1) * 100.0);
-    g_string_append_printf(buf, "cpu_restore count   %" PRId64 "\n",
-                           s->restore_count);
-    g_string_append_printf(buf, "  avg cycles        %0.1f\n",
-                           s->restore_count ?
-                           (double)s->restore_time / s->restore_count : 0);
-}
-#else
 void tcg_dump_info(GString *buf)
 {
     g_string_append_printf(buf, "[TCG profiler not compiled]\n");
 }
-#endif
 
 #ifdef ELF_HOST_MACHINE
 /* In order to use this feature, the backend needs to do three things:
diff --git a/tests/qtest/qmp-cmd-test.c b/tests/qtest/qmp-cmd-test.c
index a58de48d2a..73a670e8fa 100644
--- a/tests/qtest/qmp-cmd-test.c
+++ b/tests/qtest/qmp-cmd-test.c
@@ -46,9 +46,6 @@ static int query_error_class(const char *cmd)
         { "query-balloon", ERROR_CLASS_DEVICE_NOT_ACTIVE },
         { "query-hotpluggable-cpus", ERROR_CLASS_GENERIC_ERROR },
         { "query-vm-generation-id", ERROR_CLASS_GENERIC_ERROR },
-#ifndef CONFIG_PROFILER
-        { "x-query-profile", ERROR_CLASS_GENERIC_ERROR },
-#endif
         /* Only valid with a USB bus added */
         { "x-query-usb", ERROR_CLASS_GENERIC_ERROR },
         /* Only valid with accel=tcg */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v15 02/10] accel/tcg: introduce TBStatistics structure
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
  2023-06-07 12:24 ` [PATCH v15 01/10] accel/tcg: remove CONFIG_PROFILER Fei Wu
@ 2023-06-07 12:24 ` Fei Wu
  2023-06-07 12:24 ` [PATCH v15 03/10] accel: collecting TB execution count Fei Wu
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Fei Wu @ 2023-06-07 12:24 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel
  Cc: Vanderson M. do Rosario, Fei Wu, Paolo Bonzini

From: "Vanderson M. do Rosario" <vandersonmr2@gmail.com>

To store statistics for each TB, we created a TBStatistics structure
which is linked with the TBs. TBStatistics can stay alive after
tb_flush and be relinked to a regenerated TB. So the statistics can
be accumulated even through flushes.

The goal is to have all present and future qemu/tcg statistics and
meta-data stored in this new structure.

Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Vanderson M. do Rosario <vandersonmr2@gmail.com>
Message-Id: <20190829173437.5926-2-vandersonmr2@gmail.com>
[AJB: fix git author, review comments]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Fei Wu <fei2.wu@intel.com>
---
 MAINTAINERS                   |  1 +
 accel/tcg/meson.build         |  1 +
 accel/tcg/tb-context.h        |  1 +
 accel/tcg/tb-hash.h           |  7 +++++
 accel/tcg/tb-maint.c          | 19 ++++++++++++
 accel/tcg/tb-stats.c          | 46 ++++++++++++++++++++++++++++
 accel/tcg/translate-all.c     | 44 +++++++++++++++++++++++++++
 include/exec/exec-all.h       |  3 ++
 include/exec/tb-stats-flags.h | 19 ++++++++++++
 include/exec/tb-stats.h       | 56 +++++++++++++++++++++++++++++++++++
 10 files changed, 197 insertions(+)
 create mode 100644 accel/tcg/tb-stats.c
 create mode 100644 include/exec/tb-stats-flags.h
 create mode 100644 include/exec/tb-stats.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 1c93ab0ee5..2077889efd 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -153,6 +153,7 @@ F: include/exec/cpu*.h
 F: include/exec/exec-all.h
 F: include/exec/tb-flush.h
 F: include/exec/target_long.h
+F: include/exec/tb-stats*.h
 F: include/exec/helper*.h
 F: include/sysemu/cpus.h
 F: include/sysemu/tcg.h
diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build
index aeb20a6ef0..9263bdde11 100644
--- a/accel/tcg/meson.build
+++ b/accel/tcg/meson.build
@@ -4,6 +4,7 @@ tcg_ss.add(files(
   'cpu-exec-common.c',
   'cpu-exec.c',
   'tb-maint.c',
+  'tb-stats.c',
   'tcg-runtime-gvec.c',
   'tcg-runtime.c',
   'translate-all.c',
diff --git a/accel/tcg/tb-context.h b/accel/tcg/tb-context.h
index cac62d9749..d7910d586b 100644
--- a/accel/tcg/tb-context.h
+++ b/accel/tcg/tb-context.h
@@ -35,6 +35,7 @@ struct TBContext {
     /* statistics */
     unsigned tb_flush_count;
     unsigned tb_phys_invalidate_count;
+    struct qht tb_stats;
 };
 
 extern TBContext tb_ctx;
diff --git a/accel/tcg/tb-hash.h b/accel/tcg/tb-hash.h
index 83dc610e4c..87d657a1c6 100644
--- a/accel/tcg/tb-hash.h
+++ b/accel/tcg/tb-hash.h
@@ -67,4 +67,11 @@ uint32_t tb_hash_func(tb_page_addr_t phys_pc, target_ulong pc, uint32_t flags,
     return qemu_xxhash7(phys_pc, pc, flags, cf_mask, trace_vcpu_dstate);
 }
 
+static inline
+uint32_t tb_stats_hash_func(tb_page_addr_t phys_pc, target_ulong pc,
+                            uint32_t flags)
+{
+    return qemu_xxhash5(phys_pc, pc, flags);
+}
+
 #endif
diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c
index 991746f80f..0980fca358 100644
--- a/accel/tcg/tb-maint.c
+++ b/accel/tcg/tb-maint.c
@@ -24,6 +24,7 @@
 #include "exec/log.h"
 #include "exec/exec-all.h"
 #include "exec/tb-flush.h"
+#include "exec/tb-stats.h"
 #include "exec/translate-all.h"
 #include "sysemu/tcg.h"
 #include "tcg/tcg.h"
@@ -41,6 +42,23 @@
 #define TB_FOR_EACH_JMP(head_tb, tb, n)                                 \
     TB_FOR_EACH_TAGGED((head_tb)->jmp_list_head, tb, n, jmp_list_next)
 
+/*
+ * This is the more or less the same compare as tb_cmp(), but the
+ * data persists over tb_flush. We also aggregate the various
+ * variations of cflags under one record and ignore the details of
+ * page overlap (although we can count it).
+ */
+bool tb_stats_cmp(const void *ap, const void *bp)
+{
+    const TBStatistics *a = ap;
+    const TBStatistics *b = bp;
+
+    return a->phys_pc == b->phys_pc &&
+        a->pc == b->pc &&
+        a->cs_base == b->cs_base &&
+        a->flags == b->flags;
+}
+
 static bool tb_cmp(const void *ap, const void *bp)
 {
     const TranslationBlock *a = ap;
@@ -60,6 +78,7 @@ void tb_htable_init(void)
     unsigned int mode = QHT_MODE_AUTO_RESIZE;
 
     qht_init(&tb_ctx.htable, tb_cmp, CODE_GEN_HTABLE_SIZE, mode);
+    init_tb_stats_htable();
 }
 
 typedef struct PageDesc PageDesc;
diff --git a/accel/tcg/tb-stats.c b/accel/tcg/tb-stats.c
new file mode 100644
index 0000000000..2b6be943ef
--- /dev/null
+++ b/accel/tcg/tb-stats.c
@@ -0,0 +1,46 @@
+/*
+ * QEMU System Emulator, Code Quality Monitor System
+ *
+ * Copyright (c) 2019 Vanderson M. do Rosario <vandersonmr2@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+
+#include "disas/disas.h"
+
+#include "exec/tb-stats.h"
+#include "tb-context.h"
+
+/* TBStatistic collection controls */
+enum TBStatsStatus {
+    TB_STATS_STOPPED = 0,
+    TB_STATS_RUNNING
+};
+
+static enum TBStatsStatus tcg_collect_tb_stats;
+
+void init_tb_stats_htable(void)
+{
+    if (!tb_ctx.tb_stats.map && tb_stats_collection_enabled()) {
+        qht_init(&tb_ctx.tb_stats, tb_stats_cmp,
+                CODE_GEN_HTABLE_SIZE, QHT_MODE_AUTO_RESIZE);
+    }
+}
+
+void enable_collect_tb_stats(void)
+{
+    tcg_collect_tb_stats = TB_STATS_RUNNING;
+    init_tb_stats_htable();
+}
+
+void disable_collect_tb_stats(void)
+{
+    tcg_collect_tb_stats = TB_STATS_STOPPED;
+}
+
+bool tb_stats_collection_enabled(void)
+{
+    return tcg_collect_tb_stats == TB_STATS_RUNNING;
+}
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 4e035e0f79..4fc41a63b5 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -54,6 +54,7 @@
 #include "qemu/cacheinfo.h"
 #include "qemu/timer.h"
 #include "exec/log.h"
+#include "exec/tb-stats.h"
 #include "sysemu/cpus.h"
 #include "sysemu/cpu-timers.h"
 #include "sysemu/tcg.h"
@@ -284,6 +285,37 @@ static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb,
     return tcg_gen_code(tcg_ctx, tb, pc);
 }
 
+static TBStatistics *tb_get_stats(tb_page_addr_t phys_pc, target_ulong pc,
+                                  target_ulong cs_base, uint32_t flags)
+{
+    TBStatistics *new_stats = g_new0(TBStatistics, 1);
+    uint32_t hash = tb_stats_hash_func(phys_pc, pc, flags);
+    void *existing_stats = NULL;
+    new_stats->phys_pc = phys_pc;
+    new_stats->pc = pc;
+    new_stats->cs_base = cs_base;
+    new_stats->flags = flags;
+
+    /*
+     * All initialisation must be complete before we insert into qht
+     * table otherwise another thread might get a partially created
+     * structure.
+     */
+    qht_insert(&tb_ctx.tb_stats, new_stats, hash, &existing_stats);
+
+    if (unlikely(existing_stats)) {
+        /*
+         * If there is already a TBStatistic for this TB from a previous flush
+         * then just make the new TB point to the older TBStatistic
+         */
+        g_free(new_stats);
+        return existing_stats;
+    } else {
+        return new_stats;
+    }
+}
+
+
 /* Called with mmap_lock held for user mode emulation.  */
 TranslationBlock *tb_gen_code(CPUState *cpu,
                               target_ulong pc, target_ulong cs_base,
@@ -347,6 +379,18 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
 
     trace_translate_block(tb, pc, tb->tc.ptr);
 
+    /*
+     * We want to fetch the stats structure before we start code
+     * generation so we can count interesting things about this
+     * generation.
+     */
+    if (tb_stats_collection_enabled()) {
+        tb->tb_stats = tb_get_stats(phys_pc, cflags & CF_PCREL ? 0 : pc,
+                                    cs_base, flags);
+    } else {
+        tb->tb_stats = NULL;
+    }
+
     gen_code_size = setjmp_gen_code(env, tb, pc, host_pc, &max_insns, &ti);
     if (unlikely(gen_code_size < 0)) {
         switch (gen_code_size) {
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 4d2b151986..f8a80f63d3 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -608,6 +608,9 @@ struct TranslationBlock {
     uintptr_t jmp_list_head;
     uintptr_t jmp_list_next[2];
     uintptr_t jmp_dest[2];
+
+    /* Pointer to a struct where statistics from the TB is stored */
+    struct TBStatistics *tb_stats;
 };
 
 /* Hide the qatomic_read to make code a little easier on the eyes */
diff --git a/include/exec/tb-stats-flags.h b/include/exec/tb-stats-flags.h
new file mode 100644
index 0000000000..c994cf3b9d
--- /dev/null
+++ b/include/exec/tb-stats-flags.h
@@ -0,0 +1,19 @@
+/*
+ * QEMU System Emulator, Code Quality Monitor System
+ *
+ * We define the flags and control bits here to avoid complications of
+ * including TCG/CPU information in common code.
+ *
+ * Copyright (c) 2019 Vanderson M. do Rosario <vandersonmr2@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+#ifndef TB_STATS_FLAGS
+#define TB_STATS_FLAGS
+
+/* TBStatistic collection controls */
+void enable_collect_tb_stats(void);
+void disable_collect_tb_stats(void);
+bool tb_stats_collection_enabled(void);
+
+#endif
diff --git a/include/exec/tb-stats.h b/include/exec/tb-stats.h
new file mode 100644
index 0000000000..b519465665
--- /dev/null
+++ b/include/exec/tb-stats.h
@@ -0,0 +1,56 @@
+/*
+ * QEMU System Emulator, Code Quality Monitor System
+ *
+ * Copyright (c) 2019 Vanderson M. do Rosario <vandersonmr2@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef TB_STATS_H
+
+#define TB_STATS_H
+
+#include "exec/cpu-common.h"
+#include "exec/exec-all.h"
+#include "exec/tb-stats-flags.h"
+#include "tcg/tcg.h"
+
+typedef struct TBStatistics TBStatistics;
+
+/*
+ * This struct stores statistics such as execution count of the
+ * TranslationBlocks. Each sets of TBs for a given phys_pc/pc/flags
+ * has its own TBStatistics which will persist over tb_flush.
+ *
+ * We include additional counters to track number of translations as
+ * well as variants for compile flags.
+ */
+struct TBStatistics {
+    tb_page_addr_t phys_pc;
+    target_ulong pc;
+    uint32_t     flags;
+    /* cs_base isn't included in the hash but we do check for matches */
+    target_ulong cs_base;
+};
+
+bool tb_stats_cmp(const void *ap, const void *bp);
+
+void init_tb_stats_htable(void);
+
+#endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v15 03/10] accel: collecting TB execution count
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
  2023-06-07 12:24 ` [PATCH v15 01/10] accel/tcg: remove CONFIG_PROFILER Fei Wu
  2023-06-07 12:24 ` [PATCH v15 02/10] accel/tcg: introduce TBStatistics structure Fei Wu
@ 2023-06-07 12:24 ` Fei Wu
  2023-06-07 12:24 ` [PATCH v15 04/10] accel/tcg: add jit stats to TBStatistics Fei Wu
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Fei Wu @ 2023-06-07 12:24 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel
  Cc: Vanderson M. do Rosario, Fei Wu, Paolo Bonzini

From: "Vanderson M. do Rosario" <vandersonmr2@gmail.com>

If a TB has a TBS (TBStatistics) with the TB_EXEC_STATS
enabled, then we instrument the start code of this TB
to atomically count the number of times it is executed.
We count both the number of "normal" executions and atomic
executions of a TB.

The execution count of the TB is stored in its respective
TBS.

All TBStatistics are created by default with the flags from
default_tbstats_flag.

[Richard Henderson created the inline gen_tb_exec_count]

Signed-off-by: Vanderson M. do Rosario <vandersonmr2@gmail.com>
Message-Id: <20190829173437.5926-3-vandersonmr2@gmail.com>
[AJB: Fix author]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Fei Wu <fei2.wu@intel.com>
---
 accel/tcg/cpu-exec.c          |  6 ++++++
 accel/tcg/tb-stats.c          | 18 ++++++++++++++++++
 accel/tcg/tcg-runtime.c       |  1 +
 accel/tcg/translate-all.c     |  6 ++++--
 accel/tcg/translator.c        | 25 +++++++++++++++++++++++++
 include/exec/gen-icount.h     |  1 +
 include/exec/tb-stats-flags.h |  6 ++++++
 include/exec/tb-stats.h       |  8 ++++++++
 8 files changed, 69 insertions(+), 2 deletions(-)

diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 0e741960da..c0d8f26237 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -25,6 +25,7 @@
 #include "trace.h"
 #include "disas/disas.h"
 #include "exec/exec-all.h"
+#include "exec/tb-stats.h"
 #include "tcg/tcg.h"
 #include "qemu/atomic.h"
 #include "qemu/rcu.h"
@@ -562,7 +563,12 @@ void cpu_exec_step_atomic(CPUState *cpu)
             mmap_unlock();
         }
 
+        if (tb_stats_enabled(tb, TB_EXEC_STATS)) {
+            tb->tb_stats->executions.atomic++;
+        }
+
         cpu_exec_enter(cpu);
+
         /* execute the generated code */
         trace_exec_tb(tb, pc);
         cpu_tb_exec(cpu, tb, &tb_exit);
diff --git a/accel/tcg/tb-stats.c b/accel/tcg/tb-stats.c
index 2b6be943ef..2b7321b548 100644
--- a/accel/tcg/tb-stats.c
+++ b/accel/tcg/tb-stats.c
@@ -20,6 +20,7 @@ enum TBStatsStatus {
 };
 
 static enum TBStatsStatus tcg_collect_tb_stats;
+static uint32_t tbstats_flag;
 
 void init_tb_stats_htable(void)
 {
@@ -44,3 +45,20 @@ bool tb_stats_collection_enabled(void)
 {
     return tcg_collect_tb_stats == TB_STATS_RUNNING;
 }
+
+uint32_t get_tbstats_flag(void)
+{
+    return tbstats_flag;
+}
+
+void set_tbstats_flag(uint32_t flag)
+{
+    tbstats_flag = flag;
+}
+
+bool tb_stats_enabled(TranslationBlock *tb, uint32_t flag)
+{
+    return tb_stats_collection_enabled() &&
+           tb->tb_stats &&
+           (tbstats_flag & flag);
+}
diff --git a/accel/tcg/tcg-runtime.c b/accel/tcg/tcg-runtime.c
index e4e030043f..11c6192064 100644
--- a/accel/tcg/tcg-runtime.c
+++ b/accel/tcg/tcg-runtime.c
@@ -27,6 +27,7 @@
 #include "exec/helper-proto.h"
 #include "exec/cpu_ldst.h"
 #include "exec/exec-all.h"
+#include "exec/tb-stats.h"
 #include "disas/disas.h"
 #include "exec/log.h"
 #include "tcg/tcg.h"
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 4fc41a63b5..5963cd6fe4 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -382,9 +382,11 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
     /*
      * We want to fetch the stats structure before we start code
      * generation so we can count interesting things about this
-     * generation.
+     * generation. If dfilter is in effect we will only collect stats
+     * for the specified range.
      */
-    if (tb_stats_collection_enabled()) {
+    if (tb_stats_collection_enabled() &&
+        qemu_log_in_addr_range(tb->pc)) {
         tb->tb_stats = tb_get_stats(phys_pc, cflags & CF_PCREL ? 0 : pc,
                                     cs_base, flags);
     } else {
diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 6120ef2a92..80ffbfb455 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -11,6 +11,7 @@
 #include "qemu/error-report.h"
 #include "tcg/tcg.h"
 #include "tcg/tcg-op.h"
+#include "tcg/tcg-temp-internal.h"
 #include "exec/exec-all.h"
 #include "exec/gen-icount.h"
 #include "exec/log.h"
@@ -18,6 +19,29 @@
 #include "exec/plugin-gen.h"
 #include "exec/replay-core.h"
 
+static void gen_tb_exec_count(TranslationBlock *tb)
+{
+    if (tb_stats_enabled(tb, TB_EXEC_STATS)) {
+        TCGv_ptr ptr = tcg_temp_ebb_new_ptr();
+
+        tcg_gen_movi_ptr(ptr, (intptr_t)&tb->tb_stats->executions.normal);
+        if (sizeof(tb->tb_stats->executions.normal) == 4) {
+            TCGv_i32 t = tcg_temp_ebb_new_i32();
+            tcg_gen_ld_i32(t, ptr, 0);
+            tcg_gen_addi_i32(t, t, 1);
+            tcg_gen_st_i32(t, ptr, 0);
+            tcg_temp_free_i32(t);
+        } else {
+            TCGv_i64 t = tcg_temp_ebb_new_i64();
+            tcg_gen_ld_i64(t, ptr, 0);
+            tcg_gen_addi_i64(t, t, 1);
+            tcg_gen_st_i64(t, ptr, 0);
+            tcg_temp_free_i64(t);
+        }
+        tcg_temp_free_ptr(ptr);
+    }
+}
+
 bool translator_use_goto_tb(DisasContextBase *db, target_ulong dest)
 {
     /* Suppress goto_tb if requested. */
@@ -56,6 +80,7 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
 
     /* Start translating.  */
     gen_tb_start(db->tb);
+    gen_tb_exec_count(tb);
     ops->tb_start(db, cpu);
     tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 
diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
index f6de79a6b4..20e7835ff0 100644
--- a/include/exec/gen-icount.h
+++ b/include/exec/gen-icount.h
@@ -2,6 +2,7 @@
 #define GEN_ICOUNT_H
 
 #include "exec/exec-all.h"
+#include "exec/tb-stats.h"
 
 /* Helpers for instruction counting code generation.  */
 
diff --git a/include/exec/tb-stats-flags.h b/include/exec/tb-stats-flags.h
index c994cf3b9d..c0e63408e2 100644
--- a/include/exec/tb-stats-flags.h
+++ b/include/exec/tb-stats-flags.h
@@ -11,9 +11,15 @@
 #ifndef TB_STATS_FLAGS
 #define TB_STATS_FLAGS
 
+#define TB_NONE_STATS (0)  /* no stats */
+#define TB_EXEC_STATS (1 << 0)
+
 /* TBStatistic collection controls */
 void enable_collect_tb_stats(void);
 void disable_collect_tb_stats(void);
 bool tb_stats_collection_enabled(void);
 
+uint32_t get_tbstats_flag(void);
+void set_tbstats_flag(uint32_t flag);
+
 #endif
diff --git a/include/exec/tb-stats.h b/include/exec/tb-stats.h
index b519465665..b935c3235a 100644
--- a/include/exec/tb-stats.h
+++ b/include/exec/tb-stats.h
@@ -47,10 +47,18 @@ struct TBStatistics {
     uint32_t     flags;
     /* cs_base isn't included in the hash but we do check for matches */
     target_ulong cs_base;
+
+    /* Execution stats */
+    struct {
+        unsigned long normal;
+        unsigned long atomic;
+    } executions;
+
 };
 
 bool tb_stats_cmp(const void *ap, const void *bp);
 
 void init_tb_stats_htable(void);
+bool tb_stats_enabled(TranslationBlock *tb, uint32_t flag);
 
 #endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v15 04/10] accel/tcg: add jit stats to TBStatistics
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
                   ` (2 preceding siblings ...)
  2023-06-07 12:24 ` [PATCH v15 03/10] accel: collecting TB execution count Fei Wu
@ 2023-06-07 12:24 ` Fei Wu
  2023-06-07 12:24 ` [PATCH v15 05/10] monitor: adding tb_stats hmp command Fei Wu
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Fei Wu @ 2023-06-07 12:24 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel
  Cc: Fei Wu, Vanderson M . do Rosario, Paolo Bonzini

This collects all the statistics for TBStatistics, not only for the
whole emulation but for each TB.

Signed-off-by: Vanderson M. do Rosario <vandersonmr2@gmail.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Fei Wu <fei2.wu@intel.com>
---
 accel/tcg/monitor.c           |  6 +++
 accel/tcg/tb-stats.c          | 69 +++++++++++++++++++++++++++++++++++
 accel/tcg/translate-all.c     | 31 ++++++++++++++--
 accel/tcg/translator.c        |  5 +++
 include/exec/tb-stats-flags.h |  1 +
 include/exec/tb-stats.h       | 29 +++++++++++++++
 include/tcg/tcg.h             | 10 +++++
 tcg/tcg.c                     | 47 ++++++++++++++++++++++--
 8 files changed, 192 insertions(+), 6 deletions(-)

diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c
index 39d8260428..111ccbc4da 100644
--- a/accel/tcg/monitor.c
+++ b/accel/tcg/monitor.c
@@ -15,6 +15,7 @@
 #include "sysemu/cpus.h"
 #include "sysemu/cpu-timers.h"
 #include "sysemu/tcg.h"
+#include "exec/tb-stats.h"
 #include "internal.h"
 
 
@@ -69,6 +70,11 @@ HumanReadableText *qmp_x_query_opcount(Error **errp)
 {
     g_autoptr(GString) buf = g_string_new("");
 
+    if (!tb_stats_collection_enabled()) {
+        error_setg(errp, "TB information not being recorded");
+        return NULL;
+    }
+
     if (!tcg_enabled()) {
         error_setg(errp,
                    "Opcode count information is only available with accel=tcg");
diff --git a/accel/tcg/tb-stats.c b/accel/tcg/tb-stats.c
index 2b7321b548..11322359c7 100644
--- a/accel/tcg/tb-stats.c
+++ b/accel/tcg/tb-stats.c
@@ -9,6 +9,10 @@
 #include "qemu/osdep.h"
 
 #include "disas/disas.h"
+#include "exec/exec-all.h"
+#include "tcg/tcg.h"
+
+#include "qemu/qemu-print.h"
 
 #include "exec/tb-stats.h"
 #include "tb-context.h"
@@ -22,6 +26,71 @@ enum TBStatsStatus {
 static enum TBStatsStatus tcg_collect_tb_stats;
 static uint32_t tbstats_flag;
 
+struct jit_profile_info {
+    uint64_t translations;
+    uint64_t aborted;
+    uint64_t ops;
+    unsigned ops_max;
+    uint64_t del_ops;
+    uint64_t temps;
+    unsigned temps_max;
+    uint64_t host;
+    uint64_t guest;
+    uint64_t search_data;
+};
+
+#define stat_per_translation(stat, name) \
+    (stat->translations.total ? stat->name / stat->translations.total : 0)
+
+/* accumulate the statistics from all TBs */
+static void collect_jit_profile_info(void *p, uint32_t hash, void *userp)
+{
+    struct jit_profile_info *jpi = userp;
+    TBStatistics *tbs = p;
+
+    jpi->translations += tbs->translations.total;
+    jpi->ops += tbs->code.num_tcg_ops;
+    if (stat_per_translation(tbs, code.num_tcg_ops) > jpi->ops_max) {
+        jpi->ops_max = stat_per_translation(tbs, code.num_tcg_ops);
+    }
+    jpi->del_ops += tbs->code.deleted_ops;
+    jpi->temps += tbs->code.temps;
+    if (stat_per_translation(tbs, code.temps) > jpi->temps_max) {
+        jpi->temps_max = stat_per_translation(tbs, code.temps);
+    }
+    jpi->host += tbs->code.out_len;
+    jpi->guest += tbs->code.in_len;
+    jpi->search_data += tbs->code.search_out_len;
+}
+
+/* dump JIT statistics using TBStats */
+void dump_jit_profile_info(GString *buf)
+{
+    if (!tb_stats_collection_enabled()) {
+        return;
+    }
+
+    struct jit_profile_info *jpi = g_new0(struct jit_profile_info, 1);
+
+    qht_iter(&tb_ctx.tb_stats, collect_jit_profile_info, jpi);
+
+    if (jpi->translations) {
+        g_string_append_printf(buf, "translated TBs      %" PRId64 "\n",
+                jpi->translations);
+        g_string_append_printf(buf, "avg ops/TB          %0.1f max=%d\n",
+                jpi->ops / (double) jpi->translations, jpi->ops_max);
+        g_string_append_printf(buf, "deleted ops/TB      %0.2f\n",
+                jpi->del_ops / (double) jpi->translations);
+        g_string_append_printf(buf, "avg temps/TB        %0.2f max=%d\n",
+                jpi->temps / (double) jpi->translations, jpi->temps_max);
+        g_string_append_printf(buf, "avg host code/TB    %0.1f\n",
+                jpi->host / (double) jpi->translations);
+        g_string_append_printf(buf, "avg search data/TB  %0.1f\n",
+                jpi->search_data / (double) jpi->translations);
+    }
+    g_free(jpi);
+}
+
 void init_tb_stats_htable(void)
 {
     if (!tb_ctx.tb_stats.map && tb_stats_collection_enabled()) {
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 5963cd6fe4..f795385aac 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -267,7 +267,7 @@ void page_init(void)
  */
 static int setjmp_gen_code(CPUArchState *env, TranslationBlock *tb,
                            target_ulong pc, void *host_pc,
-                           int *max_insns, int64_t *ti)
+                           int *max_insns)
 {
     int ret = sigsetjmp(tcg_ctx->jmp_trans, 0);
     if (unlikely(ret != 0)) {
@@ -295,6 +295,8 @@ static TBStatistics *tb_get_stats(tb_page_addr_t phys_pc, target_ulong pc,
     new_stats->pc = pc;
     new_stats->cs_base = cs_base;
     new_stats->flags = flags;
+    new_stats->tbs = g_ptr_array_new();
+    qemu_mutex_init(&new_stats->jit_stats_lock);
 
     /*
      * All initialisation must be complete before we insert into qht
@@ -308,6 +310,7 @@ static TBStatistics *tb_get_stats(tb_page_addr_t phys_pc, target_ulong pc,
          * If there is already a TBStatistic for this TB from a previous flush
          * then just make the new TB point to the older TBStatistic
          */
+        g_ptr_array_free(new_stats->tbs, true);
         g_free(new_stats);
         return existing_stats;
     } else {
@@ -326,7 +329,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
     tb_page_addr_t phys_pc;
     tcg_insn_unit *gen_code_buf;
     int gen_code_size, search_size, max_insns;
-    int64_t ti;
     void *host_pc;
 
     assert_memory_lock();
@@ -393,7 +395,7 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
         tb->tb_stats = NULL;
     }
 
-    gen_code_size = setjmp_gen_code(env, tb, pc, host_pc, &max_insns, &ti);
+    gen_code_size = setjmp_gen_code(env, tb, pc, host_pc, &max_insns);
     if (unlikely(gen_code_size < 0)) {
         switch (gen_code_size) {
         case -1:
@@ -547,6 +549,29 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
         return tb;
     }
 
+    /*
+     * Collect JIT stats when enabled. We batch them all up here to
+     * avoid spamming the cache with atomic accesses
+     */
+    if (tb_stats_enabled(tb, TB_JIT_STATS)) {
+        TBStatistics *ts = tb->tb_stats;
+        qemu_mutex_lock(&ts->jit_stats_lock);
+
+        ts->code.num_tcg_ops_opt += tcg_ctx->nb_ops;
+        ts->code.in_len += tb->size;
+        ts->code.out_len += tb->tc.size;
+        ts->code.search_out_len += search_size;
+
+        ts->translations.total++;
+        if (tb_page_addr1(tb) != -1) {
+            ts->translations.spanning++;
+        }
+
+        g_ptr_array_add(ts->tbs, tb);
+
+        qemu_mutex_unlock(&ts->jit_stats_lock);
+    }
+
     /*
      * Insert TB into the corresponding region tree before publishing it
      * through QHT. Otherwise rewinding happened in the TB might fail to
diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 80ffbfb455..2fcd8bba35 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -147,6 +147,11 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
     tb->size = db->pc_next - db->pc_first;
     tb->icount = db->num_insns;
 
+    /* Save number of guest instructions for TB_JIT_STATS */
+    if (tb_stats_enabled(tb, TB_JIT_STATS)) {
+        tb->tb_stats->code.num_guest_inst += db->num_insns;
+    }
+
     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
         && qemu_log_in_addr_range(db->pc_first)) {
         FILE *logfile = qemu_log_trylock();
diff --git a/include/exec/tb-stats-flags.h b/include/exec/tb-stats-flags.h
index c0e63408e2..286ca93bcc 100644
--- a/include/exec/tb-stats-flags.h
+++ b/include/exec/tb-stats-flags.h
@@ -13,6 +13,7 @@
 
 #define TB_NONE_STATS (0)  /* no stats */
 #define TB_EXEC_STATS (1 << 0)
+#define TB_JIT_STATS  (1 << 1)
 
 /* TBStatistic collection controls */
 void enable_collect_tb_stats(void);
diff --git a/include/exec/tb-stats.h b/include/exec/tb-stats.h
index b935c3235a..6ed767f490 100644
--- a/include/exec/tb-stats.h
+++ b/include/exec/tb-stats.h
@@ -54,6 +54,33 @@ struct TBStatistics {
         unsigned long atomic;
     } executions;
 
+    /* JIT Stats - protected by lock */
+    QemuMutex jit_stats_lock;
+
+    /* Sum of all operations for all translations */
+    struct {
+        unsigned num_guest_inst;
+        unsigned num_tcg_ops;
+        unsigned num_tcg_ops_opt;
+        unsigned spills;
+
+        unsigned temps;
+        unsigned deleted_ops;
+        unsigned in_len;
+        unsigned out_len;
+        unsigned search_out_len;
+    } code;
+
+    struct {
+        unsigned long total;
+        unsigned long spanning;
+    } translations;
+
+    /*
+     * All persistent (cached) TranslationBlocks using
+     * this TBStats structure. Has to be reset on a tb_flush.
+     */
+    GPtrArray *tbs;
 };
 
 bool tb_stats_cmp(const void *ap, const void *bp);
@@ -61,4 +88,6 @@ bool tb_stats_cmp(const void *ap, const void *bp);
 void init_tb_stats_htable(void);
 bool tb_stats_enabled(TranslationBlock *tb, uint32_t flag);
 
+void dump_jit_profile_info(GString *buf);
+
 #endif
diff --git a/include/tcg/tcg.h b/include/tcg/tcg.h
index da1c8fa3b5..276a4b60ad 100644
--- a/include/tcg/tcg.h
+++ b/include/tcg/tcg.h
@@ -522,6 +522,14 @@ static inline TCGRegSet output_pref(const TCGOp *op, unsigned i)
     return i < ARRAY_SIZE(op->output_pref) ? op->output_pref[i] : 0;
 }
 
+/*
+ * The TCGProfile structure holds data for the lifetime of the translator.
+ */
+typedef struct TCGProfile {
+    /* Lifetime count of TCGOps per TCGContext when tb_stats enabled */
+    size_t table_op_count[NB_OPS];
+} TCGProfile;
+
 struct TCGContext {
     uint8_t *pool_cur, *pool_end;
     TCGPool *pool_first, *pool_current, *pool_first_large;
@@ -548,6 +556,8 @@ struct TCGContext {
     tcg_insn_unit *code_buf;      /* pointer for start of tb */
     tcg_insn_unit *code_ptr;      /* pointer for running end of tb */
 
+    TCGProfile prof;
+
 #ifdef CONFIG_DEBUG_TCG
     int goto_tb_issue_mask;
     const TCGOpcode *vecop_list;
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 4c569294db..e8c354e2f9 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -41,6 +41,7 @@
 #define NO_CPU_IO_DEFS
 
 #include "exec/exec-all.h"
+#include "exec/tb-stats.h"
 #include "tcg/tcg-op.h"
 
 #if UINTPTR_MAX == UINT32_MAX
@@ -2983,6 +2984,9 @@ void tcg_op_remove(TCGContext *s, TCGOp *op)
     QTAILQ_REMOVE(&s->ops, op, link);
     QTAILQ_INSERT_TAIL(&s->free_ops, op, link);
     s->nb_ops--;
+    if (tb_stats_enabled(s->gen_tb, TB_JIT_STATS)) {
+        s->gen_tb->tb_stats->code.deleted_ops++;
+    }
 }
 
 void tcg_remove_ops_after(TCGOp *op)
@@ -4148,6 +4152,10 @@ static TCGReg tcg_reg_alloc(TCGContext *s, TCGRegSet required_regs,
     }
 
     /* We must spill something.  */
+    if (tb_stats_enabled(s->gen_tb, TB_JIT_STATS)) {
+        s->gen_tb->tb_stats->code.spills++;
+    }
+
     for (j = f; j < 2; j++) {
         TCGRegSet set = reg_ct[j];
 
@@ -5852,9 +5860,17 @@ static void tcg_out_st_helper_args(TCGContext *s, const TCGLabelQemuLdst *ldst,
     tcg_out_helper_load_common_args(s, ldst, parm, info, next_arg);
 }
 
-void tcg_dump_op_count(GString *buf)
+static void collect_tcg_profiler(TCGProfile *prof)
 {
-    g_string_append_printf(buf, "[TCG profiler not compiled]\n");
+    unsigned int n_ctxs = qatomic_read(&tcg_cur_ctxs);
+    unsigned int i;
+
+    for (i = 0; i < n_ctxs; i++) {
+        TCGContext *s = qatomic_read(&tcg_ctxs[i]);
+        for (i = 0; i < NB_OPS; i++) {
+            prof->table_op_count[i] += s->prof.table_op_count[i];
+        }
+    }
 }
 
 int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
@@ -5862,6 +5878,12 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
     int i, num_insns;
     TCGOp *op;
 
+    /* save pre-optimisation op count */
+    if (tb_stats_enabled(tb, TB_JIT_STATS)) {
+        tb->tb_stats->code.num_tcg_ops += s->nb_ops;
+        tb->tb_stats->code.temps += s->nb_temps;
+    }
+
     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)
                  && qemu_log_in_addr_range(pc_start))) {
         FILE *logfile = qemu_log_trylock();
@@ -5949,6 +5971,13 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
     s->pool_labels = NULL;
 #endif
 
+    if (tb_stats_collection_enabled()) {
+        QTAILQ_FOREACH(op, &s->ops, link) {
+            TCGOpcode opc = op->opc;
+            s->prof.table_op_count[opc]++;
+        }
+    }
+
     num_insns = -1;
     QTAILQ_FOREACH(op, &s->ops, link) {
         TCGOpcode opc = op->opc;
@@ -6047,9 +6076,21 @@ int tcg_gen_code(TCGContext *s, TranslationBlock *tb, uint64_t pc_start)
     return tcg_current_code_size(s);
 }
 
+void tcg_dump_op_count(GString *buf)
+{
+    TCGProfile prof = {};
+    int i;
+
+    collect_tcg_profiler(&prof);
+    for (i = 0; i < NB_OPS; i++) {
+        g_string_append_printf(buf, "%s %" PRId64 "\n",
+                tcg_op_defs[i].name, prof.table_op_count[i]);
+    }
+}
+
 void tcg_dump_info(GString *buf)
 {
-    g_string_append_printf(buf, "[TCG profiler not compiled]\n");
+    dump_jit_profile_info(buf);
 }
 
 #ifdef ELF_HOST_MACHINE
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v15 05/10] monitor: adding tb_stats hmp command
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
                   ` (3 preceding siblings ...)
  2023-06-07 12:24 ` [PATCH v15 04/10] accel/tcg: add jit stats to TBStatistics Fei Wu
@ 2023-06-07 12:24 ` Fei Wu
  2023-06-07 12:24 ` [PATCH v15 06/10] tb-stats: reset the tracked TBs on a tb_flush Fei Wu
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Fei Wu @ 2023-06-07 12:24 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel
  Cc: Vanderson M. do Rosario, Dr . David Alan Gilbert, Fei Wu,
	Paolo Bonzini, Dr. David Alan Gilbert

From: "Vanderson M. do Rosario" <vandersonmr2@gmail.com>

Adding tb_stats [start|stop|status] command to hmp.
This allows controlling the collection of statistics.
It is also possible to set the flag of collection:
all, jit, or exec.

The goal of this command is to allow the dynamic exploration
of the TCG behavior and quality. Therefore, for now, a
corresponding QMP command is not worthwhile.

Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Vanderson M. do Rosario <vandersonmr2@gmail.com>
Message-Id: <20190829173437.5926-8-vandersonmr2@gmail.com>
Message-Id: <20190829173437.5926-9-vandersonmr2@gmail.com>
[AJB: fix authorship]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Fei Wu <fei2.wu@intel.com>
---
 accel/tcg/monitor.c           | 100 ++++++++++++++++++++++++++++++++++
 accel/tcg/tb-stats.c          |  17 ++++++
 hmp-commands.hx               |  16 ++++++
 include/exec/tb-stats-flags.h |   1 +
 include/exec/tb-stats.h       |   4 ++
 include/monitor/hmp.h         |   1 +
 6 files changed, 139 insertions(+)

diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c
index 111ccbc4da..094150e4af 100644
--- a/accel/tcg/monitor.c
+++ b/accel/tcg/monitor.c
@@ -11,13 +11,18 @@
 #include "qapi/error.h"
 #include "qapi/type-helpers.h"
 #include "qapi/qapi-commands-machine.h"
+#include "qapi/qmp/qdict.h"
 #include "monitor/monitor.h"
+#include "monitor/hmp.h"
 #include "sysemu/cpus.h"
 #include "sysemu/cpu-timers.h"
 #include "sysemu/tcg.h"
 #include "exec/tb-stats.h"
+#include "exec/tb-flush.h"
 #include "internal.h"
+#include "tb-context.h"
 
+enum TbstatsCmd { TBS_CMD_START, TBS_CMD_STOP, TBS_CMD_STATUS };
 
 static void dump_drift_info(GString *buf)
 {
@@ -86,6 +91,101 @@ HumanReadableText *qmp_x_query_opcount(Error **errp)
     return human_readable_text_from_str(buf);
 }
 
+struct TbstatsCommand {
+    enum TbstatsCmd cmd;
+    uint32_t flag;
+    Monitor *mon;
+};
+
+static void do_hmp_tbstats_safe(CPUState *cpu, run_on_cpu_data icmd)
+{
+    struct TbstatsCommand *cmdinfo = icmd.host_ptr;
+    int cmd = cmdinfo->cmd;
+    uint32_t flag = cmdinfo->flag;
+    Monitor *mon = cmdinfo->mon;
+
+    switch (cmd) {
+    case TBS_CMD_START:
+        if (tb_stats_collection_enabled()) {
+            monitor_printf(mon, "TB information already being recorded\n");
+            return;
+        }
+
+        qht_init(&tb_ctx.tb_stats, tb_stats_cmp, CODE_GEN_HTABLE_SIZE,
+                 QHT_MODE_AUTO_RESIZE);
+        set_tbstats_flag(flag);
+        enable_collect_tb_stats();
+        tb_flush(cpu);
+        break;
+    case TBS_CMD_STOP:
+        if (tb_stats_collection_disabled()) {
+            monitor_printf(mon, "TB information not being recorded\n");
+            return;
+        }
+
+        /* Dissalloc all TBStatistics structures and stop creating new ones */
+        disable_collect_tb_stats();
+        clean_tbstats();
+        tb_flush(cpu);
+        break;
+    case TBS_CMD_STATUS:
+        if (tb_stats_collection_enabled()) {
+            uint32_t flag = get_tbstats_flag();
+            monitor_printf(mon, "tb_stats is enabled with flag:\n");
+            monitor_printf(mon, "    EXEC: %d\n", !!(flag & TB_EXEC_STATS));
+            monitor_printf(mon, "     JIT: %d\n", !!(flag & TB_JIT_STATS));
+        } else {
+            monitor_printf(mon, "tb_stats is disabled\n");
+        }
+        break;
+    default: /* INVALID */
+        g_assert_not_reached();
+        break;
+    }
+
+    g_free(cmdinfo);
+}
+
+void hmp_tbstats(Monitor *mon, const QDict *qdict)
+{
+    if (!tcg_enabled()) {
+        monitor_printf(mon, "Only available with accel=tcg\n");
+        return;
+    }
+
+    char *cmd = (char *) qdict_get_try_str(qdict, "command");
+    enum TbstatsCmd icmd = -1;
+
+    if (strcmp(cmd, "start") == 0) {
+        icmd = TBS_CMD_START;
+    } else if (strcmp(cmd, "stop") == 0) {
+        icmd = TBS_CMD_STOP;
+    } else if (strcmp(cmd, "status") == 0) {
+        icmd = TBS_CMD_STATUS;
+    } else {
+        monitor_printf(mon, "Invalid command\n");
+        return;
+    }
+
+    char *sflag = (char *) qdict_get_try_str(qdict, "flag");
+    uint32_t flag = TB_EXEC_STATS | TB_JIT_STATS;
+    if (sflag) {
+        if (strcmp(sflag, "jit") == 0) {
+            flag = TB_JIT_STATS;
+        } else if (strcmp(sflag, "exec") == 0) {
+            flag = TB_EXEC_STATS;
+        }
+    }
+
+    struct TbstatsCommand *tbscommand = g_new0(struct TbstatsCommand, 1);
+    tbscommand->cmd = icmd;
+    tbscommand->flag = flag;
+    tbscommand->mon = mon;
+    async_safe_run_on_cpu(first_cpu, do_hmp_tbstats_safe,
+                          RUN_ON_CPU_HOST_PTR(tbscommand));
+
+}
+
 static void hmp_tcg_register(void)
 {
     monitor_register_hmp_info_hrt("jit", qmp_x_query_jit);
diff --git a/accel/tcg/tb-stats.c b/accel/tcg/tb-stats.c
index 11322359c7..c90dde37d0 100644
--- a/accel/tcg/tb-stats.c
+++ b/accel/tcg/tb-stats.c
@@ -91,6 +91,18 @@ void dump_jit_profile_info(GString *buf)
     g_free(jpi);
 }
 
+static void free_tbstats(void *p, uint32_t hash, void *userp)
+{
+    g_free(p);
+}
+
+void clean_tbstats(void)
+{
+    /* remove all tb_stats */
+    qht_iter(&tb_ctx.tb_stats, free_tbstats, NULL);
+    qht_destroy(&tb_ctx.tb_stats);
+}
+
 void init_tb_stats_htable(void)
 {
     if (!tb_ctx.tb_stats.map && tb_stats_collection_enabled()) {
@@ -115,6 +127,11 @@ bool tb_stats_collection_enabled(void)
     return tcg_collect_tb_stats == TB_STATS_RUNNING;
 }
 
+bool tb_stats_collection_disabled(void)
+{
+    return tcg_collect_tb_stats == TB_STATS_STOPPED;
+}
+
 uint32_t get_tbstats_flag(void)
 {
     return tbstats_flag;
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 2cbd0f77a0..639e9d9e53 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1670,6 +1670,22 @@ SRST
   Executes a qemu-io command on the given block device.
 ERST
 
+#if defined(CONFIG_TCG)
+    {
+        .name       = "tb_stats",
+        .args_type  = "command:s,flag:s?",
+        .params     = "command [flag]",
+        .help       = "Control tb statistics collection:"
+                        "tb_stats (start|stop|status) [all|jit|exec]",
+        .cmd        = hmp_tbstats,
+    },
+#endif
+
+SRST
+``tb_stats`` *command* *flag*
+  Control recording tb statistics
+ERST
+
     {
         .name       = "qom-list",
         .args_type  = "path:s?",
diff --git a/include/exec/tb-stats-flags.h b/include/exec/tb-stats-flags.h
index 286ca93bcc..d8b844be99 100644
--- a/include/exec/tb-stats-flags.h
+++ b/include/exec/tb-stats-flags.h
@@ -19,6 +19,7 @@
 void enable_collect_tb_stats(void);
 void disable_collect_tb_stats(void);
 bool tb_stats_collection_enabled(void);
+bool tb_stats_collection_disabled(void);
 
 uint32_t get_tbstats_flag(void);
 void set_tbstats_flag(uint32_t flag);
diff --git a/include/exec/tb-stats.h b/include/exec/tb-stats.h
index 6ed767f490..e16f947410 100644
--- a/include/exec/tb-stats.h
+++ b/include/exec/tb-stats.h
@@ -31,6 +31,8 @@
 #include "exec/tb-stats-flags.h"
 #include "tcg/tcg.h"
 
+enum SortBy { SORT_BY_HOTNESS, SORT_BY_HG /* Host/Guest */, SORT_BY_SPILLS };
+
 typedef struct TBStatistics TBStatistics;
 
 /*
@@ -90,4 +92,6 @@ bool tb_stats_enabled(TranslationBlock *tb, uint32_t flag);
 
 void dump_jit_profile_info(GString *buf);
 
+void clean_tbstats(void);
+
 #endif
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index 13f9a2dedb..2e7f141754 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -181,5 +181,6 @@ void hmp_ioport_write(Monitor *mon, const QDict *qdict);
 void hmp_boot_set(Monitor *mon, const QDict *qdict);
 void hmp_info_mtree(Monitor *mon, const QDict *qdict);
 void hmp_info_cryptodev(Monitor *mon, const QDict *qdict);
+void hmp_tbstats(Monitor *mon, const QDict *qdict);
 
 #endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v15 06/10] tb-stats: reset the tracked TBs on a tb_flush
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
                   ` (4 preceding siblings ...)
  2023-06-07 12:24 ` [PATCH v15 05/10] monitor: adding tb_stats hmp command Fei Wu
@ 2023-06-07 12:24 ` Fei Wu
  2023-06-07 12:24 ` [PATCH v15 07/10] tb-stats: Adding info [tb-list|tb] commands to HMP (WIP) Fei Wu
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Fei Wu @ 2023-06-07 12:24 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel; +Cc: Fei Wu, Paolo Bonzini

From: Alex Bennée <alex.bennee@linaro.org>

We keep track of translations but can only do so up until the
translation cache is flushed. At that point we really have no idea if
we can re-create a translation because all the active tracking
information has been reset.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Fei Wu <fei2.wu@intel.com>
---
 accel/tcg/tb-maint.c    |  1 +
 accel/tcg/tb-stats.c    | 18 ++++++++++++++++++
 include/exec/tb-stats.h |  8 ++++++++
 3 files changed, 27 insertions(+)

diff --git a/accel/tcg/tb-maint.c b/accel/tcg/tb-maint.c
index 0980fca358..11ff0ddd90 100644
--- a/accel/tcg/tb-maint.c
+++ b/accel/tcg/tb-maint.c
@@ -763,6 +763,7 @@ static void do_tb_flush(CPUState *cpu, run_on_cpu_data tb_flush_count)
     qht_reset_size(&tb_ctx.htable, CODE_GEN_HTABLE_SIZE);
     tb_remove_all();
 
+    tbstats_reset_tbs();
     tcg_region_reset_all();
     /* XXX: flush processor icache at this point if cache flush is expensive */
     qatomic_inc(&tb_ctx.tb_flush_count);
diff --git a/accel/tcg/tb-stats.c b/accel/tcg/tb-stats.c
index c90dde37d0..7c7f700c89 100644
--- a/accel/tcg/tb-stats.c
+++ b/accel/tcg/tb-stats.c
@@ -103,6 +103,24 @@ void clean_tbstats(void)
     qht_destroy(&tb_ctx.tb_stats);
 }
 
+/*
+ * We have to reset the tbs array on a tb_flush as those
+ * TranslationBlocks no longer exist.
+ */
+
+static void reset_tbs_array(void *p, uint32_t hash, void *userp)
+{
+    TBStatistics *tbs = p;
+    g_ptr_array_set_size(tbs->tbs, 0);
+}
+
+void tbstats_reset_tbs(void)
+{
+    if (tb_ctx.tb_stats.map) {
+        qht_iter(&tb_ctx.tb_stats, reset_tbs_array, NULL);
+    }
+}
+
 void init_tb_stats_htable(void)
 {
     if (!tb_ctx.tb_stats.map && tb_stats_collection_enabled()) {
diff --git a/include/exec/tb-stats.h b/include/exec/tb-stats.h
index e16f947410..77974b4b7f 100644
--- a/include/exec/tb-stats.h
+++ b/include/exec/tb-stats.h
@@ -94,4 +94,12 @@ void dump_jit_profile_info(GString *buf);
 
 void clean_tbstats(void);
 
+/**
+ * tbstats_reset_tbs: reset the linked array of TBs
+ *
+ * Reset the list of tbs for a given array. Should be called from
+ * safe work during tb_flush.
+ */
+void tbstats_reset_tbs(void);
+
 #endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v15 07/10] tb-stats: Adding info [tb-list|tb] commands to HMP (WIP)
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
                   ` (5 preceding siblings ...)
  2023-06-07 12:24 ` [PATCH v15 06/10] tb-stats: reset the tracked TBs on a tb_flush Fei Wu
@ 2023-06-07 12:24 ` Fei Wu
  2023-06-12  1:44   ` Wu, Fei
  2023-06-07 12:24 ` [PATCH v15 08/10] debug: add -d tb_stats to control TBStatistics Fei Wu
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 17+ messages in thread
From: Fei Wu @ 2023-06-07 12:24 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel
  Cc: Vanderson M. do Rosario, Dr . David Alan Gilbert, Fei Wu,
	Paolo Bonzini, Dr. David Alan Gilbert

From: "Vanderson M. do Rosario" <vandersonmr2@gmail.com>

These commands allow the exploration of TBs generated by the TCG.
Understand which one hotter, with more guest/host instructions... and
examine their guest, host and IR code.

The goal of this command is to allow the dynamic exploration of TCG
behavior and code quality. Therefore, for now, a corresponding QMP
command is not worthwhile.

[AJB: WIP - we still can't be safely sure a translation will succeed]

Example of output:

TB id:0 | phys:0x34d54 virt:0x0000000000034d54 flags:0x0000f0
	| exec:4828932/0 guest inst cov:16.38%
	| trans:1 ints: g:3 op:82 op_opt:34 spills:3
	| h/g (host bytes / guest insts): 90.666664

TB id:1 | phys:0x34d0d virt:0x0000000000034d0d flags:0x0000f0
	| exec:4825842/0 guest inst cov:21.82%
	| trans:1 ints: g:4 op:80 op_opt:38 spills:2
	| h/g (host bytes / guest insts): 84.000000

----------------

0x00034d0d:  89 de                    movl     %ebx, %esi
0x00034d0f:  26 8b 0e                 movl     %es:(%esi), %ecx
0x00034d12:  26 f6 46 08 80           testb    $0x80, %es:8(%esi)
0x00034d17:  75 3b                    jne      0x34d54

------------------------------

Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Signed-off-by: Vanderson M. do Rosario <vandersonmr2@gmail.com>
Message-Id: <20190829173437.5926-10-vandersonmr2@gmail.com>
[AJB: fix authorship, dropped coverset]
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Fei Wu <fei2.wu@intel.com>
---
 accel/tcg/monitor.c     |  69 ++++++++++++++++
 accel/tcg/tb-stats.c    | 176 ++++++++++++++++++++++++++++++++++++++++
 disas/disas.c           |   2 +
 hmp-commands-info.hx    |  16 ++++
 include/exec/tb-stats.h |  25 ++++++
 include/monitor/hmp.h   |   2 +
 6 files changed, 290 insertions(+)

diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c
index 094150e4af..d43c62b248 100644
--- a/accel/tcg/monitor.c
+++ b/accel/tcg/monitor.c
@@ -8,17 +8,21 @@
 
 #include "qemu/osdep.h"
 #include "qemu/accel.h"
+#include "qemu/log.h"
 #include "qapi/error.h"
 #include "qapi/type-helpers.h"
 #include "qapi/qapi-commands-machine.h"
 #include "qapi/qmp/qdict.h"
 #include "monitor/monitor.h"
 #include "monitor/hmp.h"
+#include "monitor/hmp-target.h"
 #include "sysemu/cpus.h"
 #include "sysemu/cpu-timers.h"
 #include "sysemu/tcg.h"
 #include "exec/tb-stats.h"
 #include "exec/tb-flush.h"
+#include "disas/disas.h"
+#include "tb-context.h"
 #include "internal.h"
 #include "tb-context.h"
 
@@ -186,6 +190,71 @@ void hmp_tbstats(Monitor *mon, const QDict *qdict)
 
 }
 
+void hmp_info_tblist(Monitor *mon, const QDict *qdict)
+{
+    int number_int;
+    const char *sortedby_str = NULL;
+    g_autoptr(GString) buf = g_string_new("");
+
+    if (!tcg_enabled()) {
+        monitor_printf(mon, "Only available with accel=tcg\n");
+        return;
+    }
+    if (!tb_ctx.tb_stats.map) {
+        monitor_printf(mon, "no TB information recorded\n");
+        return;
+    }
+
+    number_int = qdict_get_try_int(qdict, "number", 10);
+    sortedby_str = qdict_get_try_str(qdict, "sortedby");
+
+    int sortedby = SORT_BY_HOTNESS;
+    if (sortedby_str == NULL || strcmp(sortedby_str, "hotness") == 0) {
+        sortedby = SORT_BY_HOTNESS;
+    } else if (strcmp(sortedby_str, "hg") == 0) {
+        sortedby = SORT_BY_HG;
+    } else if (strcmp(sortedby_str, "spills") == 0) {
+        sortedby = SORT_BY_SPILLS;
+    } else {
+        monitor_printf(mon, "valid sort options are: hotness hg spills\n");
+        return;
+    }
+
+    dump_tblist_info(buf, number_int, sortedby);
+    monitor_printf(mon, "%s", buf->str);
+}
+
+void hmp_info_tb(Monitor *mon, const QDict *qdict)
+{
+    const int id = qdict_get_int(qdict, "id");
+    g_autoptr(GString) buf = g_string_new("");
+
+    if (!tcg_enabled()) {
+        monitor_printf(mon, "Only available with accel=tcg\n");
+        return;
+    }
+
+    TBStatistics *tbs = get_tbstats_by_id(id);
+    if (tbs == NULL) {
+        monitor_printf(mon, "TB %d information is not recorded\n", id);
+        return;
+    }
+
+    monitor_printf(mon, "\n------------------------------\n\n");
+
+    int valid_tb_num = dump_tb_info(buf, tbs, id);
+    monitor_printf(mon, "%s", buf->str);
+
+    if (valid_tb_num > 0) {
+        unsigned num_inst = tbs->code.num_guest_inst / tbs->translations.total;
+
+        monitor_printf(mon, "\n----------------n\n");
+        // FIXME: cannot disas
+        monitor_disas(mon, mon_get_cpu(mon), tbs->phys_pc, num_inst, true);
+        monitor_printf(mon, "\n------------------------------\n\n");
+    }
+}
+
 static void hmp_tcg_register(void)
 {
     monitor_register_hmp_info_hrt("jit", qmp_x_query_jit);
diff --git a/accel/tcg/tb-stats.c b/accel/tcg/tb-stats.c
index 7c7f700c89..53a4f448dc 100644
--- a/accel/tcg/tb-stats.c
+++ b/accel/tcg/tb-stats.c
@@ -11,12 +11,16 @@
 #include "disas/disas.h"
 #include "exec/exec-all.h"
 #include "tcg/tcg.h"
+#include "qapi/error.h"
 
 #include "qemu/qemu-print.h"
+#include "qemu/log.h"
 
 #include "exec/tb-stats.h"
 #include "tb-context.h"
 
+#include "internal.h"
+
 /* TBStatistic collection controls */
 enum TBStatsStatus {
     TB_STATS_STOPPED = 0,
@@ -26,6 +30,8 @@ enum TBStatsStatus {
 static enum TBStatsStatus tcg_collect_tb_stats;
 static uint32_t tbstats_flag;
 
+static GPtrArray *last_search;
+
 struct jit_profile_info {
     uint64_t translations;
     uint64_t aborted;
@@ -42,6 +48,18 @@ struct jit_profile_info {
 #define stat_per_translation(stat, name) \
     (stat->translations.total ? stat->name / stat->translations.total : 0)
 
+TBStatistics *get_tbstats_by_id(int id)
+{
+    if (!last_search) {
+        return NULL;
+    }
+
+    if (id < 0 || id >= last_search->len) {
+        return NULL;
+    }
+    return g_ptr_array_index(last_search, id);
+}
+
 /* accumulate the statistics from all TBs */
 static void collect_jit_profile_info(void *p, uint32_t hash, void *userp)
 {
@@ -98,6 +116,10 @@ static void free_tbstats(void *p, uint32_t hash, void *userp)
 
 void clean_tbstats(void)
 {
+    if (last_search) {
+        g_ptr_array_free(last_search, true);
+    }
+
     /* remove all tb_stats */
     qht_iter(&tb_ctx.tb_stats, free_tbstats, NULL);
     qht_destroy(&tb_ctx.tb_stats);
@@ -129,6 +151,154 @@ void init_tb_stats_htable(void)
     }
 }
 
+static void collect_tb_stats(void *p, uint32_t hash, void *userp)
+{
+    int *count = userp;
+
+    g_ptr_array_add(last_search, p);
+    (*count)++;
+}
+
+static void count_invalid_tbs(gpointer data, gpointer user_data)
+{
+    TranslationBlock *tb = (TranslationBlock *) data;
+    unsigned *counter = (unsigned *) user_data;
+    if (tb->cflags & CF_INVALID) {
+        *counter = *counter + 1;
+    }
+}
+
+int dump_tb_info(GString *buf, TBStatistics *tbs, int id)
+{
+    unsigned g = stat_per_translation(tbs, code.num_guest_inst);
+    unsigned ops = stat_per_translation(tbs, code.num_tcg_ops);
+    unsigned ops_opt = stat_per_translation(tbs, code.num_tcg_ops_opt);
+    unsigned spills = stat_per_translation(tbs, code.spills);
+    unsigned h = stat_per_translation(tbs, code.out_len);
+    unsigned act = tbs->tbs->len;
+    unsigned invalid = 0;
+
+    float guest_host_prop = g ? ((float) h / g) : 0;
+
+    g_ptr_array_foreach(tbs->tbs, &count_invalid_tbs, &invalid);
+
+    g_string_append_printf(buf,
+            "TB id:%d | phys:0x"TB_PAGE_ADDR_FMT" virt:0x"TARGET_FMT_lx
+            " flags:0x%08x %d inv/%d\n",
+            id, tbs->phys_pc, tbs->pc, tbs->flags, invalid, act);
+
+    if (tbs_stats_enabled(tbs, TB_EXEC_STATS)) {
+        g_string_append_printf(buf,
+                "\t| exec:%lu/%lu guest inst cov:%.2f%%\n",
+                tbs->executions.normal,
+                tbs->executions.atomic, tbs->executions.coverage / 100.0f);
+    }
+
+    if (tbs_stats_enabled(tbs, TB_JIT_STATS)) {
+        g_string_append_printf(buf,
+                "\t| trans:%lu ints: g:%u op:%u op_opt:%u spills:%d"
+                "\n\t| h/g (host bytes / guest insts): %f\n",
+                tbs->translations.total, g, ops, ops_opt, spills,
+                guest_host_prop);
+    }
+
+    g_string_append_printf(buf, "\n");
+
+    return act - invalid;
+}
+
+static gint
+inverse_sort_tbs_spills(gconstpointer p1, gconstpointer p2)
+{
+    const TBStatistics *tbs1 = *(TBStatistics **) p1;
+    const TBStatistics *tbs2 = *(TBStatistics **) p2;
+    unsigned long c1 = stat_per_translation(tbs1, code.spills);
+    unsigned long c2 = stat_per_translation(tbs2, code.spills);
+    return c1 < c2 ? 1 : c1 == c2 ? 0 : -1;
+}
+
+static gint
+inverse_sort_tbs_hotness(gconstpointer p1, gconstpointer p2)
+{
+    const TBStatistics *tbs1 = *(TBStatistics **) p1;
+    const TBStatistics *tbs2 = *(TBStatistics **) p2;
+    unsigned long c1 = stat_per_translation(tbs1, executions.normal);
+    unsigned long c2 = stat_per_translation(tbs2, executions.normal);
+    return c1 < c2 ? 1 : c1 == c2 ? 0 : -1;
+}
+
+static gint
+inverse_sort_tbs_hg(gconstpointer p1, gconstpointer p2)
+{
+    const TBStatistics *tbs1 = *(TBStatistics **) p1;
+    const TBStatistics *tbs2 = *(TBStatistics **) p2;
+
+    if (tbs1->code.num_guest_inst == 0) {
+        return -1;
+    }
+    if (tbs2->code.num_guest_inst == 0) {
+        return 1;
+    }
+
+    unsigned long c1 = tbs1->code.out_len / tbs1->code.num_guest_inst;
+    unsigned long c2 = tbs2->code.out_len / tbs2->code.num_guest_inst;
+    return c1 < c2 ? 1 : c1 == c2 ? 0 : -1;
+}
+
+static void calculate_last_search_coverages(void)
+{
+    uint64_t total_exec_count = 0;
+
+    /* Compute total execution count for all tbs */
+    for (int i = 0; i < last_search->len; ++i) {
+        TBStatistics *tbs = g_ptr_array_index(last_search, i);
+        total_exec_count +=
+            (tbs->executions.atomic + tbs->executions.normal)
+                * stat_per_translation(tbs, code.num_guest_inst);
+    }
+
+    for (int i = 0; i < last_search->len; ++i) {
+        TBStatistics *tbs = g_ptr_array_index(last_search, i);
+        uint64_t tb_total_execs =
+            (tbs->executions.atomic + tbs->executions.normal)
+                * stat_per_translation(tbs, code.num_guest_inst);
+        tbs->executions.coverage =
+            (10000 * tb_total_execs) / (total_exec_count + 1);
+    }
+}
+
+void dump_tblist_info(GString *buf, int total, int sort_by)
+{
+    int array_size = 0;
+
+    if (last_search) {
+        g_ptr_array_free(last_search, true);
+    }
+    last_search = g_ptr_array_new();
+
+    qht_iter(&tb_ctx.tb_stats, collect_tb_stats, &array_size);
+
+    calculate_last_search_coverages();
+
+    if (sort_by == SORT_BY_HOTNESS) {
+        g_ptr_array_sort(last_search, (GCompareFunc)inverse_sort_tbs_hotness);
+    } else if (sort_by == SORT_BY_SPILLS) {
+        g_ptr_array_sort(last_search, (GCompareFunc)inverse_sort_tbs_spills);
+    } else if (sort_by == SORT_BY_HG) {
+        g_ptr_array_sort(last_search, (GCompareFunc)inverse_sort_tbs_hg);
+    } else {
+        return;
+    }
+
+    array_size = (array_size > total) ? total : array_size;
+    g_ptr_array_set_size(last_search, array_size);
+
+    for (int i = 0; i < last_search->len; ++i) {
+        TBStatistics *tbs = g_ptr_array_index(last_search, i);
+        dump_tb_info(buf, tbs, i);
+    }
+}
+
 void enable_collect_tb_stats(void)
 {
     tcg_collect_tb_stats = TB_STATS_RUNNING;
@@ -166,3 +336,9 @@ bool tb_stats_enabled(TranslationBlock *tb, uint32_t flag)
            tb->tb_stats &&
            (tbstats_flag & flag);
 }
+
+bool tbs_stats_enabled(struct TBStatistics *tbs, uint32_t flag)
+{
+    return tb_stats_collection_enabled() &&
+           (tbstats_flag & flag);
+}
diff --git a/disas/disas.c b/disas/disas.c
index 0d2d06c2ec..3b19b51fca 100644
--- a/disas/disas.c
+++ b/disas/disas.c
@@ -8,6 +8,8 @@
 #include "hw/core/cpu.h"
 #include "exec/memory.h"
 
+#include "qemu/log-for-trace.h"
+
 /* Filled in by elfload.c.  Simplistic, but will do for now. */
 struct syminfo *syminfos = NULL;
 
diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index f5b37eb74a..ace1ecc3c5 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -262,6 +262,22 @@ ERST
         .params     = "",
         .help       = "show dynamic compiler info",
     },
+    {
+        .name       = "tb-list",
+        .args_type  = "number:i?,sortedby:s?",
+        .params     = "[number sortedby]",
+        .help       = "show a [number] translated blocks sorted by [sortedby]"
+                      "sortedby opts: hotness hg spills",
+        .cmd        = hmp_info_tblist,
+    },
+    {
+        .name       = "tb",
+        .args_type  = "id:i,flags:s?",
+        .params     = "id [flag1,flag2,...]",
+        .help       = "show information about one translated block by id."
+                      "dump flags can be used to set dump code level: out_asm in_asm op",
+        .cmd        = hmp_info_tb,
+    },
 #endif
 
 SRST
diff --git a/include/exec/tb-stats.h b/include/exec/tb-stats.h
index 77974b4b7f..4cdf41af6c 100644
--- a/include/exec/tb-stats.h
+++ b/include/exec/tb-stats.h
@@ -54,6 +54,8 @@ struct TBStatistics {
     struct {
         unsigned long normal;
         unsigned long atomic;
+        /* filled only when dumping x% cover set */
+        uint16_t coverage;
     } executions;
 
     /* JIT Stats - protected by lock */
@@ -89,6 +91,7 @@ bool tb_stats_cmp(const void *ap, const void *bp);
 
 void init_tb_stats_htable(void);
 bool tb_stats_enabled(TranslationBlock *tb, uint32_t flag);
+bool tbs_stats_enabled(struct TBStatistics *tbs, uint32_t flag);
 
 void dump_jit_profile_info(GString *buf);
 
@@ -102,4 +105,26 @@ void clean_tbstats(void);
  */
 void tbstats_reset_tbs(void);
 
+/**
+ * dump_tbs_info: report the hottest blocks
+ *
+ * @buf: output buffer
+ * @total: the limit of hotblocks
+ * @sort_by: property in which the dump will be sorted
+ *
+ * Report the hottest blocks to either the log or monitor
+ */
+void dump_tblist_info(GString *buf, int total, int sort_by);
+
+/**
+ * dump_tb_info: dump information about one TB
+ *
+ * @buf: output buffer
+ * @tbs: the tbs to dump
+ * @id: the display id of the block (from previous search)
+ */
+int dump_tb_info(GString *buf, TBStatistics *tbs, int id);
+
+TBStatistics *get_tbstats_by_id(int id);
+
 #endif
diff --git a/include/monitor/hmp.h b/include/monitor/hmp.h
index 2e7f141754..acdd6f1561 100644
--- a/include/monitor/hmp.h
+++ b/include/monitor/hmp.h
@@ -182,5 +182,7 @@ void hmp_boot_set(Monitor *mon, const QDict *qdict);
 void hmp_info_mtree(Monitor *mon, const QDict *qdict);
 void hmp_info_cryptodev(Monitor *mon, const QDict *qdict);
 void hmp_tbstats(Monitor *mon, const QDict *qdict);
+void hmp_info_tblist(Monitor *mon, const QDict *qdict);
+void hmp_info_tb(Monitor *mon, const QDict *qdict);
 
 #endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v15 08/10] debug: add -d tb_stats to control TBStatistics
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
                   ` (6 preceding siblings ...)
  2023-06-07 12:24 ` [PATCH v15 07/10] tb-stats: Adding info [tb-list|tb] commands to HMP (WIP) Fei Wu
@ 2023-06-07 12:24 ` Fei Wu
  2023-06-07 12:24 ` [PATCH v15 09/10] tb-stats: dump hot TBs at the end of the execution Fei Wu
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Fei Wu @ 2023-06-07 12:24 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel
  Cc: Fei Wu, Vanderson M . do Rosario, Paolo Bonzini

Capture TBS at startup instead of an explicit 'tb_stats start' command.

Signed-off-by: Vanderson M. do Rosario <vandersonmr2@gmail.com>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Fei Wu <fei2.wu@intel.com>
---
 include/exec/tb-stats-flags.h |  1 +
 include/qemu/log.h            |  1 +
 stubs/meson.build             |  1 +
 stubs/tb-stats.c              | 32 ++++++++++++++++++++++++++++++++
 util/log.c                    | 18 ++++++++++++++++++
 5 files changed, 53 insertions(+)
 create mode 100644 stubs/tb-stats.c

diff --git a/include/exec/tb-stats-flags.h b/include/exec/tb-stats-flags.h
index d8b844be99..936bd35707 100644
--- a/include/exec/tb-stats-flags.h
+++ b/include/exec/tb-stats-flags.h
@@ -14,6 +14,7 @@
 #define TB_NONE_STATS (0)  /* no stats */
 #define TB_EXEC_STATS (1 << 0)
 #define TB_JIT_STATS  (1 << 1)
+#define TB_ALL_STATS  (TB_EXEC_STATS | TB_JIT_STATS)
 
 /* TBStatistic collection controls */
 void enable_collect_tb_stats(void);
diff --git a/include/qemu/log.h b/include/qemu/log.h
index c5643d8dd5..6f3b8091cd 100644
--- a/include/qemu/log.h
+++ b/include/qemu/log.h
@@ -35,6 +35,7 @@ bool qemu_log_separate(void);
 /* LOG_STRACE is used for user-mode strace logging. */
 #define LOG_STRACE         (1 << 19)
 #define LOG_PER_THREAD     (1 << 20)
+#define CPU_LOG_TB_STATS   (1 << 21)
 
 /* Lock/unlock output. */
 
diff --git a/stubs/meson.build b/stubs/meson.build
index a56645e2f7..e926649d40 100644
--- a/stubs/meson.build
+++ b/stubs/meson.build
@@ -65,3 +65,4 @@ else
 endif
 stub_ss.add(files('semihost-all.c'))
 stub_ss.add(when: 'CONFIG_VFIO_USER_SERVER', if_false: files('vfio-user-obj.c'))
+stub_ss.add(files('tb-stats.c'))
diff --git a/stubs/tb-stats.c b/stubs/tb-stats.c
new file mode 100644
index 0000000000..38ee12313e
--- /dev/null
+++ b/stubs/tb-stats.c
@@ -0,0 +1,32 @@
+/*
+ * TB Stats Stubs
+ *
+ * Copyright (c) 2019
+ * Written by Alex Bennée <alex.bennee@linaro.org>
+ *
+ * This code is licensed under the GNU GPL v2, or later.
+ */
+
+
+#include "qemu/osdep.h"
+#include "exec/tb-stats-flags.h"
+
+void enable_collect_tb_stats(void)
+{
+    return;
+}
+
+void disable_collect_tb_stats(void)
+{
+    return;
+}
+
+bool tb_stats_collection_enabled(void)
+{
+    return false;
+}
+
+void set_tbstats_flag(uint32_t flag)
+{
+    return;
+}
diff --git a/util/log.c b/util/log.c
index 53b4f6c58e..419f02c380 100644
--- a/util/log.c
+++ b/util/log.c
@@ -27,6 +27,7 @@
 #include "qemu/thread.h"
 #include "qemu/lockable.h"
 #include "qemu/rcu.h"
+#include "exec/tb-stats-flags.h"
 #ifdef CONFIG_LINUX
 #include <sys/syscall.h>
 #endif
@@ -495,6 +496,8 @@ const QEMULogItem qemu_log_items[] = {
       "log every user-mode syscall, its input, and its result" },
     { LOG_PER_THREAD, "tid",
       "open a separate log file per thread; filename must contain '%d'" },
+    { CPU_LOG_TB_STATS, "tb_stats_{all,jit,exec}",
+      "enable collection of TBs statistics at startup" },
     { 0, NULL, NULL },
 };
 
@@ -516,6 +519,21 @@ int qemu_str_to_log_mask(const char *str)
             trace_enable_events((*tmp) + 6);
             mask |= LOG_TRACE;
 #endif
+        } else if (g_str_has_prefix(*tmp, "tb_stats_")) {
+            char *p = *tmp + 9;
+            uint32_t flag = TB_NONE_STATS;
+            if (g_str_has_prefix(p, "all")) {
+                flag = TB_ALL_STATS;
+            } else if (g_str_has_prefix(p, "jit")) {
+                flag = TB_JIT_STATS;
+            } else if (g_str_has_prefix(p, "exec")) {
+                flag = TB_EXEC_STATS;
+            }
+            if (flag != TB_NONE_STATS) {
+                mask |= CPU_LOG_TB_STATS;
+                set_tbstats_flag(flag);
+                enable_collect_tb_stats();
+            }
         } else {
             for (item = qemu_log_items; item->mask != 0; item++) {
                 if (g_str_equal(*tmp, item->name)) {
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v15 09/10] tb-stats: dump hot TBs at the end of the execution
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
                   ` (7 preceding siblings ...)
  2023-06-07 12:24 ` [PATCH v15 08/10] debug: add -d tb_stats to control TBStatistics Fei Wu
@ 2023-06-07 12:24 ` Fei Wu
  2023-06-07 12:24 ` [PATCH v15 10/10] docs: add tb-stats how to Fei Wu
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 17+ messages in thread
From: Fei Wu @ 2023-06-07 12:24 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel
  Cc: Fei Wu, Paolo Bonzini, Laurent Vivier

Dump the hottest TBs if -d tb_stats_{all,jit,exec}[:dump_num_at_exit]
---
 accel/tcg/tb-stats.c          | 21 +++++++++++++++++++++
 include/exec/tb-stats-dump.h  | 21 +++++++++++++++++++++
 include/exec/tb-stats-flags.h |  1 +
 linux-user/exit.c             |  2 ++
 softmmu/runstate.c            |  2 ++
 stubs/tb-stats.c              |  4 ++++
 util/log.c                    | 12 ++++++++++--
 7 files changed, 61 insertions(+), 2 deletions(-)
 create mode 100644 include/exec/tb-stats-dump.h

diff --git a/accel/tcg/tb-stats.c b/accel/tcg/tb-stats.c
index 53a4f448dc..a5fc3c1c74 100644
--- a/accel/tcg/tb-stats.c
+++ b/accel/tcg/tb-stats.c
@@ -17,6 +17,7 @@
 #include "qemu/log.h"
 
 #include "exec/tb-stats.h"
+#include "exec/tb-stats-dump.h"
 #include "tb-context.h"
 
 #include "internal.h"
@@ -29,6 +30,7 @@ enum TBStatsStatus {
 
 static enum TBStatsStatus tcg_collect_tb_stats;
 static uint32_t tbstats_flag;
+static int max_dump_tbs;
 
 static GPtrArray *last_search;
 
@@ -299,6 +301,20 @@ void dump_tblist_info(GString *buf, int total, int sort_by)
     }
 }
 
+/*
+ * Dump the final stats
+ */
+void tb_stats_dump(void)
+{
+    if (!tb_stats_collection_enabled()) {
+        return;
+    }
+
+    g_autoptr(GString) buf = g_string_new("");
+    dump_tblist_info(buf, max_dump_tbs, SORT_BY_HOTNESS);
+    qemu_printf("%s", buf->str);
+}
+
 void enable_collect_tb_stats(void)
 {
     tcg_collect_tb_stats = TB_STATS_RUNNING;
@@ -342,3 +358,8 @@ bool tbs_stats_enabled(struct TBStatistics *tbs, uint32_t flag)
     return tb_stats_collection_enabled() &&
            (tbstats_flag & flag);
 }
+
+void set_tbstats_max_tbs(int max)
+{
+    max_dump_tbs = max;
+}
diff --git a/include/exec/tb-stats-dump.h b/include/exec/tb-stats-dump.h
new file mode 100644
index 0000000000..197c6148e9
--- /dev/null
+++ b/include/exec/tb-stats-dump.h
@@ -0,0 +1,21 @@
+/*
+ * TB Stats common dump functions across sysemu/linux-user
+ *
+ * Copyright (c) 2019 Linaro
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#ifndef _TB_STATS_DUMP_H_
+#define _TB_STATS_DUMP_H_
+
+/**
+ * tb_stats_dump: dump final tb_stats at end of execution
+ */
+#ifdef CONFIG_TCG
+void tb_stats_dump(void);
+#else
+static inline void tb_stats_dump(void) { /* do nothing */ };
+#endif
+
+#endif /* _TB_STATS_DUMP_H_ */
diff --git a/include/exec/tb-stats-flags.h b/include/exec/tb-stats-flags.h
index 936bd35707..52d0429eeb 100644
--- a/include/exec/tb-stats-flags.h
+++ b/include/exec/tb-stats-flags.h
@@ -24,5 +24,6 @@ bool tb_stats_collection_disabled(void);
 
 uint32_t get_tbstats_flag(void);
 void set_tbstats_flag(uint32_t flag);
+void set_tbstats_max_tbs(int max);
 
 #endif
diff --git a/linux-user/exit.c b/linux-user/exit.c
index 3017d28a3c..4fd23bcf60 100644
--- a/linux-user/exit.c
+++ b/linux-user/exit.c
@@ -25,6 +25,7 @@
 #ifdef CONFIG_GPROF
 #include <sys/gmon.h>
 #endif
+#include "exec/tb-stats-dump.h"
 
 #ifdef CONFIG_GCOV
 extern void __gcov_dump(void);
@@ -41,4 +42,5 @@ void preexit_cleanup(CPUArchState *env, int code)
         gdb_exit(code);
         qemu_plugin_user_exit();
         perf_exit();
+        tb_stats_dump();
 }
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
index bd50062ed0..156156815b 100644
--- a/softmmu/runstate.c
+++ b/softmmu/runstate.c
@@ -30,6 +30,7 @@
 #include "crypto/cipher.h"
 #include "crypto/init.h"
 #include "exec/cpu-common.h"
+#include "exec/tb-stats-dump.h"
 #include "gdbstub/syscalls.h"
 #include "hw/boards.h"
 #include "migration/misc.h"
@@ -818,6 +819,7 @@ void qemu_cleanup(void)
     vm_shutdown();
     replay_finish();
 
+    tb_stats_dump();
     job_cancel_sync_all();
     bdrv_close_all();
 
diff --git a/stubs/tb-stats.c b/stubs/tb-stats.c
index 38ee12313e..78ae1aa217 100644
--- a/stubs/tb-stats.c
+++ b/stubs/tb-stats.c
@@ -30,3 +30,7 @@ void set_tbstats_flag(uint32_t flag)
 {
     return;
 }
+
+void set_tbstats_max_tbs(int max) {
+    return;
+}
diff --git a/util/log.c b/util/log.c
index 419f02c380..ae5398fb69 100644
--- a/util/log.c
+++ b/util/log.c
@@ -496,8 +496,9 @@ const QEMULogItem qemu_log_items[] = {
       "log every user-mode syscall, its input, and its result" },
     { LOG_PER_THREAD, "tid",
       "open a separate log file per thread; filename must contain '%d'" },
-    { CPU_LOG_TB_STATS, "tb_stats_{all,jit,exec}",
-      "enable collection of TBs statistics at startup" },
+    { CPU_LOG_TB_STATS, "tb_stats_{all,jit,exec}[:dump_num_at_exit]",
+      "enable collection of TBs statistics at startup "
+      "and dump at exit until given a limit" },
     { 0, NULL, NULL },
 };
 
@@ -524,16 +525,23 @@ int qemu_str_to_log_mask(const char *str)
             uint32_t flag = TB_NONE_STATS;
             if (g_str_has_prefix(p, "all")) {
                 flag = TB_ALL_STATS;
+                p += 3;
             } else if (g_str_has_prefix(p, "jit")) {
                 flag = TB_JIT_STATS;
+                p += 3;
             } else if (g_str_has_prefix(p, "exec")) {
                 flag = TB_EXEC_STATS;
+                p += 4;
             }
             if (flag != TB_NONE_STATS) {
                 mask |= CPU_LOG_TB_STATS;
                 set_tbstats_flag(flag);
                 enable_collect_tb_stats();
             }
+            if (p[0] == ':') {
+                int max_to_dump = atoi(p + 1);
+                set_tbstats_max_tbs(max_to_dump);
+            }
         } else {
             for (item = qemu_log_items; item->mask != 0; item++) {
                 if (g_str_equal(*tmp, item->name)) {
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v15 10/10] docs: add tb-stats how to
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
                   ` (8 preceding siblings ...)
  2023-06-07 12:24 ` [PATCH v15 09/10] tb-stats: dump hot TBs at the end of the execution Fei Wu
@ 2023-06-07 12:24 ` Fei Wu
  2023-06-12 11:04 ` [PATCH v15 00/10] TCG code quality tracking Wu, Fei
  2023-06-13  3:29 ` Wu, Fei
  11 siblings, 0 replies; 17+ messages in thread
From: Fei Wu @ 2023-06-07 12:24 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel; +Cc: Fei Wu, Paolo Bonzini

Signed-off-by: Fei Wu <fei2.wu@intel.com>
---
 docs/devel/tcg-tbstats.rst | 97 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100644 docs/devel/tcg-tbstats.rst

diff --git a/docs/devel/tcg-tbstats.rst b/docs/devel/tcg-tbstats.rst
new file mode 100644
index 0000000000..dd611e41f3
--- /dev/null
+++ b/docs/devel/tcg-tbstats.rst
@@ -0,0 +1,97 @@
+============
+TBStatistics
+============
+
+What is TBStatistics
+====================
+
+TBStatistics (tb_stats) is a tool to gather various internal information of TCG
+during binary translation, this allows us to identify such as hottest TBs,
+guest to host instruction translation ratio, number of spills during register
+allocation and more.
+
+
+How to use TBStatistics
+=======================
+
+1. HMP interface
+----------------
+
+TBStatistics provides HMP interface, you can try the following examples after
+connecting to the monitor.
+
+* First check the help info::
+
+    (qemu) help tb_stats
+    tb_stats command [flag] -- Control tb statistics collection:tb_stats (start|stop|status) [all|jit|exec]
+
+    (qemu) help info tb-list
+    info tb-list [number sortedby] -- show a [number] translated blocks sorted by [sortedby]sortedby opts: hotness hg spills
+
+    (qemu) help info tb
+    info tb id [flag1,flag2,...] -- show information about one translated block by id.dump flags can be used to set dump code level: out_asm in_asm op
+
+* Enable TBStatistics::
+
+    (qemu) tb_stats start all
+    (qemu)
+
+* Get interested TB list::
+
+    (qemu) info tb-list 2
+    TB id:0 | phys:0x79bca0 virt:0xffffffff8059bca0 flags:0x01024001 0 inv/1
+            | exec:1464084/0 guest inst cov:0.15%
+            | trans:1 ints: g:3 op:16 op_opt:15 spills:0
+            | h/g (host bytes / guest insts): 64.000000
+
+    TB id:1 | phys:0x2adf0c virt:0xffffffff800adf0c flags:0x01024001 0 inv/1
+            | exec:1033298/0 guest inst cov:0.28%
+            | trans:1 ints: g:8 op:35 op_opt:33 spills:0
+            | h/g (host bytes / guest insts): 86.000000
+
+* Dive into the specific TB::
+
+    (qemu) info tb 1
+    ------------------------------
+
+    TB id:0 | phys:0x79bca0 virt:0xffffffff8059bca0 flags:0x01024001 7 inv/19
+            | exec:2038349/0 guest inst cov:0.15%
+            | trans:19 ints: g:3 op:16 op_opt:15 spills:0
+            | h/g (host bytes / guest insts): 64.000000
+
+    ------------------------------
+
+* Stop TBStatistics after investigation, this will disable TBStatistics completely.::
+
+    (qemu) tb_stats stop
+    (qemu)
+
+* Definitely, TBStatistics can be restarted for another round of investigation.::
+
+    (qemu) tb_stats start all
+    (qemu)
+
+
+2. Dump at exit
+---------------
+
+New command line options have been added to enable dump TB information at exit:::
+
+    -d tb_stats_{all,jit,exec}[:dump_num_at_exit]
+
+e.g. starting qemu like this:::
+
+    -d tb_stats_all:2
+
+Qemu prints the following at exit:::
+
+    QEMU: Terminated
+    TB id:1 | phys:0x61be02 virt:0xffffffff8041be02 flags:0x01024001 0 inv/1
+            | exec:72739176/0 guest inst cov:20.22%
+            | trans:1 ints: g:9 op:35 op_opt:33 spills:0
+            | h/g (host bytes / guest insts): 51.555557
+
+    TB id:2 | phys:0x61bc66 virt:0xffffffff8041bc66 flags:0x01024001 0 inv/1
+            | exec:25069507/0 guest inst cov:0.77%
+            | trans:1 ints: g:1 op:15 op_opt:14 spills:0
+            | h/g (host bytes / guest insts): 128.000000
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v15 07/10] tb-stats: Adding info [tb-list|tb] commands to HMP (WIP)
  2023-06-07 12:24 ` [PATCH v15 07/10] tb-stats: Adding info [tb-list|tb] commands to HMP (WIP) Fei Wu
@ 2023-06-12  1:44   ` Wu, Fei
  2023-06-12  7:17     ` Richard Henderson
  0 siblings, 1 reply; 17+ messages in thread
From: Wu, Fei @ 2023-06-12  1:44 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel
  Cc: Vanderson M. do Rosario, Dr . David Alan Gilbert, Paolo Bonzini,
	Dr. David Alan Gilbert, Peter Maydell

On 6/7/2023 8:24 PM, Fei Wu wrote:
> +void hmp_info_tb(Monitor *mon, const QDict *qdict)
> +{
> +    const int id = qdict_get_int(qdict, "id");
> +    g_autoptr(GString) buf = g_string_new("");
> +
> +    if (!tcg_enabled()) {
> +        monitor_printf(mon, "Only available with accel=tcg\n");
> +        return;
> +    }
> +
> +    TBStatistics *tbs = get_tbstats_by_id(id);
> +    if (tbs == NULL) {
> +        monitor_printf(mon, "TB %d information is not recorded\n", id);
> +        return;
> +    }
> +
> +    monitor_printf(mon, "\n------------------------------\n\n");
> +
> +    int valid_tb_num = dump_tb_info(buf, tbs, id);
> +    monitor_printf(mon, "%s", buf->str);
> +
> +    if (valid_tb_num > 0) {
> +        unsigned num_inst = tbs->code.num_guest_inst / tbs->translations.total;
> +
> +        monitor_printf(mon, "\n----------------n\n");
> +        // FIXME: cannot disas
> +        monitor_disas(mon, mon_get_cpu(mon), tbs->phys_pc, num_inst, true);
> +        monitor_printf(mon, "\n------------------------------\n\n");
> +    }
> +}
> +
So far the following methods are candidates for monitor_disas:

1. still use ram_addr_t for tbs->phys_pc, and extend monitor_disas to
support disassemble ram_addr_t by using qemu_map_ram_ptr(NULL, ram_addr)
to convert it to hva first

2. use gpa for tbs->phys_pc, there is no need to change monitor_disas,
but add another parameter for get_page_addr_code_hostp() to return extra
gpa, probe_access_internal() has already returned CPUTLBEntryFull, so
it's plain to get gpa here.

3. record gpa in another field of tbs, and keep tbs->phys_pc as it is,
this is just a variation of #2.

I'm inclined to use method #2. I think gpa carries more information for
debugging than ram_addr_t, guest can map gpa to the executable file
etc., but it has little knowledge of ram_addr_t.

What do you suggest?

Thanks,
Fei.



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v15 07/10] tb-stats: Adding info [tb-list|tb] commands to HMP (WIP)
  2023-06-12  1:44   ` Wu, Fei
@ 2023-06-12  7:17     ` Richard Henderson
  2023-06-12  9:11       ` Wu, Fei
  0 siblings, 1 reply; 17+ messages in thread
From: Richard Henderson @ 2023-06-12  7:17 UTC (permalink / raw)
  To: Wu, Fei, alex.bennee, qemu-devel
  Cc: Vanderson M. do Rosario, Dr . David Alan Gilbert, Paolo Bonzini,
	Dr. David Alan Gilbert, Peter Maydell

On 6/12/23 03:44, Wu, Fei wrote:
> On 6/7/2023 8:24 PM, Fei Wu wrote:
>> +void hmp_info_tb(Monitor *mon, const QDict *qdict)
>> +{
>> +    const int id = qdict_get_int(qdict, "id");
>> +    g_autoptr(GString) buf = g_string_new("");
>> +
>> +    if (!tcg_enabled()) {
>> +        monitor_printf(mon, "Only available with accel=tcg\n");
>> +        return;
>> +    }
>> +
>> +    TBStatistics *tbs = get_tbstats_by_id(id);
>> +    if (tbs == NULL) {
>> +        monitor_printf(mon, "TB %d information is not recorded\n", id);
>> +        return;
>> +    }
>> +
>> +    monitor_printf(mon, "\n------------------------------\n\n");
>> +
>> +    int valid_tb_num = dump_tb_info(buf, tbs, id);
>> +    monitor_printf(mon, "%s", buf->str);
>> +
>> +    if (valid_tb_num > 0) {
>> +        unsigned num_inst = tbs->code.num_guest_inst / tbs->translations.total;
>> +
>> +        monitor_printf(mon, "\n----------------n\n");
>> +        // FIXME: cannot disas
>> +        monitor_disas(mon, mon_get_cpu(mon), tbs->phys_pc, num_inst, true);
>> +        monitor_printf(mon, "\n------------------------------\n\n");
>> +    }
>> +}
>> +
> So far the following methods are candidates for monitor_disas:
> 
> 1. still use ram_addr_t for tbs->phys_pc, and extend monitor_disas to
> support disassemble ram_addr_t by using qemu_map_ram_ptr(NULL, ram_addr)
> to convert it to hva first
> 
> 2. use gpa for tbs->phys_pc, there is no need to change monitor_disas,
> but add another parameter for get_page_addr_code_hostp() to return extra
> gpa, probe_access_internal() has already returned CPUTLBEntryFull, so
> it's plain to get gpa here.

No, we need the ram_addr_t for dirty-page handling in order to detect self-modifying code. 
  Leave tb->phys_pc alone.


r~

> 
> 3. record gpa in another field of tbs, and keep tbs->phys_pc as it is,
> this is just a variation of #2.
> 
> I'm inclined to use method #2. I think gpa carries more information for
> debugging than ram_addr_t, guest can map gpa to the executable file
> etc., but it has little knowledge of ram_addr_t.
> 
> What do you suggest?
> 
> Thanks,
> Fei.
> 



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v15 07/10] tb-stats: Adding info [tb-list|tb] commands to HMP (WIP)
  2023-06-12  7:17     ` Richard Henderson
@ 2023-06-12  9:11       ` Wu, Fei
  0 siblings, 0 replies; 17+ messages in thread
From: Wu, Fei @ 2023-06-12  9:11 UTC (permalink / raw)
  To: Richard Henderson, alex.bennee, qemu-devel
  Cc: Vanderson M. do Rosario, Dr . David Alan Gilbert, Paolo Bonzini,
	Dr. David Alan Gilbert, Peter Maydell

On 6/12/2023 3:17 PM, Richard Henderson wrote:
> On 6/12/23 03:44, Wu, Fei wrote:
>> On 6/7/2023 8:24 PM, Fei Wu wrote:
>>> +void hmp_info_tb(Monitor *mon, const QDict *qdict)
>>> +{
>>> +    const int id = qdict_get_int(qdict, "id");
>>> +    g_autoptr(GString) buf = g_string_new("");
>>> +
>>> +    if (!tcg_enabled()) {
>>> +        monitor_printf(mon, "Only available with accel=tcg\n");
>>> +        return;
>>> +    }
>>> +
>>> +    TBStatistics *tbs = get_tbstats_by_id(id);
>>> +    if (tbs == NULL) {
>>> +        monitor_printf(mon, "TB %d information is not recorded\n", id);
>>> +        return;
>>> +    }
>>> +
>>> +    monitor_printf(mon, "\n------------------------------\n\n");
>>> +
>>> +    int valid_tb_num = dump_tb_info(buf, tbs, id);
>>> +    monitor_printf(mon, "%s", buf->str);
>>> +
>>> +    if (valid_tb_num > 0) {
>>> +        unsigned num_inst = tbs->code.num_guest_inst /
>>> tbs->translations.total;
>>> +
>>> +        monitor_printf(mon, "\n----------------n\n");
>>> +        // FIXME: cannot disas
>>> +        monitor_disas(mon, mon_get_cpu(mon), tbs->phys_pc, num_inst,
>>> true);
>>> +        monitor_printf(mon, "\n------------------------------\n\n");
>>> +    }
>>> +}
>>> +
>> So far the following methods are candidates for monitor_disas:
>>
>> 1. still use ram_addr_t for tbs->phys_pc, and extend monitor_disas to
>> support disassemble ram_addr_t by using qemu_map_ram_ptr(NULL, ram_addr)
>> to convert it to hva first
>>
>> 2. use gpa for tbs->phys_pc, there is no need to change monitor_disas,
>> but add another parameter for get_page_addr_code_hostp() to return extra
>> gpa, probe_access_internal() has already returned CPUTLBEntryFull, so
>> it's plain to get gpa here.
> 
> No, we need the ram_addr_t for dirty-page handling in order to detect
> self-modifying code.  Leave tb->phys_pc alone.
> 
I mean return both ram_addr_t and gpa from get_page_addr_code_hostp(),
tb->phys_pc will not be changed, I'm not going to change tbs->phys_pc
either (like #3), the extra gpa will be saved in tbs for 'info tb' purpose.

In short, no change on phys_pc, but add gpa to tbs, sounds good?

Thanks,
Fei.

> 
> r~
> 
>>
>> 3. record gpa in another field of tbs, and keep tbs->phys_pc as it is,
>> this is just a variation of #2.
>>
>> I'm inclined to use method #2. I think gpa carries more information for
>> debugging than ram_addr_t, guest can map gpa to the executable file
>> etc., but it has little knowledge of ram_addr_t.
>>
>> What do you suggest?
>>
>> Thanks,
>> Fei.
>>
> 



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v15 00/10] TCG code quality tracking
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
                   ` (9 preceding siblings ...)
  2023-06-07 12:24 ` [PATCH v15 10/10] docs: add tb-stats how to Fei Wu
@ 2023-06-12 11:04 ` Wu, Fei
  2023-06-13  3:29 ` Wu, Fei
  11 siblings, 0 replies; 17+ messages in thread
From: Wu, Fei @ 2023-06-12 11:04 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel

On 6/7/2023 8:24 PM, Fei Wu wrote:
> v15
> ---
> This is a large change:
> * remove all time related stuffs, including cmd 'info profile'
> * remove the per-TB flag, use global flag instead
> * remove tb_stats pause/filter, but add status
> * remove qemu_log changes, and use monitor_printf
> * use array instead of list for sorting
> * remove async_safe_run_on_cpu for cmd info tb-list & tb

I didn't realize async_safe_run_on_cpu has such a strong semantics,
I will add it back if it's necessary.

Thanks,
Fei.

> * use monitor_disas instead of regenerate TB, but **doesn't work yet**
> * other cleanups
> 
> 
> Alex Bennée (1):
>   tb-stats: reset the tracked TBs on a tb_flush
> 
> Fei Wu (5):
>   accel/tcg: remove CONFIG_PROFILER
>   accel/tcg: add jit stats to TBStatistics
>   debug: add -d tb_stats to control TBStatistics
>   tb-stats: dump hot TBs at the end of the execution
>   docs: add tb-stats how to
> 
> Vanderson M. do Rosario (4):
>   accel/tcg: introduce TBStatistics structure
>   accel: collecting TB execution count
>   monitor: adding tb_stats hmp command
>   tb-stats: Adding info [tb-list|tb] commands to HMP (WIP)
> 
>  MAINTAINERS                   |   1 +
>  accel/tcg/cpu-exec.c          |   6 +
>  accel/tcg/meson.build         |   1 +
>  accel/tcg/monitor.c           | 184 +++++++++++++++--
>  accel/tcg/tb-context.h        |   1 +
>  accel/tcg/tb-hash.h           |   7 +
>  accel/tcg/tb-maint.c          |  20 ++
>  accel/tcg/tb-stats.c          | 365 ++++++++++++++++++++++++++++++++++
>  accel/tcg/tcg-accel-ops.c     |  10 -
>  accel/tcg/tcg-runtime.c       |   1 +
>  accel/tcg/translate-all.c     | 110 ++++++----
>  accel/tcg/translator.c        |  30 +++
>  disas/disas.c                 |   2 +
>  docs/devel/tcg-tbstats.rst    |  97 +++++++++
>  hmp-commands-info.hx          |  31 +--
>  hmp-commands.hx               |  16 ++
>  include/exec/exec-all.h       |   3 +
>  include/exec/gen-icount.h     |   1 +
>  include/exec/tb-stats-dump.h  |  21 ++
>  include/exec/tb-stats-flags.h |  29 +++
>  include/exec/tb-stats.h       | 130 ++++++++++++
>  include/monitor/hmp.h         |   3 +
>  include/qemu/log.h            |   1 +
>  include/qemu/timer.h          |   9 -
>  include/tcg/tcg.h             |  26 +--
>  linux-user/exit.c             |   2 +
>  meson.build                   |   2 -
>  meson_options.txt             |   2 -
>  qapi/machine.json             |  18 --
>  scripts/meson-buildoptions.sh |   3 -
>  softmmu/runstate.c            |  11 +-
>  stubs/meson.build             |   1 +
>  stubs/tb-stats.c              |  36 ++++
>  tcg/tcg.c                     | 237 +++-------------------
>  tests/qtest/qmp-cmd-test.c    |   3 -
>  util/log.c                    |  26 +++
>  36 files changed, 1093 insertions(+), 353 deletions(-)
>  create mode 100644 accel/tcg/tb-stats.c
>  create mode 100644 docs/devel/tcg-tbstats.rst
>  create mode 100644 include/exec/tb-stats-dump.h
>  create mode 100644 include/exec/tb-stats-flags.h
>  create mode 100644 include/exec/tb-stats.h
>  create mode 100644 stubs/tb-stats.c
> 



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v15 00/10] TCG code quality tracking
  2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
                   ` (10 preceding siblings ...)
  2023-06-12 11:04 ` [PATCH v15 00/10] TCG code quality tracking Wu, Fei
@ 2023-06-13  3:29 ` Wu, Fei
  2023-06-16  1:32   ` Wu, Fei
  11 siblings, 1 reply; 17+ messages in thread
From: Wu, Fei @ 2023-06-13  3:29 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel

On 6/7/2023 8:24 PM, Fei Wu wrote:
> v15
> ---
> This is a large change:
> * remove all time related stuffs, including cmd 'info profile'
> * remove the per-TB flag, use global flag instead
> * remove tb_stats pause/filter, but add status
> * remove qemu_log changes, and use monitor_printf
> * use array instead of list for sorting
> * remove async_safe_run_on_cpu for cmd info tb-list & tb
> * use monitor_disas instead of regenerate TB, but **doesn't work yet**
> * other cleanups
> 
Hi Richard,

Could you please take a look at this series? I hope most of the comments
on v14 have been addressed.

Next revision I will change:
* add async_safe_run_on_cpu back in case of any concurrency issue
* add tbs->gpa_pc for monitor_disas, which requires
get_page_addr_code_hostp() return both ram_addr_t and gpa
* finalize the commit logs and documents

Thanks,
Fei.

> 
> Alex Bennée (1):
>   tb-stats: reset the tracked TBs on a tb_flush
> 
> Fei Wu (5):
>   accel/tcg: remove CONFIG_PROFILER
>   accel/tcg: add jit stats to TBStatistics
>   debug: add -d tb_stats to control TBStatistics
>   tb-stats: dump hot TBs at the end of the execution
>   docs: add tb-stats how to
> 
> Vanderson M. do Rosario (4):
>   accel/tcg: introduce TBStatistics structure
>   accel: collecting TB execution count
>   monitor: adding tb_stats hmp command
>   tb-stats: Adding info [tb-list|tb] commands to HMP (WIP)
> 
>  MAINTAINERS                   |   1 +
>  accel/tcg/cpu-exec.c          |   6 +
>  accel/tcg/meson.build         |   1 +
>  accel/tcg/monitor.c           | 184 +++++++++++++++--
>  accel/tcg/tb-context.h        |   1 +
>  accel/tcg/tb-hash.h           |   7 +
>  accel/tcg/tb-maint.c          |  20 ++
>  accel/tcg/tb-stats.c          | 365 ++++++++++++++++++++++++++++++++++
>  accel/tcg/tcg-accel-ops.c     |  10 -
>  accel/tcg/tcg-runtime.c       |   1 +
>  accel/tcg/translate-all.c     | 110 ++++++----
>  accel/tcg/translator.c        |  30 +++
>  disas/disas.c                 |   2 +
>  docs/devel/tcg-tbstats.rst    |  97 +++++++++
>  hmp-commands-info.hx          |  31 +--
>  hmp-commands.hx               |  16 ++
>  include/exec/exec-all.h       |   3 +
>  include/exec/gen-icount.h     |   1 +
>  include/exec/tb-stats-dump.h  |  21 ++
>  include/exec/tb-stats-flags.h |  29 +++
>  include/exec/tb-stats.h       | 130 ++++++++++++
>  include/monitor/hmp.h         |   3 +
>  include/qemu/log.h            |   1 +
>  include/qemu/timer.h          |   9 -
>  include/tcg/tcg.h             |  26 +--
>  linux-user/exit.c             |   2 +
>  meson.build                   |   2 -
>  meson_options.txt             |   2 -
>  qapi/machine.json             |  18 --
>  scripts/meson-buildoptions.sh |   3 -
>  softmmu/runstate.c            |  11 +-
>  stubs/meson.build             |   1 +
>  stubs/tb-stats.c              |  36 ++++
>  tcg/tcg.c                     | 237 +++-------------------
>  tests/qtest/qmp-cmd-test.c    |   3 -
>  util/log.c                    |  26 +++
>  36 files changed, 1093 insertions(+), 353 deletions(-)
>  create mode 100644 accel/tcg/tb-stats.c
>  create mode 100644 docs/devel/tcg-tbstats.rst
>  create mode 100644 include/exec/tb-stats-dump.h
>  create mode 100644 include/exec/tb-stats-flags.h
>  create mode 100644 include/exec/tb-stats.h
>  create mode 100644 stubs/tb-stats.c
> 



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v15 00/10] TCG code quality tracking
  2023-06-13  3:29 ` Wu, Fei
@ 2023-06-16  1:32   ` Wu, Fei
  0 siblings, 0 replies; 17+ messages in thread
From: Wu, Fei @ 2023-06-16  1:32 UTC (permalink / raw)
  To: richard.henderson, alex.bennee, qemu-devel

On 6/13/2023 11:29 AM, Wu, Fei wrote:
> On 6/7/2023 8:24 PM, Fei Wu wrote:
>> v15
>> ---
>> This is a large change:
>> * remove all time related stuffs, including cmd 'info profile'
>> * remove the per-TB flag, use global flag instead
>> * remove tb_stats pause/filter, but add status
>> * remove qemu_log changes, and use monitor_printf
>> * use array instead of list for sorting
>> * remove async_safe_run_on_cpu for cmd info tb-list & tb
>> * use monitor_disas instead of regenerate TB, but **doesn't work yet**
>> * other cleanups
>>
> Hi Richard,
> 
> Could you please take a look at this series? I hope most of the comments
> on v14 have been addressed.
> 
> Next revision I will change:
> * add async_safe_run_on_cpu back in case of any concurrency issue
> * add tbs->gpa_pc for monitor_disas, which requires
> get_page_addr_code_hostp() return both ram_addr_t and gpa
> * finalize the commit logs and documents
> 
Should I send the new revision with these changes, or you take a look
first then I address all of them together?

Thanks,
Fei.

> Thanks,
> Fei.
> 
>>
>> Alex Bennée (1):
>>   tb-stats: reset the tracked TBs on a tb_flush
>>
>> Fei Wu (5):
>>   accel/tcg: remove CONFIG_PROFILER
>>   accel/tcg: add jit stats to TBStatistics
>>   debug: add -d tb_stats to control TBStatistics
>>   tb-stats: dump hot TBs at the end of the execution
>>   docs: add tb-stats how to
>>
>> Vanderson M. do Rosario (4):
>>   accel/tcg: introduce TBStatistics structure
>>   accel: collecting TB execution count
>>   monitor: adding tb_stats hmp command
>>   tb-stats: Adding info [tb-list|tb] commands to HMP (WIP)
>>
>>  MAINTAINERS                   |   1 +
>>  accel/tcg/cpu-exec.c          |   6 +
>>  accel/tcg/meson.build         |   1 +
>>  accel/tcg/monitor.c           | 184 +++++++++++++++--
>>  accel/tcg/tb-context.h        |   1 +
>>  accel/tcg/tb-hash.h           |   7 +
>>  accel/tcg/tb-maint.c          |  20 ++
>>  accel/tcg/tb-stats.c          | 365 ++++++++++++++++++++++++++++++++++
>>  accel/tcg/tcg-accel-ops.c     |  10 -
>>  accel/tcg/tcg-runtime.c       |   1 +
>>  accel/tcg/translate-all.c     | 110 ++++++----
>>  accel/tcg/translator.c        |  30 +++
>>  disas/disas.c                 |   2 +
>>  docs/devel/tcg-tbstats.rst    |  97 +++++++++
>>  hmp-commands-info.hx          |  31 +--
>>  hmp-commands.hx               |  16 ++
>>  include/exec/exec-all.h       |   3 +
>>  include/exec/gen-icount.h     |   1 +
>>  include/exec/tb-stats-dump.h  |  21 ++
>>  include/exec/tb-stats-flags.h |  29 +++
>>  include/exec/tb-stats.h       | 130 ++++++++++++
>>  include/monitor/hmp.h         |   3 +
>>  include/qemu/log.h            |   1 +
>>  include/qemu/timer.h          |   9 -
>>  include/tcg/tcg.h             |  26 +--
>>  linux-user/exit.c             |   2 +
>>  meson.build                   |   2 -
>>  meson_options.txt             |   2 -
>>  qapi/machine.json             |  18 --
>>  scripts/meson-buildoptions.sh |   3 -
>>  softmmu/runstate.c            |  11 +-
>>  stubs/meson.build             |   1 +
>>  stubs/tb-stats.c              |  36 ++++
>>  tcg/tcg.c                     | 237 +++-------------------
>>  tests/qtest/qmp-cmd-test.c    |   3 -
>>  util/log.c                    |  26 +++
>>  36 files changed, 1093 insertions(+), 353 deletions(-)
>>  create mode 100644 accel/tcg/tb-stats.c
>>  create mode 100644 docs/devel/tcg-tbstats.rst
>>  create mode 100644 include/exec/tb-stats-dump.h
>>  create mode 100644 include/exec/tb-stats-flags.h
>>  create mode 100644 include/exec/tb-stats.h
>>  create mode 100644 stubs/tb-stats.c
>>
> 



^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2023-06-16  1:33 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-07 12:24 [PATCH v15 00/10] TCG code quality tracking Fei Wu
2023-06-07 12:24 ` [PATCH v15 01/10] accel/tcg: remove CONFIG_PROFILER Fei Wu
2023-06-07 12:24 ` [PATCH v15 02/10] accel/tcg: introduce TBStatistics structure Fei Wu
2023-06-07 12:24 ` [PATCH v15 03/10] accel: collecting TB execution count Fei Wu
2023-06-07 12:24 ` [PATCH v15 04/10] accel/tcg: add jit stats to TBStatistics Fei Wu
2023-06-07 12:24 ` [PATCH v15 05/10] monitor: adding tb_stats hmp command Fei Wu
2023-06-07 12:24 ` [PATCH v15 06/10] tb-stats: reset the tracked TBs on a tb_flush Fei Wu
2023-06-07 12:24 ` [PATCH v15 07/10] tb-stats: Adding info [tb-list|tb] commands to HMP (WIP) Fei Wu
2023-06-12  1:44   ` Wu, Fei
2023-06-12  7:17     ` Richard Henderson
2023-06-12  9:11       ` Wu, Fei
2023-06-07 12:24 ` [PATCH v15 08/10] debug: add -d tb_stats to control TBStatistics Fei Wu
2023-06-07 12:24 ` [PATCH v15 09/10] tb-stats: dump hot TBs at the end of the execution Fei Wu
2023-06-07 12:24 ` [PATCH v15 10/10] docs: add tb-stats how to Fei Wu
2023-06-12 11:04 ` [PATCH v15 00/10] TCG code quality tracking Wu, Fei
2023-06-13  3:29 ` Wu, Fei
2023-06-16  1:32   ` Wu, Fei

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.