I found these changes useful and natural when working on a patch to improve mate reporting. I can revert some of the changes if maintainers would prefer that. E.g. I am not sure whether `unset_bound_flags()` is worth defining.
closes https://github.com/official-stockfish/Stockfish/pull/6785
No functional change
Failed VVLTC non-regression
https://tests.stockfishchess.org/tests/view/69d562b84088e069540a2288
LLR: -2.96 (-2.94,2.94) <-1.75,0.25>
Total: 386998 W: 99181 L: 99760 D: 188057
Ptnml(0-2): 35, 35792, 122429, 35203, 40
Failed STC non-regression
https://tests.stockfishchess.org/tests/view/69f3c6601e5788938e86a99e
LLR: -2.93 (-2.94,2.94) <-1.75,0.25>
Total: 33696 W: 8492 L: 8795 D: 16409
Ptnml(0-2): 124, 4209, 8504, 3868, 143
Many thanks to Dubslow, Torom, ces42, Shawn, vondele, Disservin and others for discussion.
## Summary
The venerable small net has been around for quite some time now, and while the big net architecture has substantially advanced with TI, the small net has stayed with plain HalfKA. It therefore presents a few burdens: multiple net architectures to maintain, multiple nets to train, and a whole lot of templates to deal with the variable L1 size.
Locally I measure a slowdown of -2.5% in NPS with this branch – and it's probably more on non-AVX512 architectures – but a pure slowdown of that magnitude would lead to more dramatic losses (even at VVLTC) than exhibited in the above tests, suggesting that the small net's lower eval quality is deleterious.
Bonus: Shawn found this interesting PGN among the VVLTC games: https://lichess.org/study/hvo8jflc/OeTOityv `master` seems to misevaluate the fortress because all positions go to small net (the material difference is larger than the threshold).
closes https://github.com/official-stockfish/Stockfish/pull/6796
Bench: 2877007
Recent changes to this part of the code mean that the variable `completedDepth` is no longer neeeded. The only *functional* part of this patch is the effect on the thread voting formula. Basically, compared to master this patch raises the depth weight in the formula uniformly by 1. For very, very low depths this may have a tiny effect on thread selection compared to master. But in general we expect this patch to have no effect on game play at STC and LTC.
Passed STC SMP non-reg:
LLR: 2.95 (-2.94,2.94) <-1.75,0.25>
Total: 284808 W: 72944 L: 72994 D: 138870
Ptnml(0-2): 351, 32192, 77370, 32138, 353
https://tests.stockfishchess.org/tests/view/69eddd011e5788938e86a075
closes https://github.com/official-stockfish/Stockfish/pull/6793
No functional change
The uci pv suppression and PV roll-back logic in master is a bit
convoluted, which makes it hard to reason about the code. In fact,
subtle bugs that led to wrong mated-in scores in game play or a mismatch
between bestmove and first PV move were only recently fixed. Moreover,
in master the uci pv output through `pv()` is called in four different
places.
This PR proposes to simplify this logic. In this patch, the PV is sent
to the GUI from within `iterative_deepening()` only (a) for fail
highs/lows or (b) when an iteration for a root move is completed. All
other PV outputs are now handled by `start_searching()`, just before the
bestmove extraction. This easily ensures that bestmove (and ponder move)
will always be in sync with the final PV output.
The only noticeable change to master is for multi-threaded searches that
do not involve `limits.depth`. Here master would show both the PV from
the aborted search in main thread, as well as the new PV from the
selected best thread. This patch would only show the latter.
While at it, we also remove the requirement to finish at least a depth 1
search and simplify the logic around stalemates/checkmates at root and
in particular avoid any PVs that start with `Move::none()`.
Passed STC non-reg:
LLR: 2.96 (-2.94,2.94) <-1.75,0.25>
Total: 72416 W: 18784 L: 18609 D: 35023
Ptnml(0-2): 200, 7762, 20127, 7901, 218
https://tests.stockfishchess.org/tests/view/69d3ef0c33584dad27b3c85a
closes https://github.com/official-stockfish/Stockfish/pull/6704
No functional change
[Passed STC SMP](https://tests.stockfishchess.org/tests/view/694e506c572093c1986d7276):
```
LLR: 2.97 (-2.94,2.94) <0.00,2.00>
Total: 14992 W: 3924 L: 3653 D: 7415
Ptnml(0-2): 20, 1547, 4090, 1820, 19
```
[Passed LTC SMP](https://tests.stockfishchess.org/tests/live_elo/694ead61572093c1986d7365):
```
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 41146 W: 10654 L: 10342 D: 20150
Ptnml(0-2): 17, 3999, 12225, 4319, 13
```
[Passed a sanity check STC SMP post-refactoring](https://tests.stockfishchess.org/tests/view/69503997572093c1986d763a):
```
LLR: 2.94 (-2.94,2.94) <0.00,2.00>
Total: 46728 W: 12178 L: 11863 D: 22687
Ptnml(0-2): 82, 5093, 12685, 5436, 68
```
(The large gain of the first STC was probably a fluke, and this result
is more reasonable!)
After shared correction history, Viz suggested we try sharing other
histories, especially `pawnHistory`. As far as we're aware, sharing
history besides correction history (like Caissa does) is novel. The
implementation follows the same pattern as shared correction history –
the size of the history table is scaled with
`next_power_of_two(threadsInNumaNode)` and the entry is prefetched in
`do_move`.
A bit of refactoring was done to accommodate this new history. Note that
we prefetch `&history->pawn_entry(*this)[pc][to]` rather than
`&history->pawn_entry(*this)` because unlike the other entries, each
entry contains multiple cache lines.
closes https://github.com/official-stockfish/Stockfish/pull/6498
Bench: 2503391
Co-authored-by: Michael Chaly <Vizvezdenec@gmail.com>
We did quite a few tests because this is a pretty involved change with
unknown scaling behavior, but results are decent.
[STC 10+0.1 1th, non-regression](https://tests.stockfishchess.org/tests/live_elo/6941ce3b46f342e1ec210180)
```
LLR: 2.93 (-2.94,2.94) <-1.75,0.25>
Total: 83200 W: 21615 L: 21452 D: 40133
Ptnml(0-2): 247, 9064, 22844, 9169, 276
```
[STC 5+0.05 8th](https://tests.stockfishchess.org/tests/live_elo/693dc38346f342e1ec20f555)
```
LLR: 3.48 (-2.94,2.94) <0.00,2.00>
Total: 58536 W: 15067 L: 14688 D: 28781
Ptnml(0-2): 87, 6474, 15781, 6825, 101
```
[LTC 20+0.2 8th](https://tests.stockfishchess.org/tests/live_elo/693f2afb46f342e1ec20f847)
```
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 27716 W: 7211 L: 6925 D: 13580
Ptnml(0-2): 8, 2674, 8207, 2962, 7
```
[LTC 10+0.1 64th](https://tests.stockfishchess.org/tests/live_elo/694003aa46f342e1ec20fac4):
```
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 16918 W: 4439 L: 4182 D: 8297
Ptnml(0-2): 3, 1493, 5213, 1744, 6
```
[NUMA test, 5+0.05 256th](https://tests.stockfishchess.org/tests/view/6941ee4e46f342e1ec210203)
```
LLR: 2.95 (-2.94,2.94) <0.00,2.00>
Total: 7124 W: 1910 L: 1678 D: 3536
Ptnml(0-2): 0, 560, 2211, 790, 1
```
[LTC 60+0.6 64th](https://tests.stockfishchess.org/tests/live_elo/6940a85346f342e1ec20fcde):
```
LLR: 2.94 (-2.94,2.94) <0.50,2.50>
Total: 15504 W: 4045 L: 3826 D: 7633
Ptnml(0-2): 0, 1002, 5530, 1219, 1
```
Bonus (courtesy of Viz): The 1 double kill in this last test was master
blundering a cool mate in 3: https://lichess.org/jyNZuRl4
Basically the idea here is to share correction history between threads.
That way, T1 can use the correction values produced by T2, which already
searched positions with that pawn structure etc., so that T1 can search
more efficiently. The table size per thread is about the same, so we
shouldn't get a large increase in hash collisions; in fact, I'd expect a
lower collision rate overall.
Although I came up with and implemented the idea independently,
[Caissa](https://github.com/Witek902/Caissa) was the first engine to
implement corrhist sharing (and corrhist in the first place) – this idea
is not completely novel.
The table size is rounded to a power of two. In particular, it's `65536
* nextPowerOfTwo(threadCount)`. That way, the indexing operation becomes
an AND of the key bits with a mask, rather than something more expensive
(e.g., a `mul_hi64`-style approach or a modulo).
The updates are racy, like the TT, but because `entry` is hoisted into a
register, there's no risk of writing back a value that's out of the
designated range `[-D, D]`. Various attempts at rewriting using atomics
led to substantial slowdowns, so we begrudgingly ignored the functions
in thread sanitizer, but at some point we'd like to make this better.
We allocate one shared correction history per NUMA node, because the
penalty associated with crossing nodes is substantial – I get a 40% hit
with NPS=4 and 256 threads, which is intolerable. With separate tables
per NUMA node I get a 6% penalty for nodes per second, which isn't ideal
but apparently compensated for.
closes https://github.com/official-stockfish/Stockfish/pull/6478
Bench: 2690604
Co-authored-by: Disservin <disservin.social@gmail.com>
This enables different Stockfish processes that use the same weights to use the
same memory. The approach establishes equivalence by memory content, and is
compatible with NUMA replication. The benefit of sharing is reduced memory usage
and a speedup thanks to improved (inter-process) caching of the network in the
CPUs cache, and thus reduced bandwidth usage to main memory. Even though this
change doesn't benefit a user running a single process, this helps on fishtest
or e.g. for Lichess, when multiple games run concurrently, or multiple
positions are analyzed in parallel.
This concept was probably first introduced in the Monty engine
(https://github.com/official-monty/Monty/pull/62), after a discussion in
https://github.com/official-stockfish/fishtest/issues/2077 on the issue of
memory pressure. Measurements based on Torch
(https://github.com/user-attachments/files/21386224/verbatim.pdf) further
suggested that large gains were possible. Multiple other engines have
adopted this 'verbatim' format as well.
The implementation here adds the flexibility needed for SF, for example, retains
the ability to bundle compressed networks with the binary, to load nets by uci
option, and to distribute the shared nets to the proper NUMA region. This
flexibility comes with a fair amount of complexity in the implementation, such
as OS specific code, and fallback code.
For most users this should be transparent. However, for example, those running
docker containers should ensure the `--ipc` flag is set correctly, and
`--shm-size` is sufficiently large.
The benefits of this patch significantly depend on hardware, with systems with
many cores and a large (O(150MB), the net size) L3 cache benefitting typically
most. On such systems SF speedups (as measured via nps playing games with
large concurrency but just 1 thread) can be 38%, which results in master vs.
patch Elo which gains about 25 Elo.
```
# PLAYER : RATING ERROR POINTS PLAYED (%)
1 shared_memoryPR : 24.8 1.9 39432.0 73728 53
2 master : 0.0 ---- 34296.0 73728 47
```
In a multithreaded setup, where weights are already shared, that benefit is smaller,
for example on the same HW as above, but with 8t for each side.
```
# PLAYER : RATING ERROR POINTS PLAYED (%)
1 shared_memoryPR : 5.2 3.5 9351.0 18432 51
2 master : 0.0 ---- 9081.0 18432 49
```
On fishtest with a typical hardware mix of our contributors, the following was measured:
STC, 60k games
https://tests.stockfishchess.org/tests/view/69074a49ea4b268f1fac236c
Elo: 4.69 ± 1.4 (95%) LOS: 100.0%
Total: 60000 W: 16085 L: 15275 D: 28640
Ptnml(0-2): 154, 6440, 16053, 7148, 205
nElo: 9.38 ± 2.8 (95%) PairsRatio: 1.12
To verify correctness with a single process on a NUMA architecture,
speedtest was used, confirming near equivalence:
```
master: Average (over 10): 296236186
shared_memory: Average (over 10): 295769332
```
Currently, using large pages for the shared network weights is not always possible,
which can lead to a small slowdown (1-2%), in case a single process is run.
closes https://github.com/official-stockfish/Stockfish/pull/6173
No functional change
Co-authored-by: disservin <disservin.social@gmail.com>
Co-authored-by: Joost VandeVondele <Joost.VandeVondele@gmail.com>
Since no correction histories are ever used inside Movepick, and many
existing histories are closely integrated into search, it might be more
logical to separate them into their own header. PR based on #5650
closes https://github.com/official-stockfish/Stockfish/pull/5652
No functional change
Idea of this patch comes from the fact that current history heuristics
are mostly populated by low depth entries since our stat bonus reaches
maximum value at depth 5-6 and number of low depth nodes is much bigger
than number of high depth nodes. But it doesn't make a whole lost of
sense to use this low-depth centered histories to sort moves at root.
Current patch introduces special history table that is used exclusively
at root, it remembers which quiet moves were good and which quiet moves
were not good there and uses this information for move ordering.
Passed STC:
https://tests.stockfishchess.org/tests/view/66dda74adc53972b68218cc9
LLR: 2.93 (-2.94,2.94) <0.00,2.00>
Total: 127680 W: 33579 L: 33126 D: 60975
Ptnml(0-2): 422, 15098, 32391, 15463, 466
Passed LTC:
https://tests.stockfishchess.org/tests/view/66dead2adc53972b68218d34
LLR: 2.95 (-2.94,2.94) <0.50,2.50>
Total: 381978 W: 96958 L: 95923 D: 189097
Ptnml(0-2): 277, 42165, 105089, 43162, 296
closes https://github.com/official-stockfish/Stockfish/pull/5595
Bench: 1611283
Since simplification of quiet checks in qsearch this depth isn't used by
any function at all apart movepicker, which also doesn't use passed
qsearch depth in any way, so can be removed. No functional change.
closes https://github.com/official-stockfish/Stockfish/pull/5514
No functional change
These values represent the lowest Elo rating in the skill level calculation,
and the highest one, but it's not clear from the code where these values come
from other than the comment. This should improve code readability and
maintainability. It makes the purpose of the values clear and allows for easy
modification if the Elo range for skill level calculation changes in the
future. Moved the Skill struct definition from search.cpp to search.h header
file to define the Search::Skill struct, making it accessible from other files.
closes https://github.com/official-stockfish/Stockfish/pull/5508
No functional change
- Capitalize comments
- Reformat multi-lines comments to equalize the widths of the lines
- Try to keep the width of comments around 85 characters
- Remove periods at the end of single-line comments
closes https://github.com/official-stockfish/Stockfish/pull/5469
No functional change
Currently (after #5407), SF has the property that any PV line with a decisive
TB score contains the corresponding TB position, with a score that correctly
identifies the depth at which TB are entered. The PV line that follows might
not preserve the game outcome, but can easily be verified and extended based on
TB information. This patch provides this functionality, simply extending the PV
lines on output, this doesn't affect search.
Indeed, if DTZ tables are available, search based PV lines that correspond to
decisive TB scores are verified to preserve game outcome, truncating the line
as needed. Subsequently, such PV lines are extended with a game outcome
preserving line until mate, as a possible continuation. These lines are not
optimal mating lines, but are similar to what a user could produce on a website
like https://syzygy-tables.info/ clicking always the top ranked move, i.e.
minimizing or maximizing DTZ (with a simple tie-breaker for moves that have
identical DTZ), and are thus an just an illustration of how to game can be won.
A similar approach is already in established in
https://github.com/joergoster/Stockfish/tree/matefish2
This also contributes to addressing #5175 where SF can give an incorrect TB
win/loss for positions in TB with a movecounter that doesn't reflect optimal
play. While the full solution requires either TB generated differently, or a
search when ranking rootmoves, current SF will eventually find a draw in these
cases, in practice quite quickly, e.g.
`1kq5/q2r4/5K2/8/8/8/8/7Q w - - 96 1`
`8/8/6k1/3B4/3K4/4N3/8/8 w - - 54 106`
Gives the same results as master on an extended set of test positions from
https://github.com/mcostalba/Stockfish/commit/9173d29c414ddb8f4bec74e4db3ccbe664c66bf9
with the exception of the above mentioned fen where this commit improves.
With https://github.com/vondele/matetrack using 6men TB, all generated PVs verify:
```
Using ../Stockfish/src/stockfish.syzygyExtend on matetrack.epd with --nodes 1000000 --syzygyPath /chess/syzygy/3-4-5-6/WDL:/chess/syzygy/3-4-5-6/DTZ
Engine ID: Stockfish dev-20240704-ff227954
Total FENs: 6555
Found mates: 3299
Best mates: 2582
Found TB wins: 568
```
As repeated DTZ probing could be slow a procedure (100ms+ on HDD, a few ms on
SSD), the extension is only done as long as the time taken is less than half
the `Move Overhead` parameter. For tournaments where these lines might be of
interest to the user, a suitable `Move Overhead` might be needed (e.g. TCEC has
1000ms already).
closes https://github.com/official-stockfish/Stockfish/pull/5414
No functional change