summaryrefslogtreecommitdiff
path: root/src/root.c
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-10-20 19:46:51 -0700
committerScott Gasch <[email protected]>2026-10-20 19:46:51 -0700
commit6b883e83935f5e8110788565cfcb77cd6fbf8950 (patch)
tree2ed8ca325c45edcf65bac76a20ba47e8fe8a348e /src/root.c
parent4e6e78fc767985b9a06ce0fc5dda392027bcc25a (diff)
Restore 5D-alpha + 4D-beta FH% collection (improve axis + whole-node bucket), fix two bugs found via validation
Restores the full dual-table FH% collection instrumentation under FH_TABLE_COLLECTION, which had regressed to a 4D-only alpha joint with no beta side at all (see the prior commit's note): adds back the `improve` axis to the alpha joint and a new 4D beta joint (depth, gap-to-beta, own-improve, enemy-improve), both with real INC() call sites and ALPHARAW/BETARAW/ESTRAW dump lines matching dual_table_run/'s existing (unmodified) aggregate.py/dashboard.py/marginal_crosscheck.py parsers exactly. Also adds a genuine NODE-level sample into the alpha table's previously unused late==0 bucket: "will something at this node fail high" when iEval <= iAlpha, ground truth = the real move loop's outcome. This is the alpha-side analog of the beta table (which only covers iEval > iBeta) -- together they cover every null-window child's self-estimate with no gap, motivating a follow-up (not part of this change) on combining a parent's per-move FH% prediction with a child's own node-level self-estimate for a sharper NODE_CUT/NODE_ALL signal than CommonSearchInit's current purely-structural PVS alternation. Collecting real ground truth for both new node-level samples requires not taking the beta-side static-null-move shortcut's early `goto end` during collection builds, same reasoning as the existing LMP disable. Two bugs found and fixed via validation before trusting this for a multi-day run: 1. goto-skips-initializer: Search()'s early QSearch-depth `goto end` jumped over the new collection variables' declarations, leaving them uninitialized (indeterminate stack garbage) on that path. Only manifested in the release (-O3) build -- a DEBUG (-O0) build worked by accident (the skipped stack slots happened to read as zero). Caught via lldb on a real segfault: garbage "eligible" flags feeding wildly out-of-range array indices. Fixed by moving the declarations before the early goto. 2. MAX_SPLITS amplification: the new arrays were nested inside COUNTERS.tree, which is embedded both in SEARCHER_THREAD_CONTEXT and in split.c's g_SplitInfo[MAX_SPLITS] array -- so the ~19MB growth got replicated 64x, inflating the binary's BSS from ~220MB to ~1.47GB and breaking valgrind's fixed-address mmap outright (harmless at runtime for a --cpus 1 collection shard, since g_SplitInfo's copies are never touched, but it also meant any real MP split would have silently lost a helper thread's collected data, since no merge-back code exists for these fields). Fixed by moving them into a new standalone FH_COLLECTION_COUNTERS struct referenced only from SEARCHER_THREAD_CONTEXT, not from SPLIT_INFO. BSS dropped to ~281MB; valgrind (--track-origins=yes) now runs clean: 0 errors, 0 bytes definitely/indirectly/possibly lost. Validated end-to-end against real NNUE weights (--nnueweights eval.nnue), release build, full tests/ecm_ringers.ep_ suite at sd 10: ALPHARAW/BETARAW/ESTRAW all populated (including real late==0 "whole node" rows), dual_table_run/'s existing aggregate.py and marginal_crosscheck.py parse it unmodified -- depth/gap/improve axes match exactly; the only two "mismatches" (dumb and late bucket 0) are exactly and fully explained by the new whole-node samples, which deliberately don't feed those two per-move marginals (hang=0/late=0 are placeholders there, not real measurements) -- not a real bug, and reproduced byte-for-byte identical after the struct relocation above. Co-Authored-By: Claude Sonnet 5 <[email protected]>
Diffstat (limited to 'src/root.c')
-rw-r--r--src/root.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/src/root.c b/src/root.c
index f686efa..140c662 100644
--- a/src/root.c
+++ b/src/root.c
@@ -1689,6 +1689,36 @@ Return value:
sizeof(g_Options.u64NullMoveTriesByR));
memcpy(g_Options.u64NullMoveSuccessByR, ctx->sCounters.tree.u64NullMoveSuccessByR,
sizeof(g_Options.u64NullMoveSuccessByR));
+#ifdef FH_TABLE_COLLECTION
+ memcpy(g_Options.u64Alpha5Tries, ctx->sFhCollection.u64Alpha5Tries,
+ sizeof(g_Options.u64Alpha5Tries));
+ memcpy(g_Options.u64Alpha5FH, ctx->sFhCollection.u64Alpha5FH,
+ sizeof(g_Options.u64Alpha5FH));
+ memcpy(g_Options.u64BetaTries, ctx->sFhCollection.u64BetaTries,
+ sizeof(g_Options.u64BetaTries));
+ memcpy(g_Options.u64BetaFH, ctx->sFhCollection.u64BetaFH,
+ sizeof(g_Options.u64BetaFH));
+ memcpy(g_Options.u64ImproveEstimateTries, ctx->sFhCollection.u64ImproveEstimateTries,
+ sizeof(g_Options.u64ImproveEstimateTries));
+ memcpy(g_Options.u64ImproveEstimateFH, ctx->sFhCollection.u64ImproveEstimateFH,
+ sizeof(g_Options.u64ImproveEstimateFH));
+ memcpy(g_Options.u64BetaDepthEstimateTries, ctx->sFhCollection.u64BetaDepthEstimateTries,
+ sizeof(g_Options.u64BetaDepthEstimateTries));
+ memcpy(g_Options.u64BetaDepthEstimateFH, ctx->sFhCollection.u64BetaDepthEstimateFH,
+ sizeof(g_Options.u64BetaDepthEstimateFH));
+ memcpy(g_Options.u64BetaGapEstimateTries, ctx->sFhCollection.u64BetaGapEstimateTries,
+ sizeof(g_Options.u64BetaGapEstimateTries));
+ memcpy(g_Options.u64BetaGapEstimateFH, ctx->sFhCollection.u64BetaGapEstimateFH,
+ sizeof(g_Options.u64BetaGapEstimateFH));
+ memcpy(g_Options.u64BetaOwnImpEstimateTries, ctx->sFhCollection.u64BetaOwnImpEstimateTries,
+ sizeof(g_Options.u64BetaOwnImpEstimateTries));
+ memcpy(g_Options.u64BetaOwnImpEstimateFH, ctx->sFhCollection.u64BetaOwnImpEstimateFH,
+ sizeof(g_Options.u64BetaOwnImpEstimateFH));
+ memcpy(g_Options.u64BetaEnemyImpEstimateTries, ctx->sFhCollection.u64BetaEnemyImpEstimateTries,
+ sizeof(g_Options.u64BetaEnemyImpEstimateTries));
+ memcpy(g_Options.u64BetaEnemyImpEstimateFH, ctx->sFhCollection.u64BetaEnemyImpEstimateFH,
+ sizeof(g_Options.u64BetaEnemyImpEstimateFH));
+#endif // FH_TABLE_COLLECTION
#ifdef JOINT_EXTRA_VERIFY
memcpy(g_Options.u64JointExtraVerifyTries, ctx->sCounters.tree.u64JointExtraVerifyTries,
sizeof(g_Options.u64JointExtraVerifyTries));