Re: [RFC PATCH 5/8] RFC: accel/tcg: allow cross-page goto_tb chaining 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:
> translator_use_goto_tb() refuses to chain unless the destination is on the
> same page as the start of the TB. For guests whose text is much larger than
> a page this is expensive: an emulated alpha gcc compiling a 255k line
> translation unit takes the indirect dispatch path for 8.4 billion of its
> 34.2 billion TB exits, and a large share of those are ordinary direct
> branches that simply crossed an 8 KiB page boundary.
> 
> The restriction was made unconditional by d3a2a1d803 ("accel/tcg:
> Introduce translator_use_goto_tb"), whose rationale was:
> 
>      Various targets avoid the page crossing test for CONFIG_USER_ONLY,
>      but that is wrong: mmap and mprotect can change page permissions.
> 
> That is true, but in user-only builds the invalidation path already covers
> it. There are no page tables: every mmap, mprotect and munmap reaches
> page_set_flags(), which calls tb_invalidate_phys_range() whenever the flags
> actually change, and tb_phys_invalidate() calls tb_jmp_unlink() to reset
> incoming jumps. A chained cross-page jump is therefore broken whenever the
> destination page's permissions change. This is not true in system mode,
> where TBs are keyed by physical address and a page table change invalidates
> nothing, so the restriction is kept there.
> 
> Add tests/tcg/alpha/test-xpage-chain.c to cover the hazard directly. It
> places a direct branch near the end of one page targeting the next page,
> runs it 200000 times so the chain is established, then checks that
> mprotect(PROT_NONE) makes the next call fault, and that remapping the page
> with different code runs the new code rather than a stale translation.
> 
> The test detects the hazard it is meant to detect: with the
> tb_invalidate_phys_range() call in page_set_flags() commented out, it fails
> both phases, executing page B after PROT_NONE and returning the stale
> result.
> 
> Measured with qemu-alpha running an emulated alpha gcc 16.2.0 compiling the
> SQLite 3.45.1 amalgamation on an x86-64 host, LTO build, on top of the
> preceding patches:
> 
>      before: 890,713,633,237 instructions
>      after:  869,178,598,378 instructions   -2.42%
> 
>      before: 84.44s wall clock
>      after:  80.49s wall clock              -4.68%
> 
> Note that this is worth more in time than in instructions, the reverse of
> the preceding patch: a chained jump replaces a cache probe whose loads can
> miss, so the instructions it removes are more expensive than average.
> 
> Measured before the inline jump cache probe, when a missed chain cost a
> helper call rather than an inline probe, the same change was worth -7.9%.
> 
> RFC because this reverses a deliberate decision and the reasoning above
> wants review from someone who knows the invalidation paths better than I
> do.
> 
> Signed-off-by: Matt Turner <[email protected]>
> ---
>   accel/tcg/translator.c             |  12 ++++
>   tests/tcg/alpha/Makefile.target    |   2 +-
>   tests/tcg/alpha/test-xpage-chain.c | 111 +++++++++++++++++++++++++++++
>   3 files changed, 124 insertions(+), 1 deletion(-)
>   create mode 100644 tests/tcg/alpha/test-xpage-chain.c
> 
> diff --git ./accel/tcg/translator.c ./accel/tcg/translator.c
> index 29e609b2ec..4921bf978c 100644
> --- ./accel/tcg/translator.c
> +++ ./accel/tcg/translator.c
> @@ -117,8 +117,20 @@ bool translator_use_goto_tb(DisasContextBase *db, vaddr dest)
>           return false;
>       }
>   
> +#ifdef CONFIG_USER_ONLY
> +    /*
> +     * There are no page tables in user-only mode.  Every mmap, mprotect and
> +     * munmap goes through page_set_flags(), which calls
> +     * tb_invalidate_phys_range() whenever the flags actually change, and
> +     * tb_phys_invalidate() unlinks incoming jumps.  A chained cross-page
> +     * jump is therefore broken whenever the destination page's permissions
> +     * change, so the same-page restriction is not needed here.
> +     */
> +    return true;

Should this be directly changed in translator_is_same_page() in
"exec/translator.h" instead?

> +#else
>       /* Check for the dest on the same page as the start of the TB.  */
>       return translator_is_same_page(db, dest);
> +#endif
>   }
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.