bench: add repeatable solver measurements

Add an opt-in benchmark probe and JSON runner that separate solve, construction, validation, and rendering time. Record stable search counters, environment metadata, warm-up and repetition policy, timeouts, errors, median spread, and instrumentation overhead.

Compile production solving without counters and interleave counted and plain trials when measuring overhead. Keep heavyweight cases outside the default correctness path while testing counter and report behavior cheaply.

Tests: Debug and Release CTest suites (7 passed each)

Refs: #8
This commit is contained in:
Codex instance
2026-07-30 17:08:05 +01:00
parent ce39d0a4d0
commit 598667b2f3
7 changed files with 555 additions and 1 deletions
+23
View File
@@ -281,6 +281,26 @@ namespace {
return failures;
}
auto test_search_counters() -> int {
SearchCounters counters;
auto const solution = find_solution_instrumented(2, counters);
int failures = 0;
failures += expect(solution.squares().empty(),
"instrumented solver changed an infeasible result");
failures += expect(counters.search_nodes > 0 &&
counters.loop_iterations >= counters.search_nodes,
"instrumented solver did not count search work");
failures += expect(counters.attempted_placements > 0 &&
counters.backtracks > 0,
"instrumented solver did not count placements/backtracks");
failures += expect(counters.prune_checks == 0 &&
counters.prune_hits == 0 &&
counters.generated_tasks == 0 &&
counters.completed_tasks == 0,
"unimplemented solver counters were not zero");
return failures;
}
auto test_solver_completion() -> int {
int failures = 0;
for (auto const order: std::array<std::uint64_t, 2>{1, 8}) {
@@ -317,6 +337,9 @@ int main(int argc, char **argv) {
if (test == "solver-completion") {
return test_solver_completion();
}
if (test == "search-counters") {
return test_search_counters();
}
std::cerr << "unknown test: " << test << '\n';
return 2;
}