![]() |
JaffarPlus
High-performance best-first search optimizer for tool-assisted speedruns
|
Stores serialized game states across the machine's NUMA domains and serves them to the search engine in reward-ordered, per-step batches. More...
#include <stateDb.hpp>
Classes | |
| struct | freeStateCache_t |
| Per-thread (OpenMP-thread-indexed) cache of free state slots fronting the shared free-state queues. More... | |
| struct | statCounters_t |
| Per-thread statistics counters for state-DB popping and free-state acquisition. More... | |
Public Member Functions | |
| StateDb (Runner &r, const nlohmann::json &config) | |
| Constructs the state database and reads its maximum size from configuration. | |
| size_t | getMaxBudgetBytes () const |
| Configured maximum state-DB footprint in bytes (used by the engine's combined RAM guard). | |
| ~StateDb () | |
| Frees the per-NUMA current- and next-state queues allocated in initialize(). | |
| void | initialize () |
| Allocates and initializes the per-NUMA state slabs, queues, and per-thread caches. | |
| size_t | saveStateFromRunner (Runner &r, void *statePtr) |
| Serializes the runner's state (raw, uncompressed) into the given slot. | |
| size_t | saveStateToSlot (Runner &r, void *statePtr) |
| Serializes the runner into a state-database slab slot: hot state into the slot, path (input history + step counter) into the parallel cold slot. | |
| void | captureSlotToBuffer (const void *slotPtr, void *buffer) |
| Gathers a slab slot's hot state and its cold history mirror into a contiguous full-state buffer ([hot][history], matching saveStateFromRunner's layout). | |
| size_t | getFullStateSize () const |
| Full self-contained serialized state size ([hot][history]); for standalone state buffers. | |
| bool | pushState (const float reward, Runner &r, void *statePtr) |
| Serializes the runner's state into the given slot and inserts it into the next-state queue. | |
| void | loadStateIntoRunner (Runner &r, const void *statePtr) |
| Deserializes a stored state (raw, uncompressed) from a slot into the runner. | |
| void | loadStateFromSlot (Runner &r, const void *statePtr) |
| Deserializes a state-database slab slot into the runner: hot state from the slot, path from the parallel cold slot. | |
| void | printInfo () const |
| Logs database occupancy, sizing, per-NUMA-domain figures, and reduced statistics counters. | |
| void * | getFreeState (const size_t threadId) |
| Obtains a free state slot for the calling thread to write a new state into. | |
| int | getStateNumaDomain (void *const statePtr) |
| Finds the NUMA domain whose slab contains the given state slot. | |
| void * | getHistoryPtr (const void *const statePtr) |
| Returns the cold history slot mirroring the given hot state slot (same NUMA domain + index). | |
| bool | isStateInNumaDomain (void *const statePtr, const int numaDomainId) |
| Tests whether a state slot lies within a given NUMA domain's slab. | |
| void | returnFreeState (void *const statePtr, const size_t threadId) |
| Returns a state slot to the free pool for later reuse. | |
| void | advanceStep () |
| Moves each NUMA domain's next-state queue into its current-state queue, best reward first, and clears the next-state queue. | |
| void * | popState () |
| Pops a single base state from the current-state database, preferring NUMA-local domains. | |
| size_t | popStates (void **elements, const size_t maxCount, const size_t threadId) |
| Pops a batch of base states from the current-state database, preferring NUMA-local domains. | |
| size_t | getStateCount () const |
| Returns the total number of states currently held in the current-state database. | |
| void * | getBestState () const |
| Returns a pointer to the highest-reward state recorded by the last advanceStep. | |
| void * | getWorstState () const |
| Returns a pointer to the lowest-reward state recorded by the last advanceStep. | |
| size_t | getStateSizeInDatabase () const |
| Returns the per-state size (including padding) as stored in the database. | |
Private Attributes | |
| void * | _bestState = nullptr |
| Pointer to the best (highest-reward) state from the last advanceStep(). | |
| void * | _worstState = nullptr |
| Pointer to the worst (lowest-reward) state from the last advanceStep(). | |
| Runner *const | _runner |
| The runner used to serialize states into and deserialize states out of the database. | |
| size_t | _stateSize |
| Size occupied by each stored state, including alignment padding. | |
| size_t | _stateSizeRaw |
| Raw (unpadded) serialized size of a single state. | |
| size_t | _stateSizePadding |
| Number of padding bytes added to the raw size to reach _stateSize. | |
| size_t | _maxSize |
| Total maximum size (bytes) the state database may grow to across all NUMA domains. | |
| size_t | _maxStates |
| Total maximum number of states the database can hold across all NUMA domains. | |
| std::vector< statCounters_t > | _statCounters |
| Per-thread (OpenMP-thread-indexed) statistics counters. | |
| std::vector< freeStateCache_t > | _freeStateCache |
| Per-thread free-slot caches, indexed by OpenMP thread id. | |
| size_t | _maxSizeMb |
| User-provided maximum megabytes to use for the entire state database. | |
| std::vector< size_t > | _maxSizePerNuma |
| Maximum size (bytes) of the state database in each NUMA domain. | |
| std::vector< size_t > | _maxStatesPerNuma |
| Calculated maximum number of states the state database can hold in each NUMA domain. | |
| std::vector< size_t > | _currentStatesPerNuma |
| Number of current states held in each NUMA domain (updated each advanceStep()). | |
| std::mutex | _workMutex |
| Mutex guarding the cross-NUMA best/worst-state updates in advanceStep(). | |
| std::vector< jaffarCommon::concurrent::DrainBuffer< void * > * > | _numaCurrentStateQueues |
| Per-NUMA-domain current-state queues drained by the workers during a step (null for non-delegate domains). | |
| std::vector< jaffarCommon::concurrent::concurrentMultimap_t< float, void * > * > | _numaNextStateQueues |
| Per-NUMA-domain reward-ordered queues collecting the next step's states (null for non-delegate domains). | |
| std::vector< std::unique_ptr< jaffarCommon::concurrent::atomicQueue_t< void * > > > | _freeStateQueues |
| Per-NUMA-domain queues holding pointers to all currently free state slots. | |
| std::vector< uint8_t * > | _internalBuffersStart |
| Start pointer of each NUMA domain's contiguous state slab. | |
| std::vector< uint8_t * > | _internalBuffersEnd |
| End pointer of each NUMA domain's contiguous state slab. | |
| std::vector< size_t > | _allocableBytesPerNuma |
| Number of bytes allocated for the state slab in each NUMA domain. | |
| size_t | _histSize = 0 |
| Unpadded size of one state's cold "path" data (bit-packed input history + step counter). | |
| std::vector< uint8_t * > | _histBuffersStart |
| Start pointer of each NUMA domain's parallel history (cold) slab. | |
| InputHistory * | _ih = nullptr |
| The reference runner's input-history strategy, used for the per-slot manager operations (initColdSlot / releaseColdSlot / captureColdToFull). | |
| size_t | _fullStateSizeBytes = 0 |
| Full self-contained serialized state size ([hot]+[full bit-packed history]) for standalone snapshot buffers. | |
Static Private Attributes | |
| static constexpr size_t | FREE_STATE_CACHE_CAPACITY = 32 |
| Capacity of each worker's thread-local free-slot cache ("magazine"). | |
Stores serialized game states across the machine's NUMA domains and serves them to the search engine in reward-ordered, per-step batches.
Each NUMA domain owns a contiguous slab of state slots (allocated on that node), a free-slot queue of unused slots, a reward-ordered "next" queue that collects states produced during a step, and a "current" queue that the workers drain during the following step. The queue lifecycle is: workers pushState into the next queue; advanceStep moves the next queue's pointers (best-reward first) into the current queue and clears the next queue; workers then popState / popStates the current queue. Slots are obtained with getFreeState and recycled with returnFreeState, both fronted by a per-thread free-slot cache. The per-domain queues are only allocated for NUMA domains that own a delegate worker thread; other domains hold null queue pointers, which the access paths skip.
Definition at line 42 of file stateDb.hpp.
|
inline |
Constructs the state database and reads its maximum size from configuration.
| r | The runner whose states will be serialized into and deserialized out of the database. |
| config | Configuration object; the "Max Size (Mb)" field sets the database's maximum size. |
Reads "Max Size (Mb)" from config. If the environment variable JAFFAR_ENGINE_OVERRIDE_MAX_STATEDB_SIZE_MB is set, its value overrides that maximum.
Definition at line 53 of file stateDb.hpp.
|
inline |
Frees the per-NUMA current- and next-state queues allocated in initialize().
Iterates over both queue vectors and deletes each entry. Only delegate domains hold a non-null queue; the remaining entries are nullptr, which delete ignores.
Definition at line 76 of file stateDb.hpp.
|
inline |
Moves each NUMA domain's next-state queue into its current-state queue, best reward first, and clears the next-state queue.
Runs in parallel; in each domain only the delegate thread acts. It records the domain's next-state count, clears the current-state buffer (drained during the previous step), then traverses the reward-ordered next-state map in descending-reward order, appending each pointer to the current-state buffer. After draining it clears (frees) the whole next-state map at once. It then updates the cross-NUMA best and worst state pointers under _workMutex from the first (best) and last (worst) entries seen.
Definition at line 598 of file stateDb.hpp.
|
inline |
Gathers a slab slot's hot state and its cold history mirror into a contiguous full-state buffer ([hot][history], matching saveStateFromRunner's layout).
Used to snapshot the best/worst state out of the slabs into standalone storage that loadStateIntoRunner can later restore.
Definition at line 277 of file stateDb.hpp.
|
inline |
Returns a pointer to the highest-reward state recorded by the last advanceStep.
Definition at line 767 of file stateDb.hpp.
|
inline |
Obtains a free state slot for the calling thread to write a new state into.
| threadId | The calling thread's dense OpenMP id, used to index its cache and statistics counters. |
First serves from this thread's free-slot cache (LIFO) when non-empty. Otherwise it scans NUMA domains in this thread's preference order and tries to pop from each domain's free-state queue. If all free-state queues are empty, it scans again and steals a slot from the back (worst state) of each domain's current-state queue. Updates the thread's NUMA-distance and locality/stealing statistics on success.
Definition at line 447 of file stateDb.hpp.
|
inline |
Full self-contained serialized state size ([hot][history]); for standalone state buffers.
Definition at line 286 of file stateDb.hpp.
|
inline |
Returns the cold history slot mirroring the given hot state slot (same NUMA domain + index).
| statePtr | A hot state-slab slot pointer. |
The hot slabs are fixed grids of _stateSize slots, so the slot index is plain pointer arithmetic and the cold slab is addressed at the same index with _histSize stride.
Definition at line 531 of file stateDb.hpp.
|
inline |
Configured maximum state-DB footprint in bytes (used by the engine's combined RAM guard).
Definition at line 68 of file stateDb.hpp.
|
inline |
Returns the total number of states currently held in the current-state database.
Skips unallocated (null) per-domain queues so the count is safe when threads do not cover every NUMA domain.
Definition at line 755 of file stateDb.hpp.
|
inline |
Finds the NUMA domain whose slab contains the given state slot.
| statePtr | The state slot to locate. |
| A | runtime error if the pointer does not fall within any domain's slab. |
Definition at line 515 of file stateDb.hpp.
|
inline |
Returns the per-state size (including padding) as stored in the database.
Definition at line 773 of file stateDb.hpp.
|
inline |
Returns a pointer to the lowest-reward state recorded by the last advanceStep.
Definition at line 770 of file stateDb.hpp.
|
inline |
Allocates and initializes the per-NUMA state slabs, queues, and per-thread caches.
Queries the runner's state size and pads it up to _JAFFAR_STATE_PADDING_BYTES. Allocates per-thread statistics counters and free-slot caches. Splits the configured maximum size evenly across NUMA domains, verifies each domain has enough free memory (throwing otherwise), and derives the per-domain maximum state counts. For each NUMA domain that owns a delegate thread it creates the current-state DrainBuffer (reserved to the domain's state count) and the next-state reward-ordered multimap. It then allocates the per-domain contiguous state slab on that node, touches one byte per page to fault it in, and fills the domain's free-state queue with pointers to every slot.
| A | runtime error if a domain's requested memory exceeds its free space, if a domain's state count exceeds the DrainBuffer's 32-bit capacity limit, or if a NUMA slab allocation fails. |
Definition at line 99 of file stateDb.hpp.
|
inline |
Tests whether a state slot lies within a given NUMA domain's slab.
| statePtr | The state slot to test. |
| numaDomainId | The NUMA domain whose slab is checked. |
Definition at line 544 of file stateDb.hpp.
|
inline |
Deserializes a state-database slab slot into the runner: hot state from the slot, path from the parallel cold slot.
Use only with slab-slot pointers.
Definition at line 343 of file stateDb.hpp.
|
inline |
Deserializes a stored state (raw, uncompressed) from a slot into the runner.
| r | The runner the state is loaded into. |
| statePtr | The slot the state is read from. |
Definition at line 332 of file stateDb.hpp.
|
inline |
Pops a single base state from the current-state database, preferring NUMA-local domains.
Scans NUMA domains in the calling thread's preference order (skipping unallocated null queues) and pops from the front of the first non-empty current-state queue. Updates the calling thread's NUMA-distance and locality statistics on success.
Definition at line 674 of file stateDb.hpp.
|
inline |
Pops a batch of base states from the current-state database, preferring NUMA-local domains.
| elements | Output buffer the popped state pointers are written into. |
| maxCount | Maximum number of states to retrieve. |
| threadId | The calling thread's dense OpenMP id, used to index its statistics counters. |
Batched counterpart of popState that scans NUMA domains in the calling thread's preference order (skipping unallocated null queues) and takes the whole batch from the first non-empty current-state queue under a single lock acquisition. Accumulates NUMA-distance and locality statistics once per batch.
Definition at line 718 of file stateDb.hpp.
|
inline |
Logs database occupancy, sizing, per-NUMA-domain figures, and reduced statistics counters.
Logs current vs. maximum state counts and sizes, raw and padded per-state sizes, and the first and last NUMA domains' state counts and sizes. Reduces the per-thread statistics counters into totals and logs database-pop NUMA locality rates, free-slot cache hit/absorb counts, free-state acquisition rates (including state stealing), and the average NUMA distance per access.
Definition at line 360 of file stateDb.hpp.
|
inline |
Serializes the runner's state into the given slot and inserts it into the next-state queue.
| reward | The reward used to order the state within its NUMA domain's next-state queue. |
| r | The runner whose state is serialized. |
| statePtr | The slot to serialize into and insert; determines the target NUMA domain. |
| A | runtime error if statePtr is null (interpreted as having run out of free states). |
Determines the slot's owning NUMA domain via getStateNumaDomain and inserts the {reward, statePtr} pair into that domain's next-state queue.
Definition at line 299 of file stateDb.hpp.
|
inline |
Returns a state slot to the free pool for later reuse.
| statePtr | The slot being freed. |
| threadId | The calling thread's dense OpenMP id, used to index its cache and statistics counters. |
| A | runtime error if the slot fails to push onto its owning domain's free-state queue. |
Stores the slot in this thread's free-slot cache when it has room (capped at FREE_STATE_CACHE_CAPACITY). When the cache is full, it spills the slot to the shared free-state queue of the slot's owning NUMA domain (found via getStateNumaDomain).
Definition at line 559 of file stateDb.hpp.
|
inline |
Serializes the runner's state (raw, uncompressed) into the given slot.
| r | The runner whose state is serialized. |
| statePtr | Destination slot the state is written into. |
Definition at line 250 of file stateDb.hpp.
|
inline |
Serializes the runner into a state-database slab slot: hot state into the slot, path (input history + step counter) into the parallel cold slot.
Use only with slab-slot pointers.
Definition at line 263 of file stateDb.hpp.
|
private |
Number of bytes allocated for the state slab in each NUMA domain.
Definition at line 868 of file stateDb.hpp.
|
private |
Pointer to the best (highest-reward) state from the last advanceStep().
Definition at line 776 of file stateDb.hpp.
|
private |
Number of current states held in each NUMA domain (updated each advanceStep()).
Definition at line 847 of file stateDb.hpp.
|
private |
Per-thread free-slot caches, indexed by OpenMP thread id.
Definition at line 835 of file stateDb.hpp.
|
private |
Per-NUMA-domain queues holding pointers to all currently free state slots.
Definition at line 859 of file stateDb.hpp.
|
private |
Full self-contained serialized state size ([hot]+[full bit-packed history]) for standalone snapshot buffers.
May exceed _stateSizeRaw + _histSize in trie mode (cold slot stores only a node id).
Definition at line 886 of file stateDb.hpp.
|
private |
Start pointer of each NUMA domain's parallel history (cold) slab.
Indexed identically to the state slab: the history for the hot slot at index i lives at _histBuffersStart[numa] + i*_histSize.
Definition at line 878 of file stateDb.hpp.
|
private |
Unpadded size of one state's cold "path" data (bit-packed input history + step counter).
Stored in a parallel slab (_histBuffersStart) rather than in the hot state slot, so the data the search hashes/advances every step stays dense. Written once at state creation, read once when a solution is reconstructed.
Definition at line 874 of file stateDb.hpp.
|
private |
The reference runner's input-history strategy, used for the per-slot manager operations (initColdSlot / releaseColdSlot / captureColdToFull).
Polymorphic: no-ops for raw/none, GC for trie.
Definition at line 882 of file stateDb.hpp.
|
private |
End pointer of each NUMA domain's contiguous state slab.
Definition at line 865 of file stateDb.hpp.
|
private |
Start pointer of each NUMA domain's contiguous state slab.
Definition at line 862 of file stateDb.hpp.
|
private |
Total maximum size (bytes) the state database may grow to across all NUMA domains.
Definition at line 791 of file stateDb.hpp.
|
private |
User-provided maximum megabytes to use for the entire state database.
Definition at line 838 of file stateDb.hpp.
|
private |
Maximum size (bytes) of the state database in each NUMA domain.
Definition at line 841 of file stateDb.hpp.
|
private |
Total maximum number of states the database can hold across all NUMA domains.
Definition at line 794 of file stateDb.hpp.
|
private |
Calculated maximum number of states the state database can hold in each NUMA domain.
Definition at line 844 of file stateDb.hpp.
|
private |
Per-NUMA-domain current-state queues drained by the workers during a step (null for non-delegate domains).
Definition at line 853 of file stateDb.hpp.
|
private |
Per-NUMA-domain reward-ordered queues collecting the next step's states (null for non-delegate domains).
Definition at line 856 of file stateDb.hpp.
|
private |
The runner used to serialize states into and deserialize states out of the database.
Definition at line 779 of file stateDb.hpp.
|
private |
Per-thread (OpenMP-thread-indexed) statistics counters.
Definition at line 815 of file stateDb.hpp.
|
private |
Size occupied by each stored state, including alignment padding.
Definition at line 782 of file stateDb.hpp.
|
private |
Number of padding bytes added to the raw size to reach _stateSize.
Definition at line 788 of file stateDb.hpp.
|
private |
Raw (unpadded) serialized size of a single state.
Definition at line 785 of file stateDb.hpp.
|
private |
Mutex guarding the cross-NUMA best/worst-state updates in advanceStep().
Definition at line 850 of file stateDb.hpp.
|
private |
Pointer to the worst (lowest-reward) state from the last advanceStep().
Definition at line 777 of file stateDb.hpp.
|
staticconstexprprivate |
Capacity of each worker's thread-local free-slot cache ("magazine").
Kept small so the total number of slots parked in caches (this * threadCount) stays a negligible fraction of the state database.
Definition at line 823 of file stateDb.hpp.