Re: [PATCH 4/8] RFC: tcg: probe the TB jump cache inline instead of calling a helper

Matt Turner <[email protected]>
Newsgroups gmane.comp.emulators.qemu
Message-ID <CAEdQ38EwBQJp4hsWfvmCiZNOkghEESzZ7yU3LaQeQ1AzMSnj5w@mail.gmail.com>
On Tue, Aug 18, 2026 at 5:51 PM Pierrick Bouvier
<[email protected]> wrote:
>
> On 8/18/2026 10:42 AM, Matt Turner wrote:
> > Every indirect branch that cannot use goto_tb ends in
> > tcg_gen_lookup_and_goto_ptr(), which calls helper_lookup_tb_ptr(). For an
> > emulated compiler that is 8.4 billion helper calls in a single translation
> > unit: 24.6% of all TB exits take this path, because jsr/ret/jmp have a
> > register destination and because goto_tb is restricted to same-page
> > targets.
> >
> > The helper itself is already tight, but each call pays for a call frame,
> > the can_do_io store, the get_tb_cpu_state() indirect call through
> > TCGCPUOps, curr_cflags(), and a breakpoint check, before it gets to the
> > jump cache probe that almost always hits (95.8% for this workload).
> >
> > Emit the probe inline instead. The destination PC is already in a TCG
> > temp, and the flags and cflags the destination must match are constants at
> > translation time, so the fast path is a hash, three guarded loads and a
> > goto_ptr. Only a miss calls the helper, which still owns filling the cache.
> >
> > Two details matter for the generated code. The flags and cflags guards are
> > folded into a single aligned 64-bit load and compare, since the fields are
> > adjacent. And each path emits its own goto_ptr rather than branching to a
> > shared one: a temp live across the label is spilled and reloaded on every
> > dispatch, which cost 6.3% on its own.
> >
> > Measured with qemu-alpha running an emulated alpha gcc 16.2.0 compiling
> > the SQLite 3.45.1 amalgamation (255k lines, -O2) on an x86-64 host, LTO
> > build, on top of the preceding three patches:
> >
> >     before: 1,402,816,253,499 instructions
> >     after:    890,713,633,237 instructions   -36.51%
> >
> >     before: 115.75s wall clock
> >     after:   84.44s wall clock               -27.05%
> >
> > The gap between the two is the point at which this stops being a
> > straight-line win: the helper call was highly predictable work that the
> > host pipelined well, so removing it retires far fewer instructions than it
> > saves time. IPC falls from 2.48 to 2.15 across this patch for that reason.
> >
> > Despite emitting more code, this also reduces instruction cache pressure,
> > because a dispatch no longer jumps into qemu's .text and evicts translated
> > code:
> >
> >     before: 11,476,318,964 L1-icache-load-misses
> >     after:   6,990,186,701 L1-icache-load-misses   -39.1%
> >
> > The mechanism is visible directly in a profile: helper_lookup_tb_ptr()
> > falls from 30.97% of samples to 0.42%, and qemu's own .text falls from
> > 38.9% to 5.4%, with the balance moving into generated code.
> >
> > Combined with the three preceding patches, against an unmodified LTO
> > build, 1,647,901,588,726 instructions fall to 890,713,633,237, or -45.95%.
> > The emulated compiler produces byte-identical output throughout.
> >
> > Open issues, hence RFC:
> >
> > - The flags/cflags guards use the *current* TB's values as constants. That
> >   assumes the CPU flags feeding get_tb_cpu_state() cannot change within a
> >   TB, and that curr_cflags() cannot change under a running TB (gdb
> >   attaching to enable single-step would). Both need to be established or
> >   the values need to be loaded at runtime.
> > - tcg/tcg-op.c has no business including accel/tcg/tb-jmp-cache.h or
> >   knowing the CPUJumpCache layout. The probe likely belongs in accel/tcg
> >   with a small emit helper exported from tcg/.
> > - The jump cache entry is read without qatomic_read(); entries are
> >   invalidated concurrently by setting tb to NULL.
> > - Only wired up for alpha so far, and only for 64-bit guest PCs.
> >
> > Signed-off-by: Matt Turner <[email protected]>
> > ---
> >  include/tcg/tcg-op-common.h |  2 +
> >  target/alpha/translate.c    |  4 +-
> >  tcg/tcg-op.c                | 79 +++++++++++++++++++++++++++++++++++++
> >  3 files changed, 83 insertions(+), 2 deletions(-)
> >
>
> This change breaks following tcg test:
> alpha-linux-user/gdbstub-follow-fork-mode-child
>
> Reproduce with:
> ninja -C build &&
> make -C build/tests/tcg/alpha-linux-user/ &&
> make -C build/tests/tcg/alpha-linux-user/ run-gdbstub-follow-fork-mode-child
>
> Need gdb-multiarch and gcc-alpha-linux-gnu installed on your machine.

Thanks! I had gdb available, I apparently just needed to configure
with `--cross-prefix-alpha=alpha-unknown-linux-gnu-` to get this test
to run.

Fixed locally.
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.