Skip to content

aowlspt_rdcache.h

Source: abi/aowlspt_rdcache.h — 222 lines, 12 file-scope functions.

What this header owns

Reproduced verbatim from the header's own banner comment — these notes are frequently the only written record of why the subsystem is shaped the way it is.

text
 aowlspt_rdcache.h -- a CACHE in front of the readability syscall, for the
host's per-frame GAME-DATA reads only.

WHY. `aowl_is_readable` (abi/aowlspt_shim.h) is one `VirtualQuery` SYSCALL per
call, and the host's guarded-read discipline means one call per POINTER HOP.
MEASURED on the deployed build (natesp's own sub-phase meter, aowlspt-host.log):

    sub[scan]: mean=23052.9us max=37983.2us n=1387

for a census bounded at 64 contacts. The census makes roughly ten guarded hops
per contact (slot, IsYourPlayer, MovementContext + PreviousPosition, and the
five-hop Profile->Info->Settings side/role walk), i.e. ~600 VirtualQuery calls
per pass. That is the cost, and it is a syscall cost, not a work cost.

The identical remedy has already been measured twice in this repo
(mods/maps/sp/rdcache.h): -85% on maps, -96% on admin. This file is that same
cache, moved to the host so the host's own hot paths can use it.

THE ASYMMETRY IS THE WHOLE DESIGN, and it is not a tuning knob:

  A STALE POSITIVE IS A CRASH.   A STALE NEGATIVE IS A DECLINE.

so positives get a SHORT ttl (250ms) and are stored ONLY for regions of 64KB
or more -- a heap segment or an image section, the things that do not get
unmapped between two frames. A small region that happened to read positive is
answered honestly and then FORGOTTEN, counted in `uncacheable`. Negatives are
cheap to be wrong about, so they get 2000ms.

SIZING. A 32-slot round-robin v1 FAILED in the maps mod: it hit within a call
and missed across calls, because the working set is the set of distinct 64KB
chunks the walk touches, which is hundreds. 1024 sets x 2 ways is sized for
that, and `evict-live` MEASURES whether it still is -- a rising evict-live is
the table being too small, reported rather than assumed.

DRIFT. The predicate below is replicated clause-for-clause from
`aowl_is_readable`, applied to an mbi we already hold so a miss costs ONE
syscall rather than two. To keep the copy from silently drifting, one miss in
AOWL_RDC_AUDIT_EVERY also calls the real `aowl_is_readable` and compares.
`aowl_rdc_disagree()` MUST read 0; non-zero means this file has drifted and is
a measurement, not a claim.

SCOPE -- READ THIS BEFORE ADDING A CALLER. This is for reading GAME DATA in a
per-frame path. It is deliberately NOT wired into:
  - detour binding or prologue verification (aowlspt_prologue.h, codegen),
  - `aowl_is_code_pointer`,
  - anything that decides whether to WRITE or PATCH.
Those are one-off, are not hot, and are exactly the places where a stale
positive is unrecoverable. They keep calling the uncached shim, unchanged.

IT OPENS NO GUARD AND INSTALLS NOTHING. No detour, no name resolved, no RVA
called, nothing in the game dereferenced. It sits strictly outside any
`aowl_p_p_seh` (that guard is NOT re-entrant), holds only fixed-size static
storage, and allocates nothing, managed or otherwise.

Constants

  • AOWLSPT_RDCACHE_H
  • AOWL_RDC_AUDIT_EVERY
  • AOWL_RDC_CHUNK_SHIFT
  • AOWL_RDC_MIN_POS_SIZE
  • AOWL_RDC_NEG_TTL_MS
  • AOWL_RDC_POS_TTL_MS
  • AOWL_RDC_SETS
  • AOWL_RDC_WAYS

Functions

SignatureLine
void aowl_rdc_flush(void)99
int32_t aowl_rdc_pred(const MEMORY_BASIC_INFORMATION* mbi, uintptr_t a, uintptr_t need)108
uint32_t aowl_rdc_set_of(uintptr_t tag)123
int32_t aowl_rdc_readable(void* p, int32_t size)132
int64_t aowl_rdc_hits(void)212
int64_t aowl_rdc_misses(void)213
int64_t aowl_rdc_flushes(void)214
int64_t aowl_rdc_uncacheable(void)215
int64_t aowl_rdc_evict_live(void)216
int64_t aowl_rdc_expired(void)217
int64_t aowl_rdc_audits(void)218
int64_t aowl_rdc_disagree(void)219

aoughwl — self-hosted platform for things n stuff. Contact / Support on Discord for access to the private backends.