mirror of
https://github.com/sockspls/badfish
synced 2025-05-02 17:49:35 +00:00
Large API rename in ThreadsManager
No functional change. Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
parent
339e1b49f6
commit
05cfb00f26
6 changed files with 150 additions and 155 deletions
|
@ -303,7 +303,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
||||||
margins[WHITE] = margins[BLACK] = VALUE_ZERO;
|
margins[WHITE] = margins[BLACK] = VALUE_ZERO;
|
||||||
|
|
||||||
// Probe the material hash table
|
// Probe the material hash table
|
||||||
MaterialInfo* mi = ThreadsMgr[pos.thread()].materialTable.get_material_info(pos);
|
MaterialInfo* mi = Threads[pos.thread()].materialTable.get_material_info(pos);
|
||||||
bonus += mi->material_value();
|
bonus += mi->material_value();
|
||||||
|
|
||||||
// If we have a specialized evaluation function for the current material
|
// If we have a specialized evaluation function for the current material
|
||||||
|
@ -315,7 +315,7 @@ Value do_evaluate(const Position& pos, Value& margin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Probe the pawn hash table
|
// Probe the pawn hash table
|
||||||
ei.pi = ThreadsMgr[pos.thread()].pawnTable.get_pawn_info(pos);
|
ei.pi = Threads[pos.thread()].pawnTable.get_pawn_info(pos);
|
||||||
bonus += apply_weight(ei.pi->pawns_value(), Weights[PawnStructure]);
|
bonus += apply_weight(ei.pi->pawns_value(), Weights[PawnStructure]);
|
||||||
|
|
||||||
// Initialize attack and king safety bitboards
|
// Initialize attack and king safety bitboards
|
||||||
|
|
|
@ -55,7 +55,7 @@ int main(int argc, char* argv[]) {
|
||||||
Position::init_piece_square_tables();
|
Position::init_piece_square_tables();
|
||||||
init_kpk_bitbase();
|
init_kpk_bitbase();
|
||||||
init_search();
|
init_search();
|
||||||
ThreadsMgr.init_threads();
|
Threads.init();
|
||||||
|
|
||||||
#ifdef USE_CALLGRIND
|
#ifdef USE_CALLGRIND
|
||||||
CALLGRIND_START_INSTRUMENTATION;
|
CALLGRIND_START_INSTRUMENTATION;
|
||||||
|
@ -82,6 +82,6 @@ int main(int argc, char* argv[]) {
|
||||||
<< "[limit = 12] [fen positions file = default] "
|
<< "[limit = 12] [fen positions file = default] "
|
||||||
<< "[depth, time, perft or node limited = depth]" << endl;
|
<< "[depth, time, perft or node limited = depth]" << endl;
|
||||||
|
|
||||||
ThreadsMgr.exit_threads();
|
Threads.exit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1048,8 +1048,8 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prefetch pawn and material hash tables
|
// Prefetch pawn and material hash tables
|
||||||
ThreadsMgr[threadID].pawnTable.prefetch(st->pawnKey);
|
Threads[threadID].pawnTable.prefetch(st->pawnKey);
|
||||||
ThreadsMgr[threadID].materialTable.prefetch(st->materialKey);
|
Threads[threadID].materialTable.prefetch(st->materialKey);
|
||||||
|
|
||||||
// Update incremental scores
|
// Update incremental scores
|
||||||
st->value += pst_delta(piece, from, to);
|
st->value += pst_delta(piece, from, to);
|
||||||
|
|
|
@ -436,10 +436,10 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
|
||||||
SkillLevel = Options["Skill level"].value<int>();
|
SkillLevel = Options["Skill level"].value<int>();
|
||||||
|
|
||||||
read_evaluation_uci_options(pos.side_to_move());
|
read_evaluation_uci_options(pos.side_to_move());
|
||||||
ThreadsMgr.read_uci_options();
|
Threads.read_uci_options();
|
||||||
|
|
||||||
// If needed allocate pawn and material hash tables and adjust TT size
|
// If needed allocate pawn and material hash tables and adjust TT size
|
||||||
ThreadsMgr.init_hash_tables();
|
Threads.init_hash_tables();
|
||||||
TT.set_size(Options["Hash"].value<int>());
|
TT.set_size(Options["Hash"].value<int>());
|
||||||
|
|
||||||
if (Options["Clear Hash"].value<bool>())
|
if (Options["Clear Hash"].value<bool>())
|
||||||
|
@ -454,10 +454,10 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
|
||||||
MultiPV = (SkillLevelEnabled ? Max(UCIMultiPV, 4) : UCIMultiPV);
|
MultiPV = (SkillLevelEnabled ? Max(UCIMultiPV, 4) : UCIMultiPV);
|
||||||
|
|
||||||
// Wake up needed threads and reset maxPly counter
|
// Wake up needed threads and reset maxPly counter
|
||||||
for (int i = 0; i < ThreadsMgr.active_threads(); i++)
|
for (int i = 0; i < Threads.size(); i++)
|
||||||
{
|
{
|
||||||
ThreadsMgr[i].wake_up();
|
Threads[i].wake_up();
|
||||||
ThreadsMgr[i].maxPly = 0;
|
Threads[i].maxPly = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write to log file and keep it open to be accessed during the search
|
// Write to log file and keep it open to be accessed during the search
|
||||||
|
@ -499,7 +499,7 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// This makes all the threads to go to sleep
|
// This makes all the threads to go to sleep
|
||||||
ThreadsMgr.set_active_threads(1);
|
Threads.set_size(1);
|
||||||
|
|
||||||
// If we are pondering or in infinite search, we shouldn't print the
|
// If we are pondering or in infinite search, we shouldn't print the
|
||||||
// best move before we are told to do so.
|
// best move before we are told to do so.
|
||||||
|
@ -625,9 +625,9 @@ namespace {
|
||||||
|
|
||||||
// Retrieve max searched depth among threads
|
// Retrieve max searched depth among threads
|
||||||
selDepth = 0;
|
selDepth = 0;
|
||||||
for (int i = 0; i < ThreadsMgr.active_threads(); i++)
|
for (int i = 0; i < Threads.size(); i++)
|
||||||
if (ThreadsMgr[i].maxPly > selDepth)
|
if (Threads[i].maxPly > selDepth)
|
||||||
selDepth = ThreadsMgr[i].maxPly;
|
selDepth = Threads[i].maxPly;
|
||||||
|
|
||||||
// Send PV line to GUI and to log file
|
// Send PV line to GUI and to log file
|
||||||
for (int i = 0; i < Min(UCIMultiPV, (int)Rml.size()); i++)
|
for (int i = 0; i < Min(UCIMultiPV, (int)Rml.size()); i++)
|
||||||
|
@ -708,7 +708,7 @@ namespace {
|
||||||
assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE);
|
assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE);
|
||||||
assert(beta > alpha && beta <= VALUE_INFINITE);
|
assert(beta > alpha && beta <= VALUE_INFINITE);
|
||||||
assert(PvNode || alpha == beta - 1);
|
assert(PvNode || alpha == beta - 1);
|
||||||
assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
|
assert(pos.thread() >= 0 && pos.thread() < Threads.size());
|
||||||
|
|
||||||
Move movesSearched[MAX_MOVES];
|
Move movesSearched[MAX_MOVES];
|
||||||
int64_t nodes;
|
int64_t nodes;
|
||||||
|
@ -731,8 +731,8 @@ namespace {
|
||||||
ss->ply = (ss-1)->ply + 1;
|
ss->ply = (ss-1)->ply + 1;
|
||||||
|
|
||||||
// Used to send selDepth info to GUI
|
// Used to send selDepth info to GUI
|
||||||
if (PvNode && ThreadsMgr[threadID].maxPly < ss->ply)
|
if (PvNode && Threads[threadID].maxPly < ss->ply)
|
||||||
ThreadsMgr[threadID].maxPly = ss->ply;
|
Threads[threadID].maxPly = ss->ply;
|
||||||
|
|
||||||
if (SpNode)
|
if (SpNode)
|
||||||
{
|
{
|
||||||
|
@ -758,7 +758,7 @@ namespace {
|
||||||
|
|
||||||
// Step 2. Check for aborted search and immediate draw
|
// Step 2. Check for aborted search and immediate draw
|
||||||
if (( StopRequest
|
if (( StopRequest
|
||||||
|| ThreadsMgr.cutoff_at_splitpoint(threadID)
|
|| Threads[threadID].cutoff_occurred()
|
||||||
|| pos.is_draw()
|
|| pos.is_draw()
|
||||||
|| ss->ply > PLY_MAX) && !Root)
|
|| ss->ply > PLY_MAX) && !Root)
|
||||||
return VALUE_DRAW;
|
return VALUE_DRAW;
|
||||||
|
@ -939,7 +939,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
// Loop through all legal moves until no moves remain or a beta cutoff occurs
|
// Loop through all legal moves until no moves remain or a beta cutoff occurs
|
||||||
while ( bestValue < beta
|
while ( bestValue < beta
|
||||||
&& (move = mp.get_next_move()) != MOVE_NONE
|
&& (move = mp.get_next_move()) != MOVE_NONE
|
||||||
&& !ThreadsMgr.cutoff_at_splitpoint(threadID))
|
&& !Threads[threadID].cutoff_occurred())
|
||||||
{
|
{
|
||||||
assert(move_is_ok(move));
|
assert(move_is_ok(move));
|
||||||
|
|
||||||
|
@ -1154,7 +1154,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
alpha = sp->alpha;
|
alpha = sp->alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value > bestValue && !(SpNode && ThreadsMgr.cutoff_at_splitpoint(threadID)))
|
if (value > bestValue && !(SpNode && Threads[threadID].cutoff_occurred()))
|
||||||
{
|
{
|
||||||
bestValue = value;
|
bestValue = value;
|
||||||
|
|
||||||
|
@ -1171,7 +1171,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
sp->alpha = value;
|
sp->alpha = value;
|
||||||
}
|
}
|
||||||
else if (SpNode)
|
else if (SpNode)
|
||||||
sp->betaCutoff = true;
|
sp->is_betaCutoff = true;
|
||||||
|
|
||||||
if (value == value_mate_in(ss->ply + 1))
|
if (value == value_mate_in(ss->ply + 1))
|
||||||
ss->mateKiller = move;
|
ss->mateKiller = move;
|
||||||
|
@ -1227,13 +1227,12 @@ split_point_start: // At split points actual search starts from here
|
||||||
// Step 18. Check for split
|
// Step 18. Check for split
|
||||||
if ( !Root
|
if ( !Root
|
||||||
&& !SpNode
|
&& !SpNode
|
||||||
&& depth >= ThreadsMgr.min_split_depth()
|
&& depth >= Threads.min_split_depth()
|
||||||
&& ThreadsMgr.active_threads() > 1
|
|
||||||
&& bestValue < beta
|
&& bestValue < beta
|
||||||
&& ThreadsMgr.available_thread_exists(threadID)
|
&& Threads.available_slave_exists(threadID)
|
||||||
&& !StopRequest
|
&& !StopRequest
|
||||||
&& !ThreadsMgr.cutoff_at_splitpoint(threadID))
|
&& !Threads[threadID].cutoff_occurred())
|
||||||
ThreadsMgr.split<FakeSplit>(pos, ss, &alpha, beta, &bestValue, depth,
|
Threads.split<FakeSplit>(pos, ss, &alpha, beta, &bestValue, depth,
|
||||||
threatMove, moveCount, &mp, PvNode);
|
threatMove, moveCount, &mp, PvNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1247,7 +1246,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
// Step 20. Update tables
|
// Step 20. Update tables
|
||||||
// If the search is not aborted, update the transposition table,
|
// If the search is not aborted, update the transposition table,
|
||||||
// history counters, and killer moves.
|
// history counters, and killer moves.
|
||||||
if (!SpNode && !StopRequest && !ThreadsMgr.cutoff_at_splitpoint(threadID))
|
if (!SpNode && !StopRequest && !Threads[threadID].cutoff_occurred())
|
||||||
{
|
{
|
||||||
move = bestValue <= oldAlpha ? MOVE_NONE : ss->bestMove;
|
move = bestValue <= oldAlpha ? MOVE_NONE : ss->bestMove;
|
||||||
vt = bestValue <= oldAlpha ? VALUE_TYPE_UPPER
|
vt = bestValue <= oldAlpha ? VALUE_TYPE_UPPER
|
||||||
|
@ -1271,7 +1270,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
if (SpNode)
|
if (SpNode)
|
||||||
{
|
{
|
||||||
// Here we have the lock still grabbed
|
// Here we have the lock still grabbed
|
||||||
sp->slaves[threadID] = 0;
|
sp->is_slave[threadID] = false;
|
||||||
sp->nodes += pos.nodes_searched();
|
sp->nodes += pos.nodes_searched();
|
||||||
lock_release(&(sp->lock));
|
lock_release(&(sp->lock));
|
||||||
}
|
}
|
||||||
|
@ -1292,7 +1291,7 @@ split_point_start: // At split points actual search starts from here
|
||||||
assert(beta >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
|
assert(beta >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
|
||||||
assert(PvNode || alpha == beta - 1);
|
assert(PvNode || alpha == beta - 1);
|
||||||
assert(depth <= 0);
|
assert(depth <= 0);
|
||||||
assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
|
assert(pos.thread() >= 0 && pos.thread() < Threads.size());
|
||||||
|
|
||||||
StateInfo st;
|
StateInfo st;
|
||||||
Move ttMove, move;
|
Move ttMove, move;
|
||||||
|
@ -2112,27 +2111,27 @@ void ThreadsManager::idle_loop(int threadID, SplitPoint* sp) {
|
||||||
if (allThreadsShouldExit)
|
if (allThreadsShouldExit)
|
||||||
{
|
{
|
||||||
assert(!sp);
|
assert(!sp);
|
||||||
threads[threadID].state = THREAD_TERMINATED;
|
threads[threadID].state = Thread::TERMINATED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are not thinking, wait for a condition to be signaled
|
// If we are not thinking, wait for a condition to be signaled
|
||||||
// instead of wasting CPU time polling for work.
|
// instead of wasting CPU time polling for work.
|
||||||
while ( threadID >= activeThreads
|
while ( threadID >= activeThreads
|
||||||
|| threads[threadID].state == THREAD_INITIALIZING
|
|| threads[threadID].state == Thread::INITIALIZING
|
||||||
|| (useSleepingThreads && threads[threadID].state == THREAD_AVAILABLE))
|
|| (useSleepingThreads && threads[threadID].state == Thread::AVAILABLE))
|
||||||
{
|
{
|
||||||
assert(!sp || useSleepingThreads);
|
assert(!sp || useSleepingThreads);
|
||||||
assert(threadID != 0 || useSleepingThreads);
|
assert(threadID != 0 || useSleepingThreads);
|
||||||
|
|
||||||
if (threads[threadID].state == THREAD_INITIALIZING)
|
if (threads[threadID].state == Thread::INITIALIZING)
|
||||||
threads[threadID].state = THREAD_AVAILABLE;
|
threads[threadID].state = Thread::AVAILABLE;
|
||||||
|
|
||||||
// Grab the lock to avoid races with Thread::wake_up()
|
// Grab the lock to avoid races with Thread::wake_up()
|
||||||
lock_grab(&threads[threadID].sleepLock);
|
lock_grab(&threads[threadID].sleepLock);
|
||||||
|
|
||||||
// If we are master and all slaves have finished do not go to sleep
|
// If we are master and all slaves have finished do not go to sleep
|
||||||
for (i = 0; sp && i < activeThreads && !sp->slaves[i]; i++) {}
|
for (i = 0; sp && i < activeThreads && !sp->is_slave[i]; i++) {}
|
||||||
allFinished = (i == activeThreads);
|
allFinished = (i == activeThreads);
|
||||||
|
|
||||||
if (allFinished || allThreadsShouldExit)
|
if (allFinished || allThreadsShouldExit)
|
||||||
|
@ -2142,18 +2141,18 @@ void ThreadsManager::idle_loop(int threadID, SplitPoint* sp) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do sleep here after retesting sleep conditions
|
// Do sleep here after retesting sleep conditions
|
||||||
if (threadID >= activeThreads || threads[threadID].state == THREAD_AVAILABLE)
|
if (threadID >= activeThreads || threads[threadID].state == Thread::AVAILABLE)
|
||||||
cond_wait(&threads[threadID].sleepCond, &threads[threadID].sleepLock);
|
cond_wait(&threads[threadID].sleepCond, &threads[threadID].sleepLock);
|
||||||
|
|
||||||
lock_release(&threads[threadID].sleepLock);
|
lock_release(&threads[threadID].sleepLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this thread has been assigned work, launch a search
|
// If this thread has been assigned work, launch a search
|
||||||
if (threads[threadID].state == THREAD_WORKISWAITING)
|
if (threads[threadID].state == Thread::WORKISWAITING)
|
||||||
{
|
{
|
||||||
assert(!allThreadsShouldExit);
|
assert(!allThreadsShouldExit);
|
||||||
|
|
||||||
threads[threadID].state = THREAD_SEARCHING;
|
threads[threadID].state = Thread::SEARCHING;
|
||||||
|
|
||||||
// Copy split point position and search stack and call search()
|
// Copy split point position and search stack and call search()
|
||||||
// with SplitPoint template parameter set to true.
|
// with SplitPoint template parameter set to true.
|
||||||
|
@ -2169,21 +2168,21 @@ void ThreadsManager::idle_loop(int threadID, SplitPoint* sp) {
|
||||||
else
|
else
|
||||||
search<NonPV, true, false>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
|
search<NonPV, true, false>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
|
||||||
|
|
||||||
assert(threads[threadID].state == THREAD_SEARCHING);
|
assert(threads[threadID].state == Thread::SEARCHING);
|
||||||
|
|
||||||
threads[threadID].state = THREAD_AVAILABLE;
|
threads[threadID].state = Thread::AVAILABLE;
|
||||||
|
|
||||||
// Wake up master thread so to allow it to return from the idle loop in
|
// Wake up master thread so to allow it to return from the idle loop in
|
||||||
// case we are the last slave of the split point.
|
// case we are the last slave of the split point.
|
||||||
if ( useSleepingThreads
|
if ( useSleepingThreads
|
||||||
&& threadID != tsp->master
|
&& threadID != tsp->master
|
||||||
&& threads[tsp->master].state == THREAD_AVAILABLE)
|
&& threads[tsp->master].state == Thread::AVAILABLE)
|
||||||
threads[tsp->master].wake_up();
|
threads[tsp->master].wake_up();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this thread is the master of a split point and all slaves have
|
// If this thread is the master of a split point and all slaves have
|
||||||
// finished their work at this split point, return from the idle loop.
|
// finished their work at this split point, return from the idle loop.
|
||||||
for (i = 0; sp && i < activeThreads && !sp->slaves[i]; i++) {}
|
for (i = 0; sp && i < activeThreads && !sp->is_slave[i]; i++) {}
|
||||||
allFinished = (i == activeThreads);
|
allFinished = (i == activeThreads);
|
||||||
|
|
||||||
if (allFinished)
|
if (allFinished)
|
||||||
|
@ -2195,9 +2194,9 @@ void ThreadsManager::idle_loop(int threadID, SplitPoint* sp) {
|
||||||
|
|
||||||
// In helpful master concept a master can help only a sub-tree, and
|
// In helpful master concept a master can help only a sub-tree, and
|
||||||
// because here is all finished is not possible master is booked.
|
// because here is all finished is not possible master is booked.
|
||||||
assert(threads[threadID].state == THREAD_AVAILABLE);
|
assert(threads[threadID].state == Thread::AVAILABLE);
|
||||||
|
|
||||||
threads[threadID].state = THREAD_SEARCHING;
|
threads[threadID].state = Thread::SEARCHING;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
151
src/thread.cpp
151
src/thread.cpp
|
@ -22,7 +22,7 @@
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "ucioption.h"
|
#include "ucioption.h"
|
||||||
|
|
||||||
ThreadsManager ThreadsMgr; // Global object definition
|
ThreadsManager Threads; // Global object definition
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ namespace {
|
||||||
|
|
||||||
void* init_thread(void* threadID) {
|
void* init_thread(void* threadID) {
|
||||||
|
|
||||||
ThreadsMgr.idle_loop(*(int*)threadID, NULL);
|
Threads.idle_loop(*(int*)threadID, NULL);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ namespace {
|
||||||
|
|
||||||
DWORD WINAPI init_thread(LPVOID threadID) {
|
DWORD WINAPI init_thread(LPVOID threadID) {
|
||||||
|
|
||||||
ThreadsMgr.idle_loop(*(int*)threadID, NULL);
|
Threads.idle_loop(*(int*)threadID, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +52,56 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// wake_up() wakes up the thread, normally at the beginning of the search or,
|
||||||
|
// if "sleeping threads" is used, when there is some work to do.
|
||||||
|
|
||||||
|
void Thread::wake_up() {
|
||||||
|
|
||||||
|
lock_grab(&sleepLock);
|
||||||
|
cond_signal(&sleepCond);
|
||||||
|
lock_release(&sleepLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// cutoff_occurred() checks whether a beta cutoff has occurred in
|
||||||
|
// the thread's currently active split point, or in some ancestor of
|
||||||
|
// the current split point.
|
||||||
|
|
||||||
|
bool Thread::cutoff_occurred() const {
|
||||||
|
|
||||||
|
for (SplitPoint* sp = splitPoint; sp; sp = sp->parent)
|
||||||
|
if (sp->is_betaCutoff)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// is_available_to() checks whether the thread is available to help the thread with
|
||||||
|
// threadID "master" at a split point. An obvious requirement is that thread must be
|
||||||
|
// idle. With more than two threads, this is not by itself sufficient: If the thread
|
||||||
|
// is the master of some active split point, it is only available as a slave to the
|
||||||
|
// threads which are busy searching the split point at the top of "slave"'s split
|
||||||
|
// point stack (the "helpful master concept" in YBWC terminology).
|
||||||
|
|
||||||
|
bool Thread::is_available_to(int master) const {
|
||||||
|
|
||||||
|
if (state != AVAILABLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Make a local copy to be sure doesn't become zero under our feet while
|
||||||
|
// testing next condition and so leading to an out of bound access.
|
||||||
|
int localActiveSplitPoints = activeSplitPoints;
|
||||||
|
|
||||||
|
// No active split points means that the thread is available as a slave for any
|
||||||
|
// other thread otherwise apply the "helpful master" concept if possible.
|
||||||
|
if ( !localActiveSplitPoints
|
||||||
|
|| splitPoints[localActiveSplitPoints - 1].is_slave[master])
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// read_uci_options() updates number of active threads and other internal
|
// read_uci_options() updates number of active threads and other internal
|
||||||
// parameters according to the UCI options values. It is called before
|
// parameters according to the UCI options values. It is called before
|
||||||
// to start a new search.
|
// to start a new search.
|
||||||
|
@ -68,7 +118,7 @@ void ThreadsManager::read_uci_options() {
|
||||||
// init_threads() is called during startup. Initializes locks and condition
|
// init_threads() is called during startup. Initializes locks and condition
|
||||||
// variables and launches all threads sending them immediately to sleep.
|
// variables and launches all threads sending them immediately to sleep.
|
||||||
|
|
||||||
void ThreadsManager::init_threads() {
|
void ThreadsManager::init() {
|
||||||
|
|
||||||
int arg[MAX_THREADS];
|
int arg[MAX_THREADS];
|
||||||
|
|
||||||
|
@ -77,7 +127,7 @@ void ThreadsManager::init_threads() {
|
||||||
|
|
||||||
// Threads will sent to sleep as soon as created, only main thread is kept alive
|
// Threads will sent to sleep as soon as created, only main thread is kept alive
|
||||||
activeThreads = 1;
|
activeThreads = 1;
|
||||||
threads[0].state = THREAD_SEARCHING;
|
threads[0].state = Thread::SEARCHING;
|
||||||
|
|
||||||
// Allocate pawn and material hash tables for main thread
|
// Allocate pawn and material hash tables for main thread
|
||||||
init_hash_tables();
|
init_hash_tables();
|
||||||
|
@ -97,7 +147,7 @@ void ThreadsManager::init_threads() {
|
||||||
// Create and startup all the threads but the main that is already running
|
// Create and startup all the threads but the main that is already running
|
||||||
for (int i = 1; i < MAX_THREADS; i++)
|
for (int i = 1; i < MAX_THREADS; i++)
|
||||||
{
|
{
|
||||||
threads[i].state = THREAD_INITIALIZING;
|
threads[i].state = Thread::INITIALIZING;
|
||||||
arg[i] = i;
|
arg[i] = i;
|
||||||
|
|
||||||
#if !defined(_MSC_VER)
|
#if !defined(_MSC_VER)
|
||||||
|
@ -110,11 +160,11 @@ void ThreadsManager::init_threads() {
|
||||||
if (!ok)
|
if (!ok)
|
||||||
{
|
{
|
||||||
std::cout << "Failed to create thread number " << i << std::endl;
|
std::cout << "Failed to create thread number " << i << std::endl;
|
||||||
exit(EXIT_FAILURE);
|
::exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait until the thread has finished launching and is gone to sleep
|
// Wait until the thread has finished launching and is gone to sleep
|
||||||
while (threads[i].state == THREAD_INITIALIZING) {}
|
while (threads[i].state == Thread::INITIALIZING) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,7 +172,7 @@ void ThreadsManager::init_threads() {
|
||||||
// exit_threads() is called when the program exits. It makes all the
|
// exit_threads() is called when the program exits. It makes all the
|
||||||
// helper threads exit cleanly.
|
// helper threads exit cleanly.
|
||||||
|
|
||||||
void ThreadsManager::exit_threads() {
|
void ThreadsManager::exit() {
|
||||||
|
|
||||||
// Force the woken up threads to exit idle_loop() and hence terminate
|
// Force the woken up threads to exit idle_loop() and hence terminate
|
||||||
allThreadsShouldExit = true;
|
allThreadsShouldExit = true;
|
||||||
|
@ -133,7 +183,7 @@ void ThreadsManager::exit_threads() {
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
{
|
{
|
||||||
threads[i].wake_up();
|
threads[i].wake_up();
|
||||||
while (threads[i].state != THREAD_TERMINATED) {}
|
while (threads[i].state != Thread::TERMINATED) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we can safely destroy the locks and wait conditions
|
// Now we can safely destroy the locks and wait conditions
|
||||||
|
@ -164,66 +214,15 @@ void ThreadsManager::init_hash_tables() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// cutoff_at_splitpoint() checks whether a beta cutoff has occurred in
|
// available_slave_exists() tries to find an idle thread which is available as
|
||||||
// the thread's currently active split point, or in some ancestor of
|
|
||||||
// the current split point.
|
|
||||||
|
|
||||||
bool ThreadsManager::cutoff_at_splitpoint(int threadID) const {
|
|
||||||
|
|
||||||
assert(threadID >= 0 && threadID < activeThreads);
|
|
||||||
|
|
||||||
SplitPoint* sp = threads[threadID].splitPoint;
|
|
||||||
|
|
||||||
for ( ; sp && !sp->betaCutoff; sp = sp->parent) {}
|
|
||||||
return sp != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// thread_is_available() checks whether the thread with threadID "slave" is
|
|
||||||
// available to help the thread with threadID "master" at a split point. An
|
|
||||||
// obvious requirement is that "slave" must be idle. With more than two
|
|
||||||
// threads, this is not by itself sufficient: If "slave" is the master of
|
|
||||||
// some active split point, it is only available as a slave to the other
|
|
||||||
// threads which are busy searching the split point at the top of "slave"'s
|
|
||||||
// split point stack (the "helpful master concept" in YBWC terminology).
|
|
||||||
|
|
||||||
bool ThreadsManager::thread_is_available(int slave, int master) const {
|
|
||||||
|
|
||||||
assert(slave >= 0 && slave < activeThreads);
|
|
||||||
assert(master >= 0 && master < activeThreads);
|
|
||||||
assert(activeThreads > 1);
|
|
||||||
|
|
||||||
if (threads[slave].state != THREAD_AVAILABLE || slave == master)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Make a local copy to be sure doesn't change under our feet
|
|
||||||
int localActiveSplitPoints = threads[slave].activeSplitPoints;
|
|
||||||
|
|
||||||
// No active split points means that the thread is available as
|
|
||||||
// a slave for any other thread.
|
|
||||||
if (localActiveSplitPoints == 0 || activeThreads == 2)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Apply the "helpful master" concept if possible. Use localActiveSplitPoints
|
|
||||||
// that is known to be > 0, instead of threads[slave].activeSplitPoints that
|
|
||||||
// could have been set to 0 by another thread leading to an out of bound access.
|
|
||||||
if (threads[slave].splitPoints[localActiveSplitPoints - 1].slaves[master])
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// available_thread_exists() tries to find an idle thread which is available as
|
|
||||||
// a slave for the thread with threadID "master".
|
// a slave for the thread with threadID "master".
|
||||||
|
|
||||||
bool ThreadsManager::available_thread_exists(int master) const {
|
bool ThreadsManager::available_slave_exists(int master) const {
|
||||||
|
|
||||||
assert(master >= 0 && master < activeThreads);
|
assert(master >= 0 && master < activeThreads);
|
||||||
assert(activeThreads > 1);
|
|
||||||
|
|
||||||
for (int i = 0; i < activeThreads; i++)
|
for (int i = 0; i < activeThreads; i++)
|
||||||
if (thread_is_available(i, master))
|
if (i != master && threads[i].is_available_to(master))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -259,7 +258,7 @@ void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const V
|
||||||
|
|
||||||
// If no other thread is available to help us, or if we have too many
|
// If no other thread is available to help us, or if we have too many
|
||||||
// active split points, don't split.
|
// active split points, don't split.
|
||||||
if ( !available_thread_exists(master)
|
if ( !available_slave_exists(master)
|
||||||
|| masterThread.activeSplitPoints >= MAX_ACTIVE_SPLIT_POINTS)
|
|| masterThread.activeSplitPoints >= MAX_ACTIVE_SPLIT_POINTS)
|
||||||
{
|
{
|
||||||
lock_release(&mpLock);
|
lock_release(&mpLock);
|
||||||
|
@ -272,7 +271,7 @@ void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const V
|
||||||
// Initialize the split point object
|
// Initialize the split point object
|
||||||
splitPoint.parent = masterThread.splitPoint;
|
splitPoint.parent = masterThread.splitPoint;
|
||||||
splitPoint.master = master;
|
splitPoint.master = master;
|
||||||
splitPoint.betaCutoff = false;
|
splitPoint.is_betaCutoff = false;
|
||||||
splitPoint.depth = depth;
|
splitPoint.depth = depth;
|
||||||
splitPoint.threatMove = threatMove;
|
splitPoint.threatMove = threatMove;
|
||||||
splitPoint.alpha = *alpha;
|
splitPoint.alpha = *alpha;
|
||||||
|
@ -285,22 +284,22 @@ void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const V
|
||||||
splitPoint.nodes = 0;
|
splitPoint.nodes = 0;
|
||||||
splitPoint.ss = ss;
|
splitPoint.ss = ss;
|
||||||
for (i = 0; i < activeThreads; i++)
|
for (i = 0; i < activeThreads; i++)
|
||||||
splitPoint.slaves[i] = 0;
|
splitPoint.is_slave[i] = false;
|
||||||
|
|
||||||
masterThread.splitPoint = &splitPoint;
|
masterThread.splitPoint = &splitPoint;
|
||||||
|
|
||||||
// If we are here it means we are not available
|
// If we are here it means we are not available
|
||||||
assert(masterThread.state != THREAD_AVAILABLE);
|
assert(masterThread.state != Thread::AVAILABLE);
|
||||||
|
|
||||||
int workersCnt = 1; // At least the master is included
|
int workersCnt = 1; // At least the master is included
|
||||||
|
|
||||||
// Allocate available threads setting state to THREAD_BOOKED
|
// Allocate available threads setting state to THREAD_BOOKED
|
||||||
for (i = 0; !Fake && i < activeThreads && workersCnt < maxThreadsPerSplitPoint; i++)
|
for (i = 0; !Fake && i < activeThreads && workersCnt < maxThreadsPerSplitPoint; i++)
|
||||||
if (thread_is_available(i, master))
|
if (i != master && threads[i].is_available_to(master))
|
||||||
{
|
{
|
||||||
threads[i].state = THREAD_BOOKED;
|
threads[i].state = Thread::BOOKED;
|
||||||
threads[i].splitPoint = &splitPoint;
|
threads[i].splitPoint = &splitPoint;
|
||||||
splitPoint.slaves[i] = 1;
|
splitPoint.is_slave[i] = true;
|
||||||
workersCnt++;
|
workersCnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,11 +311,11 @@ void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const V
|
||||||
// Tell the threads that they have work to do. This will make them leave
|
// Tell the threads that they have work to do. This will make them leave
|
||||||
// their idle loop.
|
// their idle loop.
|
||||||
for (i = 0; i < activeThreads; i++)
|
for (i = 0; i < activeThreads; i++)
|
||||||
if (i == master || splitPoint.slaves[i])
|
if (i == master || splitPoint.is_slave[i])
|
||||||
{
|
{
|
||||||
assert(i == master || threads[i].state == THREAD_BOOKED);
|
assert(i == master || threads[i].state == Thread::BOOKED);
|
||||||
|
|
||||||
threads[i].state = THREAD_WORKISWAITING; // This makes the slave to exit from idle_loop()
|
threads[i].state = Thread::WORKISWAITING; // This makes the slave to exit from idle_loop()
|
||||||
|
|
||||||
if (useSleepingThreads && i != master)
|
if (useSleepingThreads && i != master)
|
||||||
threads[i].wake_up();
|
threads[i].wake_up();
|
||||||
|
@ -343,5 +342,5 @@ void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const V
|
||||||
}
|
}
|
||||||
|
|
||||||
// Explicit template instantiations
|
// Explicit template instantiations
|
||||||
template void ThreadsManager::split<0>(Position&, SearchStack*, Value*, const Value, Value*, Depth, Move, int, MovePicker*, bool);
|
template void ThreadsManager::split<false>(Position&, SearchStack*, Value*, const Value, Value*, Depth, Move, int, MovePicker*, bool);
|
||||||
template void ThreadsManager::split<1>(Position&, SearchStack*, Value*, const Value, Value*, Depth, Move, int, MovePicker*, bool);
|
template void ThreadsManager::split<true>(Position&, SearchStack*, Value*, const Value, Value*, Depth, Move, int, MovePicker*, bool);
|
||||||
|
|
63
src/thread.h
63
src/thread.h
|
@ -53,27 +53,32 @@ struct SplitPoint {
|
||||||
volatile Value alpha;
|
volatile Value alpha;
|
||||||
volatile Value bestValue;
|
volatile Value bestValue;
|
||||||
volatile int moveCount;
|
volatile int moveCount;
|
||||||
volatile bool betaCutoff;
|
volatile bool is_betaCutoff;
|
||||||
volatile int slaves[MAX_THREADS];
|
volatile bool is_slave[MAX_THREADS];
|
||||||
};
|
|
||||||
|
|
||||||
// ThreadState type is used to represent thread's current state
|
|
||||||
enum ThreadState
|
|
||||||
{
|
|
||||||
THREAD_INITIALIZING, // thread is initializing itself
|
|
||||||
THREAD_SEARCHING, // thread is performing work
|
|
||||||
THREAD_AVAILABLE, // thread is waiting for work
|
|
||||||
THREAD_BOOKED, // other thread (master) has booked us as a slave
|
|
||||||
THREAD_WORKISWAITING, // master has ordered us to start
|
|
||||||
THREAD_TERMINATED // we are quitting and thread is terminated
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// We use per-thread Pawn and material hash tables so that once we get a
|
/// Thread struct is used to keep together all the thread related stuff like locks,
|
||||||
// pointer to an entry its life time is unlimited and we don't have to
|
/// state and especially split points. We also use per-thread pawn and material hash
|
||||||
// care about someone changing the entry under our feet.
|
/// 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.
|
||||||
|
|
||||||
struct Thread {
|
struct Thread {
|
||||||
|
|
||||||
|
enum ThreadState
|
||||||
|
{
|
||||||
|
INITIALIZING, // Thread is initializing itself
|
||||||
|
SEARCHING, // Thread is performing work
|
||||||
|
AVAILABLE, // Thread is waiting for work
|
||||||
|
BOOKED, // Other thread (master) has booked us as a slave
|
||||||
|
WORKISWAITING, // Master has ordered us to start
|
||||||
|
TERMINATED // We are quitting and thread is terminated
|
||||||
|
};
|
||||||
|
|
||||||
|
void wake_up();
|
||||||
|
bool cutoff_occurred() const;
|
||||||
|
bool is_available_to(int master) const;
|
||||||
|
|
||||||
MaterialInfoTable materialTable;
|
MaterialInfoTable materialTable;
|
||||||
PawnInfoTable pawnTable;
|
PawnInfoTable pawnTable;
|
||||||
int maxPly;
|
int maxPly;
|
||||||
|
@ -83,18 +88,12 @@ struct Thread {
|
||||||
SplitPoint* volatile splitPoint;
|
SplitPoint* volatile splitPoint;
|
||||||
volatile int activeSplitPoints;
|
volatile int activeSplitPoints;
|
||||||
SplitPoint splitPoints[MAX_ACTIVE_SPLIT_POINTS];
|
SplitPoint splitPoints[MAX_ACTIVE_SPLIT_POINTS];
|
||||||
|
|
||||||
void wake_up() {
|
|
||||||
lock_grab(&sleepLock);
|
|
||||||
cond_signal(&sleepCond);
|
|
||||||
lock_release(&sleepLock);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// ThreadsManager class is used to handle all the threads related stuff like init,
|
/// ThreadsManager class is used to handle all the threads related stuff like init,
|
||||||
// starting, parking and, the most important, launching a slave thread at a split
|
/// starting, parking and, the most important, launching a slave thread at a split
|
||||||
// point. All the access to shared thread data is done through this class.
|
/// point. All the access to shared thread data is done through this class.
|
||||||
|
|
||||||
class ThreadsManager {
|
class ThreadsManager {
|
||||||
/* As long as the single ThreadsManager object is defined as a global we don't
|
/* As long as the single ThreadsManager object is defined as a global we don't
|
||||||
|
@ -103,18 +102,16 @@ class ThreadsManager {
|
||||||
*/
|
*/
|
||||||
public:
|
public:
|
||||||
Thread& operator[](int threadID) { return threads[threadID]; }
|
Thread& operator[](int threadID) { return threads[threadID]; }
|
||||||
void init_threads();
|
void init();
|
||||||
void exit_threads();
|
void exit();
|
||||||
void init_hash_tables();
|
void init_hash_tables();
|
||||||
|
|
||||||
int min_split_depth() const { return minimumSplitDepth; }
|
int min_split_depth() const { return minimumSplitDepth; }
|
||||||
int active_threads() const { return activeThreads; }
|
int size() const { return activeThreads; }
|
||||||
void set_active_threads(int cnt) { activeThreads = cnt; }
|
void set_size(int cnt) { activeThreads = cnt; }
|
||||||
|
|
||||||
void read_uci_options();
|
void read_uci_options();
|
||||||
bool available_thread_exists(int master) const;
|
bool available_slave_exists(int master) const;
|
||||||
bool thread_is_available(int slave, int master) const;
|
|
||||||
bool cutoff_at_splitpoint(int threadID) const;
|
|
||||||
void idle_loop(int threadID, SplitPoint* sp);
|
void idle_loop(int threadID, SplitPoint* sp);
|
||||||
|
|
||||||
template <bool Fake>
|
template <bool Fake>
|
||||||
|
@ -130,6 +127,6 @@ private:
|
||||||
Thread threads[MAX_THREADS];
|
Thread threads[MAX_THREADS];
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ThreadsManager ThreadsMgr;
|
extern ThreadsManager Threads;
|
||||||
|
|
||||||
#endif // !defined(THREAD_H_INCLUDED)
|
#endif // !defined(THREAD_H_INCLUDED)
|
||||||
|
|
Loading…
Add table
Reference in a new issue