2008-08-31 23:59:13 -06:00
|
|
|
/*
|
2008-10-19 10:56:28 -06:00
|
|
|
Stockfish, a UCI chess playing engine derived from Glaurung 2.1
|
2021-01-08 09:04:23 -07:00
|
|
|
Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file)
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2008-10-19 10:56:28 -06:00
|
|
|
Stockfish is free software: you can redistribute it and/or modify
|
2008-08-31 23:59:13 -06:00
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2009-01-07 06:28:04 -07:00
|
|
|
|
2008-10-19 10:56:28 -06:00
|
|
|
Stockfish is distributed in the hope that it will be useful,
|
2008-08-31 23:59:13 -06:00
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2009-01-07 06:28:04 -07:00
|
|
|
|
2008-08-31 23:59:13 -06:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2013-07-23 07:31:57 -06:00
|
|
|
#ifndef THREAD_H_INCLUDED
|
2008-08-31 23:59:13 -06:00
|
|
|
#define THREAD_H_INCLUDED
|
|
|
|
|
2015-02-22 06:40:46 -07:00
|
|
|
#include <atomic>
|
2015-01-18 00:00:50 -07:00
|
|
|
#include <condition_variable>
|
|
|
|
#include <mutex>
|
|
|
|
#include <thread>
|
2012-03-24 14:36:33 -06:00
|
|
|
#include <vector>
|
2010-02-13 03:40:55 -07:00
|
|
|
|
2011-04-24 02:20:03 -06:00
|
|
|
#include "material.h"
|
2008-08-31 23:59:13 -06:00
|
|
|
#include "movepick.h"
|
2011-04-24 02:20:03 -06:00
|
|
|
#include "pawns.h"
|
2008-08-31 23:59:13 -06:00
|
|
|
#include "position.h"
|
2011-11-23 12:07:29 -07:00
|
|
|
#include "search.h"
|
2019-03-12 01:35:10 -06:00
|
|
|
#include "thread_win32_osx.h"
|
2008-08-31 23:59:13 -06:00
|
|
|
|
2021-02-26 02:02:13 -07:00
|
|
|
namespace Stockfish {
|
2011-04-24 02:20:03 -06:00
|
|
|
|
2017-08-13 00:58:31 -06:00
|
|
|
/// Thread class keeps together all the thread-related stuff. We use
|
|
|
|
/// per-thread pawn and material hash tables so that once we get a
|
|
|
|
/// pointer to an entry its life time is unlimited and we don't have
|
|
|
|
/// to care about someone changing the entry under our feet.
|
2013-07-31 01:33:26 -06:00
|
|
|
|
2015-11-20 23:48:50 -07:00
|
|
|
class Thread {
|
2013-07-31 01:33:26 -06:00
|
|
|
|
2019-09-15 23:51:25 -06:00
|
|
|
std::mutex mutex;
|
|
|
|
std::condition_variable cv;
|
2017-08-13 00:58:31 -06:00
|
|
|
size_t idx;
|
|
|
|
bool exit = false, searching = true; // Set before starting std::thread
|
2019-03-12 01:35:10 -06:00
|
|
|
NativeThread stdThread;
|
2015-11-20 23:48:50 -07:00
|
|
|
|
|
|
|
public:
|
2017-08-13 00:58:31 -06:00
|
|
|
explicit Thread(size_t);
|
2015-11-05 00:40:23 -07:00
|
|
|
virtual ~Thread();
|
|
|
|
virtual void search();
|
2017-08-31 01:34:32 -06:00
|
|
|
void clear();
|
2015-11-05 00:40:23 -07:00
|
|
|
void idle_loop();
|
2017-08-04 11:48:07 -06:00
|
|
|
void start_searching();
|
2015-11-20 23:48:50 -07:00
|
|
|
void wait_for_search_finished();
|
2021-05-17 01:13:34 -06:00
|
|
|
size_t id() const { return idx; }
|
2013-07-31 01:33:26 -06:00
|
|
|
|
2015-01-09 04:35:44 -07:00
|
|
|
Pawns::Table pawnsTable;
|
2012-12-16 04:00:54 -07:00
|
|
|
Material::Table materialTable;
|
2019-11-02 18:04:05 -06:00
|
|
|
size_t pvIdx, pvLast;
|
Detect search explosions
This patch detects some search explosions (due to double extensions in
search.cpp) which can happen in some pathological positions, and takes
measures to ensure progress in search even for these pathological situations.
While a small number of double extensions can be useful during search
(for example to resolve a tactical sequence), a sustained regime of
double extensions leads to search explosion and a non-finishing search.
See the discussion in https://github.com/official-stockfish/Stockfish/pull/3544
and the issue https://github.com/official-stockfish/Stockfish/issues/3532 .
The implemented algorithm is the following:
a) at each node during search, store the current depth in the stack.
Double extensions are by definition levels of the stack where the
depth at ply N is strictly higher than depth at ply N-1.
b) during search, calculate for each thread a running average of the
number of double extensions in the last 4096 visited nodes.
c) if one thread has more than 2% of double extensions for a sustained
period of time (6 millions consecutive nodes, or about 4 seconds on
my iMac), we decide that this thread is in an explosion state and
we calm down this thread by preventing it to do any double extension
for the next 6 millions nodes.
To calculate the running averages, we also introduced a auxiliary class
generalizing the computations of ttHitAverage variable we already had in
code. The implementation uses an exponential moving average of period 4096
and resolution 1/1024, and all computations are done with integers for
efficiency.
-----------
Example where the patch solves a search explosion:
```
./stockfish
ucinewgame
position fen 8/Pk6/8/1p6/8/P1K5/8/6B1 w - - 37 130
go infinite
```
This algorithm does not affect search in normal, non-pathological positions.
We verified, for instance, that the usual bench is unchanged up to depth 20
at least, and that the node numbers are unchanged for a search of the starting
position at depth 32.
-------------
See https://github.com/official-stockfish/Stockfish/pull/3714
Bench: 5575265
2021-09-23 15:19:06 -06:00
|
|
|
RunningAverage doubleExtensionAverage[COLOR_NB];
|
|
|
|
uint64_t nodesLastExplosive;
|
|
|
|
uint64_t nodesLastNormal;
|
|
|
|
std::atomic<uint64_t> nodes, tbHits, bestMoveChanges;
|
2018-06-02 09:41:37 -06:00
|
|
|
int selDepth, nmpMinPly;
|
|
|
|
Color nmpColor;
|
Detect search explosions
This patch detects some search explosions (due to double extensions in
search.cpp) which can happen in some pathological positions, and takes
measures to ensure progress in search even for these pathological situations.
While a small number of double extensions can be useful during search
(for example to resolve a tactical sequence), a sustained regime of
double extensions leads to search explosion and a non-finishing search.
See the discussion in https://github.com/official-stockfish/Stockfish/pull/3544
and the issue https://github.com/official-stockfish/Stockfish/issues/3532 .
The implemented algorithm is the following:
a) at each node during search, store the current depth in the stack.
Double extensions are by definition levels of the stack where the
depth at ply N is strictly higher than depth at ply N-1.
b) during search, calculate for each thread a running average of the
number of double extensions in the last 4096 visited nodes.
c) if one thread has more than 2% of double extensions for a sustained
period of time (6 millions consecutive nodes, or about 4 seconds on
my iMac), we decide that this thread is in an explosion state and
we calm down this thread by preventing it to do any double extension
for the next 6 millions nodes.
To calculate the running averages, we also introduced a auxiliary class
generalizing the computations of ttHitAverage variable we already had in
code. The implementation uses an exponential moving average of period 4096
and resolution 1/1024, and all computations are done with integers for
efficiency.
-----------
Example where the patch solves a search explosion:
```
./stockfish
ucinewgame
position fen 8/Pk6/8/1p6/8/P1K5/8/6B1 w - - 37 130
go infinite
```
This algorithm does not affect search in normal, non-pathological positions.
We verified, for instance, that the usual bench is unchanged up to depth 20
at least, and that the node numbers are unchanged for a search of the starting
position at depth 32.
-------------
See https://github.com/official-stockfish/Stockfish/pull/3714
Bench: 5575265
2021-09-23 15:19:06 -06:00
|
|
|
ExplosionState state;
|
Lazy SMP
Start all threads searching on root position and
use only the shared TT table as synching scheme.
It seems this scheme scales better than YBWC for
high number of threads.
Verified for nor regression at STC 3 threads
LLR: -2.95 (-2.94,2.94) [-3.00,1.00]
Total: 40232 W: 6908 L: 7130 D: 26194
Verified for nor regression at LTC 3 threads
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 28186 W: 3908 L: 3798 D: 20480
Verified for nor regression at STC 7 threads
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 3607 W: 674 L: 526 D: 2407
Verified for nor regression at LTC 7 threads
LLR: 2.95 (-2.94,2.94) [-3.00,1.00]
Total: 4235 W: 671 L: 528 D: 3036
Tested with fixed games at LTC with 20 threads
ELO: 44.75 +-7.6 (95%) LOS: 100.0%
Total: 2069 W: 407 L: 142 D: 1520
Tested with fixed games at XLTC (120secs) with 20 threads
ELO: 28.01 +-6.7 (95%) LOS: 100.0%
Total: 2275 W: 349 L: 166 D: 1760
Original patch of mbootsector, with additional work
from Ivan Ivec (log formula), Joerg Oster (id loop
simplification) and Marco Costalba (assorted formatting
and rework).
Bench: 8116244
2015-10-06 00:15:17 -06:00
|
|
|
|
|
|
|
Position rootPos;
|
2020-08-09 10:11:38 -06:00
|
|
|
StateInfo rootState;
|
2016-04-11 08:45:36 -06:00
|
|
|
Search::RootMoves rootMoves;
|
2019-05-15 02:50:27 -06:00
|
|
|
Depth rootDepth, completedDepth;
|
2017-06-30 09:20:00 -06:00
|
|
|
CounterMoveHistory counterMoves;
|
|
|
|
ButterflyHistory mainHistory;
|
Improve move order near the root
Current move histories are known to work well near the leaves, whilst at
higher depths they aren't very helpful. To address this problem this
patch introduces a table dedicated for what's happening at plies 0-3.
It's structured like mainHistory with ply index instead of color.
It get cleared with each new search and is filled during iterative
deepening at higher depths when recording successful quiet moves near
the root or traversing nodes which were in the principal variation
(ttPv).
Medium TC (20+0.2):
https://tests.stockfishchess.org/tests/view/5e4d358790a0a02810d096dc
LLR: 2.94 (-2.94,2.94) {-0.50,1.50}
Total: 100910 W: 16682 L: 16376 D: 67852
Ptnml(0-2): 1177, 10983, 25883, 11181, 1231
LTC:
https://tests.stockfishchess.org/tests/view/5e4e2cb790a0a02810d09714
LLR: 2.95 (-2.94,2.94) {0.25,1.75}
Total: 80444 W: 10495 L: 10095 D: 59854
Ptnml(0-2): 551, 7479, 23803, 7797, 592
closes https://github.com/official-stockfish/Stockfish/pull/2557
Bench: 4705960
2020-02-21 06:01:59 -07:00
|
|
|
LowPlyHistory lowPlyHistory;
|
2017-11-03 05:37:11 -06:00
|
|
|
CapturePieceToHistory captureHistory;
|
2019-10-08 08:44:01 -06:00
|
|
|
ContinuationHistory continuationHistory[2][2];
|
Remove the Contempt UCI option
This patch removes the UCI option for setting Contempt in classical evaluation.
It is exactly equivalent to using Contempt=0 for the UCI contempt value and keeping
the dynamic part in the algo (renaming this dynamic part `trend` to better describe
what it does). We have tried quite hard to implement a working Contempt feature for
NNUE but nothing really worked, so it is probably time to give up.
Interested chess fans wishing to keep playing with the UCI option for Contempt and
use it with the classical eval are urged to download the version tagged "SF_Classical"
of Stockfish (dated 31 July 2020), as it was the last version where our search
algorithm was tuned for the classical eval and is probably our strongest classical
player ever: https://github.com/official-stockfish/Stockfish/tags
Passed STC:
LLR: 2.95 (-2.94,2.94) <-2.50,0.50>
Total: 72904 W: 6228 L: 6175 D: 60501
Ptnml(0-2): 221, 5006, 25971, 5007, 247
https://tests.stockfishchess.org/tests/view/60c98bf9457376eb8bcab18d
Passed LTC:
LLR: 2.93 (-2.94,2.94) <-2.50,0.50>
Total: 45168 W: 1601 L: 1547 D: 42020
Ptnml(0-2): 38, 1331, 19786, 1397, 32
https://tests.stockfishchess.org/tests/view/60c9c7fa457376eb8bcab1bb
closes https://github.com/official-stockfish/Stockfish/pull/3575
Bench: 4947716
2021-06-15 23:23:26 -06:00
|
|
|
Score trend;
|
2008-08-31 23:59:13 -06:00
|
|
|
};
|
|
|
|
|
2013-01-16 01:28:41 -07:00
|
|
|
|
2017-08-13 00:58:31 -06:00
|
|
|
/// MainThread is a derived class specific for main thread
|
2013-01-16 01:28:41 -07:00
|
|
|
|
|
|
|
struct MainThread : public Thread {
|
2017-08-13 00:58:31 -06:00
|
|
|
|
|
|
|
using Thread::Thread;
|
|
|
|
|
2017-08-13 06:33:25 -06:00
|
|
|
void search() override;
|
2017-06-23 23:15:46 -06:00
|
|
|
void check_time();
|
2015-12-23 02:07:54 -07:00
|
|
|
|
Use average bestMoveChanges across all threads #2072
The current update only by main thread depends on the luck of
whether main thread sees any/many changes to the best move or not.
It then makes large, lumpy changes to the time to be
used (1x, 2x, 3x, etc) depending on that sample of 1.
Use the average across all threads to get a more reliable
number with a smoother distribution.
STC @ 5+0.05 th 4 :
LLR: 2.95 (-2.94,2.94) [0.50,4.50]
Total: 51899 W: 11446 L: 11029 D: 29424
http://tests.stockfishchess.org/tests/view/5ca32ff20ebc5925cf0016fb
STC @ 5+0.05 th 8 :
LLR: 2.96 (-2.94,2.94) [0.50,4.50]
Total: 13851 W: 2843 L: 2620 D: 8388
http://tests.stockfishchess.org/tests/view/5ca35ae00ebc5925cf001adb
LTC @ 20+0.2 th 8 :
LLR: 2.95 (-2.94,2.94) [0.00,3.50]
Total: 48527 W: 7941 L: 7635 D: 32951
http://tests.stockfishchess.org/tests/view/5ca37cb70ebc5925cf001cec
Further work:
Similar changes might be possible for the fallingEval and timeReduction calculations (and elsewhere?), using either the min, average or max values across all threads.
Bench 3506898
2019-04-03 01:35:55 -06:00
|
|
|
double previousTimeReduction;
|
2020-04-12 12:30:08 -06:00
|
|
|
Value bestPreviousScore;
|
2019-12-08 04:06:19 -07:00
|
|
|
Value iterValue[4];
|
2017-08-13 00:58:31 -06:00
|
|
|
int callsCnt;
|
Simplify pondering time management (#1899)
stopOnPonderhit is used to stop search quickly on a ponderhit. It is set by mainThread as part of its time management. However, master employs it as a signal between mainThread and the UCI thread. This is not necessary, it is sufficient for the UCI thread to signal that pondering finished, and mainThread should do its usual time-keeping job, and in this case stop immediately.
This patch implements this, removing stopOnPonderHit as an atomic variable from the ThreadPool,
and moving it as a normal variable to mainThread, reducing its scope. In MainThread::check_time() the search is stopped immediately if ponder switches to false, and the variable stopOnPonderHit is set.
Furthermore, ponder has been moved to mainThread, as the variable is only used to exchange signals between the UCI thread and mainThread.
The version has been tested locally (as fishtest doesn't support ponder):
Score of ponderSimp vs master: 2616 - 2528 - 8630 [0.503] 13774
Elo difference: 2.22 +/- 3.54
which indicates no regression.
No functional change.
2019-01-20 11:14:24 -07:00
|
|
|
bool stopOnPonderhit;
|
|
|
|
std::atomic_bool ponder;
|
2013-01-13 16:32:30 -07:00
|
|
|
};
|
|
|
|
|
2011-04-24 02:20:03 -06:00
|
|
|
|
2016-01-16 14:34:29 -07:00
|
|
|
/// ThreadPool struct handles all the threads-related stuff like init, starting,
|
2015-11-20 23:48:50 -07:00
|
|
|
/// parking and, most importantly, launching a thread. All the access to threads
|
2017-08-13 00:58:31 -06:00
|
|
|
/// is done through this class.
|
2011-04-24 02:20:03 -06:00
|
|
|
|
2013-02-04 14:38:42 -07:00
|
|
|
struct ThreadPool : public std::vector<Thread*> {
|
2012-08-19 03:20:15 -06:00
|
|
|
|
2017-08-10 13:32:50 -06:00
|
|
|
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&, bool = false);
|
2017-12-26 02:40:42 -07:00
|
|
|
void clear();
|
2017-08-13 00:58:31 -06:00
|
|
|
void set(size_t);
|
|
|
|
|
|
|
|
MainThread* main() const { return static_cast<MainThread*>(front()); }
|
|
|
|
uint64_t nodes_searched() const { return accumulate(&Thread::nodes); }
|
|
|
|
uint64_t tb_hits() const { return accumulate(&Thread::tbHits); }
|
2020-05-31 23:31:14 -06:00
|
|
|
Thread* get_best_thread() const;
|
|
|
|
void start_searching();
|
|
|
|
void wait_for_search_finished() const;
|
2016-04-11 08:45:36 -06:00
|
|
|
|
Smarter time management near stop limit
This patch makes Stockfish search same depth again if > 60% of optimum time is
already used, instead of trying the next iteration. The idea is that the next
iteration will generally take about the same amount of time as has already been
used in total. When we are likely to begin the last iteration, as judged by total
time taken so far > 0.6 * optimum time, searching the last depth again instead of
increasing the depth still helps the other threads in lazy SMP and prepares better
move ordering for the next moves.
STC :
LLR: 2.95 (-2.94,2.94) {-1.00,3.00}
Total: 13436 W: 2695 L: 2558 D: 8183
Ptnml(0-2): 222, 1538, 3087, 1611, 253
https://tests.stockfishchess.org/tests/view/5e1618a761fe5f83a67dd964
LTC :
LLR: 2.94 (-2.94,2.94) {0.00,2.00}
Total: 32160 W: 4261 L: 4047 D: 23852
Ptnml(0-2): 211, 2988, 9448, 3135, 247
https://tests.stockfishchess.org/tests/view/5e162ca061fe5f83a67dd96d
The code was revised as suggested by @vondele for multithreading:
STC (8 threads):
LLR: 2.95 (-2.94,2.94) {0.00,2.00}
Total: 16640 W: 2049 L: 1885 D: 12706
Ptnml(0-2): 119, 1369, 5158, 1557, 108
https://tests.stockfishchess.org/tests/view/5e19826a2cc590e03c3c2f52
LTC (8 threads):
LLR: 2.95 (-2.94,2.94) {-1.00,3.00}
Total: 16536 W: 2758 L: 2629 D: 11149
Ptnml(0-2): 182, 1758, 4296, 1802, 224
https://tests.stockfishchess.org/tests/view/5e18b91a27dab692fcf9a140
Thanks to those discussing Stockfish lazy SMP on fishcooking which made me
try this, and to @vondele for suggestions and doing related tests.
See full discussion in the pull request thread:
https://github.com/official-stockfish/Stockfish/pull/2482
Bench: 4586187
2020-01-11 15:10:22 -07:00
|
|
|
std::atomic_bool stop, increaseDepth;
|
2017-07-13 17:07:19 -06:00
|
|
|
|
2016-04-11 08:45:36 -06:00
|
|
|
private:
|
|
|
|
StateListPtr setupStates;
|
2017-08-13 00:58:31 -06:00
|
|
|
|
|
|
|
uint64_t accumulate(std::atomic<uint64_t> Thread::* member) const {
|
|
|
|
|
|
|
|
uint64_t sum = 0;
|
|
|
|
for (Thread* th : *this)
|
|
|
|
sum += (th->*member).load(std::memory_order_relaxed);
|
|
|
|
return sum;
|
|
|
|
}
|
2011-04-24 02:20:03 -06:00
|
|
|
};
|
|
|
|
|
2012-06-24 02:30:40 -06:00
|
|
|
extern ThreadPool Threads;
|
2011-04-24 02:20:03 -06:00
|
|
|
|
2021-02-26 02:02:13 -07:00
|
|
|
} // namespace Stockfish
|
|
|
|
|
2013-07-23 07:31:57 -06:00
|
|
|
#endif // #ifndef THREAD_H_INCLUDED
|