16#include <emulatorList.hpp>
17#include <gameList.hpp>
18#include <jaffarCommon/deserializers/base.hpp>
19#include <jaffarCommon/hash.hpp>
20#include <jaffarCommon/json.hpp>
21#include <jaffarCommon/logger.hpp>
22#include <jaffarCommon/parallel.hpp>
23#include <jaffarCommon/serializers/base.hpp>
24#include <jaffarCommon/timing.hpp>
33#ifdef JAFFARPLUS_DETAILED_PROFILING
35#define JAFFAR_PROF_DECL(var) const auto var = jaffarCommon::timing::now()
37#define JAFFAR_PROF_ACC(field, var) field += jaffarCommon::timing::timeDeltaMicroseconds(jaffarCommon::timing::now(), var)
39#define JAFFAR_PROF_DECL(var) ((void)0)
40#define JAFFAR_PROF_ACC(field, var) ((void)0)
67 Engine(
const nlohmann::json& emulatorConfig,
const nlohmann::json& gameConfig,
const nlohmann::json& runnerConfig,
const nlohmann::json& engineConfig)
73 if (_threadCount == 0) JAFFAR_THROW_LOGIC(
"The number of worker threads must be at least one. Provided: %lu\n", _threadCount);
76 jaffarCommon::logger::log(
"[J+] Using %lu worker threads.\n", _threadCount);
91 _runners[jaffarCommon::parallel::getThreadId()] = std::move(r);
98 auto engineConfigRemaining = engineConfig;
101 auto stateDatabaseJs = jaffarCommon::json::popObject(engineConfigRemaining,
"State Database");
102 _stateDb = std::make_unique<jaffarPlus::StateDb>(r, stateDatabaseJs);
105 auto hashDbConfig = jaffarCommon::json::popObject(engineConfigRemaining,
"Hash Database");
106 _hashDbEnabled = jaffarCommon::json::getBoolean(hashDbConfig,
"Enabled");
113 _baseStateBatch = engineConfigRemaining.contains(
"Base State Batch Size") ? jaffarCommon::json::popNumber<size_t>(engineConfigRemaining,
"Base State Batch Size") : 0;
117 jaffarCommon::json::checkEmpty(engineConfigRemaining,
"Engine Configuration");
190 auto& r =
_runners[jaffarCommon::parallel::getThreadId()];
193 r->setInputHistoryBacking(
_inputHistoryBacking, (uint32_t)jaffarCommon::parallel::getThreadId(), _threadCount + 1);
202 const size_t stateBudget =
_stateDb->getMaxBudgetBytes();
211 const size_t hashPeak = hashBudget * 2;
212 const size_t totalBudget = stateBudget + hashPeak + historyBound;
214 for (
int i = 0; i < _numaCount; i++)
216 long long nodeFree = 0;
217 numa_node_size64(i, &nodeFree);
218 freeRam += (size_t)nodeFree;
220 const size_t usable = (size_t)((
double)freeRam * 0.90);
221 if (totalBudget > usable)
223 const double GB = 1024.0 * 1024.0 * 1024.0;
224 JAFFAR_THROW_RUNTIME(
"Configured database budget exceeds available memory:\n"
225 " State DB ('Max Size (Mb)', fixed pool) = %.1f GB\n"
226 " Hash DB peak (2 x 'Max Store Size' x 'Max Store Count') = %.1f GB\n"
227 " Input-history trie (hard node-storage ceiling) = %.1f GB\n"
229 " Usable (90%% of %.1f GB free RAM) = %.1f GB\n"
230 "Reduce 'State Database/Max Size (Mb)' and/or 'Hash Database/Max Store Size (Mb)'.\n"
231 "NOTE: the hash DB phmap doubles on growth, so a rehash briefly holds the old + new (2x) table; the\n"
232 "Trie input-history is a separate structure that grows up to ~384 GiB. Both are otherwise uncounted.\n",
233 (
double)stateBudget / GB, (
double)hashPeak / GB, (
double)historyBound / GB, (
double)totalBudget / GB, (
double)freeRam / GB, (
double)usable / GB);
255 const size_t stateSize = r.getStateSize();
256 std::vector<char> scratch(stateSize);
258 jaffarCommon::serializer::Contiguous s(scratch.data(), stateSize);
262 const auto allowedInputs = r.getAllowedInputs();
265 const size_t CAL_FRAMES = 200;
266 const auto tCal0 = jaffarCommon::timing::now();
267 for (
size_t i = 0; i < CAL_FRAMES; i++) r.advanceState(calInput);
268 const size_t perStateNs = jaffarCommon::timing::timeDeltaNanoseconds(jaffarCommon::timing::now(), tCal0) / CAL_FRAMES;
272 jaffarCommon::deserializer::Contiguous d(scratch.data(), stateSize);
273 r.deserializeState(d);
277 constexpr size_t TARGET_BATCH_NS = 200000;
278 size_t b = (perStateNs > 0) ? ((TARGET_BATCH_NS + perStateNs / 2) / perStateNs) :
BASE_STATE_BATCH_MAX;
282 jaffarCommon::logger::log(
"[J+] Auto-tuned base-state batch size: %lu (measured %.1f us/state)\n",
_baseStateBatch, (
double)perStateNs / 1000.0);
287 r.getGame()->evaluateRules();
290 r.getGame()->updateGameStateType();
293 r.getGame()->runGameSpecificRuleActions();
296 r.getGame()->updateReward();
299 const auto reward = r.getGame()->getReward();
302 auto stateData =
_stateDb->getFreeState(0);
305 _stateDb->pushState(reward, r, stateData);
323 const auto hash = r.computeHash();
340 const auto tStep = jaffarCommon::timing::now();
382 for (ssize_t i = 0; i < _threadCount; i++)
409 const auto t0 = jaffarCommon::timing::now();
414 const auto t1 = jaffarCommon::timing::now();
426 _currentStepTime = jaffarCommon::timing::timeDeltaMicroseconds(jaffarCommon::timing::now(), tStep);
434 for (ssize_t i = 0; i < _threadCount; i++)
551 jaffarCommon::logger::log(
"[J+] Thread Count / NUMA Domains: %3d / %d\n", _threadCount, _numaCount);
552#ifdef JAFFARPLUS_DETAILED_PROFILING
553 jaffarCommon::logger::log(
"[J+] Elapsed Time (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_currentStepTime),
557 jaffarCommon::logger::log(
"[J+] + Runner State Avance (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_runnerStateAdvanceAverageTime),
561 jaffarCommon::logger::log(
"[J+] + Runner State Load (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_runnerStateLoadAverageTime),
565 jaffarCommon::logger::log(
"[J+] + Runner State Save (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_runnerStateSaveAverageTime),
569 jaffarCommon::logger::log(
"[J+] + Hash Calculation (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_calculateHashAverageTime),
573 jaffarCommon::logger::log(
"[J+] + Hash Checking (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_checkHashAverageTime),
577 jaffarCommon::logger::log(
"[J+] + Rule Checking (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_ruleCheckingAverageTime),
581 jaffarCommon::logger::log(
"[J+] + Get Free State (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_getFreeStateAverageTime),
585 jaffarCommon::logger::log(
"[J+] + Return Free State (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_returnFreeStateAverageTime),
589 jaffarCommon::logger::log(
"[J+] + Calculate Reward (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_calculateRewardAverageTime),
593 jaffarCommon::logger::log(
"[J+] + Popping Base State (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_popBaseStateDbAverageTime),
597 jaffarCommon::logger::log(
"[J+] + Get Allowed Inputs (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_getAllowedInputsAverageTime),
601 jaffarCommon::logger::log(
"[J+] + Get Candidate Inputs (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_getCandidateInputsAverageTime),
608 jaffarCommon::logger::log(
"[J+] Elapsed Time (Step/Total): %9.3fs / %9.3fs (per-operation breakdown disabled; build -DdetailedProfiling=true)\n",
612 jaffarCommon::logger::log(
"[J+] + Advance Hash Db (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_advanceHashDbAverageTime),
616 jaffarCommon::logger::log(
"[J+] + Advance State Db (Step/Total): %9.3fs (%7.3f%%) / %9.3fs (%3.3f%%)\n", 1.0e-6 * (
double)(
_advanceStateDbAverageTime),
621 jaffarCommon::logger::log(
"[J+] Base States Processed: %.3f Mstates (Total: %.3f Mstates)\n", 1.0e-6 * (
double)
_stepBaseStatesProcessed,
623 jaffarCommon::logger::log(
"[J+] New States Processed: %.3f Mstates (Total: %.3f Mstates)\n", 1.0e-6 * (
double)
_stepNewStatesProcessed,
626 jaffarCommon::logger::log(
"[J+] Base States Performance: %.3f Mstates/s (Average: %.3f Mstates/s)\n",
629 jaffarCommon::logger::log(
"[J+] New States Performance: %.3f Mstates/s (Average: %.3f Mstates/s)\n",
633 jaffarCommon::logger::log(
"[J+] Dropped States (No Storage Available): %lu (%5.3f%% of New States Processed) \n",
_droppedStatesNoStorage.load(),
637 jaffarCommon::logger::log(
"[J+] Dropped States (Checkpoint): %lu (%5.3f%% of New States Processed) \n",
_droppedStatesCheckpoint.load(),
639 jaffarCommon::logger::log(
"[J+] Failed States: %lu (%5.3f%% of New States Processed) \n",
_failedStates.load(),
641 jaffarCommon::logger::log(
"[J+] Repeated States: %lu (%5.3f%% of New States Processed) \n",
_repeatedStates.load(),
643 jaffarCommon::logger::log(
"[J+] Normal States: %lu (%5.3f%% of New States Processed) \n",
_normalStates.load(),
645 jaffarCommon::logger::log(
"[J+] Win States: %lu (%5.3f%% of New States Processed) \n",
_winStates.load(),
649 jaffarCommon::logger::log(
"[J+] State Database Information:\n");
654 jaffarCommon::logger::log(
"[J+] Hash Database Information:\n");
658 jaffarCommon::logger::log(
"[J+] Manually Saved Solution:\n");
665 jaffarCommon::logger::log(
"[J+] Candidate Inputs:\n");
668 jaffarCommon::logger::log(
"[J+] + Hash: %s\n", jaffarCommon::hash::hashToString(entry.first).c_str());
669 for (
const auto input : entry.second) jaffarCommon::logger::log(
"[J+] + %3lu %s\n", input,
_runners[0]->getInputStringFromIndex(input).c_str());
782 const auto threadId = jaffarCommon::parallel::getThreadId();
788 const auto threadTime0 = jaffarCommon::timing::now();
804 while (batchIdx < batchCount)
807 void* baseStateData = baseStateBatch[batchIdx++];
810 acc.baseStatesProcessed++;
814 _stateDb->loadStateFromSlot(*r, baseStateData);
820 const auto allowedInputs = r->getAllowedInputs();
826 auto candidateInputs = r->getCandidateInputs();
830 std::vector<InputSet::inputIndex_t> uniqueCandidateInputs;
831 for (
const auto& input : candidateInputs)
832 if (std::find(allowedInputs.begin(), allowedInputs.end(), input) == allowedInputs.end()) uniqueCandidateInputs.push_back(input);
837 jaffarCommon::hash::hash_t baseStateInputHash{};
838 if (uniqueCandidateInputs.empty() ==
false) baseStateInputHash = r->getGame()->getStateInputHash();
841 for (
auto inputItr = allowedInputs.begin(); inputItr != allowedInputs.end(); inputItr++)
runNewInput(*r, baseStateData, *inputItr, acc, threadId);
844 for (
const auto input : uniqueCandidateInputs)
851 const auto result =
runNewInput(*r, baseStateData, input, acc, threadId);
859 _stateDb->returnFreeState(baseStateData, threadId);
863 if (batchIdx >= batchCount)
873 _threadStepTime[threadId] = jaffarCommon::timing::timeDeltaMicroseconds(jaffarCommon::timing::now(), threadTime0);
892 _stateDb->loadStateFromSlot(r, baseStateData);
897 const auto result =
runInput(r, input, acc, threadId);
981 void* newStateData =
_stateDb->getFreeState(threadId);
1012 _stateDb->returnFreeState(newStateData, threadId);
1024 auto success =
_stateDb->pushState(reward, r, newStateData);
1028 if (success ==
false)
1032 _stateDb->returnFreeState(newStateData, threadId);
1068 jaffarCommon::concurrent::HashMap_t<jaffarCommon::hash::hash_t, jaffarCommon::concurrent::HashSet_t<InputSet::inputIndex_t>>
_candidateInputsDetected;
Parallel state-space search engine.
std::atomic< size_t > _getFreeStateAverageTime
Per-thread-average get-free-state time for the step.
std::atomic< size_t > _advanceHashDbAverageTime
Hash-DB advance time reported for the step.
std::atomic< size_t > _getCandidateInputsAverageTime
Per-thread-average get-candidate-inputs time for the step.
std::atomic< size_t > _checkHashThreadRawTime
Summed per-thread hash-checking time for the step.
std::atomic< size_t > _advanceStateDbThreadRawTime
Serially-measured state-DB advance time for the step.
size_t getStateSizeInDatabase() const
Returns the size, in bytes, of a single state as stored in the database.
std::atomic< size_t > _droppedStatesFailedSerialization
Counter for states dropped due to failed serialization.
std::atomic< size_t > _popBaseStateDbThreadRawTime
Summed per-thread base-state pop time for the step.
size_t _checkpointTolerance
Tolerance (in steps) associated with the current checkpoint level.
size_t getInputHistoryMaxMemoryBytes() const
Hard memory ceiling (bytes) of the shared input-history backing; 0 for None/Raw (no ceiling).
std::atomic< size_t > _advanceHashDbThreadRawTime
Serially-measured hash-DB advance time for the step.
std::atomic< size_t > _getCandidateInputsAverageCumulativeTime
Cumulative per-thread-average get-candidate-inputs time.
std::atomic< size_t > _checkHashAverageCumulativeTime
Cumulative per-thread-average hash-checking time.
std::atomic< size_t > _totalBaseStatesProcessed
Base states processed across all steps so far.
std::atomic< size_t > _returnFreeStateAverageTime
Per-thread-average return-free-state time for the step.
static constexpr size_t BASE_STATE_BATCH_MAX
Number of base states a worker pulls from the state-DB queue per lock acquisition (batch size).
std::atomic< size_t > _ruleCheckingThreadRawTime
Summed per-thread rule-checking time for the step.
std::unique_ptr< jaffarPlus::HashDb > _hashDb
Thread-safe hash database used to detect repeated states.
std::atomic< size_t > _getFreeStateThreadRawTime
Summed per-thread get-free-state time for the step.
void initialize()
Resets execution back to step zero and clears all databases and counters.
size_t _fullStateSize
Full self-contained serialized state size ([hot]+[history]) for standalone snapshot buffers.
std::atomic< size_t > _advanceStateDbAverageCumulativeTime
Cumulative state-DB advance time.
std::string _manualSaveSolutionLastPath
Path of the most recently activated manual-save solution.
std::atomic< size_t > _runnerStateLoadAverageTime
Per-thread-average state-load time for the step.
std::atomic< size_t > _stepBaseStatesProcessed
Base states processed during the current step.
std::atomic< size_t > _calculateRewardAverageTime
Per-thread-average reward-calculation time for the step.
std::atomic< size_t > _runnerStateSaveAverageTime
Per-thread-average state-save time for the step.
size_t _maxThreadStepTime
Maximum per-thread step time for the current step.
std::vector< std::unique_ptr< Runner > > _runners
Collection of runners for the workers to use (one per thread).
manualSaveSolution_t _manualSaveSolution
Best manually saved solution for the current step.
size_t _totalRunningTime
Total running time so far, in microseconds.
std::atomic< size_t > _popBaseStateDbAverageTime
Per-thread-average base-state pop time for the step.
std::atomic< size_t > _calculateHashAverageCumulativeTime
Cumulative per-thread-average hash-calculation time.
std::atomic< size_t > _checkHashAverageTime
Per-thread-average hash-checking time for the step.
size_t _subTotalAverageTime
Sum of all per-operation average times for the current step.
std::atomic< size_t > _winStates
Counter for win states.
stateInfo_t _stepBestWinState
Best win state (by reward) found during the current step.
std::atomic< size_t > _runnerStateSaveThreadRawTime
Summed per-thread state-save time for the step.
std::atomic< size_t > _calculateRewardAverageCumulativeTime
Cumulative per-thread-average reward-calculation time.
size_t _currentStepTime
Overall running time of the current step, in microseconds.
std::atomic< size_t > _runnerStateAdvanceAverageCumulativeTime
Cumulative per-thread-average runner-advance time.
bool _hashDbEnabled
Whether hashing is enabled. Games that cannot loop skip the hash DB to save memory and computation.
std::atomic< size_t > _droppedStatesCheckpoint
Counter for states dropped due to not meeting the checkpoint.
auto getStepBestWinState() const
Returns a copy of the best win state recorded in the current step.
std::atomic< size_t > _popBaseStateDbAverageCumulativeTime
Cumulative per-thread-average base-state pop time.
std::atomic< size_t > _getAllowedInputsAverageCumulativeTime
Cumulative per-thread-average get-allowed-inputs time.
jaffarCommon::concurrent::HashMap_t< jaffarCommon::hash::hash_t, jaffarCommon::concurrent::HashSet_t< InputSet::inputIndex_t > > _candidateInputsDetected
Per-base-state-input-hash set of candidate inputs already detected, used to dedup candidate-input pro...
std::atomic< size_t > _getAllowedInputsThreadRawTime
Summed per-thread get-allowed-inputs time for the step.
void workerFunction()
Worker body executed in parallel by every thread during a step.
std::vector< threadAccumulator_t > _threadAccumulators
Per-thread accumulators for hot-loop timing/counters, reduced once per step.
size_t getFullStateSize() const
Full self-contained state size ([hot]+[history]); for standalone snapshots outside the slabs.
std::unique_ptr< jaffarPlus::StateDb > _stateDb
Thread-safe state database holding the current and next step's states.
std::atomic< size_t > _calculateHashAverageTime
Per-thread-average hash-calculation time for the step.
std::atomic< size_t > _runnerStateSaveAverageCumulativeTime
Cumulative per-thread-average state-save time.
bool _manualSaveSolutionUpdatedLastRuleId
Whether the manual-save last-rule id changed this step.
std::atomic< size_t > _runnerStateLoadThreadRawTime
Summed per-thread state-load time for the step.
inputResult_t runInput(Runner &r, const InputSet::inputIndex_t input, threadAccumulator_t &acc, const size_t threadId)
Advances the runner by one input and classifies/stores the resulting state.
std::mutex _stepBestWinStateLock
Guards updates to _stepBestWinState.
std::atomic< size_t > _advanceStateDbAverageTime
State-DB advance time reported for the step.
std::atomic< size_t > _getAllowedInputsAverageTime
Per-thread-average get-allowed-inputs time for the step.
auto getManualSaveSolution() const
Returns a copy of the most recent manually saved solution.
inputResult_t runNewInput(Runner &r, const void *baseStateData, const InputSet::inputIndex_t input, threadAccumulator_t &acc, const size_t threadId)
Re-loads the base state, runs a single input, updates per-outcome counters and checkpoint tracking.
size_t _maxThreadStepTimeThreadId
Id of the thread with the maximum step time.
auto getStateCount() const
Returns the number of states currently held in the state database.
size_t _stateSizeInDatabase
Size of a single state as stored in the database, in bytes.
ssize_t _manualSaveSolutionActiveLastRuleId
Currently active manual-save last-rule id across steps.
std::shared_ptr< void > _inputHistoryBacking
The one shared input-history backing (e.g.
std::atomic< size_t > _repeatedStates
Counter for repeated states (detected via hash collision).
std::atomic< size_t > _runnerStateAdvanceAverageTime
Per-thread-average runner-advance time for the step.
std::atomic< size_t > _calculateRewardThreadRawTime
Summed per-thread reward-calculation time for the step.
std::atomic< size_t > _normalStates
Counter for normal states.
std::atomic< size_t > _returnFreeStateAverageCumulativeTime
Cumulative per-thread-average return-free-state time.
inputResult_t
Outcome of running a single input on a base state.
@ normal
Resulting state was a normal state and was stored.
@ repeated
Resulting state's hash was already seen.
@ win
Resulting state was a win state.
@ droppedNoStorage
No free state slot was available to store the new state.
@ droppedFailedSerialization
Pushing the state into the database failed (e.g. serialization error).
@ failed
Resulting state was classified as a loss.
@ droppedCheckpoint
State did not meet the current checkpoint level past the cutoff step.
void runStep()
Runs a single search step: expands all current base states in parallel and advances the databases.
std::atomic< size_t > _failedStates
Counter for failed states (reached a point in the game considered a loss).
size_t _currentStep
Counter for the current step.
std::atomic< size_t > _returnFreeStateThreadRawTime
Summed per-thread return-free-state time for the step.
std::atomic< size_t > _stepNewStatesProcessed
New states processed during the current step.
std::atomic< size_t > _getFreeStateAverageCumulativeTime
Cumulative per-thread-average get-free-state time.
size_t _subTotalAverageCumulativeTime
Sum of all per-operation cumulative average times.
std::atomic< size_t > _advanceHashDbAverageCumulativeTime
Cumulative hash-DB advance time.
std::vector< size_t > _threadStepTime
Per-thread running time of the current step, in microseconds.
std::atomic< size_t > _runnerStateLoadAverageCumulativeTime
Cumulative per-thread-average state-load time.
bool isInputHistoryExhausted() const
True if the shared input-history backing (the Trie) has hit its hard node-storage ceiling.
void printInfo()
Logs engine status: timing breakdown, throughput, state counts, checkpoints, databases,...
auto & getStateDb() const
Returns a reference to the owned state database.
size_t _checkpointCutoff
Step index after which states below _checkpointLevel are dropped.
std::atomic< size_t > _ruleCheckingAverageCumulativeTime
Cumulative per-thread-average rule-checking time.
std::atomic< size_t > _runnerStateAdvanceThreadRawTime
Summed per-thread runner-advance time for the step.
size_t _baseStateBatch
Active base-state pull batch size ("Base State Batch Size").
auto getWinStatesFound() const
Returns the cumulative number of win states found so far.
std::atomic< size_t > _calculateHashThreadRawTime
Summed per-thread hash-calculation time for the step.
size_t getInputHistoryApproxMemoryBytes() const
Current (approximate) live memory (bytes) of the shared input-history backing; 0 for None/Raw.
std::atomic< size_t > _ruleCheckingAverageTime
Per-thread-average rule-checking time for the step.
std::atomic< size_t > _droppedStatesNoStorage
Counter for states dropped due to lack of free states.
Engine(const nlohmann::json &emulatorConfig, const nlohmann::json &gameConfig, const nlohmann::json &runnerConfig, const nlohmann::json &engineConfig)
Constructs the engine, building one runner per worker thread and the state/hash databases.
std::atomic< size_t > _totalNewStatesProcessed
New states processed across all steps so far.
size_t _checkpointLevel
Highest checkpoint level reached so far.
std::mutex _manualSaveSolutionLock
Guards updates to _manualSaveSolution.
~Engine()
Frees the best-win and manual-save state buffers allocated in initialize.
std::atomic< size_t > _getCandidateInputsThreadRawTime
Summed per-thread get-candidate-inputs time for the step.
size_t getCheckpointTolerance() const
Returns the current state's checkpoint tolerance.
bool isSaveSolution() const
Indicates whether the current state should trigger a save solution.
ssize_t getSaveSolutionCurrentLastRuleIdx() const
Returns the current last rule index that set a save solution.
void updateReward()
Recomputes the current state's reward from the satisfied rules.
size_t getCheckpointLevel() const
Returns the current state's checkpoint level.
void evaluateRules()
Evaluates the rule set against the current state.
float getReward() const
Returns the current state's reward.
void updateGameStateType()
Recomputes the state type and checkpoint level from the satisfied rules.
stateType_t getStateType() const
Returns the current state type (normal, win or fail).
@ normal
No win or fail rule is currently satisfied.
@ fail
A fail rule is currently satisfied.
@ win
A win rule is currently satisfied.
const std::string getSaveSolutionPath() const
Returns the save path of the rule that activated the current save solution.
Owns a Game instance and advances it according to configured inputs.
static std::unique_ptr< Runner > getRunner(const nlohmann::json &emulatorConfig, const nlohmann::json &gameConfig, const nlohmann::json &runnerConfig)
Creates a runner from the emulator, game and runner configurations.
void advanceState(const InputSet::inputIndex_t inputIdx)
Advances the game by one input, then by the configured number of frameskip frames.
void setSearchStep(const size_t searchStep)
Sets the step counter from a search step.
jaffarCommon::hash::hash_t computeHash() const
Computes a hash of the current runner state.
Game * getGame() const
Returns a pointer to the owned game instance.
size_t getStepCount() const
Returns the current step counter (number of inputs applied / the state's depth).
#define JAFFAR_PROF_ACC(field, var)
Accumulates the microseconds elapsed since timestamp var into field.
#define JAFFAR_PROF_DECL(var)
Declares a timestamp variable var holding the current time (detailed-profiling build).
Abstract base for a JaffarPlus game: wraps an emulator, registers game properties,...
Two-tier (per-domain L1 + shared global L2) hash database used to deduplicate visited search states,...
NUMA topology detection: distance/preference matrices and per-domain delegate-thread selection,...
void initializeNUMA()
Initializes NUMA / core-affinity state.
Drives a Game forward one input at a time, managing the allowed/candidate input sets,...
Per-NUMA-domain database of serialized game states, with reward-ordered queues that feed the search o...
A manually saved solution: its input path, reward, serialized state, and triggering rule index.
ssize_t lastRuleIdx
Index of the last rule active when the state was saved.
float reward
Reward of the saved state.
std::string path
Input sequence (solution path) that reached the saved state.
size_t stepCount
Depth (input count) of the saved state, recorded at capture.
void * stateData
Raw buffer holding the serialized saved state, or nullptr if unset.
A reward value paired with a serialized state buffer.
size_t stepCount
Depth (input count) of the saved state, recorded at capture (the count is not serialized per-state).
void * stateData
Raw buffer holding the serialized state, or nullptr if unset.
float reward
Reward associated with the stored state.
Per-thread accumulator for timing and counters.
size_t normalStates
Number of normal states produced.
size_t runnerStateAdvance
Time spent advancing the runner state with an input.
size_t baseStatesProcessed
Number of base states this thread expanded.
size_t calculateHash
Time spent computing state hashes.
size_t getAllowedInputs
Time spent querying the runner's allowed inputs.
size_t droppedStatesCheckpoint
Number of states dropped for not meeting the checkpoint.
void reset()
Resets all timers and counters to zero.
size_t getCandidateInputs
Time spent querying the runner's candidate inputs.
size_t droppedStatesFailedSerialization
Number of states dropped due to failed serialization.
size_t runnerStateLoad
Time spent loading states into the runner.
size_t repeatedStates
Number of states dropped as repeated.
size_t runnerStateSave
Time spent saving runner states into the state database.
size_t newStatesProcessed
Number of new states this thread produced via inputs.
size_t popBaseStateDb
Time spent popping base-state batches from the state database.
size_t failedStates
Number of states classified as failures.
size_t calculateReward
Time spent computing state rewards.
size_t checkHash
Time spent checking hashes against the hash database.
size_t returnFreeState
Time spent returning state slots to the free queue.
size_t droppedStatesNoStorage
Number of states dropped for lack of free storage.
size_t ruleChecking
Time spent evaluating rules and determining state type.
size_t winStates
Number of win states produced.
size_t getFreeState
Time spent acquiring free state slots.