Verify the exit-check removal at 6.3%; record the TLB experiment as refuted

Two results, one positive and one negative.

CONFIRMED - removing the exit-request check from the guest load/store path
(ea079b8) is worth 6.3%. That commit went in on a single A/B pair because
the device wedged mid-measurement; re-run on a freshly rebooted Pixel 6a,
three interleaved pairs, load to first OnCarLoaded:

    without the check: 33.42 / 33.10 / 33.32 s   mean 33.28
    with the check:    35.62 / 35.43 / 35.49 s   mean 35.51

Ranges do not overlap and each spread is under a third of a second.

REFUTED - raising CPU_TLB_DYN_DEFAULT_BITS from 8 to 12. The premise checked
out: a probe in tlb_mmu_resize_locked showed it runs only about twice per
second and current_entries stayed at 256 for a whole run, so the adaptive
TLB genuinely never grows for this workload and sits at 1 MB of coverage
against a working set of hundreds of MB.

Raising it took effect (current_entries=4096, verified live) and bought
nothing:

    12 bits: 32.36 / 32.26 s
     8 bits: 32.86 / 32.32 s     0.28s apart, ranges overlap

The profile moved the WRONG way - tlb_set_page_with_attrs 0.86% -> 2.92%,
since a larger TLB costs more to fill and flush. So the softmmu lookup cost
(flatview_translate + find_memory_mapping, ~7.5%) is not driven by TLB
capacity. Reverted to the upstream default, with the refutation recorded in
place so nobody retries it without a new theory.

Also removes the temporary TLB probe.

Worth noting for future measurements: after the device was rebooted, the
same build measured ~33s where it had measured ~41s before. The earlier
drift was device state, not code.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-20 03:59:47 +03:00
co-authored by Claude
parent ea079b8e9f
commit daa537bfe8
2 changed files with 28 additions and 0 deletions
@@ -83,6 +83,26 @@ typedef uint64_t target_ulong;
#endif
#define CPU_TLB_DYN_MIN_BITS 6
// NFSMW arm64-poc, 2026-09-19: raising this to 12 was TRIED AND REFUTED.
//
// The reasoning looked sound: 8 bits = 256 entries x 4KB = 1 MB of guest
// coverage against a working set of hundreds of MB, and
// tlb_mmu_resize_locked resizes ONLY on a TLB flush. Measured on device,
// that function runs about twice per second and current_entries stayed at
// 256 for a whole run - so adaptive growth genuinely never helps here.
//
// Setting 12 (4096 entries, 16 MB covered) did take effect - verified live,
// current_entries=4096 - and bought nothing:
//
// interleaved A/B, load to first OnCarLoaded
// 12 bits: 32.36 / 32.26 s
// 8 bits: 32.86 / 32.32 s (0.28s apart, ranges overlap)
//
// The profile actually moved the wrong way: tlb_set_page_with_attrs went
// 0.86% -> 2.92%, because a larger TLB costs more to fill and flush. So the
// softmmu lookup cost (flatview_translate + find_memory_mapping, ~7.5%) is
// NOT driven by TLB capacity. Left at the upstream default; do not retry
// without a different theory for where those misses come from.
#define CPU_TLB_DYN_DEFAULT_BITS 8
# if HOST_LONG_BITS == 32
@@ -2867,6 +2867,14 @@ static void gen_ldst_i64(TCGContext *tcg_ctx, TCGOpcode opc, TCGv_i64 val, TCGv
// uc_emu_stop (FnvHashAccelHookCb) is a UC_HOOK_CODE hook, where the check is
// still emitted. So the per-access check is pure overhead here.
//
// VERIFIED 2026-09-19 on a freshly rebooted device, three interleaved pairs,
// load to first OnCarLoaded:
// without the check: 33.42 / 33.10 / 33.32 s mean 33.28
// with the check: 35.62 / 35.43 / 35.49 s mean 35.51
// 6.3% faster, ranges completely separate. (The first attempt at this
// measurement produced one usable pair before the device's screen dozed and
// the engine stopped rendering entirely - see the session log.)
//
// Kept as a named constant rather than deleted, because this is a vendored
// tree: anyone adding a memory hook that calls uc_emu_stop MUST flip this
// back, or that stop will be deferred to the next block boundary.