Skip to content

Latest commit

 

History

History
72 lines (56 loc) · 3.65 KB

File metadata and controls

72 lines (56 loc) · 3.65 KB

Simulator performance mode

The simulator has two execution modes with the same game-rule path:

  • Debug/default: Simulator(cards) retains its existing public API and records a complete replay after every action.
  • Training: Simulator(cards, record_replay=False) keeps the same rules, validation, event ordering, rewards, and terminal detection, but does not serialize debug replay snapshots. step_fast() executes that same action path without producing the unused defensive state clone returned by the public step() API. SelfPlayRunner uses this mode automatically.

GameState.clone_for_search() remains the isolation boundary for MCTS branches. MCTS now keeps legal actions and their priors at expansion time, then clones and executes a successor only when PUCT selects it. Thus an unvisited legal action never allocates a full independent state; when it is visited, it uses the exact same Action.execute() rule implementation.

Reproducible profiler

Run the API-level profiler from the repository root:

D:\KardsAI\training-venv-py312\Scripts\python.exe tools\profile_simulator.py --games 12 --max-steps 300 --seed 71
D:\KardsAI\training-venv-py312\Scripts\python.exe tools\profile_simulator.py --games 12 --max-steps 300 --seed 71 --no-replay --training-path

Measured on the local machine before the MCTS lazy-child change (same random games, 1,469 steps):

Path Games/s Steps/s CPU Main elapsed work
Public debug API 6.34 776.5 97.5% replay 1.28s, state clones 0.35s
Training path 44.35 5,429.2 98.2% action validation/generation

This is a 7.0x end-to-end speed-up for identical games through the two execution modes. tracemalloc on an 8-game / 925-step run reduced peak Python allocations from 36.56 MiB to 4.99 MiB. The post-change CUDA MCTS benchmark (benchmark_selfplay.py --episodes 1 --simulations 64 --max-actions 300 --workers 1) measured 0.1174 games/s, compared with 0.0577 games/s before lazy MCTS child generation in this checkout.

Profiling conclusions

The native rule engine pre-parses card data when CardDatabase is loaded and caches the resulting rule objects by card ID. Card text is not parsed in the turn loop. High-frequency action generation now also reads cached static action-shape facts rather than repeatedly scanning each card rule.

The remaining primary cost in neural MCTS is deliberate search work: independent state branches, action validation, and policy/value inference. For higher GPU use, run independent self-play workers through the existing SelfPlayRunner.run_parallel() / training worker configuration. Each worker has its own simulator state and seed; static card definitions are not mutated.

Training-stage facilities

tools/benchmark_training.py reports the four training-relevant rates in one run: public random simulation, clone-free step_fast, MCTS self-play, and raw network inference. It prints games/s, steps/s, and legal candidate actions/s (network prints inference and batch rates).

MCTS now uses prior-ordered progressive widening. All legal actions are still generated by the normal validator and remain eligible; the high-prior subset is materialised first and the allowed width grows with square-root visits. A virtual-visit accounting field is included in PUCT so future parallel tree selection does not select the same pending branch repeatedly.

VectorizedSelfPlay provides independent simulator lanes with a shared BatchedInference queue. It is intended for GPU-backed MCTS: rule states remain local to each lane while policy/value requests from concurrent lanes are coalesced into GPU batches.