[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v17 16/16] accel/tcg: Dump hot TBs at the end of the execution
From: |
Richard Henderson |
Subject: |
[PATCH v17 16/16] accel/tcg: Dump hot TBs at the end of the execution |
Date: |
Tue, 3 Oct 2023 11:30:58 -0700 |
From: Fei Wu <fei2.wu@intel.com>
Dump the hottest TBs if -d tb_stats:{all,jit,exec}[:dump_num_at_exit]
Signed-off-by: Fei Wu <fei2.wu@intel.com>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
bsd-user/bsd-proc.h | 2 ++
include/tcg/tb-stats.h | 10 +++++++++-
accel/tcg/monitor.c | 8 +++++---
accel/tcg/tb-stats.c | 27 ++++++++++++++++++++++++++-
linux-user/exit.c | 10 ++++++----
softmmu/runstate.c | 2 ++
stubs/tb-stats.c | 6 +++++-
util/log.c | 20 ++++++++++++++++----
8 files changed, 71 insertions(+), 14 deletions(-)
diff --git a/bsd-user/bsd-proc.h b/bsd-user/bsd-proc.h
index 0e1d461c4c..84b52b399a 100644
--- a/bsd-user/bsd-proc.h
+++ b/bsd-user/bsd-proc.h
@@ -21,12 +21,14 @@
#define BSD_PROC_H_
#include <sys/resource.h>
+#include "tcg/tb-stats.h"
/* exit(2) */
static inline abi_long do_bsd_exit(void *cpu_env, abi_long arg1)
{
gdb_exit(arg1);
qemu_plugin_user_exit();
+ tb_stats_dump_atexit();
_exit(arg1);
return 0;
diff --git a/include/tcg/tb-stats.h b/include/tcg/tb-stats.h
index edee73b63b..d3cca94f84 100644
--- a/include/tcg/tb-stats.h
+++ b/include/tcg/tb-stats.h
@@ -41,11 +41,12 @@ extern uint32_t tb_stats_enabled;
/**
* tb_stats_init:
* @flags: TB_STATS_* flags to enable.
+ * @atexit: count of hottest tbs to log.
*
* Initialize translation block statistics, enabling @flags.
* If @flags is 0, disable all statistics.
*/
-void tb_stats_init(uint32_t flags);
+void tb_stats_init(uint32_t flags, uint32_t atexit);
/*
* This struct stores statistics such as execution count of the
@@ -154,4 +155,11 @@ gint tb_stats_sort_by_hg(gconstpointer, gconstpointer);
*/
GString *tb_stats_dump(TBStatistics *s, unsigned index);
+/**
+ * tb_stats_dump_atexit:
+ *
+ * Log any requested TBs at end of execution.
+ */
+void tb_stats_dump_atexit(void);
+
#endif /* TCG_TB_STATS_H */
diff --git a/accel/tcg/monitor.c b/accel/tcg/monitor.c
index 1be3218715..7719583654 100644
--- a/accel/tcg/monitor.c
+++ b/accel/tcg/monitor.c
@@ -245,7 +245,7 @@ static void tb_stats_init_safe(CPUState *cpu,
run_on_cpu_data icmd)
{
uint32_t flags = icmd.host_int;
- tb_stats_init(flags);
+ tb_stats_init(flags, 0);
tb_flush(cpu);
}
@@ -335,8 +335,10 @@ static void hmp_info_tblist(Monitor *mon, const QDict
*qdict)
return;
}
- g_ptr_array_unref(tb_ctx.last_search);
- tb_ctx.last_search = NULL;
+ if (tb_ctx.last_search) {
+ g_ptr_array_unref(tb_ctx.last_search);
+ tb_ctx.last_search = NULL;
+ }
array = tb_stats_collect(max, sort);
max = array->len;
diff --git a/accel/tcg/tb-stats.c b/accel/tcg/tb-stats.c
index 0f84c14a88..62a6228799 100644
--- a/accel/tcg/tb-stats.c
+++ b/accel/tcg/tb-stats.c
@@ -8,10 +8,12 @@
#include "qemu/osdep.h"
#include "qemu/xxhash.h"
+#include "qemu/log.h"
#include "tcg/tb-stats.h"
#include "tb-context.h"
uint32_t tb_stats_enabled;
+static uint32_t tb_stats_atexit;
static bool tb_stats_cmp(const void *ap, const void *bp)
{
@@ -34,7 +36,7 @@ static void tb_stats_free(void *p, uint32_t hash, void *userp)
g_free(s);
}
-void tb_stats_init(uint32_t flags)
+void tb_stats_init(uint32_t flags, uint32_t atexit)
{
tb_stats_enabled = flags;
if (flags) {
@@ -48,6 +50,14 @@ void tb_stats_init(uint32_t flags)
qht_iter(&tb_ctx.stats, tb_stats_free, NULL);
qht_destroy(&tb_ctx.stats);
}
+
+ /*
+ * This function is also used by HMP, when atexit is 0.
+ * Preserve the value set from the command-line.
+ */
+ if (atexit) {
+ tb_stats_atexit = atexit;
+ }
}
static void tb_stats_reset(void *p, uint32_t hash, void *userp)
@@ -204,3 +214,18 @@ GString *tb_stats_dump(TBStatistics *s, unsigned index)
}
return buf;
}
+
+void tb_stats_dump_atexit(void)
+{
+ if (tb_stats_enabled && tb_stats_atexit) {
+ g_autoptr(GPtrArray) array =
+ tb_stats_collect(tb_stats_atexit, tb_stats_sort_by_coverage);
+
+ for (uint32_t i = 0, n = array->len; i < n; ++i) {
+ TBStatistics *s = g_ptr_array_index(array, i);
+ g_autoptr(GString) str = tb_stats_dump(s, i);
+
+ qemu_log("%s\n", str->str);
+ }
+ }
+}
diff --git a/linux-user/exit.c b/linux-user/exit.c
index 50266314e0..4487aaac7e 100644
--- a/linux-user/exit.c
+++ b/linux-user/exit.c
@@ -22,6 +22,7 @@
#include "qemu.h"
#include "user-internals.h"
#include "qemu/plugin.h"
+#include "tcg/tb-stats.h"
#ifdef CONFIG_GCOV
extern void __gcov_dump(void);
@@ -30,9 +31,10 @@ extern void __gcov_dump(void);
void preexit_cleanup(CPUArchState *env, int code)
{
#ifdef CONFIG_GCOV
- __gcov_dump();
+ __gcov_dump();
#endif
- gdb_exit(code);
- qemu_plugin_user_exit();
- perf_exit();
+ gdb_exit(code);
+ qemu_plugin_user_exit();
+ perf_exit();
+ tb_stats_dump_atexit();
}
diff --git a/softmmu/runstate.c b/softmmu/runstate.c
index 1652ed0439..2c6fb9bff1 100644
--- a/softmmu/runstate.c
+++ b/softmmu/runstate.c
@@ -59,6 +59,7 @@
#include "sysemu/runstate-action.h"
#include "sysemu/sysemu.h"
#include "sysemu/tpm.h"
+#include "tcg/tb-stats.h"
#include "trace.h"
static NotifierList exit_notifiers =
@@ -846,6 +847,7 @@ void qemu_cleanup(void)
/* No more vcpu or device emulation activity beyond this point */
vm_shutdown();
replay_finish();
+ tb_stats_dump_atexit();
/*
* We must cancel all block jobs while the block layer is drained,
diff --git a/stubs/tb-stats.c b/stubs/tb-stats.c
index ceaa1622ce..f9e4ef5d04 100644
--- a/stubs/tb-stats.c
+++ b/stubs/tb-stats.c
@@ -11,6 +11,10 @@
#include "qemu/osdep.h"
#include "tcg/tb-stats.h"
-void tb_stats_init(uint32_t flags)
+void tb_stats_init(uint32_t flags, uint32_t atexit)
+{
+}
+
+void tb_stats_dump_atexit(void)
{
}
diff --git a/util/log.c b/util/log.c
index 0cb987fb74..789b19a226 100644
--- a/util/log.c
+++ b/util/log.c
@@ -526,19 +526,31 @@ int qemu_str_to_log_mask(const char *str, Error **errp)
#ifdef CONFIG_TCG
} else if (g_str_has_prefix(t, "tb_stats:") && t[9] != '\0') {
int flags = TB_STATS_NONE;
+ unsigned atexit = 0;
char *v = t + 9;
+ char *e = strchr(v, ':');
+ size_t len;
- if (g_str_equal(v, "all")) {
+ if (e) {
+ len = e - v;
+ if (qemu_strtoui(e + 1, NULL, 10, &atexit) < 0) {
+ error_setg(errp, "Invalid -d option \"%s\"", t);
+ goto error;
+ }
+ } else {
+ len = strlen(v);
+ }
+ if (strncmp(v, "all", len) == 0) {
flags = TB_STATS_ALL;
- } else if (g_str_equal(v, "jit")) {
+ } else if (strncmp(v, "jit", len) == 0) {
flags = TB_STATS_JIT;
- } else if (g_str_equal(v, "exec")) {
+ } else if (strncmp(v, "exec", len) == 0) {
flags = TB_STATS_EXEC;
} else {
error_setg(errp, "Invalid -d option \"%s\"", t);
goto error;
}
- tb_stats_init(flags);
+ tb_stats_init(flags, atexit);
#endif
} else {
for (item = qemu_log_items; item->mask != 0; item++) {
--
2.34.1
- Re: [PATCH v17 13/16] disas: Allow monitor_disas to read from ram_addr_t, (continued)