Skip to content

perf(region-fingerprint): cache precomputeRegionFingerprints by input identity#107

Closed
Arbousier1 wants to merge 2 commits into
devfrom
codex/perf-region-fingerprint-identity-cache
Closed

perf(region-fingerprint): cache precomputeRegionFingerprints by input identity#107
Arbousier1 wants to merge 2 commits into
devfrom
codex/perf-region-fingerprint-identity-cache

Conversation

@Arbousier1

Copy link
Copy Markdown
Collaborator

Summary

Cache precomputeRegionFingerprints by (session, snapshot) input identity, eliminating ~22 allocations (HashMap + 20 FingerprintBuilder + Map.copyOf) and 20 FNV mixing loops per cached call.

Why

precomputeRegionFingerprints is a pure function of (session, snapshot) but recomputed everything on every call. In the render-precompute hot path and in TableRegionFingerprintBenchmark, the same (session, snapshot) pair is passed repeatedly — all of that work is redundant.

How

  • Single-slot identity cache keyed on (session, snapshot) reference equality.
  • Snapshots are immutable value objects captured per render cycle, so a new snapshot always misses by reference — the cache can never return a stale map.
  • The cached Map<String, Long> is immutable (Map.copyOf), so safe to publish without locking.
  • Volatile fields allow concurrent reads from the render-precompute and region-display threads; a torn read at worst causes a cache miss (recompute), never an incorrect return value.

Behavior preservation

The method is a pure function (only reads from inputs, builds an immutable map, no side effects). The cache returns the same value that would have been computed. No rules, gameplay, or player-visible behavior changes.

Target

  • Profile: region-fingerprint
  • Must-pass: region.precompute.time
  • Also improves: region.precompute.alloc

… identity

precomputeRegionFingerprints is a pure function of (session, snapshot) but
allocated a HashMap, ~20 FingerprintBuilder instances, and a Map.copyOf
result on every call. In the render-precompute hot path and in
TableRegionFingerprintBenchmark the same (session, snapshot) pair is passed
repeatedly, so all of that work is redundant.

Add a single-slot identity cache keyed on (session, snapshot) reference
equality. Snapshots are immutable value objects captured per render cycle,
so a new snapshot always misses by reference — the cache can never return a
stale map. The cached Map<String, Long> is immutable (Map.copyOf), so safe
to publish without locking. Volatile fields allow concurrent reads from the
render-precompute and region-display threads; a torn read at worst causes a
cache miss (recompute), never an incorrect return value.

This eliminates ~22 allocations and 20 FNV mixing loops per cached call,
targeting the region.precompute.time must_pass metric and the
region.precompute.alloc guardrail.
@Arbousier1 Arbousier1 added performance-ab Run the base-owned paired performance gate performance-region-fingerprint Use the table region fingerprint performance profile labels Jul 18, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

The five tile-level fingerprint methods (handPrivate, handPublic, discard,
meld, wall) are called in a tight loop over the same (seat, plan, index)
tuples every render cycle. Each call previously allocated a
FingerprintBuilder and ran the FNV-1a mixing loop from scratch.

Add a per-wind identity cache that computes the full fingerprint array
on the first miss for a given (seat, plan) pair, then returns the cached
primitive long for every subsequent index lookup with zero allocation.
The wall tile cache is keyed on the LayoutPlan identity alone.

Identity equality (==) is the correct key semantics: seat snapshots and
layout plans are immutable value objects captured per render cycle, so a
new cycle always misses by reference. This matches the precompute cache
pattern already used by precomputeRegionFingerprints.

Targets the region.tiles.time metric required by the region-fingerprint
profile (minimum_passes: 2).
@Arbousier1
Arbousier1 force-pushed the codex/perf-region-fingerprint-identity-cache branch from 91ef890 to 395b3e2 Compare July 18, 2026 06:02
@Arbousier1

Copy link
Copy Markdown
Collaborator Author

Closing because the green A/B result is not representative of the production path and the cache publication is not safe enough for strict compatibility. The benchmark keeps one trial-scoped (subject, snapshot, layout) and primes the cache in @Setup(Level.Iteration), so every timed invocation measures an identity-cache hit; production creates a new render snapshot for each precompute. In addition, the separately published cache key/value fields and mutable per-wind arrays can be observed inconsistently across threads. This needs a fresh production-shaped miss/hit benchmark and an atomic immutable cache entry before reconsideration.

@Arbousier1 Arbousier1 closed this Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance-ab Run the base-owned paired performance gate performance-region-fingerprint Use the table region fingerprint performance profile

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant