From 41acbcae1a8af4b23be397f7fe7234f3bc49a26e Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Wed, 29 May 2024 16:14:24 +0300 Subject: [PATCH 01/32] Simplifying malus for putting piece en prise formula Patch author: @ehsanrashid Passed STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 116192 W: 30229 L: 30094 D: 55869 Ptnml(0-2): 451, 13880, 29351, 13911, 503 https://tests.stockfishchess.org/tests/view/66510a40a86388d5e27da936 Passed LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 441312 W: 111009 L: 111220 D: 219083 Ptnml(0-2): 217, 49390, 121659, 49167, 223 https://tests.stockfishchess.org/tests/view/66530696a86388d5e27da9e3 closes https://github.com/official-stockfish/Stockfish/pull/5304 Bench: 1987574 --- AUTHORS | 1 + src/movepick.cpp | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/AUTHORS b/AUTHORS index 36b2b6f79..a232e115f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -68,6 +68,7 @@ Douglas Matos Gomes (dsmsgms) Dubslow Eduardo Cáceres (eduherminio) Eelco de Groot (KingDefender) +Ehsan Rashid (erashid) Elvin Liu (solarlight2) erbsenzaehler Ernesto Gatti diff --git a/src/movepick.cpp b/src/movepick.cpp index 7def0ce84..55f9ca0e8 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -197,13 +197,11 @@ void MovePicker::score() { : 0; // malus for putting piece en prise - m.value -= !(threatenedPieces & from) - ? (pt == QUEEN ? bool(to & threatenedByRook) * 48150 - + bool(to & threatenedByMinor) * 10650 - : pt == ROOK ? bool(to & threatenedByMinor) * 24335 - : pt != PAWN ? bool(to & threatenedByPawn) * 14950 - : 0) - : 0; + m.value -= (pt == QUEEN ? bool(to & threatenedByRook) * 48150 + + bool(to & threatenedByMinor) * 10650 + : pt == ROOK ? bool(to & threatenedByMinor) * 24335 + : pt != PAWN ? bool(to & threatenedByPawn) * 14950 + : 0); } else // Type == EVASIONS From c7b80f6c8a7b8267e019fc4ecb496f14f5256f3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Mon, 27 May 2024 04:32:04 +0200 Subject: [PATCH 02/32] Merge pawn count terms using their average This simplification patch merges the pawn count terms in the eval formula with the material term, updating the offset constant for the nnue part of the formula from 34000 to 34300 because the average pawn count in middlegame positions evaluated during search is around 8. STC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 138240 W: 35834 L: 35723 D: 66683 Ptnml(0-2): 527, 16587, 34817, 16626, 563 https://tests.stockfishchess.org/tests/view/6653f474a86388d5e27daaac LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 454272 W: 114787 L: 115012 D: 224473 Ptnml(0-2): 246, 51168, 124553, 50903, 266 https://tests.stockfishchess.org/tests/view/6654f256a86388d5e27db131 closes https://github.com/official-stockfish/Stockfish/pull/5303 Bench: 1279635 --- src/evaluate.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 13a3f2117..849b7bb68 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -77,12 +77,10 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, optimism += optimism * nnueComplexity / 470; nnue -= nnue * (nnueComplexity * 5 / 3) / 32621; - int material = 200 * pos.count() + 350 * pos.count() + 400 * pos.count() + int material = 300 * pos.count() + 350 * pos.count() + 400 * pos.count() + 640 * pos.count() + 1200 * pos.count(); - v = (nnue * (34000 + material + 135 * pos.count()) - + optimism * (4400 + material + 99 * pos.count())) - / 35967; + v = (nnue * (34300 + material) + optimism * (4400 + material)) / 35967; // Damp down the evaluation linearly when shuffling v = v * (204 - pos.rule50_count()) / 208; From c14297a483f7905d61e6f22068d33b199916257a Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Mon, 27 May 2024 01:21:32 -0700 Subject: [PATCH 03/32] Tune Fail Low Bonus Fractional bonus idea is from @Ergodice on [discord](https://discord.com/channels/435943710472011776/735707599353151579/1244039134499180614). Values are tuned for 149k games at LTC. SPSA tune: https://tests.stockfishchess.org/tests/view/6652d5d5a86388d5e27da9d6 Failed STC: LLR: -2.95 (-2.94,2.94) <0.00,2.00> Total: 67424 W: 17364 L: 17528 D: 32532 Ptnml(0-2): 238, 8043, 17299, 7909, 223 https://tests.stockfishchess.org/tests/view/66551e1ba86388d5e27db9f9 Passed LTC: LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 146910 W: 37141 L: 36695 D: 73074 Ptnml(0-2): 84, 16201, 40441, 16643, 86 https://tests.stockfishchess.org/tests/view/66559949a86388d5e27dcc5d Passed VLTC: LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 27248 W: 6924 L: 6633 D: 13691 Ptnml(0-2): 5, 2744, 7835, 3035, 5 https://tests.stockfishchess.org/tests/view/66563f4da86388d5e27dd27a closes https://github.com/official-stockfish/Stockfish/pull/5299 Bench: 1390709 --- src/search.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index c074e3421..425782ebf 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1341,18 +1341,19 @@ moves_loop: // When in check, search starts here // Bonus for prior countermove that caused the fail low else if (!priorCapture && prevSq != SQ_NONE) { - int bonus = (depth > 4) + (depth > 5) + (PvNode || cutNode) + ((ss - 1)->statScore < -14144) - + ((ss - 1)->moveCount > 9) + (!ss->inCheck && bestValue <= ss->staticEval - 115) - + (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 81); + int bonus = (54 * (depth > 4) + 62 * (depth > 5) + 115 * (PvNode || cutNode) + + 186 * ((ss - 1)->statScore < -14144) + 121 * ((ss - 1)->moveCount > 9) + + 64 * (!ss->inCheck && bestValue <= ss->staticEval - 115) + + 137 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 81)); update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, - stat_bonus(depth) * bonus); + stat_bonus(depth) * bonus / 100); thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] - << stat_bonus(depth) * bonus / 2; + << stat_bonus(depth) * bonus / 200; if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] - << stat_bonus(depth) * bonus * 4; + << stat_bonus(depth) * bonus / 25; } if (PvNode) From a2f4e988aa03a1011b671af07a152682e35b4617 Mon Sep 17 00:00:00 2001 From: mstembera Date: Tue, 28 May 2024 13:32:09 -0700 Subject: [PATCH 04/32] Fix MSVC NUMA compile issues closes https://github.com/official-stockfish/Stockfish/pull/5298 No functional change --- src/misc.h | 4 ++-- src/numa.h | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/misc.h b/src/misc.h index 99cbecfdd..ec7f7b76c 100644 --- a/src/misc.h +++ b/src/misc.h @@ -77,6 +77,8 @@ using AlignedPtr = std::unique_ptr>; template using LargePagePtr = std::unique_ptr>; +#if defined(__linux__) + struct PipeDeleter { void operator()(FILE* file) const { if (file != nullptr) @@ -86,8 +88,6 @@ struct PipeDeleter { } }; -#if defined(__linux__) - inline std::optional get_system_command_output(const std::string& command) { std::unique_ptr pipe(popen(command.c_str(), "r")); if (!pipe) diff --git a/src/numa.h b/src/numa.h index c04292daf..03ee1fdf1 100644 --- a/src/numa.h +++ b/src/numa.h @@ -51,6 +51,9 @@ static constexpr size_t WIN_PROCESSOR_GROUP_SIZE = 64; #define NOMINMAX #endif #include + #if defined small + #undef small + #endif // https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadselectedcpusetmasks using SetThreadSelectedCpuSetMasks_t = BOOL (*)(HANDLE, PGROUP_AFFINITY, USHORT); @@ -561,8 +564,8 @@ class NumaConfig { if (SetThreadSelectedCpuSetMasks_f != nullptr) { // Only available on Windows 11 and Windows Server 2022 onwards. - const USHORT numProcGroups = - ((highestCpuIndex + 1) + WIN_PROCESSOR_GROUP_SIZE - 1) / WIN_PROCESSOR_GROUP_SIZE; + const USHORT numProcGroups = USHORT( + ((highestCpuIndex + 1) + WIN_PROCESSOR_GROUP_SIZE - 1) / WIN_PROCESSOR_GROUP_SIZE); auto groupAffinities = std::make_unique(numProcGroups); std::memset(groupAffinities.get(), 0, sizeof(GROUP_AFFINITY) * numProcGroups); for (WORD i = 0; i < numProcGroups; ++i) From ae7eef51fde6d74f1a10269dec36bf6d80855a0a Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Tue, 28 May 2024 14:31:56 -0700 Subject: [PATCH 05/32] Simplify Fail Low Bonus Formula Tested against PR #5299 Passed Non-regression STC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 76352 W: 19797 L: 19619 D: 36936 Ptnml(0-2): 236, 9017, 19509, 9161, 253 https://tests.stockfishchess.org/tests/view/66564f60a86388d5e27dd307 Passed Non-regression LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 114624 W: 28946 L: 28821 D: 56857 Ptnml(0-2): 59, 12675, 31714, 12810, 54 https://tests.stockfishchess.org/tests/view/6656543da86388d5e27dd329 closes https://github.com/official-stockfish/Stockfish/pull/5301 Bench: 1212167 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 425782ebf..5e9f64763 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1341,7 +1341,7 @@ moves_loop: // When in check, search starts here // Bonus for prior countermove that caused the fail low else if (!priorCapture && prevSq != SQ_NONE) { - int bonus = (54 * (depth > 4) + 62 * (depth > 5) + 115 * (PvNode || cutNode) + int bonus = (116 * (depth > 5) + 115 * (PvNode || cutNode) + 186 * ((ss - 1)->statScore < -14144) + 121 * ((ss - 1)->moveCount > 9) + 64 * (!ss->inCheck && bestValue <= ss->staticEval - 115) + 137 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 81)); From 3c62ad7e077a5ed0ea7b55422e03e7316dcbce7e Mon Sep 17 00:00:00 2001 From: xoto10 <23479932+xoto10@users.noreply.github.com> Date: Tue, 28 May 2024 19:40:40 +0100 Subject: [PATCH 06/32] Add compensation factor to adjust extra time according to time control As stockfish nets and search evolve, the existing time control appears to give too little time at STC, roughly correct at LTC, and too little at VLTC+. This change adds an adjustment to the optExtra calculation. This adjustment is easy to retune and refine, so it should be easier to keep up-to-date than the more complex calculations used for optConstant and optScale. Passed STC 10+0.1: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 169568 W: 43803 L: 43295 D: 82470 Ptnml(0-2): 485, 19679, 44055, 19973, 592 https://tests.stockfishchess.org/tests/view/66531865a86388d5e27da9fa Yellow LTC 60+0.6: LLR: -2.94 (-2.94,2.94) <0.50,2.50> Total: 209970 W: 53087 L: 52914 D: 103969 Ptnml(0-2): 91, 19652, 65314, 19849, 79 https://tests.stockfishchess.org/tests/view/6653e38ba86388d5e27daaa0 Passed VLTC 180+1.8 : LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 85618 W: 21735 L: 21342 D: 42541 Ptnml(0-2): 15, 8267, 25848, 8668, 11 https://tests.stockfishchess.org/tests/view/6655131da86388d5e27db95f closes https://github.com/official-stockfish/Stockfish/pull/5297 Bench: 1212167 --- src/search.cpp | 2 +- src/search.h | 1 + src/thread.cpp | 1 + src/timeman.cpp | 14 ++++++++++++-- src/timeman.h | 8 ++++++-- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 5e9f64763..ec4ae79d5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -161,7 +161,7 @@ void Search::Worker::start_searching() { } main_manager()->tm.init(limits, rootPos.side_to_move(), rootPos.game_ply(), options, - main_manager()->originalPly); + main_manager()->originalPly, main_manager()->originalTimeAdjust); tt.new_search(); if (rootMoves.empty()) diff --git a/src/search.h b/src/search.h index a61f253c0..7cff10d55 100644 --- a/src/search.h +++ b/src/search.h @@ -208,6 +208,7 @@ class SearchManager: public ISearchManager { Depth depth) const; Stockfish::TimeManagement tm; + double originalTimeAdjust; int originalPly; int callsCnt; std::atomic_bool ponder; diff --git a/src/thread.cpp b/src/thread.cpp index 5893f4b6d..71134ead6 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -217,6 +217,7 @@ void ThreadPool::clear() { main_manager()->bestPreviousScore = VALUE_INFINITE; main_manager()->bestPreviousAverageScore = VALUE_INFINITE; main_manager()->originalPly = -1; + main_manager()->originalTimeAdjust = -1; main_manager()->previousTimeReduction = 1.0; main_manager()->tm.clear(); } diff --git a/src/timeman.cpp b/src/timeman.cpp index f389e082d..f6ca298a8 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -44,8 +44,12 @@ void TimeManagement::advance_nodes_time(std::int64_t nodes) { // the bounds of time allowed for the current game ply. We currently support: // 1) x basetime (+ z increment) // 2) x moves in y seconds (+ z increment) -void TimeManagement::init( - Search::LimitsType& limits, Color us, int ply, const OptionsMap& options, int& originalPly) { +void TimeManagement::init(Search::LimitsType& limits, + Color us, + int ply, + const OptionsMap& options, + int& originalPly, + double& originalTimeAdjust) { TimePoint npmsec = TimePoint(options["nodestime"]); // If we have no time, we don't need to fully initialize TM. @@ -100,6 +104,10 @@ void TimeManagement::init( TimePoint timeLeft = std::max(TimePoint(1), limits.time[us] + limits.inc[us] * (mtg - 1) - moveOverhead * (2 + mtg)); + // Extra time according to timeLeft + if (originalTimeAdjust < 0) + originalTimeAdjust = 0.2078 + 0.1623 * std::log10(timeLeft); + // x basetime (+ z increment) // If there is a healthy increment, timeLeft can exceed the actual available // game time for the current move, so also cap to a percentage of available game time. @@ -109,6 +117,7 @@ void TimeManagement::init( double optExtra = scaledInc < 500 ? 1.0 : 1.13; if (ply - originalPly < 2) optExtra *= 0.95; + optExtra *= originalTimeAdjust; // Calculate time constants based on current time left. double logTimeInSec = std::log10(scaledTime / 1000.0); @@ -118,6 +127,7 @@ void TimeManagement::init( optScale = std::min(0.0122 + std::pow(ply + 2.95, 0.462) * optConstant, 0.213 * limits.time[us] / timeLeft) * optExtra; + maxScale = std::min(6.64, maxConstant + ply / 12.0); } diff --git a/src/timeman.h b/src/timeman.h index 8f1bb5639..8b763089a 100644 --- a/src/timeman.h +++ b/src/timeman.h @@ -36,8 +36,12 @@ struct LimitsType; // the maximum available time, the game move number, and other parameters. class TimeManagement { public: - void init( - Search::LimitsType& limits, Color us, int ply, const OptionsMap& options, int& originalPly); + void init(Search::LimitsType& limits, + Color us, + int ply, + const OptionsMap& options, + int& originalPly, + double& originalTimeAdjust); TimePoint optimum() const; TimePoint maximum() const; From 4a2291ed337730e5093af1532d36acf1f066989b Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Thu, 23 May 2024 19:22:41 -0700 Subject: [PATCH 07/32] Simplify Away Quadruple Extension Passed non-regression VVLTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 90792 W: 23155 L: 23018 D: 44619 Ptnml(0-2): 6, 8406, 28432, 8549, 3 https://tests.stockfishchess.org/tests/view/664ffa4ca86388d5e27d8e7a Passed non-regression VLTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 288136 W: 72608 L: 72659 D: 142869 Ptnml(0-2): 38, 30258, 83525, 30211, 36 https://tests.stockfishchess.org/tests/view/66551609a86388d5e27db9ae closes https://github.com/official-stockfish/Stockfish/pull/5293 bench 1501735 --- src/search.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index ec4ae79d5..22e82be8f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1066,11 +1066,9 @@ moves_loop: // When in check, search starts here { int doubleMargin = 304 * PvNode - 203 * !ttCapture; int tripleMargin = 117 + 259 * PvNode - 296 * !ttCapture + 97 * ss->ttPv; - int quadMargin = 486 + 343 * PvNode - 273 * !ttCapture + 232 * ss->ttPv; extension = 1 + (value < singularBeta - doubleMargin) - + (value < singularBeta - tripleMargin) - + (value < singularBeta - quadMargin); + + (value < singularBeta - tripleMargin); depth += ((!PvNode) && (depth < 16)); } From 5ab3fe6db8ea7dff1310c792d66f2a906a5c19c5 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Tue, 28 May 2024 19:39:55 -0400 Subject: [PATCH 08/32] Simplify blending eval with nnue complexity Passed non-regression STC: https://tests.stockfishchess.org/tests/view/66567377a86388d5e27dd89c LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 144000 W: 37443 L: 37338 D: 69219 Ptnml(0-2): 587, 17260, 36208, 17351, 594 Passed non-regression LTC: https://tests.stockfishchess.org/tests/view/66567f29a86388d5e27dd924 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 112326 W: 28550 L: 28421 D: 55355 Ptnml(0-2): 66, 12732, 30434, 12869, 62 closes https://github.com/official-stockfish/Stockfish/pull/5305 bench 1554486 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 849b7bb68..666697ddd 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -75,7 +75,7 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, // Blend optimism and eval with nnue complexity optimism += optimism * nnueComplexity / 470; - nnue -= nnue * (nnueComplexity * 5 / 3) / 32621; + nnue -= nnue * nnueComplexity / 20000; int material = 300 * pos.count() + 350 * pos.count() + 400 * pos.count() + 640 * pos.count() + 1200 * pos.count(); From 0ea6337ccfffa39b665e3a8371fcde668dddf4aa Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Thu, 30 May 2024 03:36:38 +0300 Subject: [PATCH 09/32] Remove Queen threatenedByMinor Remove Queen threatenedByMinor from movepick Passed STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 54432 W: 14053 L: 13855 D: 26524 Ptnml(0-2): 124, 6347, 14090, 6517, 138 https://tests.stockfishchess.org/tests/view/66578d036b0e318cefa8d43d Passed LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 198168 W: 49979 L: 49940 D: 98249 Ptnml(0-2): 84, 21824, 55236, 21849, 91 https://tests.stockfishchess.org/tests/view/66579cf86b0e318cefa8d5b1 closes https://github.com/official-stockfish/Stockfish/pull/5306 bench: 1342438 --- src/movepick.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 55f9ca0e8..6c41916cd 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -197,8 +197,7 @@ void MovePicker::score() { : 0; // malus for putting piece en prise - m.value -= (pt == QUEEN ? bool(to & threatenedByRook) * 48150 - + bool(to & threatenedByMinor) * 10650 + m.value -= (pt == QUEEN ? bool(to & threatenedByRook) * 49000 : pt == ROOK ? bool(to & threatenedByMinor) * 24335 : pt != PAWN ? bool(to & threatenedByPawn) * 14950 : 0); From 35aff79843658aef55426d5d88be412f54d936b8 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Wed, 29 May 2024 21:18:55 -0400 Subject: [PATCH 10/32] Update default main net to nn-ddcfb9224cdb.nnue Created by further tuning the spsa-tuned main net `nn-c721dfca8cd3.nnue` with the same methods described in https://github.com/official-stockfish/Stockfish/pull/5254 This net was reached at 61k / 120k spsa games at 70+0.7 th 7: https://tests.stockfishchess.org/tests/view/665639d0a86388d5e27dd259 Passed STC: https://tests.stockfishchess.org/tests/view/6657d44e6b0e318cefa8d771 LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 114688 W: 29775 L: 29344 D: 55569 Ptnml(0-2): 274, 13633, 29149, 13964, 324 Passed LTC: https://tests.stockfishchess.org/tests/view/6657e1e46b0e318cefa8d7a6 LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 88152 W: 22412 L: 21988 D: 43752 Ptnml(0-2): 56, 9560, 24409, 10006, 45 closes https://github.com/official-stockfish/Stockfish/pull/5308 Bench: 1434678 --- src/evaluate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.h b/src/evaluate.h index 4b3e91acf..4fab1a001 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -33,7 +33,7 @@ namespace Eval { // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro or the location where this macro is defined, as it is used // in the Makefile/Fishtest. -#define EvalFileDefaultNameBig "nn-c721dfca8cd3.nnue" +#define EvalFileDefaultNameBig "nn-ddcfb9224cdb.nnue" #define EvalFileDefaultNameSmall "nn-baff1ede1f90.nnue" namespace NNUE { From a4ea183e7839f62665e706c13b508ccce86d5fd6 Mon Sep 17 00:00:00 2001 From: "Robert Nurnberg @ elitebook" Date: Thu, 30 May 2024 09:05:36 +0200 Subject: [PATCH 11/32] Tweak and update the WDL model This PR updates the internal WDL model, using data from 2.5M games played by SF-dev (3c62ad7). Note that the normalizing constant has increased from 329 to 368. Changes to the fitting procedure: * the value for --materialMin was increased from 10 to 17: including data with less material leads to less accuracy for larger material count values * the data was filtered to only include single thread LTC games at 60+0.6 * the data was filtered to only include games from master against patches that are (approximatively) within 5 nElo of master For more information and plots of the model see PR#5309 closes https://github.com/official-stockfish/Stockfish/pull/5309 No functional change --- src/uci.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/uci.cpp b/src/uci.cpp index ab0dae394..4b683116a 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -382,12 +382,12 @@ WinRateParams win_rate_params(const Position& pos) { int material = pos.count() + 3 * pos.count() + 3 * pos.count() + 5 * pos.count() + 9 * pos.count(); - // The fitted model only uses data for material counts in [10, 78], and is anchored at count 58. - double m = std::clamp(material, 10, 78) / 58.0; + // The fitted model only uses data for material counts in [17, 78], and is anchored at count 58. + double m = std::clamp(material, 17, 78) / 58.0; // Return a = p_a(material) and b = p_b(material), see github.com/official-stockfish/WDL_model - constexpr double as[] = {-150.77043883, 394.96159472, -321.73403766, 406.15850091}; - constexpr double bs[] = {62.33245393, -91.02264855, 45.88486850, 51.63461272}; + constexpr double as[] = {-41.25712052, 121.47473115, -124.46958843, 411.84490997}; + constexpr double bs[] = {84.92998051, -143.66658718, 80.09988253, 49.80869370}; double a = (((as[0] * m + as[1]) * m + as[2]) * m) + as[3]; double b = (((bs[0] * m + bs[1]) * m + bs[2]) * m) + bs[3]; @@ -428,8 +428,8 @@ std::string UCIEngine::format_score(const Score& s) { // without treatment of mate and similar special scores. int UCIEngine::to_cp(Value v, const Position& pos) { - // In general, the score can be defined via the the WDL as - // (log(1/L - 1) - log(1/W - 1)) / ((log(1/L - 1) + log(1/W - 1)) + // In general, the score can be defined via the WDL as + // (log(1/L - 1) - log(1/W - 1)) / (log(1/L - 1) + log(1/W - 1)). // Based on our win_rate_model, this simply yields v / a. auto [a, b] = win_rate_params(pos); From a77a895c3b7460f86b11a3ddfe3528f5be1276b9 Mon Sep 17 00:00:00 2001 From: Viren6 <94880762+Viren6@users.noreply.github.com> Date: Thu, 30 May 2024 08:18:04 +0100 Subject: [PATCH 12/32] Add extension condition to cutoffCnt Decrease cutoffCnt increment by 1 if extension is 2 or greater. Passed STC: https://tests.stockfishchess.org/tests/view/66577a696b0e318cefa8d34d LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 99200 W: 25703 L: 25297 D: 48200 Ptnml(0-2): 253, 11660, 25390, 12022, 275 Passed LTC: https://tests.stockfishchess.org/tests/view/665787ab6b0e318cefa8d411 LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 124530 W: 31659 L: 31161 D: 61710 Ptnml(0-2): 58, 13578, 34489, 14088, 52 closes https://github.com/official-stockfish/Stockfish/pull/5310 bench 1623228 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 22e82be8f..d72dbfa15 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1289,7 +1289,7 @@ moves_loop: // When in check, search starts here if (value >= beta) { - ss->cutoffCnt += 1 + !ttMove; + ss->cutoffCnt += 1 + !ttMove - (extension >= 2); assert(value >= beta); // Fail high break; } From d1a71fdaa7cc7d749495bbf5d63919a4a0b42303 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sat, 18 May 2024 17:54:13 +0300 Subject: [PATCH 13/32] Functional simplification in the transposition table Passed STC: LLR: 2.98 (-2.94,2.94) <-1.75,0.25> Total: 154848 W: 39838 L: 39750 D: 75260 Ptnml(0-2): 404, 16214, 44087, 16328, 391 https://tests.stockfishchess.org/tests/view/664892b088b8c6a2bbe430fc Passed LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 68172 W: 17296 L: 17137 D: 33739 Ptnml(0-2): 23, 6349, 21185, 6504, 25 https://tests.stockfishchess.org/tests/view/6648aabfa0781149e383e526 closes https://github.com/official-stockfish/Stockfish/pull/5263 Bench: 1623228 --- src/tt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tt.cpp b/src/tt.cpp index 79274f525..f95170e94 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -124,7 +124,7 @@ TTEntry* TranspositionTable::probe(const Key key, bool& found) const { const uint16_t key16 = uint16_t(key); // Use the low 16 bits as key inside the cluster for (int i = 0; i < ClusterSize; ++i) - if (tte[i].key16 == key16 || !tte[i].depth8) + if (tte[i].key16 == key16) return found = bool(tte[i].depth8), &tte[i]; // Find an entry to be replaced according to the replacement strategy From b280d2f06553e8c8d98379fe547f3b995cc56d59 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Thu, 30 May 2024 19:27:12 +0300 Subject: [PATCH 14/32] Allow tt cutoffs for shallower depths in certain conditions Current master allows tt cutoffs only when depth from tt is strictly greater than current node depth. This patch also allows them when it's equal and if tt value is lower or equal to beta. Passed STC: https://tests.stockfishchess.org/tests/view/66578e2e6b0e318cefa8d447 LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 26592 W: 6944 L: 6645 D: 13003 Ptnml(0-2): 67, 3039, 6795, 3318, 77 Passed LTC: https://tests.stockfishchess.org/tests/view/6657f46b6b0e318cefa8d7e9 LLR: 2.96 (-2.94,2.94) <0.50,2.50> Total: 142572 W: 36315 L: 35776 D: 70481 Ptnml(0-2): 70, 15666, 39288, 16179, 83 closes https://github.com/official-stockfish/Stockfish/pull/5314 Bench: 1368486 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index d72dbfa15..638af546d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -618,7 +618,7 @@ Value Search::Worker::search( ss->ttPv = PvNode || (ss->ttHit && tte->is_pv()); // At non-PV nodes we check for an early TT cutoff - if (!PvNode && !excludedMove && tte->depth() > depth + if (!PvNode && !excludedMove && tte->depth() > depth - (ttValue <= beta) && ttValue != VALUE_NONE // Possible in case of TT access race or if !ttHit && (tte->bound() & (ttValue >= beta ? BOUND_LOWER : BOUND_UPPER))) { From 02eae528330347b4c91f3d8fa4de7fc8629a5ac0 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Thu, 30 May 2024 20:44:21 +0300 Subject: [PATCH 15/32] Simplifying the malus for putting piece en prise formula Simplifying the malus for putting piece en prise formula by merging the minor pieces and pawns (removing the pawn exclusion from the formula). Passed STC: https://tests.stockfishchess.org/tests/view/66578d9c6b0e318cefa8d441 LLR: 2.99 (-2.94,2.94) <-1.75,0.25> Total: 314272 W: 80705 L: 80786 D: 152781 Ptnml(0-2): 873, 37577, 80366, 37398, 922 Passed LTC (before rebasing): https://tests.stockfishchess.org/tests/view/6657b5ee6b0e318cefa8d6ab LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 117000 W: 29447 L: 29324 D: 58229 Ptnml(0-2): 47, 12877, 32535, 12988, 53 Passed LTC (also after rebasing): https://tests.stockfishchess.org/tests/view/6658803d6b0e318cefa8fd99 LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 244992 W: 61807 L: 61814 D: 121371 Ptnml(0-2): 125, 27420, 67414, 27411, 126 closes https://github.com/official-stockfish/Stockfish/pull/5316 Bench: 1484840 --- src/movepick.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 6c41916cd..b6828a30b 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -199,8 +199,7 @@ void MovePicker::score() { // malus for putting piece en prise m.value -= (pt == QUEEN ? bool(to & threatenedByRook) * 49000 : pt == ROOK ? bool(to & threatenedByMinor) * 24335 - : pt != PAWN ? bool(to & threatenedByPawn) * 14950 - : 0); + : bool(to & threatenedByPawn) * 14900); } else // Type == EVASIONS From 596fb4842bdbb872dae8023a930f1dda8b48cad1 Mon Sep 17 00:00:00 2001 From: Disservin Date: Thu, 30 May 2024 19:55:59 +0200 Subject: [PATCH 16/32] NUMA: Fix concurrency counting for windows systems If there is more than 1 processor group, std::thread::hardware_concurrency should not be used. fixes #5307 closes https://github.com/official-stockfish/Stockfish/pull/5311 No functional change --- src/misc.cpp | 41 ++++++++++++++++++----------------------- src/numa.h | 25 +++++++++++++++++++++++-- 2 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index d48b75e1c..a45becf5d 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -34,16 +34,10 @@ // the calls at compile time), try to load them at runtime. To do this we need // first to define the corresponding function pointers. extern "C" { -using fun1_t = bool (*)(LOGICAL_PROCESSOR_RELATIONSHIP, - PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, - PDWORD); -using fun2_t = bool (*)(USHORT, PGROUP_AFFINITY); -using fun3_t = bool (*)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY); -using fun4_t = bool (*)(USHORT, PGROUP_AFFINITY, USHORT, PUSHORT); -using fun5_t = WORD (*)(); -using fun6_t = bool (*)(HANDLE, DWORD, PHANDLE); -using fun7_t = bool (*)(LPCSTR, LPCSTR, PLUID); -using fun8_t = bool (*)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); +using OpenProcessToken_t = bool (*)(HANDLE, DWORD, PHANDLE); +using LookupPrivilegeValueA_t = bool (*)(LPCSTR, LPCSTR, PLUID); +using AdjustTokenPrivileges_t = + bool (*)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); } #endif @@ -488,23 +482,25 @@ static void* aligned_large_pages_alloc_windows([[maybe_unused]] size_t allocSize if (!hAdvapi32) hAdvapi32 = LoadLibrary(TEXT("advapi32.dll")); - auto fun6 = fun6_t((void (*)()) GetProcAddress(hAdvapi32, "OpenProcessToken")); - if (!fun6) + auto OpenProcessToken_f = + OpenProcessToken_t((void (*)()) GetProcAddress(hAdvapi32, "OpenProcessToken")); + if (!OpenProcessToken_f) return nullptr; - auto fun7 = fun7_t((void (*)()) GetProcAddress(hAdvapi32, "LookupPrivilegeValueA")); - if (!fun7) + auto LookupPrivilegeValueA_f = + LookupPrivilegeValueA_t((void (*)()) GetProcAddress(hAdvapi32, "LookupPrivilegeValueA")); + if (!LookupPrivilegeValueA_f) return nullptr; - auto fun8 = fun8_t((void (*)()) GetProcAddress(hAdvapi32, "AdjustTokenPrivileges")); - if (!fun8) + auto AdjustTokenPrivileges_f = + AdjustTokenPrivileges_t((void (*)()) GetProcAddress(hAdvapi32, "AdjustTokenPrivileges")); + if (!AdjustTokenPrivileges_f) return nullptr; // We need SeLockMemoryPrivilege, so try to enable it for the process - if (!fun6( // OpenProcessToken() + if (!OpenProcessToken_f( // OpenProcessToken() GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hProcessToken)) return nullptr; - if (fun7( // LookupPrivilegeValue(nullptr, SE_LOCK_MEMORY_NAME, &luid) - nullptr, "SeLockMemoryPrivilege", &luid)) + if (LookupPrivilegeValueA_f(nullptr, "SeLockMemoryPrivilege", &luid)) { TOKEN_PRIVILEGES tp{}; TOKEN_PRIVILEGES prevTp{}; @@ -516,8 +512,8 @@ static void* aligned_large_pages_alloc_windows([[maybe_unused]] size_t allocSize // Try to enable SeLockMemoryPrivilege. Note that even if AdjustTokenPrivileges() succeeds, // we still need to query GetLastError() to ensure that the privileges were actually obtained. - if (fun8( // AdjustTokenPrivileges() - hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, &prevTpLen) + if (AdjustTokenPrivileges_f(hProcessToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), &prevTp, + &prevTpLen) && GetLastError() == ERROR_SUCCESS) { // Round up size to full pages and allocate @@ -526,8 +522,7 @@ static void* aligned_large_pages_alloc_windows([[maybe_unused]] size_t allocSize PAGE_READWRITE); // Privilege no longer needed, restore previous state - fun8( // AdjustTokenPrivileges () - hProcessToken, FALSE, &prevTp, 0, nullptr, nullptr); + AdjustTokenPrivileges_f(hProcessToken, FALSE, &prevTp, 0, nullptr, nullptr); } } diff --git a/src/numa.h b/src/numa.h index 03ee1fdf1..644f212ee 100644 --- a/src/numa.h +++ b/src/numa.h @@ -61,6 +61,7 @@ using SetThreadSelectedCpuSetMasks_t = BOOL (*)(HANDLE, PGROUP_AFFINITY, USHORT) // https://learn.microsoft.com/en-us/windows/win32/api/processtopologyapi/nf-processtopologyapi-setthreadgroupaffinity using SetThreadGroupAffinity_t = BOOL (*)(HANDLE, const GROUP_AFFINITY*, PGROUP_AFFINITY); +using GetActiveProcessorCount_t = DWORD (*)(WORD); #endif #include "misc.h" @@ -70,8 +71,28 @@ namespace Stockfish { using CpuIndex = size_t; using NumaIndex = size_t; -inline const CpuIndex SYSTEM_THREADS_NB = - std::max(1, std::thread::hardware_concurrency()); +inline CpuIndex get_hardware_concurrency() { + CpuIndex concurrency = std::thread::hardware_concurrency(); + + // Get all processors across all processor groups on windows, since ::hardware_concurrency + // only returns the number of processors in the first group, because only these + // are available to std::thread. +#ifdef _WIN64 + HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll")); + auto GetActiveProcessorCount_f = + GetActiveProcessorCount_t((void (*)()) GetProcAddress(k32, "GetActiveProcessorCount")); + + if (GetActiveProcessorCount_f != nullptr) + { + concurrency = GetActiveProcessorCount_f(ALL_PROCESSOR_GROUPS); + } +#endif + + return concurrency; +} + +inline const CpuIndex SYSTEM_THREADS_NB = std::max(1, get_hardware_concurrency()); + // We want to abstract the purpose of storing the numa node index somewhat. // Whoever is using this does not need to know the specifics of the replication From f1bb4164bf481c44e707751aa8a4bb8da20d4fa1 Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Thu, 30 May 2024 12:56:44 +0200 Subject: [PATCH 17/32] Fix process' processor affinity determination on Windows. Specialize and privatize NumaConfig::get_process_affinity. Only enable NUMA capability for 64-bit Windows. Following #5307 and some more testing it was determined that the way affinity was being determined on Windows was incorrect, based on incorrect assumptions about GetNumaProcessorNodeEx. This patch fixes the issue by attempting to retrieve the actual process' processor affinity using Windows API. However one issue persists that is not addressable due to limitations of Windows, and will have to be considered a limitation. If affinities were set using SetThreadAffinityMask instead of SetThreadSelectedCpuSetMasks and GetProcessGroupAffinity returns more than 1 group it is NOT POSSIBLE to determine the affinity programmatically on Windows. In such case the implementation assumes no affinites are set and will consider all processors available for execution. closes https://github.com/official-stockfish/Stockfish/pull/5312 No functional change --- src/numa.h | 260 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 167 insertions(+), 93 deletions(-) diff --git a/src/numa.h b/src/numa.h index 644f212ee..3c9c823aa 100644 --- a/src/numa.h +++ b/src/numa.h @@ -41,7 +41,7 @@ #define _GNU_SOURCE #endif #include -#elif defined(_WIN32) +#elif defined(_WIN64) // On Windows each processor group can have up to 64 processors. // https://learn.microsoft.com/en-us/windows/win32/procthread/processor-groups @@ -61,7 +61,18 @@ using SetThreadSelectedCpuSetMasks_t = BOOL (*)(HANDLE, PGROUP_AFFINITY, USHORT) // https://learn.microsoft.com/en-us/windows/win32/api/processtopologyapi/nf-processtopologyapi-setthreadgroupaffinity using SetThreadGroupAffinity_t = BOOL (*)(HANDLE, const GROUP_AFFINITY*, PGROUP_AFFINITY); +// https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadselectedcpusetmasks +using GetThreadSelectedCpuSetMasks_t = BOOL (*)(HANDLE, PGROUP_AFFINITY, USHORT, PUSHORT); + +// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getprocessaffinitymask +using GetProcessAffinityMask_t = BOOL (*)(HANDLE, PDWORD_PTR, PDWORD_PTR); + +// https://learn.microsoft.com/en-us/windows/win32/api/processtopologyapi/nf-processtopologyapi-getprocessgroupaffinity +using GetProcessGroupAffinity_t = BOOL (*)(HANDLE, PUSHORT, PUSHORT); + +// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getactiveprocessorcount using GetActiveProcessorCount_t = DWORD (*)(WORD); + #endif #include "misc.h" @@ -115,8 +126,6 @@ class NumaReplicatedAccessToken { // in a way that doesn't require recreating it completely, and it would be complex and expensive // to maintain class invariants. // The CPU (processor) numbers always correspond to the actual numbering used by the system. -// NOTE: the numbering is only valid within the process, as for example on Windows -// every process gets a "virtualized" set of processors that respects the current affinity // The NUMA node numbers MAY NOT correspond to the system's numbering of the NUMA nodes. // In particular, empty nodes may be removed, or the user may create custom nodes. // It is guaranteed that NUMA nodes are NOT empty, i.e. every node exposed by NumaConfig @@ -133,92 +142,21 @@ class NumaConfig { add_cpu_range_to_node(NumaIndex{0}, CpuIndex{0}, numCpus - 1); } - static std::set get_process_affinity() { - std::set cpus; - - // For unsupported systems, or in case of a soft error, we may assume all processors - // are available for use. - [[maybe_unused]] auto set_to_all_cpus = [&]() { - for (CpuIndex c = 0; c < SYSTEM_THREADS_NB; ++c) - cpus.insert(c); - }; - -#if defined(__linux__) && !defined(__ANDROID__) - - // cpu_set_t by default holds 1024 entries. This may not be enough soon, - // but there is no easy way to determine how many threads there actually is. - // In this case we just choose a reasonable upper bound. - static constexpr CpuIndex MaxNumCpus = 1024 * 64; - - cpu_set_t* mask = CPU_ALLOC(MaxNumCpus); - if (mask == nullptr) - std::exit(EXIT_FAILURE); - - const size_t masksize = CPU_ALLOC_SIZE(MaxNumCpus); - - CPU_ZERO_S(masksize, mask); - - const int status = sched_getaffinity(0, masksize, mask); - - if (status != 0) - { - CPU_FREE(mask); - std::exit(EXIT_FAILURE); - } - - for (CpuIndex c = 0; c < MaxNumCpus; ++c) - if (CPU_ISSET_S(c, masksize, mask)) - cpus.insert(c); - - CPU_FREE(mask); - -#elif defined(_WIN32) - - // Windows is problematic and weird due to multiple ways of setting affinity, processor groups, - // and behaviour changes between versions. It's unclear if we can support this feature - // on Windows in the same way we do on Linux. - // Apparently when affinity is set via either start /affinity or msys2 taskset - // the function GetNumaProcessorNodeEx completely disregards the processors that we do not - // have affinity more. Moreover, the indices are shifted to start from 0, indicating that Windows - // is providing a whole new mapping of processors to this process. This is problematic in some cases - // but it at least allows us to [probably] support this affinity restriction feature by default. - // So overall, Windows appears to "virtualize" a set of processors and processor groups for every - // process. It's unclear if this assignment can change while the process is running. - // std::thread::hardware_concurrency() returns the number of processors that's consistent - // with GetNumaProcessorNodeEx, so we can just add all of them. - - set_to_all_cpus(); - -#else - - // For other systems we assume the process is allowed to execute on all processors. - set_to_all_cpus(); - -#endif - - return cpus; - } - // This function queries the system for the mapping of processors to NUMA nodes. // On Linux we utilize `lscpu` to avoid libnuma. - // On Windows we utilize GetNumaProcessorNodeEx, which has its quirks, see - // comment for Windows implementation of get_process_affinity - static NumaConfig from_system(bool respectProcessAffinity = true) { + static NumaConfig from_system([[maybe_unused]] bool respectProcessAffinity = true) { NumaConfig cfg = empty(); +#if defined(__linux__) && !defined(__ANDROID__) + std::set allowedCpus; if (respectProcessAffinity) allowedCpus = get_process_affinity(); - else - { - for (CpuIndex c = 0; c < SYSTEM_THREADS_NB; ++c) - allowedCpus.insert(c); - } - auto is_cpu_allowed = [&](CpuIndex c) { return allowedCpus.count(c) == 1; }; - -#if defined(__linux__) && !defined(__ANDROID__) + auto is_cpu_allowed = [respectProcessAffinity, &allowedCpus](CpuIndex c) { + return !respectProcessAffinity || allowedCpus.count(c) == 1; + }; // On Linux things are straightforward, since there's no processor groups and // any thread can be scheduled on all processors. @@ -270,7 +208,19 @@ class NumaConfig { cfg.add_cpu_to_node(NumaIndex{0}, c); } -#elif defined(_WIN32) +#elif defined(_WIN64) + + std::optional> allowedCpus; + + if (respectProcessAffinity) + allowedCpus = get_process_affinity(); + + // The affinity can't be determined in all cases on Windows, but we at least guarantee + // that the number of allowed processors is >= number of processors in the affinity mask. + // In case the user is not satisfied they must set the processor numbers explicitly. + auto is_cpu_allowed = [&allowedCpus](CpuIndex c) { + return !allowedCpus.has_value() || allowedCpus->count(c) == 1; + }; // Since Windows 11 and Windows Server 2022 thread affinities can span // processor groups and can be set as such by a new WinAPI function. @@ -292,14 +242,6 @@ class NumaConfig { procnum.Reserved = 0; USHORT nodeNumber; - // When start /affinity or taskset was used to run this process with restricted affinity - // GetNumaProcessorNodeEx will NOT correspond to the system's processor setup, instead - // it appears to follow a completely new processor assignment, made specifically for this process, - // in which processors that this process has affinity for are remapped, and only those are remapped, - // to form a new set of processors. In other words, we can only get processors - // which we have affinity for this way. This means that the behaviour for - // `respectProcessAffinity == false` may be unexpected when affinity is set from outside, - // while the behaviour for `respectProcessAffinity == true` is given by default. const BOOL status = GetNumaProcessorNodeEx(&procnum, &nodeNumber); const CpuIndex c = static_cast(procGroup) * WIN_PROCESSOR_GROUP_SIZE + static_cast(number); @@ -347,8 +289,7 @@ class NumaConfig { // Fallback for unsupported systems. for (CpuIndex c = 0; c < SYSTEM_THREADS_NB; ++c) - if (is_cpu_allowed(c)) - cfg.add_cpu_to_node(NumaIndex{0}, c); + cfg.add_cpu_to_node(NumaIndex{0}, c); #endif @@ -573,7 +514,7 @@ class NumaConfig { // This is defensive, allowed because this code is not performance critical. sched_yield(); -#elif defined(_WIN32) +#elif defined(_WIN64) // Requires Windows 11. No good way to set thread affinity spanning processor groups before that. HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll")); @@ -627,9 +568,9 @@ class NumaConfig { // See https://learn.microsoft.com/en-us/windows/win32/procthread/numa-support GROUP_AFFINITY affinity; std::memset(&affinity, 0, sizeof(GROUP_AFFINITY)); - affinity.Group = static_cast(n); // We use an ordered set so we're guaranteed to get the smallest cpu number here. const size_t forcedProcGroupIndex = *(nodes[n].begin()) / WIN_PROCESSOR_GROUP_SIZE; + affinity.Group = static_cast(forcedProcGroupIndex); for (CpuIndex c : nodes[n]) { const size_t procGroupIndex = c / WIN_PROCESSOR_GROUP_SIZE; @@ -733,6 +674,139 @@ class NumaConfig { return true; } + + +#if defined(__linux__) && !defined(__ANDROID__) + + static std::set get_process_affinity() { + + std::set cpus; + + // For unsupported systems, or in case of a soft error, we may assume all processors + // are available for use. + [[maybe_unused]] auto set_to_all_cpus = [&]() { + for (CpuIndex c = 0; c < SYSTEM_THREADS_NB; ++c) + cpus.insert(c); + }; + + // cpu_set_t by default holds 1024 entries. This may not be enough soon, + // but there is no easy way to determine how many threads there actually is. + // In this case we just choose a reasonable upper bound. + static constexpr CpuIndex MaxNumCpus = 1024 * 64; + + cpu_set_t* mask = CPU_ALLOC(MaxNumCpus); + if (mask == nullptr) + std::exit(EXIT_FAILURE); + + const size_t masksize = CPU_ALLOC_SIZE(MaxNumCpus); + + CPU_ZERO_S(masksize, mask); + + const int status = sched_getaffinity(0, masksize, mask); + + if (status != 0) + { + CPU_FREE(mask); + std::exit(EXIT_FAILURE); + } + + for (CpuIndex c = 0; c < MaxNumCpus; ++c) + if (CPU_ISSET_S(c, masksize, mask)) + cpus.insert(c); + + CPU_FREE(mask); + + return cpus; + } + +#elif defined(_WIN64) + + // On Windows there are two ways to set affinity, and therefore 2 ways to get it. + // These are not consistent, so we have to check both. + // In some cases it is actually not possible to determine affinity. + // For example when two different threads have affinity on different processor groups, + // set using SetThreadAffinityMask, we can't retrieve the actual affinities. + // From documentation on GetProcessAffinityMask: + // > If the calling process contains threads in multiple groups, + // > the function returns zero for both affinity masks. + // In such cases we just give up and assume we have affinity for all processors. + // nullopt means no affinity is set, that is, all processors are allowed + static std::optional> get_process_affinity() { + HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll")); + auto GetThreadSelectedCpuSetMasks_f = GetThreadSelectedCpuSetMasks_t( + (void (*)()) GetProcAddress(k32, "GetThreadSelectedCpuSetMasks")); + auto GetProcessAffinityMask_f = + GetProcessAffinityMask_t((void (*)()) GetProcAddress(k32, "GetProcessAffinityMask")); + auto GetProcessGroupAffinity_f = + GetProcessGroupAffinity_t((void (*)()) GetProcAddress(k32, "GetProcessGroupAffinity")); + + if (GetThreadSelectedCpuSetMasks_f != nullptr) + { + std::set cpus; + + USHORT RequiredMaskCount; + GetThreadSelectedCpuSetMasks_f(GetCurrentThread(), nullptr, 0, &RequiredMaskCount); + + // If RequiredMaskCount then these affinities were never set, but it's not consistent + // so GetProcessAffinityMask may still return some affinity. + if (RequiredMaskCount > 0) + { + auto groupAffinities = std::make_unique(RequiredMaskCount); + + GetThreadSelectedCpuSetMasks_f(GetCurrentThread(), groupAffinities.get(), + RequiredMaskCount, &RequiredMaskCount); + + for (USHORT i = 0; i < RequiredMaskCount; ++i) + { + const size_t procGroupIndex = groupAffinities[i].Group; + + for (size_t j = 0; j < WIN_PROCESSOR_GROUP_SIZE; ++j) + { + if (groupAffinities[i].Mask & (KAFFINITY(1) << j)) + cpus.insert(procGroupIndex * WIN_PROCESSOR_GROUP_SIZE + j); + } + } + + return cpus; + } + } + + if (GetProcessAffinityMask_f != nullptr && GetProcessGroupAffinity_f != nullptr) + { + std::set cpus; + + DWORD_PTR proc, sys; + BOOL status = GetProcessAffinityMask_f(GetCurrentProcess(), &proc, &sys); + if (status == 0) + return std::nullopt; + + // We can't determine affinity because it spans processor groups. + if (proc == 0) + return std::nullopt; + + // We are expecting a single group. + USHORT GroupCount = 1; + USHORT GroupArray[1]; + status = GetProcessGroupAffinity_f(GetCurrentProcess(), &GroupCount, GroupArray); + if (status == 0 || GroupCount != 1) + return std::nullopt; + + const size_t procGroupIndex = GroupArray[0]; + + uint64_t mask = static_cast(proc); + for (size_t j = 0; j < WIN_PROCESSOR_GROUP_SIZE; ++j) + { + if (mask & (KAFFINITY(1) << j)) + cpus.insert(procGroupIndex * WIN_PROCESSOR_GROUP_SIZE + j); + } + + return cpus; + } + + return std::nullopt; + } + +#endif }; class NumaReplicationContext; From 86694b5914c63ee5b0f964108cbd7eacca14c93a Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Thu, 30 May 2024 18:18:51 +0200 Subject: [PATCH 18/32] Replace std::from_chars with std::stoull the former was not widely supported, requiring newer compiler versions. closes https://github.com/official-stockfish/Stockfish/pull/5313 No functional change --- src/misc.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index a45becf5d..7a4473294 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -42,16 +42,15 @@ using AdjustTokenPrivileges_t = #endif #include -#include #include #include #include #include #include +#include #include #include #include -#include #include "types.h" @@ -598,13 +597,10 @@ void aligned_large_pages_free(void* mem) { std_aligned_free(mem); } #endif size_t str_to_size_t(const std::string& s) { - size_t value; - auto result = std::from_chars(s.data(), s.data() + s.size(), value); - - if (result.ec != std::errc()) + unsigned long long value = std::stoull(s); + if (value > std::numeric_limits::max()) std::exit(EXIT_FAILURE); - - return value; + return static_cast(value); } std::string CommandLine::get_binary_directory(std::string argv0) { From c8375c2fbd398f07b8488ae2d1b12fa1251fb69f Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Thu, 30 May 2024 17:22:53 +0200 Subject: [PATCH 19/32] On linux use sysfs instead of lscpu Use sysfs (https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-devices-node) to determine processor to NUMA node mapping. Avoids problems on some machines with high core count where lscpu was showing high cpu utilization. closes https://github.com/official-stockfish/Stockfish/pull/5315 No functional change --- src/misc.cpp | 13 +++++ src/misc.h | 24 ++++---- src/numa.h | 154 ++++++++++++++++++++++++++++----------------------- 3 files changed, 107 insertions(+), 84 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index 7a4473294..aa22e61f2 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -42,12 +42,14 @@ using AdjustTokenPrivileges_t = #endif #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -603,6 +605,17 @@ size_t str_to_size_t(const std::string& s) { return static_cast(value); } +std::optional read_file_to_string(const std::string& path) { + std::ifstream f(path, std::ios_base::binary); + if (!f) + return std::nullopt; + return std::string(std::istreambuf_iterator(f), std::istreambuf_iterator()); +} + +void remove_whitespace(std::string& s) { + s.erase(std::remove_if(s.begin(), s.end(), [](char c) { return std::isspace(c); }), s.end()); +} + std::string CommandLine::get_binary_directory(std::string argv0) { std::string pathSeparator; diff --git a/src/misc.h b/src/misc.h index ec7f7b76c..5c0bde44e 100644 --- a/src/misc.h +++ b/src/misc.h @@ -88,21 +88,12 @@ struct PipeDeleter { } }; -inline std::optional get_system_command_output(const std::string& command) { - std::unique_ptr pipe(popen(command.c_str(), "r")); - if (!pipe) - return std::nullopt; - - std::string result; - char buffer[1024]; - while (fgets(buffer, sizeof(buffer), pipe.get()) != nullptr) - result += buffer; - - return result; -} - #endif +// Reads the file as bytes. +// Returns std::nullopt if the file does not exist. +std::optional read_file_to_string(const std::string& path); + void dbg_hit_on(bool cond, int slot = 0); void dbg_mean_of(int64_t value, int slot = 0); void dbg_stdev_of(int64_t value, int slot = 0); @@ -118,9 +109,12 @@ inline TimePoint now() { } inline std::vector split(const std::string& s, const std::string& delimiter) { - size_t begin = 0; std::vector res; + if (s.empty()) + return res; + + size_t begin = 0; for (;;) { const size_t end = s.find(delimiter, begin); @@ -136,6 +130,8 @@ inline std::vector split(const std::string& s, const std::string& d return res; } +void remove_whitespace(std::string& s); + enum SyncCout { IO_LOCK, IO_UNLOCK diff --git a/src/numa.h b/src/numa.h index 3c9c823aa..0553309af 100644 --- a/src/numa.h +++ b/src/numa.h @@ -33,9 +33,8 @@ #include #include -// We support linux very well, but we explicitly do NOT support Android, partially because -// there are potential issues with `lscpu`, `popen` availability, and partially because -// there's no NUMA environments running Android and there probably won't be. +// We support linux very well, but we explicitly do NOT support Android, because there's +// no affected systems, not worth maintaining. #if defined(__linux__) && !defined(__ANDROID__) #if !defined(_GNU_SOURCE) #define _GNU_SOURCE @@ -143,7 +142,9 @@ class NumaConfig { } // This function queries the system for the mapping of processors to NUMA nodes. - // On Linux we utilize `lscpu` to avoid libnuma. + // On Linux we read from standardized kernel sysfs, with a fallback to single NUMA node. + // On Windows we utilize GetNumaProcessorNodeEx, which has its quirks, see + // comment for Windows implementation of get_process_affinity static NumaConfig from_system([[maybe_unused]] bool respectProcessAffinity = true) { NumaConfig cfg = empty(); @@ -160,48 +161,52 @@ class NumaConfig { // On Linux things are straightforward, since there's no processor groups and // any thread can be scheduled on all processors. - // This command produces output in the following form - // CPU NODE - // 0 0 - // 1 0 - // 2 1 - // 3 1 - // - // On some systems it may use '-' to signify no NUMA node, in which case we assume it's in node 0. - auto lscpuOpt = get_system_command_output("lscpu -e=cpu,node"); - if (lscpuOpt.has_value()) + + // We try to gather this information from the sysfs first + // https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-devices-node + + bool useFallback = false; + auto fallback = [&]() { + useFallback = true; + cfg = empty(); + }; + + // /sys/devices/system/node/online contains information about active NUMA nodes + auto nodeIdsStr = read_file_to_string("/sys/devices/system/node/online"); + if (!nodeIdsStr.has_value() || nodeIdsStr->empty()) { - - std::istringstream ss(*lscpuOpt); - - // skip the list header - ss.ignore(std::numeric_limits::max(), '\n'); - - while (true) - { - CpuIndex c; - NumaIndex n; - - ss >> c; - - if (!ss) - break; - - ss >> n; - - if (!ss) - { - ss.clear(); - std::string dummy; - ss >> dummy; - n = 0; - } - - if (is_cpu_allowed(c)) - cfg.add_cpu_to_node(n, c); - } + fallback(); } else + { + remove_whitespace(*nodeIdsStr); + for (size_t n : indices_from_shortened_string(*nodeIdsStr)) + { + // /sys/devices/system/node/node.../cpulist + std::string path = + std::string("/sys/devices/system/node/node") + std::to_string(n) + "/cpulist"; + auto cpuIdsStr = read_file_to_string(path); + // Now, we only bail if the file does not exist. Some nodes may be empty, that's fine. + // An empty node still has a file that appears to have some whitespace, so we need + // to handle that. + if (!cpuIdsStr.has_value()) + { + fallback(); + break; + } + else + { + remove_whitespace(*cpuIdsStr); + for (size_t c : indices_from_shortened_string(*cpuIdsStr)) + { + if (is_cpu_allowed(c)) + cfg.add_cpu_to_node(n, c); + } + } + } + } + + if (useFallback) { for (CpuIndex c = 0; c < SYSTEM_THREADS_NB; ++c) if (is_cpu_allowed(c)) @@ -309,38 +314,17 @@ class NumaConfig { NumaIndex n = 0; for (auto&& nodeStr : split(s, ":")) { - bool addedAnyCpuInThisNode = false; - - for (const std::string& cpuStr : split(nodeStr, ",")) + auto indices = indices_from_shortened_string(nodeStr); + if (!indices.empty()) { - if (cpuStr.empty()) - continue; - - auto parts = split(cpuStr, "-"); - if (parts.size() == 1) + for (auto idx : indices) { - const CpuIndex c = CpuIndex{str_to_size_t(parts[0])}; - if (!cfg.add_cpu_to_node(n, c)) + if (!cfg.add_cpu_to_node(n, CpuIndex(idx))) std::exit(EXIT_FAILURE); } - else if (parts.size() == 2) - { - const CpuIndex cfirst = CpuIndex{str_to_size_t(parts[0])}; - const CpuIndex clast = CpuIndex{str_to_size_t(parts[1])}; - if (!cfg.add_cpu_range_to_node(n, cfirst, clast)) - std::exit(EXIT_FAILURE); - } - else - { - std::exit(EXIT_FAILURE); - } - - addedAnyCpuInThisNode = true; - } - - if (addedAnyCpuInThisNode) n += 1; + } } cfg.customAffinity = true; @@ -675,7 +659,6 @@ class NumaConfig { return true; } - #if defined(__linux__) && !defined(__ANDROID__) static std::set get_process_affinity() { @@ -807,6 +790,37 @@ class NumaConfig { } #endif + + static std::vector indices_from_shortened_string(const std::string& s) { + std::vector indices; + + if (s.empty()) + return indices; + + for (const std::string& ss : split(s, ",")) + { + if (ss.empty()) + continue; + + auto parts = split(ss, "-"); + if (parts.size() == 1) + { + const CpuIndex c = CpuIndex{str_to_size_t(parts[0])}; + indices.emplace_back(c); + } + else if (parts.size() == 2) + { + const CpuIndex cfirst = CpuIndex{str_to_size_t(parts[0])}; + const CpuIndex clast = CpuIndex{str_to_size_t(parts[1])}; + for (size_t c = cfirst; c <= clast; ++c) + { + indices.emplace_back(c); + } + } + } + + return indices; + } }; class NumaReplicationContext; From 54e74919d478def20cb103d1e9677a696073c92f Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 30 May 2024 21:42:48 +0200 Subject: [PATCH 20/32] Fix cross from Linux to Windows specifies Windows 7 required https://learn.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt?view=msvc-170 closes https://github.com/official-stockfish/Stockfish/pull/5319 No functional change --- src/numa.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/numa.h b/src/numa.h index 0553309af..ee84e1cf3 100644 --- a/src/numa.h +++ b/src/numa.h @@ -42,6 +42,11 @@ #include #elif defined(_WIN64) + #if _WIN32_WINNT < 0x0601 + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0601 // Force to include needed API prototypes + #endif + // On Windows each processor group can have up to 64 processors. // https://learn.microsoft.com/en-us/windows/win32/procthread/processor-groups static constexpr size_t WIN_PROCESSOR_GROUP_SIZE = 64; From de1ae4949daf2c6d36c50e51c132cee808e2ade0 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Fri, 31 May 2024 04:01:02 +0300 Subject: [PATCH 21/32] Tweak first picked move (ttMove) reduction rule Tweak first picked move (ttMove) reduction rule: Instead of always resetting the reduction to 0, we now only do so if the current reduction is less than 2. If the current reduction is 2 or more, we decrease it by 2 instead. Passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 109504 W: 28340 L: 27919 D: 53245 Ptnml(0-2): 305, 12848, 28028, 13263, 308 https://tests.stockfishchess.org/tests/view/6658c2fa6b0e318cefa900c2 Passed LTC: LLR: 2.96 (-2.94,2.94) <0.50,2.50> Total: 130410 W: 33248 L: 32738 D: 64424 Ptnml(0-2): 53, 14139, 36328, 14615, 70 https://tests.stockfishchess.org/tests/view/6658dd8a6b0e318cefa90173 closes https://github.com/official-stockfish/Stockfish/pull/5321 bench: 1224588 --- src/search.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 638af546d..4086d50f1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1149,10 +1149,10 @@ moves_loop: // When in check, search starts here if ((ss + 1)->cutoffCnt > 3) r++; - // Set reduction to 0 for first picked move (ttMove) (~2 Elo) - // Nullifies all previous reduction adjustments to ttMove and leaves only history to do them + // For first picked move (ttMove) reduce reduction + // but never allow it to go below 0 (~3 Elo) else if (move == ttMove) - r = 0; + r = std::max(0, r - 2); ss->statScore = 2 * thisThread->mainHistory[us][move.from_to()] + (*contHist[0])[movedPiece][move.to_sq()] From 0ef809ac71702ee496a88f2cf305117511b555b2 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Wed, 29 May 2024 13:56:15 -0400 Subject: [PATCH 22/32] Quadratic smallnet threshold with re-evaluation The threshold now decreases more quickly as pawn count decreases, using the smallnet more compared to before. Combo of two eval patches: https://tests.stockfishchess.org/tests/view/66576c5f6b0e318cefa8d26e https://tests.stockfishchess.org/tests/view/664ced40830eb9f886616a77 Passed STC: https://tests.stockfishchess.org/tests/view/66588c136b0e318cefa8ff21 LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 112608 W: 29336 L: 28908 D: 54364 Ptnml(0-2): 344, 13223, 28718, 13699, 320 Passed LTC: https://tests.stockfishchess.org/tests/view/6658c8786b0e318cefa900f5 LLR: 2.96 (-2.94,2.94) <0.50,2.50> Total: 108288 W: 27493 L: 27026 D: 53769 Ptnml(0-2): 54, 11821, 29930, 12282, 57 closes https://github.com/official-stockfish/Stockfish/pull/5323 bench 1728074 --- src/evaluate.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 666697ddd..35bc9301a 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -46,7 +46,8 @@ int Eval::simple_eval(const Position& pos, Color c) { bool Eval::use_smallnet(const Position& pos) { int simpleEval = simple_eval(pos, pos.side_to_move()); - return std::abs(simpleEval) > 992 + 6 * pos.count(); + int pawnCount = pos.count(); + return std::abs(simpleEval) > 992 + 6 * pawnCount * pawnCount / 16; } // Evaluate is the evaluator for the outer world. It returns a static evaluation @@ -67,7 +68,7 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, : networks.big.evaluate(pos, &caches.big, true, &nnueComplexity); // Re-evaluate the position when higher eval accuracy is worth the time spent - if (smallNet && nnue * simpleEval < 0) + if (smallNet && (nnue * simpleEval < 0 || std::abs(nnue) < 250)) { nnue = networks.big.evaluate(pos, &caches.big, true, &nnueComplexity); smallNet = false; From b34a690cd4aa6d828ae0f47b427167f4e6392db7 Mon Sep 17 00:00:00 2001 From: rn5f107s2 Date: Thu, 30 May 2024 21:18:42 +0200 Subject: [PATCH 23/32] MCP more after a bad singular search The idea is, that if we have the information that the singular search failed low and therefore produced an upperbound score, we can use the score from singularsearch as approximate upperbound as to what bestValue our non ttMoves will produce. If this value is well below alpha, we assume that all non-ttMoves will score below alpha and therfore can skip more moves. This patch also sets up variables for future patches wanting to use teh singular search result outside of singular extensions, in singularBound and singularValue, meaning further patches using this search result to affect various pruning techniques can be tried. Passed STC: https://tests.stockfishchess.org/tests/view/6658d13e6b0e318cefa90120 LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 85632 W: 22112 L: 21725 D: 41795 Ptnml(0-2): 243, 10010, 21947, 10349, 267 Passed LTC: https://tests.stockfishchess.org/tests/view/6658dd356b0e318cefa9016a LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 243978 W: 62014 L: 61272 D: 120692 Ptnml(0-2): 128, 26598, 67791, 27348, 124 closes https://github.com/official-stockfish/Stockfish/pull/5325 bench 1397172 --- src/search.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 4086d50f1..f738530ad 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -550,11 +550,12 @@ Value Search::Worker::search( Key posKey; Move ttMove, move, excludedMove, bestMove; Depth extension, newDepth; - Value bestValue, value, ttValue, eval, maxValue, probCutBeta; + Value bestValue, value, ttValue, eval, maxValue, probCutBeta, singularValue; bool givesCheck, improving, priorCapture, opponentWorsening; bool capture, moveCountPruning, ttCapture; Piece movedPiece; int moveCount, captureCount, quietCount; + Bound singularBound; // Step 1. Initialize node Worker* thisThread = this; @@ -923,6 +924,8 @@ moves_loop: // When in check, search starts here value = bestValue; moveCountPruning = false; + singularValue = VALUE_INFINITE; + singularBound = BOUND_NONE; // Step 13. Loop through all pseudo-legal moves until no moves remain // or a beta cutoff occurs. @@ -972,7 +975,9 @@ moves_loop: // When in check, search starts here if (!rootNode && pos.non_pawn_material(us) && bestValue > VALUE_TB_LOSS_IN_MAX_PLY) { // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold (~8 Elo) - moveCountPruning = moveCount >= futility_move_count(improving, depth); + moveCountPruning = + moveCount >= futility_move_count(improving, depth) + - (singularBound == BOUND_UPPER && singularValue < alpha - 50); // Reduced depth of the next LMR search int lmrDepth = newDepth - r; @@ -1058,8 +1063,9 @@ moves_loop: // When in check, search starts here Depth singularDepth = newDepth / 2; ss->excludedMove = move; - value = + value = singularValue = search(pos, ss, singularBeta - 1, singularBeta, singularDepth, cutNode); + singularBound = singularValue >= singularBeta ? BOUND_LOWER : BOUND_UPPER; ss->excludedMove = Move::none(); if (value < singularBeta) From cb4a62311985f685ba6f5457851527a3289073e6 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Mon, 27 May 2024 10:40:25 -0400 Subject: [PATCH 24/32] Update default smallnet to nn-37f18f62d772.nnue Created by training L1-128 from scratch with: - skipping based on simple eval in the trainer, for compatibility with regular binpacks without requiring pre-filtering all binpacks - minimum simple eval of 950, lower than 1000 previously - usage of some hse-v1 binpacks with minimum simple eval 1000 - addition of hse-v6 binpacks with minimum simple eval 500 - permuting the FT with 10k positions from fishpack32.binpack - torch.compile to speed up smallnet training Training is significantly slower when using non-pre-filtered binpacks due to the increased skipping required. This net was reached at epoch 339. ``` experiment-name: 128--S1-hse-1k-T80-v6-unfilt-less-sf--se-gt950-no-wld-skip training-dataset: /data/: - dfrc99-16tb7p.v2.min.binpack /data/hse-v1/: - leela96-filt-v2.min.high-simple-eval-1k.min-v2.binpack - test60-novdec2021-12tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack - test77-nov2021-2tb7p.no-db.min.high-simple-eval-1k.min-v2.binpack - test77-dec2021-16tb7p.no-db.min.high-simple-eval-1k.min-v2.binpack - test77-jan2022-2tb7p.high-simple-eval-1k.min-v2.binpack - test78-jantomay2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack - test78-juntosep2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack - test79-apr2022-16tb7p.min.high-simple-eval-1k.min-v2.binpack - test79-may2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack - test80-apr2022-16tb7p.min.high-simple-eval-1k.min-v2.binpack - test80-may2022-16tb7p.high-simple-eval-1k.min-v2.binpack - test80-jun2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack - test80-jul2022-16tb7p.v6-dd.min.high-simple-eval-1k.min-v2.binpack - test80-sep2022-16tb7p-filter-v6-dd.min-mar2023.unmin.high-simple-eval-1k.min-v2.binpack - test80-nov2022-16tb7p-v6-dd.min.high-simple-eval-1k.min-v2.binpack /data/S11-mar2024/: - test80-2022-08-aug-16tb7p.v6-dd.min.binpack - test80-2022-10-oct-16tb7p.v6-dd.binpack - test80-2022-12-dec-16tb7p.min.binpack - test80-2023-01-jan-16tb7p.v6-sk20.min.binpack - test80-2023-02-feb-16tb7p.v6-sk20.min.binpack - test80-2023-03-mar-2tb7p.v6-sk16.min.binpack - test80-2023-04-apr-2tb7p.v6-sk16.min.binpack - test80-2023-05-may-2tb7p.v6.min.binpack - test80-2023-06-jun-2tb7p.binpack.min-v2.binpack - test80-2023-07-jul-2tb7p.binpack.min-v2.binpack - test80-2023-08-aug-2tb7p.v6.min.binpack - test80-2023-09-sep-2tb7p.binpack.hse-v6.binpack - test80-2023-10-oct-2tb7p.binpack.hse-v6.binpack - test80-2023-11-nov-2tb7p.binpack.hse-v6.binpack - test80-2023-12-dec-2tb7p.binpack.hse-v6.binpack - test80-2024-01-jan-2tb7p.binpack.hse-v6.binpack - test80-2024-02-feb-2tb7p.binpack.hse-v6.binpack - test80-2024-03-mar-2tb7p.binpack wld-fen-skipping: False nnue-pytorch-branch: linrock/nnue-pytorch/128-skipSimpleEval-lt950-torch-compile engine-test-branch: linrock/Stockfish/L1-128-nolazy engine-base-branch: linrock/Stockfish/L1-128 start-from-engine-test-net: False num-epochs: 500 start-lambda: 1.0 end-lambda: 1.0 ``` Training data can be found at: https://robotmoon.com/nnue-training-data/ Passed STC: https://tests.stockfishchess.org/tests/view/66549c16a86388d5e27daff5 LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 196608 W: 51254 L: 50697 D: 94657 Ptnml(0-2): 722, 23244, 49796, 23839, 703 Passed LTC: https://tests.stockfishchess.org/tests/view/6658d1aa6b0e318cefa90122 LLR: 2.96 (-2.94,2.94) <0.50,2.50> Total: 122538 W: 31332 L: 30835 D: 60371 Ptnml(0-2): 69, 13407, 33811, 13922, 60 closes https://github.com/official-stockfish/Stockfish/pull/5333 bench --- src/evaluate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.h b/src/evaluate.h index 4fab1a001..bdef9ceb6 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -34,7 +34,7 @@ namespace Eval { // name of the macro or the location where this macro is defined, as it is used // in the Makefile/Fishtest. #define EvalFileDefaultNameBig "nn-ddcfb9224cdb.nnue" -#define EvalFileDefaultNameSmall "nn-baff1ede1f90.nnue" +#define EvalFileDefaultNameSmall "nn-37f18f62d772.nnue" namespace NNUE { struct Networks; From 783dfc2eb235236ff799618436d68d0c1a3f3807 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sat, 1 Jun 2024 20:44:06 +0300 Subject: [PATCH 25/32] Adjust return bonus from tt cutoffs at fail highs This is reintroduction of the recently simplified logic - if positive tt cutoff occurs return not a tt value but smth between it and beta. Difference is that instead of static linear combination there we use basically the same formula as we do in the main search - with the only difference being using tt depth instead of depth, which makes a lot of sense. Passed STC: https://tests.stockfishchess.org/tests/view/665b3a34f4a1fd0c208ea870 LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 54944 W: 14239 L: 13896 D: 26809 Ptnml(0-2): 151, 6407, 14008, 6760, 146 Passed LTC: https://tests.stockfishchess.org/tests/view/665b520011645bd3d3fac341 LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 90540 W: 23070 L: 22640 D: 44830 Ptnml(0-2): 39, 9903, 24965, 10315, 48 closes https://github.com/official-stockfish/Stockfish/pull/5336 bench 1381237 --- src/search.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index f738530ad..514b7b7d9 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -640,7 +640,12 @@ Value Search::Worker::search( // Partial workaround for the graph history interaction problem // For high rule50 counts don't produce transposition table cutoffs. if (pos.rule50_count() < 90) + { + if (ttValue >= beta && std::abs(ttValue) < VALUE_TB_WIN_IN_MAX_PLY + && std::abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) + ttValue = (ttValue * tte->depth() + beta) / (tte->depth() + 1); return ttValue; + } } // Step 5. Tablebases probe From b0870cf528ef90e8873719a36a448dafd73e3aee Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 1 Jun 2024 15:13:41 +0200 Subject: [PATCH 26/32] Avoid changing bestvalue in the case the ttValue contains mate scores, do not return them as bestValue, since they are not proven. passed STC https://tests.stockfishchess.org/tests/view/665b1ea5586058766677cfa3 LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 58912 W: 15319 L: 15130 D: 28463 Ptnml(0-2): 141, 6562, 15854, 6765, 134 passed LTC: https://tests.stockfishchess.org/tests/view/665b2712586058766677cfc4 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 141666 W: 35976 L: 35879 D: 69811 Ptnml(0-2): 61, 15513, 39584, 15618, 57 closes https://github.com/official-stockfish/Stockfish/pull/5335 Bench: 1336115 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 514b7b7d9..4dc7d3300 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1495,7 +1495,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, to_corrected_static_eval(unadjustedStaticEval, *thisThread, pos); // ttValue can be used as a better position evaluation (~13 Elo) - if (ttValue != VALUE_NONE + if (std::abs(ttValue) < VALUE_TB_WIN_IN_MAX_PLY && (tte->bound() & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER))) bestValue = ttValue; } From ec1cda1d819f534c8d0bfc4624836157bc548eb6 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Fri, 31 May 2024 22:29:29 +0300 Subject: [PATCH 27/32] Simplify histories movepick formula Passed STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 81440 W: 21100 L: 20929 D: 39411 Ptnml(0-2): 248, 9659, 20718, 9864, 231 https://tests.stockfishchess.org/tests/view/6659a8b7ea624d64ea5f3208 Passed LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 85758 W: 21763 L: 21607 D: 42388 Ptnml(0-2): 34, 9606, 23463, 9722, 54 https://tests.stockfishchess.org/tests/view/6659d7bff426908fcc6b692c closes https://github.com/official-stockfish/Stockfish/pull/5326 bench: 1280472 --- src/movepick.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index b6828a30b..d33359075 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -178,7 +178,7 @@ void MovePicker::score() { Square to = m.to_sq(); // histories - m.value = 2 * (*mainHistory)[pos.side_to_move()][m.from_to()]; + m.value = (*mainHistory)[pos.side_to_move()][m.from_to()]; m.value += 2 * (*pawnHistory)[pawn_structure_index(pos)][pc][to]; m.value += 2 * (*continuationHistory[0])[pc][to]; m.value += (*continuationHistory[1])[pc][to]; From 180cab443896a6a37a3c39852ff124ce856987d2 Mon Sep 17 00:00:00 2001 From: MinetaS Date: Sat, 1 Jun 2024 06:11:51 +0900 Subject: [PATCH 28/32] Simplify 50 move rule dampening Refactor the logic of 50 move rule dampening by removing a constant. Passed non-regression STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 35232 W: 9214 L: 8992 D: 17026 Ptnml(0-2): 114, 4081, 8999, 4313, 109 https://tests.stockfishchess.org/tests/view/665a329013d08af3c1725610 Passed non-regression LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 38406 W: 9732 L: 9530 D: 19144 Ptnml(0-2): 14, 4132, 10708, 4336, 13 https://tests.stockfishchess.org/tests/view/665a370913d08af3c1725651 https://github.com/official-stockfish/Stockfish/pull/5327 Bench: 1059739 --- src/evaluate.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 35bc9301a..eaf7ab5f9 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -81,10 +81,10 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, int material = 300 * pos.count() + 350 * pos.count() + 400 * pos.count() + 640 * pos.count() + 1200 * pos.count(); - v = (nnue * (34300 + material) + optimism * (4400 + material)) / 35967; + v = (nnue * (34300 + material) + optimism * (4400 + material)) / 36672; // Damp down the evaluation linearly when shuffling - v = v * (204 - pos.rule50_count()) / 208; + v -= v * pos.rule50_count() / 212; // Guarantee evaluation does not hit the tablebase range v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1); From b009c43254c3483dd356e28b5b66ba62a724aa1d Mon Sep 17 00:00:00 2001 From: xoto10 <23479932+xoto10@users.noreply.github.com> Date: Sat, 1 Jun 2024 17:10:06 +0100 Subject: [PATCH 29/32] Simplify tm, removing faster 1st move and 1.13 extraTime. Passed STC 10+0.1 : LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 349760 W: 90112 L: 90231 D: 169417 Ptnml(0-2): 784, 37970, 97496, 37841, 789 https://tests.stockfishchess.org/tests/view/665aeee00223e235f05b7d21 Passed LTC 60+0.6 : LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 140082 W: 35463 L: 35370 D: 69249 Ptnml(0-2): 59, 13492, 42851, 13575, 64 https://tests.stockfishchess.org/tests/view/665b15e78da109e362924e5a closes https://github.com/official-stockfish/Stockfish/pull/5334 No functional change --- src/search.cpp | 3 +-- src/search.h | 1 - src/thread.cpp | 7 ++++--- src/timeman.cpp | 18 ++++-------------- src/timeman.h | 1 - 5 files changed, 9 insertions(+), 21 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 4dc7d3300..35de756ff 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -160,8 +160,7 @@ void Search::Worker::start_searching() { return; } - main_manager()->tm.init(limits, rootPos.side_to_move(), rootPos.game_ply(), options, - main_manager()->originalPly, main_manager()->originalTimeAdjust); + main_manager()->tm.init(limits, rootPos.side_to_move(), rootPos.game_ply(), options, main_manager()->originalTimeAdjust); tt.new_search(); if (rootMoves.empty()) diff --git a/src/search.h b/src/search.h index 7cff10d55..01f7b8bdb 100644 --- a/src/search.h +++ b/src/search.h @@ -209,7 +209,6 @@ class SearchManager: public ISearchManager { Stockfish::TimeManagement tm; double originalTimeAdjust; - int originalPly; int callsCnt; std::atomic_bool ponder; diff --git a/src/thread.cpp b/src/thread.cpp index 71134ead6..1b0fffc35 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -213,12 +213,13 @@ void ThreadPool::clear() { for (auto&& th : threads) th->wait_for_search_finished(); + // These two affect the time taken on the first move of a game: + main_manager()->bestPreviousAverageScore = VALUE_INFINITE; + main_manager()->previousTimeReduction = 0.85; + main_manager()->callsCnt = 0; main_manager()->bestPreviousScore = VALUE_INFINITE; - main_manager()->bestPreviousAverageScore = VALUE_INFINITE; - main_manager()->originalPly = -1; main_manager()->originalTimeAdjust = -1; - main_manager()->previousTimeReduction = 1.0; main_manager()->tm.clear(); } diff --git a/src/timeman.cpp b/src/timeman.cpp index f6ca298a8..9de70fdc6 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -48,7 +48,6 @@ void TimeManagement::init(Search::LimitsType& limits, Color us, int ply, const OptionsMap& options, - int& originalPly, double& originalTimeAdjust) { TimePoint npmsec = TimePoint(options["nodestime"]); @@ -60,9 +59,6 @@ void TimeManagement::init(Search::LimitsType& limits, if (limits.time[us] == 0) return; - if (originalPly == -1) - originalPly = ply; - TimePoint moveOverhead = TimePoint(options["Move Overhead"]); // optScale is a percentage of available time to use for the current move. @@ -104,20 +100,14 @@ void TimeManagement::init(Search::LimitsType& limits, TimePoint timeLeft = std::max(TimePoint(1), limits.time[us] + limits.inc[us] * (mtg - 1) - moveOverhead * (2 + mtg)); - // Extra time according to timeLeft - if (originalTimeAdjust < 0) - originalTimeAdjust = 0.2078 + 0.1623 * std::log10(timeLeft); - // x basetime (+ z increment) // If there is a healthy increment, timeLeft can exceed the actual available // game time for the current move, so also cap to a percentage of available game time. if (limits.movestogo == 0) { - // Use extra time with larger increments - double optExtra = scaledInc < 500 ? 1.0 : 1.13; - if (ply - originalPly < 2) - optExtra *= 0.95; - optExtra *= originalTimeAdjust; + // Extra time according to timeLeft + if (originalTimeAdjust < 0) + originalTimeAdjust = 0.3285 * std::log10(timeLeft) - 0.4830; // Calculate time constants based on current time left. double logTimeInSec = std::log10(scaledTime / 1000.0); @@ -126,7 +116,7 @@ void TimeManagement::init(Search::LimitsType& limits, optScale = std::min(0.0122 + std::pow(ply + 2.95, 0.462) * optConstant, 0.213 * limits.time[us] / timeLeft) - * optExtra; + * originalTimeAdjust; maxScale = std::min(6.64, maxConstant + ply / 12.0); } diff --git a/src/timeman.h b/src/timeman.h index 8b763089a..10207a8a7 100644 --- a/src/timeman.h +++ b/src/timeman.h @@ -40,7 +40,6 @@ class TimeManagement { Color us, int ply, const OptionsMap& options, - int& originalPly, double& originalTimeAdjust); TimePoint optimum() const; From c17d73c554054db8cdc6eb39d667c1dca47d3818 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Sat, 1 Jun 2024 11:07:08 -0400 Subject: [PATCH 30/32] Simplify statScore divisor into a constant Passed non-regression STC: https://tests.stockfishchess.org/tests/view/665b392ff4a1fd0c208ea864 LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 114752 W: 29628 L: 29495 D: 55629 Ptnml(0-2): 293, 13694, 29269, 13827, 293 Passed non-regression LTC: https://tests.stockfishchess.org/tests/view/665b588c11645bd3d3fac467 LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 65322 W: 16549 L: 16373 D: 32400 Ptnml(0-2): 30, 7146, 18133, 7322, 30 closes https://github.com/official-stockfish/Stockfish/pull/5337 bench 1241443 --- src/numa.h | 2 +- src/search.cpp | 5 +++-- src/thread.cpp | 6 +++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/numa.h b/src/numa.h index ee84e1cf3..967e24a66 100644 --- a/src/numa.h +++ b/src/numa.h @@ -564,7 +564,7 @@ class NumaConfig { { const size_t procGroupIndex = c / WIN_PROCESSOR_GROUP_SIZE; const size_t idxWithinProcGroup = c % WIN_PROCESSOR_GROUP_SIZE; - // We skip processors that are not in the same proccessor group. + // We skip processors that are not in the same processor group. // If everything was set up correctly this will never be an issue, // but we have to account for bad NUMA node specification. if (procGroupIndex != forcedProcGroupIndex) diff --git a/src/search.cpp b/src/search.cpp index 35de756ff..84ca93f8e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -160,7 +160,8 @@ void Search::Worker::start_searching() { return; } - main_manager()->tm.init(limits, rootPos.side_to_move(), rootPos.game_ply(), options, main_manager()->originalTimeAdjust); + main_manager()->tm.init(limits, rootPos.side_to_move(), rootPos.game_ply(), options, + main_manager()->originalTimeAdjust); tt.new_search(); if (rootMoves.empty()) @@ -1169,7 +1170,7 @@ moves_loop: // When in check, search starts here + (*contHist[1])[movedPiece][move.to_sq()] - 5169; // Decrease/increase reduction for moves with a good/bad history (~8 Elo) - r -= ss->statScore / (12219 - std::min(depth, 13) * 120); + r -= ss->statScore / 11049; // Step 17. Late moves reduction / extension (LMR, ~117 Elo) if (depth >= 2 && moveCount > 1 + rootNode) diff --git a/src/thread.cpp b/src/thread.cpp index 1b0fffc35..a36c2efb7 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -217,9 +217,9 @@ void ThreadPool::clear() { main_manager()->bestPreviousAverageScore = VALUE_INFINITE; main_manager()->previousTimeReduction = 0.85; - main_manager()->callsCnt = 0; - main_manager()->bestPreviousScore = VALUE_INFINITE; - main_manager()->originalTimeAdjust = -1; + main_manager()->callsCnt = 0; + main_manager()->bestPreviousScore = VALUE_INFINITE; + main_manager()->originalTimeAdjust = -1; main_manager()->tm.clear(); } From 8aaae0367cfed7ae5da54d330b65d76d4b1b13ae Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 2 Jun 2024 09:18:19 +0200 Subject: [PATCH 31/32] Revert "Adjust return bonus from tt cutoffs at fail highs" This reverts commit 783dfc2eb235236ff799618436d68d0c1a3f3807. could lead to a division by zero for: ttValue = (ttValue * tte->depth() + beta) / (tte->depth() + 1) as other threads can overwrite the tte with a QS depth of -1. closes https://github.com/official-stockfish/Stockfish/pull/5338 Bench: 1280020 --- src/search.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 84ca93f8e..a2a75af0c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -640,12 +640,7 @@ Value Search::Worker::search( // Partial workaround for the graph history interaction problem // For high rule50 counts don't produce transposition table cutoffs. if (pos.rule50_count() < 90) - { - if (ttValue >= beta && std::abs(ttValue) < VALUE_TB_WIN_IN_MAX_PLY - && std::abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) - ttValue = (ttValue * tte->depth() + beta) / (tte->depth() + 1); return ttValue; - } } // Step 5. Tablebases probe From a2a7edf4c8fa145667135bf1bc7f4f67016f7608 Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Sun, 2 Jun 2024 20:39:25 +0200 Subject: [PATCH 32/32] Fix GetProcessGroupAffinity call `GetProcessGroupAffinity` appears to require 4 byte alignment for `GroupArray` memory. See https://stackoverflow.com/q/78567676 for further information closes https://github.com/official-stockfish/Stockfish/pull/5340 No functional change --- src/numa.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/numa.h b/src/numa.h index 967e24a66..5934a0cd8 100644 --- a/src/numa.h +++ b/src/numa.h @@ -773,8 +773,8 @@ class NumaConfig { return std::nullopt; // We are expecting a single group. - USHORT GroupCount = 1; - USHORT GroupArray[1]; + USHORT GroupCount = 1; + alignas(4) USHORT GroupArray[1]; status = GetProcessGroupAffinity_f(GetCurrentProcess(), &GroupCount, GroupArray); if (status == 0 || GroupCount != 1) return std::nullopt;