[PATCH v3 3/7] accel/tcg: skip the can_do_io stores in user-only builds
Matt Turner <[email protected]>
| Newsgroups | org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Every translation block stores to cpu->neg.can_do_io twice: false before
the first instruction, true before the last one. Nothing reads it in a
user-only build. There is no memory-mapped I/O in linux-user, and every
reader is in system_ss: cputlb.c, watchpoint.c, icount-common.c and
tcg-accel-ops-icount.c.
Two stores per TB is not much on its own, but TBs are short. An emulated
alpha gcc 16.2.0 compiling the SQLite 3.45.1 amalgamation (255k lines,
-O2) executes 34.2 billion TBs at 6.04 guest instructions each, so this is
68 billion stores for nothing.
Measured on an x86-64 host, LTO build, on top of the preceding two
patches:
before: 1,469,772,951,575 instructions
after: 1,402,667,803,616 instructions -4.57%
before: 121.04s wall clock
after: 115.56s wall clock -4.53%
The emulated compiler produces byte-identical output.
v3: Use #ifndef CONFIG_USER_ONLY again rather than
if (IS_ENABLED(CONFIG_USER_ONLY)). QEMU's IS_ENABLED() is IS_EMPTY(),
which is only true for a symbol Meson defines empty; CONFIG_USER_ONLY
is defined as 1, so the test was always false and v2 emitted the two
stores after all. The measurements above are from the working form.
Reviewed-by: Richard Henderson <[email protected]>
Reviewed-by: Philippe Mathieu-Daudé <[email protected]>
Signed-off-by: Matt Turner <[email protected]>
---
accel/tcg/translator.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git ./accel/tcg/translator.c ./accel/tcg/translator.c
index 57daded60f..6c8fcd7a20 100644
--- ./accel/tcg/translator.c
+++ ./accel/tcg/translator.c
@@ -21,12 +21,14 @@
#include "disas/disas.h"
#include "tb-internal.h"
+#ifndef CONFIG_USER_ONLY
static void set_can_do_io(DisasContextBase *db, bool val)
{
QEMU_BUILD_BUG_ON(sizeof_field(CPUState, neg.can_do_io) != 1);
tcg_gen_st8_i32(tcg_constant_i32(val), tcg_env,
offsetof(CPUState, neg.can_do_io) - sizeof(CPUState));
}
+#endif
bool translator_io_start(DisasContextBase *db)
{
@@ -210,17 +212,25 @@ void translator_loop(CPUState *cpu, TranslationBlock *tb, int *max_insns,
/*
* Manage can_do_io for the translation block: set to false before
* the first insn and set to true before the last insn.
+ *
+ * Nothing reads can_do_io in user-only builds. There is no MMIO
+ * there, and every reader (cputlb.c, watchpoint.c, icount) is in
+ * system_ss, so skip the two stores per TB entirely.
*/
if (db->num_insns == 1) {
tcg_debug_assert(first_insn_start == db->insn_start);
} else {
tcg_debug_assert(first_insn_start != db->insn_start);
+#ifndef CONFIG_USER_ONLY
tcg_ctx->emit_before_op = first_insn_start;
set_can_do_io(db, false);
+#endif
}
+#ifndef CONFIG_USER_ONLY
tcg_ctx->emit_before_op = db->insn_start;
set_can_do_io(db, true);
tcg_ctx->emit_before_op = NULL;
+#endif
/* May be used by disas_log or plugin callbacks. */
tb->size = db->pc_next - db->pc_first;
--
2.54.0