Skip to main content

Performance Toolkit

The performance toolkit includes a lightweight benchmarking and fuzzing harness so you can keep an eye on hot paths as the engine evolves. Everything lives in-repo—no external datasets needed.

Criterion benches

Run the core suite with:

cargo bench -p tiletangle-engine

The benchmarks cover dictionary lookups, move generation on empty/mid-game boards, and greedy AI search (depth 0/1). HTML reports land in target/criterion. Enable the optional parallel evaluator with the parallel feature:

cargo bench -p tiletangle-engine --features parallel
Pre-recorded run showing baseline vs current Criterion timings.
Click the button to fetch a canned benchmark run.

After running the suite locally you can diff against the checked-in baseline:

./tools/report_bench.py --baseline bench/baselines/main.json

Optional parallel evaluation

When the parallel feature is enabled and AiConfig::parallel_eval is set to true, the greedy AI can fan out candidate evaluation on the root ply when heuristics are deterministic (no noise, no node/time budget). Bindings expose a parallel_eval flag on best_move_greedy so tooling can opt in.

SIMD scoring (optional)

Enable the simd feature to use small vector lanes when scoring words under the default StackScoring::TopOnly policy. The engine folds the per-letter score × multiplier products in chunks of four using the wide crate, which keeps the evaluation fast even when bingo bonuses and word multipliers stack up.

cargo bench -p tiletangle-engine --features simd

The feature is an additive optimisation—behaviour stays identical with or without it, so you can leave it off for targets where SIMD isn't available.

Fuzz harnesses

A minimal cargo fuzz setup lives under fuzz/:

  • fuzz_config_load throws random JSON at GameConfig deserialisation and GameState::new.
  • fuzz_move_draft generates placements around the centre cell and runs them through CrosswordRules::validate / commit.

Run them with (requires nightly and cargo fuzz installed):

cargo fuzz run fuzz_config_load
cargo fuzz run fuzz_move_draft

Artifacts land in fuzz/artifacts/; keep interesting crashes around for regression suites.

Tips

  • Bake cargo bench --features parallel into your CI matrix to catch regressions when the parallel evaluator is enabled.
  • Fuzz harnesses are intentionally small—extend them with richer board setups or rule plugins as your variants expand.
  • Criterion profiles are deterministic; commit the generated summary tables when you need to track a specific performance budget over time.
  • Example CI gate: compare results against the stored baseline and fail the build on ≥2× regression. A complementary job can exercise the fuzz harnesses for a short, fixed budget with libFuzzer.

Memory profiling

Use the same sample configs in bench/ to capture heap behaviour:

  • Linux: valgrind --tool=massif cargo run -p tiletangle-engine --example stress for timeline snapshots, or heaptrack cargo bench -p tiletangle-engine for flamegraphs.
  • macOS: Instruments' "Allocations" template pairs well with cargo bench --profile release.
  • Windows: run cargo bench under the Visual Studio Diagnostic Tools or wpaexporter for sampling traces.

Remember to build without --features parallel when profiling single-threaded behaviour—this keeps the traces easier to interpret. For detailed leak hunts, recompile with RUSTFLAGS="-Zsanitizer=address" on nightly and run the benches under AddressSanitizer.