Re: [RFC PATCH 3/8] accel/tcg: skip the can_do_io stores in user-only builds

Philippe Mathieu-Daudé <[email protected]>
Newsgroups org.nongnu.qemu-devel
Message-ID <[email protected]>
On 17/8/26 21:00, Matt Turner wrote:
> 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,729,281,442 instructions
>      after:  1,402,816,253,499 instructions   -4.55%
> 
>      before: 120.97s wall clock
>      after:  115.75s wall clock              -4.32%

Nice.

> The emulated compiler produces byte-identical output.
> 
> 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 cd7d079fe0..29e609b2ec 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

I'm a bit reluctant to clutter translator.c with #ifdef'ry (in
particular when we are not protecting system-specific API, so
this can be evaluated at runtime).
We could have a tcg_user_emulation() or user_mode_emulation()
helper hidding the #ifdef; or could move set_can_do_io() to
accel/tcg/translate-all.c, or maybe others have better idea.
The overall change LGTM otherwise.

>   
>   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;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.