mirror of
https://github.com/libretro/parallel-ps2.git
synced 2026-11-10 11:21:36 -10:00
The texture cache's hash cache was a std::unordered_map, with nodes from GSNodeAllocator's pool. It becomes a GSStableMap, new in C89. Sources point at their entries, so an entry can't move the way a GSFlatMap's values do. Here the slots are a stored hash and a node pointer, sixteen bytes each, at most a quarter in use, with linear probing. Each node holds its key next to its value, so a hit reads the slot and the node. A node knows its slot and its place in a dense list of nodes, so an erase neither looks it up nor hashes it again (backward shift for the slots, the last node into its place in the list). A walk goes down the list and can erase the entry it is at. AgeHashCache does that instead of erasing through an iterator. Its purge list is a plain array of entries, grown only when the cache is fuller than it has been. The slots for 800 entries are made when the cache is. tests/gsstablemap checks the map against a model, with nodes from a pool and from the allocator, including erases during a walk. With GSSM_BENCH=1 it times both maps on 40-byte keys at 32 to 800 entries, best of five, ns per operation, std then stable: find hit 9-13 vs 6-9 (1.3-1.6x) find miss 9-11 vs 7-8 (1.1-1.5x) walk 1.1-3.8 vs 0.6-1.3 per entry (1.2-2.9x) insert+erase 20-29 vs 15-20 (1.3-1.5x) Within a few percent of the quarter-load boundary the miss and insert times are even. Ridge Racer V's intro presents the same 19 frames, bit for bit, and the steady-state allocation count stays at zero.