diff options
| author | Scott Gasch <[email protected]> | 2026-10-05 13:05:34 -0700 |
|---|---|---|
| committer | Scott Gasch <[email protected]> | 2026-10-05 13:05:34 -0700 |
| commit | bb7cdcda4c8c30ad0ed71d0f60427daf05977b24 (patch) | |
| tree | 99a5a3f9fa6edcced73d966df0af07274ff67962 /src | |
| parent | 5d9a5cf4036d07252e81d51e78e6dd36e65c9275 (diff) | |
New telemetry.
Diffstat (limited to 'src')
| -rwxr-xr-x | src/chess.h | 24 | ||||
| -rw-r--r-- | src/root.c | 44 | ||||
| -rw-r--r-- | src/search.c | 21 | ||||
| -rw-r--r-- | src/searchsup.c | 13 |
4 files changed, 96 insertions, 6 deletions
diff --git a/src/chess.h b/src/chess.h index 420e313..b9cba3d 100755 --- a/src/chess.h +++ b/src/chess.h @@ -1014,6 +1014,14 @@ MOVE_STACK; // which would have been a search-behavior change rather than a fix. #define JOINT_EXTRA_TIER_COUNT (6) +// Null-move R-factor breakdown (post-move dump, root.c) -- bucketed by +// SelectNullmoveRFactor's whole-ply R value (searchsup.c). R is +// currently TWO_PLY (sparse material) or THREE_PLY + depth/6 (Crafty- +// style growth), so real traffic never gets near this bound; sized +// with headroom and clamped at the top bucket rather than tied exactly +// to a formula that might grow later. +#define NULL_R_BUCKETS (12) + // 2026-10-03: PRUNE_VERIFY (GNUmakefile) -- shadow verification for the // DEEP PRUNE gate (ShouldLatePrune), answering a question the LMR-side // JOINT_EXTRA_VERIFY cannot: "this move was about to be skipped @@ -1241,6 +1249,16 @@ typedef struct _COUNTERS // leftover pool near the leaves. Counts every move this was // applied to. UINT64 u64LMPPruned; + // 2026-10-05: extended futility pruning (EFP, search.c) -- same + // shape as u64LMPPruned above, for the other overt-skip (not + // reduction) mechanism in the move loop. + UINT64 u64EFPPruned; + // 2026-10-05: null-move R-factor breakdown -- which whole-ply R + // SelectNullmoveRFactor chose, and how often the null-move + // search at that R actually failed high. Indexed by R/ONE_PLY, + // clamped to NULL_R_BUCKETS - 1. + UINT64 u64NullMoveTriesByR[NULL_R_BUCKETS]; + UINT64 u64NullMoveSuccessByR[NULL_R_BUCKETS]; #ifdef PRUNE_VERIFY // [predicted-FH band][shipped depth bucket] -- see // PRUNE_VERIFY_BANDS above. Tries = moves the deep-prune gate @@ -1985,6 +2003,9 @@ typedef struct _GAME_OPTIONS UINT64 u64JointExtraTries[JOINT_EXTRA_TIER_COUNT]; UINT64 u64JointExtraResearch[JOINT_EXTRA_TIER_COUNT]; UINT64 u64LMPPruned; + UINT64 u64EFPPruned; + UINT64 u64NullMoveTriesByR[NULL_R_BUCKETS]; + UINT64 u64NullMoveSuccessByR[NULL_R_BUCKETS]; #ifdef PRUNE_VERIFY UINT64 u64PruneVerifyTries[PRUNE_VERIFY_BANDS][SHIP_DEPTH_BUCKETS]; UINT64 u64PruneVerifyFailHigh[PRUNE_VERIFY_BANDS][SHIP_DEPTH_BUCKETS]; @@ -3735,7 +3756,8 @@ TryNullmovePruning(IN OUT SEARCHER_THREAD_CONTEXT *ctx, IN SCORE iBeta, IN ULONG uNullDepth, IN OUT INT *piOrigExtend, - OUT SCORE *piNullScore); + OUT SCORE *piNullScore, + IN ULONG uNullRBucket); void UpdatePV(SEARCHER_THREAD_CONTEXT *ctx, MOVE mv); @@ -469,6 +469,45 @@ Return value: Trace("Null move cutoff rate: %5.3f percent.\n", ((n / d) * 100.0)); #ifdef PERF_COUNTERS + Trace("Overt move skips: LMP=%llu EFP=%llu moves.\n", + ctx->sCounters.tree.u64LMPPruned, + ctx->sCounters.tree.u64EFPPruned); + { + ULONG uR; + UINT64 u64TotalTries = 0; + for (uR = 0; uR < NULL_R_BUCKETS; uR++) + { + u64TotalTries += ctx->sCounters.tree.u64NullMoveTriesByR[uR]; + } + u64TotalTries += (0 == u64TotalTries); // avoid /0 if never tried + Trace("Null move (R): tries/successes, successes%% of ALL null-move " + "tries (sums to the overall cutoff rate above):\n"); + for (uR = 0; uR < NULL_R_BUCKETS; uR++) + { + UINT64 u64Tries = ctx->sCounters.tree.u64NullMoveTriesByR[uR]; + if (0 == u64Tries) continue; + Trace(" %u/%" COMPILER_LONGLONG_UNSIGNED_FORMAT + "/%" COMPILER_LONGLONG_UNSIGNED_FORMAT + "(%.1f%%)", + uR, u64Tries, + ctx->sCounters.tree.u64NullMoveSuccessByR[uR], + 100.0 * (double)ctx->sCounters.tree.u64NullMoveSuccessByR[uR] / + (double)u64TotalTries); + } + Trace("\n"); + } + { + ULONG uTier; + Trace("LMR reductions (plies):"); + for (uTier = 0; uTier < JOINT_EXTRA_TIER_COUNT; uTier++) + { + UINT64 u64Tries = ctx->sCounters.tree.u64JointExtraTries[uTier]; + if (0 == u64Tries) continue; + Trace(" %u/%" COMPILER_LONGLONG_UNSIGNED_FORMAT, + uTier + 1, u64Tries); + } + Trace("\n"); + } // 2026-10-03: percentages added, each against the count of nodes of // THAT TYPE (u64NodeTypeCount, incremented in CommonSearchInit), // not against total nodes -- dividing by total nodes understates @@ -1629,6 +1668,11 @@ Return value: memcpy(g_Options.u64JointExtraResearch, ctx->sCounters.tree.u64JointExtraResearch, sizeof(g_Options.u64JointExtraResearch)); g_Options.u64LMPPruned = ctx->sCounters.tree.u64LMPPruned; + g_Options.u64EFPPruned = ctx->sCounters.tree.u64EFPPruned; + memcpy(g_Options.u64NullMoveTriesByR, ctx->sCounters.tree.u64NullMoveTriesByR, + sizeof(g_Options.u64NullMoveTriesByR)); + memcpy(g_Options.u64NullMoveSuccessByR, ctx->sCounters.tree.u64NullMoveSuccessByR, + sizeof(g_Options.u64NullMoveSuccessByR)); #ifdef PRUNE_VERIFY memcpy(g_Options.u64PruneVerifyTries, ctx->sCounters.tree.u64PruneVerifyTries, sizeof(g_Options.u64PruneVerifyTries)); diff --git a/src/search.c b/src/search.c index ee055a4..ccaae74 100644 --- a/src/search.c +++ b/src/search.c @@ -458,6 +458,7 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, INT iPositionalExtend = 0; INT iExtend; ULONG uNextDepth; + ULONG uNullR; ULONG uLegalMoves = 0; FLAG fIsLeftoverMove = FALSE; // Stamped once below, right after this node's own Eval() call and @@ -631,7 +632,8 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, (!IS_CHECKING_MOVE(mvLast) && (FALSE == pi->fInCheck))); // Prepare next depth for nullmove and hashtable lookup - uNextDepth = uDepth - SelectNullmoveRFactor(ctx, uDepth) - ONE_PLY; + uNullR = SelectNullmoveRFactor(ctx, uDepth); + uNextDepth = uDepth - uNullR - ONE_PLY; if (uNextDepth > MAX_DEPTH_PER_SEARCH) uNextDepth = 0; // Check the transposition table. This may give us a cutoff @@ -862,13 +864,22 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, iImprovement, uNextDepth)) { + ULONG uNullRBucket = uNullR / ONE_PLY; + if (uNullRBucket >= NULL_R_BUCKETS) + { + uNullRBucket = NULL_R_BUCKETS - 1; + } +#ifdef PERF_COUNTERS + INC(ctx->sCounters.tree.u64NullMoveTriesByR[uNullRBucket]); +#endif if (TryNullmovePruning(ctx, &fThreat, iAlpha, iBeta, uNextDepth, &iPositionalExtend, - &iScore)) + &iScore, + uNullRBucket)) { if (iScore > iBeta) { @@ -1407,6 +1418,12 @@ Search(IN SEARCHER_THREAD_CONTEXT *ctx, #endif } } +#ifdef PERF_COUNTERS + if (TRUE == fThisMoveEFPPruned) + { + INC(ctx->sCounters.tree.u64EFPPruned); + } +#endif // If neither LMP nor EFP fired, we are going to search below // this move. But if the move is very late, we might reduce diff --git a/src/searchsup.c b/src/searchsup.c index 2bbf1ef..9e11631 100644 --- a/src/searchsup.c +++ b/src/searchsup.c @@ -999,8 +999,11 @@ Parameters: Return value: FLAG : TRUE iff mv should be pruned outright (skipped, not merely - reduced) -- see search.c's call site comment for why that's - currently audit-only, not wired to actually skip the move. + reduced). Live, not audit-only: search.c's move loop actually + `continue`s past mv when this returns TRUE (the same final check + that consumes fThisMoveEFPPruned), after INCrementing + u64LMPPruned for the script-summary "late-move pruning (overt + skip, not reduction)" line under PERF_COUNTERS. **/ { @@ -2306,7 +2309,8 @@ TryNullmovePruning(SEARCHER_THREAD_CONTEXT *ctx, SCORE iBeta, ULONG uNullDepth, INT *piOrigExtend, - SCORE *piNullScore) + SCORE *piNullScore, + ULONG uNullRBucket) { static INT _bm_by_piece[7] = { -1, -1, QUARTER_PLY, QUARTER_PLY, HALF_PLY, HALF_PLY, -1 @@ -2367,6 +2371,9 @@ TryNullmovePruning(SEARCHER_THREAD_CONTEXT *ctx, // Nullmove succeeded and either no need to verify or verify // succeeded too. INC(ctx->sCounters.tree.u64NullMoveSuccess); +#ifdef PERF_COUNTERS + INC(ctx->sCounters.tree.u64NullMoveSuccessByR[uNullRBucket]); +#endif if (*piNullScore > +NMATE) *piNullScore = +NMATE; return TRUE; } |
