From 5dda4037c73ead63b145c9a77f1dbb41422e058f Mon Sep 17 00:00:00 2001 From: rn5f107s2 Date: Wed, 5 Jun 2024 18:56:25 +0200 Subject: [PATCH 1/8] Simplify razor changes Remove razoring changes from https://github.com/official-stockfish/Stockfish/pull/5360 The mentioned patch introduced the usage of futility_margin into razoring alongside a tune to futility_margin. It seems the elo gained in this patch comes from the tune of futility_margin and not the introduction of futility_margin to razoring, so simplify it away here. Passed Non-regression STC: https://tests.stockfishchess.org/tests/view/66606581c340c8eed7757bc8 LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 169056 W: 43922 L: 43848 D: 81286 Ptnml(0-2): 438, 20288, 43034, 20298, 470 Passed Non-regression LTC: https://tests.stockfishchess.org/tests/view/66607764c340c8eed7757c58 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 157134 W: 39805 L: 39723 D: 77606 Ptnml(0-2): 74, 17444, 43461, 17502, 86 Passed rebased Non-regression LTC: https://tests.stockfishchess.org/tests/view/6660c696c340c8eed77580c0 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 135984 W: 34427 L: 34324 D: 67233 Ptnml(0-2): 67, 15063, 37615, 15194, 53 closes https://github.com/official-stockfish/Stockfish/pull/5366 Bench: 1150518 --- src/search.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 2cbc76774..e0a49dba8 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -554,7 +554,7 @@ Value Search::Worker::search( bool givesCheck, improving, priorCapture, opponentWorsening; bool capture, moveCountPruning, ttCapture; Piece movedPiece; - int moveCount, captureCount, quietCount, futilityMargin; + int moveCount, captureCount, quietCount; Bound singularBound; // Step 1. Initialize node @@ -762,12 +762,10 @@ Value Search::Worker::search( opponentWorsening = ss->staticEval + (ss - 1)->staticEval > 2; - futilityMargin = futility_margin(depth, cutNode && !ss->ttHit, improving, opponentWorsening); - // Step 7. Razoring (~1 Elo) // If eval is really low check with qsearch if it can exceed alpha, if it can't, // return a fail low. - if (eval < alpha - 465 - futilityMargin * depth * 33 / 32) + if (eval < alpha - 512 - 293 * depth * depth) { value = qsearch(pos, ss, alpha - 1, alpha); if (value < alpha) @@ -776,7 +774,10 @@ Value Search::Worker::search( // Step 8. Futility pruning: child node (~40 Elo) // The depth condition is important for mate finding. - if (!ss->ttPv && depth < 13 && eval - futilityMargin - (ss - 1)->statScore / 263 >= beta + if (!ss->ttPv && depth < 13 + && eval - futility_margin(depth, cutNode && !ss->ttHit, improving, opponentWorsening) + - (ss - 1)->statScore / 263 + >= beta && eval >= beta && eval < VALUE_TB_WIN_IN_MAX_PLY && (!ttMove || ttCapture)) return beta > VALUE_TB_LOSS_IN_MAX_PLY ? beta + (eval - beta) / 3 : eval; From e2be0aaf67569788f0d1e726d0a86ce1604958da Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Thu, 6 Jun 2024 13:07:45 +0300 Subject: [PATCH 2/8] Tweak pruning formula Tweak pruning formula, including a constant. I started from an old yellow patch, if I'm not mistaken by Viz (Unfortunately I lost the link) where he tried something similar. I worked on it, trying different variations, until I came up with a good configuration to pass. Passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 213120 W: 55351 L: 54778 D: 102991 Ptnml(0-2): 572, 25209, 54437, 25758, 584 https://tests.stockfishchess.org/tests/view/6660c9a7c340c8eed7758195 Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 315324 W: 80176 L: 79284 D: 155864 Ptnml(0-2): 155, 34711, 87030, 35619, 147 https://tests.stockfishchess.org/tests/view/6660d7bb6489614cdad13d66 closes https://github.com/official-stockfish/Stockfish/pull/5370 Bench: 1231853 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index e0a49dba8..7417a4b6f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1580,7 +1580,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, // If static exchange evaluation is much worse than what is needed to not // fall below alpha we can prune this move. - if (futilityBase > alpha && !pos.see_ge(move, (alpha - futilityBase) * 4)) + if (futilityBase > alpha && !pos.see_ge(move, (alpha - futilityBase) * 2 - 30)) { bestValue = alpha; continue; From f55239b2f374a2f98717e7c361732f7c4510388b Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Thu, 6 Jun 2024 12:47:24 +0200 Subject: [PATCH 3/8] NumaPolicy fixes and robustness improvements 1. Fix GetProcessGroupAffinity still not getting properly aligned memory sometimes. 2. Fix a very theoretically possible heap corruption if GetActiveProcessorGroupCount changes between calls. 3. Fully determine affinity on Windows 11 and Windows Server 2022. It should only ever be indeterminate in case of an error. 4. Separate isDeterminate for old and new API, as they are &'d together we still can end up with a subset of processors even if one API is indeterminate. 5. likely_used_old_api() that is based on actual affinity that's been detected 6. IMPORTANT: Gather affinities at startup, so that we only later use the affinites set at startup. Not only does this prevent us from our own calls interfering with detection but it also means subsequent setoption NumaPolicy calls should behave as expected. 7. Fix ERROR_INSUFFICIENT_BUFFER from GetThreadSelectedCpuSetMasks being treated like an error. Should resolve https://github.com/vondele/Stockfish/commit/02ff76630b358e5f958793cc93df0009d2da65a5#commitcomment-142790025 closes https://github.com/official-stockfish/Stockfish/pull/5372 Bench: 1231853 --- src/numa.h | 284 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 203 insertions(+), 81 deletions(-) diff --git a/src/numa.h b/src/numa.h index c170c178e..fd9abd4db 100644 --- a/src/numa.h +++ b/src/numa.h @@ -35,6 +35,8 @@ #include #include +#include "memory.h" + // 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__) @@ -96,15 +98,15 @@ inline const CpuIndex SYSTEM_THREADS_NB = std::max(1, get_hardware_con struct WindowsAffinity { std::optional> oldApi; std::optional> newApi; - bool isDeterminate = true; + + // We also provide diagnostic for when the affinity is set to nullopt + // whether it was due to being indeterminate. If affinity is indeterminate + // it's best to assume it is not set at all, so consistent with the meaning + // of the nullopt affinity. + bool isNewDeterminate = true; + bool isOldDeterminate = true; std::optional> get_combined() const { - // When the affinity is not determinate we treat it as no affinity, - // because otherwise we would have to set affinity to fewer - // processors than we currently have affinity to. - if (!isDeterminate) - return std::nullopt; - if (!oldApi.has_value()) return newApi; if (!newApi.has_value()) @@ -115,47 +117,53 @@ struct WindowsAffinity { std::inserter(intersect, intersect.begin())); return intersect; } + + // Since Windows 11 and Windows Server 2022 thread affinities can span + // processor groups and can be set as such by a new WinAPI function. + // However, we may need to force using the old API if we detect + // that the process has affinity set by the old API already and we want to override that. + // Due to the limitations of the old API we can't detect its use reliably. + // There will be cases where we detect not use but it has actually been used and vice versa. + bool likely_used_old_api() const { return oldApi.has_value() || !isOldDeterminate; } }; inline std::pair> get_process_group_affinity() { - WORD numProcGroups = GetActiveProcessorGroupCount(); - // GetProcessGroupAffinity requires the GroupArray argument to be // aligned to 4 bytes instead of just 2. static constexpr size_t GroupArrayMinimumAlignment = 4; static_assert(GroupArrayMinimumAlignment >= alignof(USHORT)); - auto GroupArray = std::make_unique( - numProcGroups + (GroupArrayMinimumAlignment / alignof(USHORT) - 1)); + // The function should succeed the second time, but it may fail if the group + // affinity has changed between GetProcessGroupAffinity calls. + // In such case we consider this a hard error, as we can't work with unstable affinities + // anyway. + static constexpr int MAX_TRIES = 2; + USHORT GroupCount = 1; + for (int i = 0; i < MAX_TRIES; ++i) + { + auto GroupArray = std::make_unique( + GroupCount + (GroupArrayMinimumAlignment / alignof(USHORT) - 1)); - USHORT GroupCount = static_cast(numProcGroups); - const BOOL status = GetProcessGroupAffinity(GetCurrentProcess(), &GroupCount, GroupArray.get()); + USHORT* GroupArrayAligned = align_ptr_up(GroupArray.get()); - return std::make_pair(status, std::vector(GroupArray.get(), GroupArray.get() + GroupCount)); + const BOOL status = + GetProcessGroupAffinity(GetCurrentProcess(), &GroupCount, GroupArrayAligned); + + if (status == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + break; + } + + if (status != 0) + { + return std::make_pair(status, + std::vector(GroupArrayAligned, GroupArrayAligned + GroupCount)); + } + } + + return std::make_pair(0, std::vector()); } -// Since Windows 11 and Windows Server 2022 thread affinities can span -// processor groups and can be set as such by a new WinAPI function. -// However, we may need to force using the old API if we detect -// that the process has affinity set by the old API already and we want to override that. -inline bool use_old_affinity_api() { - HMODULE k32 = GetModuleHandle(TEXT("Kernel32.dll")); - auto SetThreadSelectedCpuSetMasks_f = SetThreadSelectedCpuSetMasks_t( - (void (*)()) GetProcAddress(k32, "SetThreadSelectedCpuSetMasks")); - - if (SetThreadSelectedCpuSetMasks_f == nullptr) - return true; - - auto [status, groupAffinity] = get_process_group_affinity(); - - // If GroupCount > 1 then we know old API was never used and we can stick - // to the new API safely. - if (status != 0 && groupAffinity.size() > 1) - return false; - - return true; -}; - // 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. @@ -171,83 +179,183 @@ inline WindowsAffinity get_process_affinity() { auto GetThreadSelectedCpuSetMasks_f = GetThreadSelectedCpuSetMasks_t( (void (*)()) GetProcAddress(k32, "GetThreadSelectedCpuSetMasks")); + BOOL status = 0; + WindowsAffinity affinity; if (GetThreadSelectedCpuSetMasks_f != nullptr) { USHORT RequiredMaskCount; - BOOL status = - GetThreadSelectedCpuSetMasks_f(GetCurrentThread(), nullptr, 0, &RequiredMaskCount); + status = 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 (status == 0) + // We expect ERROR_INSUFFICIENT_BUFFER from GetThreadSelectedCpuSetMasks, + // but other failure is an actual error. + if (status == 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) { - affinity.isDeterminate = false; - return affinity; + affinity.isNewDeterminate = false; } - - if (RequiredMaskCount > 0) + else if (RequiredMaskCount > 0) { - std::set cpus; - + // If RequiredMaskCount then these affinities were never set, but it's not consistent + // so GetProcessAffinityMask may still return some affinity. auto groupAffinities = std::make_unique(RequiredMaskCount); - GetThreadSelectedCpuSetMasks_f(GetCurrentThread(), groupAffinities.get(), - RequiredMaskCount, &RequiredMaskCount); + status = GetThreadSelectedCpuSetMasks_f(GetCurrentThread(), groupAffinities.get(), + RequiredMaskCount, &RequiredMaskCount); - for (USHORT i = 0; i < RequiredMaskCount; ++i) + if (status == 0) { - 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); - } + affinity.isNewDeterminate = false; } + else + { + std::set cpus; - affinity.newApi = std::move(cpus); + 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); + } + } + + affinity.newApi = std::move(cpus); + } } } + // NOTE: There is no way to determine full affinity using the old API if + // individual threads set affinity on different processor groups. + DWORD_PTR proc, sys; - BOOL status = GetProcessAffinityMask(GetCurrentProcess(), &proc, &sys); + status = GetProcessAffinityMask(GetCurrentProcess(), &proc, &sys); // If proc == 0 then we can't determine affinity because it spans processor groups. + // On Windows 11 and Server 2022 it will instead + // > If, however, hHandle specifies a handle to the current process, the function + // > always uses the calling thread's primary group (which by default is the same + // > as the process' primary group) in order to set the + // > lpProcessAffinityMask and lpSystemAffinityMask. + // So it will never be indeterminate here. We can only make assumptions later. if (status == 0 || proc == 0) { - affinity.isDeterminate = false; + affinity.isOldDeterminate = false; return affinity; } // If SetProcessAffinityMask was never called the affinity // must span all processor groups, but if it was called it must only span one. - auto [status2, groupAffinity] = get_process_group_affinity(); - if (status2 == 0) + std::vector groupAffinity; // We need to capture this later and capturing + // from structured bindings requires c++20. + std::tie(status, groupAffinity) = get_process_group_affinity(); + if (status == 0) { - affinity.isDeterminate = false; + affinity.isOldDeterminate = false; return affinity; } - // If we have affinity for more than 1 group then at this point we - // can assume SetProcessAffinityMask has never been called and therefore - // according ot old API we do not have any affinity set. - // Otherwise we have to assume we have affinity set and gather the processor IDs. if (groupAffinity.size() == 1) { - std::set cpus; - - const size_t procGroupIndex = groupAffinity[0]; - - uint64_t mask = static_cast(proc); - for (size_t j = 0; j < WIN_PROCESSOR_GROUP_SIZE; ++j) + // We detect the case when affinity is set to all processors and correctly + // leave affinity.oldApi as nullopt. + if (GetActiveProcessorGroupCount() != 1 || proc != sys) { - if (mask & (KAFFINITY(1) << j)) - cpus.insert(procGroupIndex * WIN_PROCESSOR_GROUP_SIZE + j); - } + std::set cpus; - affinity.oldApi = std::move(cpus); + const size_t procGroupIndex = groupAffinity[0]; + + const 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); + } + + affinity.oldApi = std::move(cpus); + } + } + else + { + // If we got here it means that either SetProcessAffinityMask was never set + // or we're on Windows 11/Server 2022. + + // Since Windows 11 and Windows Server 2022 the behaviour of GetProcessAffinityMask changed + // > If, however, hHandle specifies a handle to the current process, the function + // > always uses the calling thread's primary group (which by default is the same + // > as the process' primary group) in order to set the + // > lpProcessAffinityMask and lpSystemAffinityMask. + // In which case we can actually retrieve the full affinity. + + if (GetThreadSelectedCpuSetMasks_f != nullptr) + { + std::thread th([&]() { + std::set cpus; + bool isAffinityFull = true; + + for (auto procGroupIndex : groupAffinity) + { + const int numActiveProcessors = + GetActiveProcessorCount(static_cast(procGroupIndex)); + + // We have to schedule to 2 different processors and & the affinities we get. + // Otherwise our processor choice could influence the resulting affinity. + // We assume the processor IDs within the group are filled sequentially from 0. + uint64_t procCombined = std::numeric_limits::max(); + uint64_t sysCombined = std::numeric_limits::max(); + + for (int i = 0; i < std::min(numActiveProcessors, 2); ++i) + { + GROUP_AFFINITY GroupAffinity; + std::memset(&GroupAffinity, 0, sizeof(GROUP_AFFINITY)); + GroupAffinity.Group = static_cast(procGroupIndex); + + GroupAffinity.Mask = static_cast(1) << i; + + status = + SetThreadGroupAffinity(GetCurrentThread(), &GroupAffinity, nullptr); + if (status == 0) + { + affinity.isOldDeterminate = false; + return; + } + + SwitchToThread(); + + DWORD_PTR proc2, sys2; + status = GetProcessAffinityMask(GetCurrentProcess(), &proc2, &sys2); + if (status == 0) + { + affinity.isOldDeterminate = false; + return; + } + + procCombined &= static_cast(proc2); + sysCombined &= static_cast(sys2); + } + + if (procCombined != sysCombined) + isAffinityFull = false; + + for (size_t j = 0; j < WIN_PROCESSOR_GROUP_SIZE; ++j) + { + if (procCombined & (KAFFINITY(1) << j)) + cpus.insert(procGroupIndex * WIN_PROCESSOR_GROUP_SIZE + j); + } + } + + // We have to detect the case where the affinity was not set, or is set to all processors + // so that we correctly produce as std::nullopt result. + if (!isAffinityFull) + { + affinity.oldApi = std::move(cpus); + } + }); + + th.join(); + } } return affinity; @@ -300,6 +408,18 @@ inline std::set get_process_affinity() { #endif +#if defined(__linux__) && !defined(__ANDROID__) + +inline static const auto STARTUP_PROCESSOR_AFFINITY = get_process_affinity(); + +#elif defined(_WIN64) + +inline static const auto STARTUP_PROCESSOR_AFFINITY = get_process_affinity(); +inline static const auto STARTUP_USE_OLD_AFFINITY_API = + STARTUP_PROCESSOR_AFFINITY.likely_used_old_api(); + +#endif + // 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 // machinery to be able to access NUMA replicated memory. @@ -326,6 +446,8 @@ class NumaReplicatedAccessToken { // It is guaranteed that NUMA nodes are NOT empty, i.e. every node exposed by NumaConfig // has at least one processor assigned. // +// We use startup affinities so as not to modify its own behaviour in time. +// // Until Stockfish doesn't support exceptions all places where an exception should be thrown // are replaced by std::exit. class NumaConfig { @@ -349,7 +471,7 @@ class NumaConfig { std::set allowedCpus; if (respectProcessAffinity) - allowedCpus = get_process_affinity(); + allowedCpus = STARTUP_PROCESSOR_AFFINITY; auto is_cpu_allowed = [respectProcessAffinity, &allowedCpus](CpuIndex c) { return !respectProcessAffinity || allowedCpus.count(c) == 1; @@ -414,7 +536,7 @@ class NumaConfig { std::optional> allowedCpus; if (respectProcessAffinity) - allowedCpus = get_process_affinity().get_combined(); + allowedCpus = STARTUP_PROCESSOR_AFFINITY.get_combined(); // 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. @@ -451,7 +573,7 @@ class NumaConfig { // still no way to set thread affinity spanning multiple processor groups. // See https://learn.microsoft.com/en-us/windows/win32/procthread/numa-support // We also do this is if need to force old API for some reason. - if (use_old_affinity_api()) + if (STARTUP_USE_OLD_AFFINITY_API) { NumaConfig splitCfg = empty(); @@ -733,7 +855,7 @@ class NumaConfig { } // Sometimes we need to force the old API, but do not use it unless necessary. - if (SetThreadSelectedCpuSetMasks_f == nullptr || use_old_affinity_api()) + if (SetThreadSelectedCpuSetMasks_f == nullptr || STARTUP_USE_OLD_AFFINITY_API) { // On earlier windows version (since windows 7) we can't run a single thread // on multiple processor groups, so we need to restrict the group. From 7d4ffa175c52a425c6ebc19737586baf93f5b6ff Mon Sep 17 00:00:00 2001 From: Dubslow Date: Mon, 3 Jun 2024 17:47:03 -0500 Subject: [PATCH 4/8] Remove delta from evaluation Passed STC: https://tests.stockfishchess.org/tests/view/6660e49c6489614cdad14e29 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 188768 W: 48907 L: 48854 D: 91007 Ptnml(0-2): 584, 22571, 48005, 22656, 568 Passed LTC: https://tests.stockfishchess.org/tests/view/6660ff9791e372763104b38c LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 310680 W: 78651 L: 78727 D: 153302 Ptnml(0-2): 180, 34818, 85433, 34716, 193 closes https://github.com/official-stockfish/Stockfish/pull/5373 Bench: 1214575 --- src/evaluate.cpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index fdf35eb17..1317a01ec 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -47,7 +47,7 @@ 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; + return std::abs(simpleEval) > 962; } // Evaluate is the evaluator for the outer world. It returns a static evaluation @@ -66,25 +66,24 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, auto [psqt, positional] = smallNet ? networks.small.evaluate(pos, &caches.small) : networks.big.evaluate(pos, &caches.big); - constexpr int delta = 3; - Value nnue = ((128 - delta) * psqt + (128 + delta) * positional) / 128; - int nnueComplexity = std::abs(psqt - positional); + Value nnue = psqt + positional; + int nnueComplexity = std::abs(psqt - positional); // Re-evaluate the position when higher eval accuracy is worth the time spent - if (smallNet && (nnue * simpleEval < 0 || std::abs(nnue) < 250)) + if (smallNet && (nnue * simpleEval < 0 || std::abs(nnue) < 227)) { std::tie(psqt, positional) = networks.big.evaluate(pos, &caches.big); - nnue = ((128 - delta) * psqt + (128 + delta) * positional) / 128; + nnue = psqt + positional; nnueComplexity = std::abs(psqt - positional); smallNet = false; } // Blend optimism and eval with nnue complexity - optimism += optimism * nnueComplexity / 470; - nnue -= nnue * nnueComplexity / 20000; + optimism += optimism * nnueComplexity / 457; + nnue -= nnue * nnueComplexity / 19157; - int material = 600 * pos.count() + pos.non_pawn_material(); - v = (nnue * (68600 + material) + optimism * (8800 + material)) / 73344; + int material = 554 * pos.count() + pos.non_pawn_material(); + v = (nnue * (73921 + material) + optimism * (8112 + material)) / 73260; // Damp down the evaluation linearly when shuffling v -= v * pos.rule50_count() / 212; From 1c67b46caf91a0e6277967ea9a7e4b2f6afbc971 Mon Sep 17 00:00:00 2001 From: Dubslow Date: Thu, 6 Jun 2024 13:10:30 -0500 Subject: [PATCH 5/8] Linearize corrHist Passed STC: https://tests.stockfishchess.org/tests/view/6661fff88dd8f31ed3c5d819 LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 17504 W: 4651 L: 4406 D: 8447 Ptnml(0-2): 71, 1975, 4384, 2282, 40 Passed LTC: https://tests.stockfishchess.org/tests/view/666205b48dd8f31ed3c61296 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 24522 W: 6313 L: 6094 D: 12115 Ptnml(0-2): 14, 2643, 6726, 2866, 12 closes https://github.com/official-stockfish/Stockfish/pull/5374 Bench: 1237729 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 7417a4b6f..06adc92a3 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -74,7 +74,7 @@ constexpr int futility_move_count(bool improving, Depth depth) { // Add correctionHistory value to raw staticEval and guarantee evaluation does not hit the tablebase range Value to_corrected_static_eval(Value v, const Worker& w, const Position& pos) { auto cv = w.correctionHistory[pos.side_to_move()][pawn_structure_index(pos)]; - v += cv * std::abs(cv) / 4990; + v += cv / 10; return std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1); } From 4151c06b744a3145617200ca8f76285aae193dc2 Mon Sep 17 00:00:00 2001 From: evqsx <149484438+evqsx@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:43:55 +0800 Subject: [PATCH 6/8] Remove the correction history bonus in null move search Passed STC: https://tests.stockfishchess.org/tests/view/666168e191e372763104c664 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 94848 W: 24708 L: 24550 D: 45590 Ptnml(0-2): 289, 11355, 24033, 11403, 344 Passed LTC: https://tests.stockfishchess.org/tests/view/6661e73591e372763104c751 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 70452 W: 17849 L: 17679 D: 34924 Ptnml(0-2): 27, 7707, 19596, 7861, 35 closes https://github.com/official-stockfish/Stockfish/pull/5375 Bench: 1174094 --- AUTHORS | 1 + src/search.cpp | 9 --------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/AUTHORS b/AUTHORS index a232e115f..6eefb56dd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -72,6 +72,7 @@ Ehsan Rashid (erashid) Elvin Liu (solarlight2) erbsenzaehler Ernesto Gatti +evqsx Fabian Beuke (madnight) Fabian Fichter (ianfab) Fanael Linithien (Fanael) diff --git a/src/search.cpp b/src/search.cpp index 06adc92a3..8ae12e68b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -805,16 +805,7 @@ Value Search::Worker::search( if (nullValue >= beta && nullValue < VALUE_TB_WIN_IN_MAX_PLY) { if (thisThread->nmpMinPly || depth < 16) - { - if (nullValue >= ss->staticEval) - { - auto bonus = std::min(int(nullValue - ss->staticEval) * depth / 32, - CORRECTION_HISTORY_LIMIT / 16); - thisThread->correctionHistory[us][pawn_structure_index(pos)] - << bonus; - } return nullValue; - } assert(!thisThread->nmpMinPly); // Recursive verification is not allowed From e271059e08c6258420af12897367ea2149220171 Mon Sep 17 00:00:00 2001 From: cj5716 <125858804+cj5716@users.noreply.github.com> Date: Fri, 7 Jun 2024 18:30:33 +0800 Subject: [PATCH 7/8] Make repeated bench runs identical fixes https://github.com/official-stockfish/Stockfish/issues/5376 closes https://github.com/official-stockfish/Stockfish/pull/5377 No functional changes --- src/tt.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tt.cpp b/src/tt.cpp index 56779b861..5a44759e4 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -94,6 +94,7 @@ void TranspositionTable::resize(size_t mbSize, ThreadPool& threads) { // Initializes the entire transposition table to zero, // in a multi-threaded way. void TranspositionTable::clear(ThreadPool& threads) { + generation8 = 0; const size_t threadCount = threads.num_threads(); for (size_t i = 0; i < threadCount; ++i) From 7e890fd048e22bfd213d46ec8eb88f7931f0315d Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 7 Jun 2024 23:53:33 +0200 Subject: [PATCH 8/8] Keep mate PVs intact. do not return a cutoff value in razoring if that value is in the mate/tb range. passed STC: https://tests.stockfishchess.org/tests/view/666381880ff7cb4868d1fe58 LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 130848 W: 34046 L: 33931 D: 62871 Ptnml(0-2): 429, 14968, 34524, 15065, 438 passed LTC: https://tests.stockfishchess.org/tests/view/66643f120612cd151f9e7788 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 39702 W: 10157 L: 9959 D: 19586 Ptnml(0-2): 20, 4108, 11402, 4296, 25 closes https://github.com/official-stockfish/Stockfish/pull/5379 Bench: 1174094 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 8ae12e68b..3dbdfd47c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -768,7 +768,7 @@ Value Search::Worker::search( if (eval < alpha - 512 - 293 * depth * depth) { value = qsearch(pos, ss, alpha - 1, alpha); - if (value < alpha) + if (value < alpha && std::abs(value) < VALUE_TB_WIN_IN_MAX_PLY) return value; }