Compare commits

...

10 Commits

Author SHA1 Message Date
FauziAkram
ce73441f20 Simplify sudden death time optimization
Passed Sudden Death STC:
https://tests.stockfishchess.org/tests/view/68455fe5375c2b77d9855351
LLR: 2.91 (-2.94,2.94) <-1.75,0.25>
Total: 49248 W: 13008 L: 12798 D: 23442
Ptnml(0-2): 309, 5491, 12821, 5687, 316

Passed Sudden Death LTC:
https://tests.stockfishchess.org/tests/view/6845a392375c2b77d98553cf
LLR: 3.01 (-2.94,2.94) <-1.75,0.25>
Total: 551070 W: 141699 L: 142031 D: 267340
Ptnml(0-2): 1923, 60608, 150916, 60054, 2034

Passed Standard STC:
https://tests.stockfishchess.org/tests/view/683c5ebb6ec7634154f9d989
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 142624 W: 36808 L: 36709 D: 69107
Ptnml(0-2): 302, 15448, 39745, 15483, 334

Passed Standard LTC:
https://tests.stockfishchess.org/tests/view/683f1a4f6ec7634154f9dc5a
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 146922 W: 37381 L: 37296 D: 72245
Ptnml(0-2): 69, 13552, 46117, 13671, 52

closes https://github.com/official-stockfish/Stockfish/pull/6132

Bench: 2249459
2025-07-02 18:41:46 +02:00
FauziAkram
e695b9537e Remove eval & beta diff from NM reduction
Passed STC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 43456 W: 11178 L: 10966 D: 21312
Ptnml(0-2): 114, 5078, 11114, 5326, 96
https://tests.stockfishchess.org/tests/view/6849ae13e84567164b5c9de9

Passed LTC:
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 63090 W: 16302 L: 16125 D: 30663
Ptnml(0-2): 37, 6837, 17603, 7048, 20
https://tests.stockfishchess.org/tests/view/684ab516e84567164b5ca02f

closes https://github.com/official-stockfish/Stockfish/pull/6134

Bench: 2249459
2025-07-02 18:41:46 +02:00
mstembera
ce7254b5ea Optimize find_nnz() using AVX512
About a 1% speedup for ARCH x86-64-avx512 and x86-64-vnni512.

Note:  This could be optimized further if we wanted to add an ARCH
supporting VBMI2 which is even more modern than VNNI.

https://en.wikichip.org/wiki/x86/avx512_vbmi2

closes https://github.com/official-stockfish/Stockfish/pull/6139

No functional change
2025-07-02 18:41:45 +02:00
MinetaS
ea85a54fef Fix trivial errors in Makefile
1. Remove "default" rule as "default" has no special meaning as a rule
name. Make runs the very first rule whose name doesn't begin with a dot
(which is "help" currently).

2. Make "format" rule not update dependencies.

closes https://github.com/official-stockfish/Stockfish/pull/6140

No functional change
2025-07-02 18:32:12 +02:00
Robert Nurnberg @ elitebook
84e2f3851d Introduce a constant for ValueList size in search()
Having the size of these lists in two separate places likely contributed
to the crashes seen during the recent tuning attempt
https://tests.stockfishchess.org/tests/view/685c413343ce022d15794536.

Thanks to @MinetaS for spotting this.

closes https://github.com/official-stockfish/Stockfish/pull/6142

No functional change
2025-07-02 18:32:02 +02:00
Daniel Monroe
3a0fff96cf Simplify quiet move streak logic
Passed non-regression STC
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 148960 W: 38409 L: 38312 D: 72239
Ptnml(0-2): 372, 17664, 38318, 17747, 379
https://tests.stockfishchess.org/tests/view/684c5773703522d4f129c5f7

Passed non-regression LTC
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 180720 W: 46188 L: 46130 D: 88402
Ptnml(0-2): 84, 19608, 50929, 19644, 95
https://tests.stockfishchess.org/tests/view/68505fa5703522d4f129cbab

closes https://github.com/official-stockfish/Stockfish/pull/6143

Bench: 2055894
2025-07-02 18:31:04 +02:00
Shawn Xu
318c948c4d Remove non-functional low-ply history fill
lowPlyHistory is always cleared at the start of `iterative_deepening`, so clearing it here is non-functional.

closes https://github.com/official-stockfish/Stockfish/pull/6144

No functional change
2025-07-02 18:31:04 +02:00
Daniel Monroe
a7a56c41f6 Simplify history term in futility pruning
Passed simplification STC
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 298816 W: 76814 L: 76881 D: 145121
Ptnml(0-2): 726, 35477, 77057, 35434, 714
https://tests.stockfishchess.org/tests/view/683f440f6ec7634154f9dc7f

Passed simplification LTC
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 237774 W: 60801 L: 60802 D: 116171
Ptnml(0-2): 91, 26088, 66532, 26083, 93
https://tests.stockfishchess.org/tests/view/68441189ffbc71bd236778de

closes https://github.com/official-stockfish/Stockfish/pull/6130

Bench: 2411502
2025-07-02 18:31:04 +02:00
pb00067
34b75f1575 Restore integrity of MovePicker::can_move_king_or_pawn
PR6005 broken by PR6071

passed STC non regression
https://tests.stockfishchess.org/tests/view/6839791f6ec7634154f9d312
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 31776 W: 8353 L: 8130 D: 15293
Ptnml(0-2): 74, 3566, 8382, 3795, 71

passed LTC non-regression
https://tests.stockfishchess.org/tests/view/6839c87a6ec7634154f9d367
LLR: 2.94 (-2.94,2.94) <-1.75,0.25>
Total: 120756 W: 31015 L: 30899 D: 58842
Ptnml(0-2): 50, 12732, 34703, 12838, 55

closes https://github.com/official-stockfish/Stockfish/pull/6119

Bench: 1945300
2025-07-02 18:31:02 +02:00
disservin
15555e8f4a Disable linux gcc riscv64 (#6145)
Temporarily disable it, until we figure out the toolchain issues which are causing the crashes.

closes https://github.com/official-stockfish/Stockfish/pull/6145

No functional change
2025-06-29 12:33:20 +02:00
7 changed files with 89 additions and 64 deletions

View File

@@ -39,14 +39,15 @@ jobs:
comp: ndk
run_armv7_tests: true
shell: bash
- name: Linux GCC riscv64
os: ubuntu-22.04
compiler: g++
comp: gcc
run_riscv64_tests: true
base_image: "riscv64/alpine:edge"
platform: linux/riscv64
shell: bash
# Currently segfaults in the CI unrelated to a Stockfish change.
# - name: Linux GCC riscv64
# os: ubuntu-22.04
# compiler: g++
# comp: gcc
# run_riscv64_tests: true
# base_image: "riscv64/alpine:edge"
# platform: linux/riscv64
# shell: bash
- name: Linux GCC ppc64
os: ubuntu-22.04
compiler: g++

View File

@@ -701,7 +701,7 @@ endif
ifeq ($(avx512),yes)
CXXFLAGS += -DUSE_AVX512
ifeq ($(comp),$(filter $(comp),gcc clang mingw icx))
CXXFLAGS += -mavx512f -mavx512bw
CXXFLAGS += -mavx512f -mavx512bw -mavx512dq -mavx512vl
endif
endif
@@ -996,10 +996,6 @@ net:
format:
$(CLANG-FORMAT) -i $(SRCS) $(HEADERS) -style=file
# default target
default:
help
### ==========================================================================
### Section 5. Private Targets
### ==========================================================================
@@ -1125,6 +1121,6 @@ icx-profile-use:
.depend: $(SRCS)
-@$(CXX) $(DEPENDFLAGS) -MM $(SRCS) > $@ 2> /dev/null
ifeq (, $(filter $(MAKECMDGOALS), help strip install clean net objclean profileclean config-sanity))
ifeq (, $(filter $(MAKECMDGOALS), help strip install clean net objclean profileclean format config-sanity))
-include .depend
endif

View File

@@ -56,6 +56,7 @@ enum Stages {
QCAPTURE
};
// Sort moves in descending order up to and including a given limit.
// The order of moves smaller than the limit is left unspecified.
void partial_insertion_sort(ExtMove* begin, ExtMove* end, int limit) {
@@ -207,6 +208,7 @@ Move MovePicker::select(Pred filter) {
// picking the move with the highest score from a list of generated moves.
Move MovePicker::next_move() {
constexpr int goodQuietThreshold = -14000;
top:
switch (stage)
{
@@ -222,7 +224,7 @@ top:
case PROBCUT_INIT :
case QCAPTURE_INIT :
cur = endBadCaptures = moves;
endCur = generate<CAPTURES>(pos, cur);
endCur = endCaptures = generate<CAPTURES>(pos, cur);
score<CAPTURES>();
partial_insertion_sort(cur, endCur, std::numeric_limits<int>::min());
@@ -244,8 +246,7 @@ top:
case QUIET_INIT :
if (!skipQuiets)
{
cur = endBadQuiets = endBadCaptures;
endCur = generate<QUIETS>(pos, cur);
endCur = endGenerated = generate<QUIETS>(pos, cur);
score<QUIETS>();
partial_insertion_sort(cur, endCur, -3560 * depth);
@@ -255,12 +256,7 @@ top:
[[fallthrough]];
case GOOD_QUIET :
if (!skipQuiets && select([&]() {
if (cur->value > -14000)
return true;
*endBadQuiets++ = *cur;
return false;
}))
if (!skipQuiets && select([&]() { return cur->value > goodQuietThreshold; }))
return *(cur - 1);
// Prepare the pointers to loop over the bad captures
@@ -274,22 +270,22 @@ top:
if (select([]() { return true; }))
return *(cur - 1);
// Prepare the pointers to loop over the bad quiets
cur = endBadCaptures;
endCur = endBadQuiets;
// Prepare the pointers to loop over quiets again
cur = endCaptures;
endCur = endGenerated;
++stage;
[[fallthrough]];
case BAD_QUIET :
if (!skipQuiets)
return select([]() { return true; });
return select([&]() { return cur->value <= goodQuietThreshold; });
return Move::none();
case EVASION_INIT :
cur = moves;
endCur = generate<EVASIONS>(pos, cur);
endCur = endGenerated = generate<EVASIONS>(pos, cur);
score<EVASIONS>();
partial_insertion_sort(cur, endCur, std::numeric_limits<int>::min());
@@ -315,7 +311,7 @@ bool MovePicker::can_move_king_or_pawn() const {
// SEE negative captures shouldn't be returned in GOOD_CAPTURE stage
assert(stage > GOOD_CAPTURE && stage != EVASION_INIT);
for (const ExtMove* m = moves; m < endCur; ++m)
for (const ExtMove* m = moves; m < endGenerated; ++m)
{
PieceType movedPieceType = type_of(pos.moved_piece(*m));
if ((movedPieceType == PAWN || movedPieceType == KING) && pos.legal(*m))

View File

@@ -67,7 +67,7 @@ class MovePicker {
const PieceToHistory** continuationHistory;
const PawnHistory* pawnHistory;
Move ttMove;
ExtMove * cur, *endCur, *endBadCaptures, *endBadQuiets;
ExtMove * cur, *endCur, *endBadCaptures, *endCaptures, *endGenerated;
int stage;
int threshold;
Depth depth;

View File

@@ -68,9 +68,42 @@ alignas(CacheLineSize) static constexpr struct OffsetIndices {
} Lookup;
#if defined(__GNUC__) || defined(__clang__)
#define RESTRICT __restrict__
#elif defined(_MSC_VER)
#define RESTRICT __restrict
#else
#define RESTRICT
#endif
// Find indices of nonzero numbers in an int32_t array
template<const IndexType InputDimensions>
void find_nnz(const std::int32_t* input, std::uint16_t* out, IndexType& count_out) {
void find_nnz(const std::int32_t* RESTRICT input,
std::uint16_t* RESTRICT out,
IndexType& count_out) {
#ifdef USE_AVX512
constexpr IndexType SimdWidth = 16; // 512 bits / 32 bits
constexpr IndexType NumChunks = InputDimensions / SimdWidth;
const __m512i increment = _mm512_set1_epi32(SimdWidth);
__m512i base = _mm512_set_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0);
IndexType count = 0;
for (IndexType i = 0; i < NumChunks; ++i)
{
const __m512i inputV = _mm512_load_si512(input + i * SimdWidth);
// Get a bitmask and gather non zero indices
const __mmask16 nnzMask = _mm512_test_epi32_mask(inputV, inputV);
const __m512i nnzV = _mm512_maskz_compress_epi32(nnzMask, base);
_mm512_mask_cvtepi32_storeu_epi16(out + count, 0xFFFF, nnzV);
count += popcount(nnzMask);
base = _mm512_add_epi32(base, increment);
}
count_out = count;
#else
using namespace SIMD;
constexpr IndexType InputSimdWidth = sizeof(vec_uint_t) / sizeof(std::int32_t);
@@ -104,6 +137,7 @@ void find_nnz(const std::int32_t* input, std::uint16_t* out, IndexType& count_ou
}
}
count_out = count;
#endif
}
#endif

View File

@@ -63,6 +63,9 @@ using namespace Search;
namespace {
constexpr int SEARCHEDLIST_CAPACITY = 32;
using SearchedList = ValueList<Move, SEARCHEDLIST_CAPACITY>;
// (*Scalers):
// The values with Scaler asterisks have proven non-linear scaling.
// They are optimized to time controls of 180 + 1.8 and longer,
@@ -124,8 +127,8 @@ void update_all_stats(const Position& pos,
Search::Worker& workerThread,
Move bestMove,
Square prevSq,
ValueList<Move, 32>& quietsSearched,
ValueList<Move, 32>& capturesSearched,
SearchedList& quietsSearched,
SearchedList& capturesSearched,
Depth depth,
Move TTMove,
int moveCount);
@@ -536,7 +539,6 @@ void Search::Worker::undo_null_move(Position& pos) { pos.undo_null_move(); }
// Reset histories, usually before a new game
void Search::Worker::clear() {
mainHistory.fill(67);
lowPlyHistory.fill(107);
captureHistory.fill(-688);
pawnHistory.fill(-1287);
pawnCorrectionHistory.fill(5);
@@ -606,8 +608,8 @@ Value Search::Worker::search(
int priorReduction;
Piece movedPiece;
ValueList<Move, 32> capturesSearched;
ValueList<Move, 32> quietsSearched;
SearchedList capturesSearched;
SearchedList quietsSearched;
// Step 1. Initialize node
Worker* thisThread = this;
@@ -857,8 +859,8 @@ Value Search::Worker::search(
{
assert(eval - beta >= 0);
// Null move dynamic reduction based on depth and eval
Depth R = std::min(int(eval - beta) / 213, 6) + depth / 3 + 5;
// Null move dynamic reduction based on depth
Depth R = 7 + depth / 3;
ss->currentMove = Move::null();
ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0];
@@ -1083,7 +1085,7 @@ moves_loop: // When in check, search starts here
lmrDepth += history / 3388;
Value baseFutility = (bestMove ? 46 : 138 + std::abs(history / 300));
Value baseFutility = (bestMove ? 46 : 230);
Value futilityValue =
ss->staticEval + baseFutility + 117 * lmrDepth + 102 * (ss->staticEval > alpha);
@@ -1207,8 +1209,7 @@ moves_loop: // When in check, search starts here
if ((ss + 1)->cutoffCnt > 2)
r += 1036 + allNode * 848;
if (!capture && !givesCheck && ss->quietMoveStreak >= 2)
r += (ss->quietMoveStreak - 1) * 50;
r += (ss + 1)->quietMoveStreak * 50;
// For first picked move (ttMove) reduce reduction
if (move == ttData.move)
@@ -1392,7 +1393,7 @@ moves_loop: // When in check, search starts here
// If the move is worse than some previously searched move,
// remember it, to update its stats later.
if (move != bestMove && moveCount <= 32)
if (move != bestMove && moveCount <= SEARCHEDLIST_CAPACITY)
{
if (capture)
capturesSearched.push_back(move);
@@ -1840,8 +1841,8 @@ void update_all_stats(const Position& pos,
Search::Worker& workerThread,
Move bestMove,
Square prevSq,
ValueList<Move, 32>& quietsSearched,
ValueList<Move, 32>& capturesSearched,
SearchedList& quietsSearched,
SearchedList& capturesSearched,
Depth depth,
Move ttMove,
int moveCount) {

View File

@@ -85,16 +85,13 @@ void TimeManagement::init(Search::LimitsType& limits,
// with constants are involved.
const int64_t scaleFactor = useNodesTime ? npmsec : 1;
const TimePoint scaledTime = limits.time[us] / scaleFactor;
const TimePoint scaledInc = limits.inc[us] / scaleFactor;
// Maximum move horizon
int centiMTG = limits.movestogo ? std::min(limits.movestogo * 100, 5000) : 5051;
// If less than one second, gradually reduce mtg
if (scaledTime < 1000 && double(centiMTG) / scaledInc > 5.051)
{
if (scaledTime < 1000)
centiMTG = scaledTime * 5.051;
}
// Make sure timeLeft is > 0 since we may use it as a divisor
TimePoint timeLeft =