1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-07-11 19:49:14 +00:00

Reformat threads code

Apart from some renaming the biggest change
is the retire of split_point_finished()
replaced by slavesMask flags. As a side
effect we now take also split point lock
when allocation available threads.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
Marco Costalba 2012-01-26 23:18:43 +01:00
parent a189a5f0c5
commit 7fb6fd2f55
3 changed files with 72 additions and 95 deletions

View file

@ -573,19 +573,25 @@ namespace {
thread.maxPly = ss->ply; thread.maxPly = ss->ply;
// Step 1. Initialize node // Step 1. Initialize node
if (!SpNode) if (SpNode)
{
tte = NULL;
ttMove = excludedMove = MOVE_NONE;
sp = ss->sp;
threatMove = sp->threatMove;
bestValue = sp->bestValue;
moveCount = sp->moveCount; // Lock must be held here
assert(bestValue > -VALUE_INFINITE && moveCount > 0);
goto split_point_start;
}
else
{ {
ss->currentMove = ss->bestMove = threatMove = (ss+1)->excludedMove = MOVE_NONE; ss->currentMove = ss->bestMove = threatMove = (ss+1)->excludedMove = MOVE_NONE;
(ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO; (ss+1)->skipNullMove = false; (ss+1)->reduction = DEPTH_ZERO;
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE; (ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
}
else
{
sp = ss->sp;
tte = NULL;
ttMove = excludedMove = MOVE_NONE;
threatMove = sp->threatMove;
goto split_point_start;
} }
// Step 2. Check for aborted search and immediate draw // Step 2. Check for aborted search and immediate draw
@ -820,14 +826,6 @@ split_point_start: // At split points actual search starts from here
&& !excludedMove // Recursive singular search is not allowed && !excludedMove // Recursive singular search is not allowed
&& (tte->type() & VALUE_TYPE_LOWER) && (tte->type() & VALUE_TYPE_LOWER)
&& tte->depth() >= depth - 3 * ONE_PLY; && tte->depth() >= depth - 3 * ONE_PLY;
if (SpNode)
{
lock_grab(sp->lock);
bestValue = sp->bestValue;
moveCount = sp->moveCount;
assert(bestValue > -VALUE_INFINITE && moveCount > 0);
}
// Step 11. Loop through moves // Step 11. Loop through moves
// Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
@ -1129,14 +1127,6 @@ split_point_start: // At split points actual search starts from here
} }
} }
if (SpNode)
{
// Here we have the lock still grabbed
sp->is_slave[pos.thread()] = false;
sp->nodes += pos.nodes_searched();
lock_release(sp->lock);
}
assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE);
return bestValue; return bestValue;
@ -1836,24 +1826,24 @@ void RootMove::insert_pv_in_tt(Position& pos) {
/// Thread::idle_loop() is where the thread is parked when it has no work to do. /// Thread::idle_loop() is where the thread is parked when it has no work to do.
/// The parameter 'sp', if non-NULL, is a pointer to an active SplitPoint object /// The parameter 'master_sp', if non-NULL, is a pointer to an active SplitPoint
/// for which the thread is the master. /// object for which the thread is the master.
void Thread::idle_loop(SplitPoint* sp) { void Thread::idle_loop(SplitPoint* sp_master) {
while (true) // 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.
while (!sp_master || sp_master->slavesMask)
{ {
// If we are not searching, wait for a condition to be signaled // If we are not searching, wait for a condition to be signaled
// instead of wasting CPU time polling for work. // instead of wasting CPU time polling for work.
while ( do_sleep while ( do_sleep
|| do_terminate || do_exit
|| (Threads.use_sleeping_threads() && !is_searching)) || (!is_searching && Threads.use_sleeping_threads()))
{ {
assert((!sp && threadID) || Threads.use_sleeping_threads()); if (do_exit)
if (do_terminate)
{ {
assert(!sp); assert(!sp_master);
return; return;
} }
@ -1861,7 +1851,7 @@ void Thread::idle_loop(SplitPoint* sp) {
lock_grab(sleepLock); lock_grab(sleepLock);
// If we are master and all slaves have finished don't go to sleep // If we are master and all slaves have finished don't go to sleep
if (sp && Threads.split_point_finished(sp)) if (sp_master && !sp_master->slavesMask)
{ {
lock_release(sleepLock); lock_release(sleepLock);
break; break;
@ -1880,46 +1870,42 @@ void Thread::idle_loop(SplitPoint* sp) {
// If this thread has been assigned work, launch a search // If this thread has been assigned work, launch a search
if (is_searching) if (is_searching)
{ {
assert(!do_terminate); assert(!do_sleep && !do_exit);
// Copy split point position and search stack and call search() // Copy split point position and search stack and call search()
Stack ss[MAX_PLY_PLUS_2]; Stack ss[MAX_PLY_PLUS_2];
SplitPoint* tsp = splitPoint; SplitPoint* sp = splitPoint;
Position pos(*tsp->pos, threadID); Position pos(*sp->pos, threadID);
memcpy(ss, tsp->ss - 1, 4 * sizeof(Stack)); memcpy(ss, sp->ss - 1, 4 * sizeof(Stack));
(ss+1)->sp = tsp; (ss+1)->sp = sp;
if (tsp->nodeType == Root) lock_grab(sp->lock);
search<SplitPointRoot>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth);
else if (tsp->nodeType == PV) if (sp->nodeType == Root)
search<SplitPointPV>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth); search<SplitPointRoot>(pos, ss+1, sp->alpha, sp->beta, sp->depth);
else if (tsp->nodeType == NonPV) else if (sp->nodeType == PV)
search<SplitPointNonPV>(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth); search<SplitPointPV>(pos, ss+1, sp->alpha, sp->beta, sp->depth);
else if (sp->nodeType == NonPV)
search<SplitPointNonPV>(pos, ss+1, sp->alpha, sp->beta, sp->depth);
else else
assert(false); assert(false);
assert(is_searching); assert(is_searching);
// We return from search with lock held
sp->slavesMask &= ~(1ULL << threadID);
sp->nodes += pos.nodes_searched();
lock_release(sp->lock);
is_searching = false; is_searching = false;
// 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 ( Threads.use_sleeping_threads() if ( Threads.use_sleeping_threads()
&& threadID != tsp->master && threadID != sp->master
&& !Threads[tsp->master].is_searching) && !Threads[sp->master].is_searching)
Threads[tsp->master].wake_up(); Threads[sp->master].wake_up();
}
// 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.
if (sp && Threads.split_point_finished(sp))
{
// Because sp->is_slave[] is reset under lock protection,
// be sure sp->lock has been released before to return.
lock_grab(sp->lock);
lock_release(sp->lock);
return;
} }
} }
} }

View file

@ -97,12 +97,11 @@ bool Thread::is_available_to(int master) const {
// Make a local copy to be sure doesn't become zero under our feet while // 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. // testing next condition and so leading to an out of bound access.
int localActiveSplitPoints = activeSplitPoints; int sp_count = activeSplitPoints;
// No active split points means that the thread is available as a slave for any // 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. // other thread otherwise apply the "helpful master" concept if possible.
if ( !localActiveSplitPoints if (!sp_count || (splitPoints[sp_count - 1].slavesMask & (1ULL << master)))
|| splitPoints[localActiveSplitPoints - 1].is_slave[master])
return true; return true;
return false; return false;
@ -190,9 +189,11 @@ void ThreadsManager::init() {
void ThreadsManager::exit() { void ThreadsManager::exit() {
assert(threads[0].is_searching == false);
for (int i = 0; i <= MAX_THREADS; i++) for (int i = 0; i <= MAX_THREADS; i++)
{ {
threads[i].do_terminate = true; // Search must be already finished threads[i].do_exit = true; // Search must be already finished
threads[i].wake_up(); threads[i].wake_up();
thread_join(threads[i].handle); // Wait for thread termination thread_join(threads[i].handle); // Wait for thread termination
@ -225,19 +226,6 @@ bool ThreadsManager::available_slave_exists(int master) const {
} }
// split_point_finished() checks if all the slave threads of a given split
// point have finished searching.
bool ThreadsManager::split_point_finished(SplitPoint* sp) const {
for (int i = 0; i < activeThreads; i++)
if (sp->is_slave[i])
return false;
return true;
}
// split() does the actual work of distributing the work at a node between // split() does the actual work of distributing the work at a node between
// several available threads. If it does not succeed in splitting the node // several available threads. If it does not succeed in splitting the node
// (because no idle threads are available, or because we have no unused split // (because no idle threads are available, or because we have no unused split
@ -274,6 +262,7 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta,
sp->parent = masterThread.splitPoint; sp->parent = masterThread.splitPoint;
sp->master = master; sp->master = master;
sp->is_betaCutoff = false; sp->is_betaCutoff = false;
sp->slavesMask = (1ULL << master);
sp->depth = depth; sp->depth = depth;
sp->threatMove = threatMove; sp->threatMove = threatMove;
sp->alpha = alpha; sp->alpha = alpha;
@ -286,9 +275,6 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta,
sp->nodes = 0; sp->nodes = 0;
sp->ss = ss; sp->ss = ss;
for (i = 0; i < activeThreads; i++)
sp->is_slave[i] = false;
// If we are here it means we are not available // If we are here it means we are not available
assert(masterThread.is_searching); assert(masterThread.is_searching);
@ -298,21 +284,25 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta,
// is_searching flag. This must be done under lock protection to avoid concurrent // is_searching flag. This must be done under lock protection to avoid concurrent
// allocation of the same slave by another master. // allocation of the same slave by another master.
lock_grab(threadsLock); lock_grab(threadsLock);
lock_grab(sp->lock); // To protect sp->slaves_mask
for (i = 0; !Fake && i < activeThreads && workersCnt < maxThreadsPerSplitPoint; i++) for (i = 0; !Fake && i < activeThreads; i++)
if (threads[i].is_available_to(master)) if (threads[i].is_available_to(master))
{ {
workersCnt++; sp->slavesMask |= (1ULL << i);
sp->is_slave[i] = true;
threads[i].splitPoint = sp; threads[i].splitPoint = sp;
// This makes the slave to exit from idle_loop() // Allocate the slave and make it exit from idle_loop()
threads[i].is_searching = true; threads[i].is_searching = true;
if (useSleepingThreads) if (useSleepingThreads)
threads[i].wake_up(); threads[i].wake_up();
if (++workersCnt >= maxThreadsPerSplitPoint)
break;
} }
lock_release(sp->lock);
lock_release(threadsLock); lock_release(threadsLock);
// We failed to allocate even one slave, return // We failed to allocate even one slave, return
@ -337,15 +327,17 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta,
// finished. Note that changing state and decreasing activeSplitPoints is done // finished. Note that changing state and decreasing activeSplitPoints is done
// under lock protection to avoid a race with Thread::is_available_to(). // under lock protection to avoid a race with Thread::is_available_to().
lock_grab(threadsLock); lock_grab(threadsLock);
lock_grab(sp->lock); // To protect sp->nodes
masterThread.is_searching = true; masterThread.is_searching = true;
masterThread.activeSplitPoints--; masterThread.activeSplitPoints--;
lock_release(threadsLock);
masterThread.splitPoint = sp->parent; masterThread.splitPoint = sp->parent;
pos.set_nodes_searched(pos.nodes_searched() + sp->nodes); pos.set_nodes_searched(pos.nodes_searched() + sp->nodes);
lock_release(sp->lock);
lock_release(threadsLock);
return sp->bestValue; return sp->bestValue;
} }
@ -360,7 +352,7 @@ extern void check_time();
void Thread::timer_loop() { void Thread::timer_loop() {
while (!do_terminate) while (!do_exit)
{ {
lock_grab(sleepLock); lock_grab(sleepLock);
timed_wait(sleepCond, sleepLock, maxPly ? maxPly : INT_MAX); timed_wait(sleepCond, sleepLock, maxPly ? maxPly : INT_MAX);
@ -396,7 +388,7 @@ void Thread::main_loop() {
do_sleep = true; // Always return to sleep after a search do_sleep = true; // Always return to sleep after a search
is_searching = false; is_searching = false;
while (do_sleep && !do_terminate) while (do_sleep && !do_exit)
{ {
cond_signal(Threads.sleepCond); // Wake up UI thread if needed cond_signal(Threads.sleepCond); // Wake up UI thread if needed
cond_wait(sleepCond, sleepLock); cond_wait(sleepCond, sleepLock);
@ -406,7 +398,7 @@ void Thread::main_loop() {
lock_release(sleepLock); lock_release(sleepLock);
if (do_terminate) if (do_exit)
return; return;
Search::think(); Search::think();

View file

@ -50,12 +50,12 @@ struct SplitPoint {
// Shared data // Shared data
Lock lock; Lock lock;
volatile uint64_t slavesMask;
volatile int64_t nodes; volatile int64_t nodes;
volatile Value alpha; volatile Value alpha;
volatile Value bestValue; volatile Value bestValue;
volatile int moveCount; volatile int moveCount;
volatile bool is_betaCutoff; volatile bool is_betaCutoff;
volatile bool is_slave[MAX_THREADS];
}; };
@ -69,7 +69,7 @@ struct Thread {
void wake_up(); void wake_up();
bool cutoff_occurred() const; bool cutoff_occurred() const;
bool is_available_to(int master) const; bool is_available_to(int master) const;
void idle_loop(SplitPoint* sp); void idle_loop(SplitPoint* sp_master);
void main_loop(); void main_loop();
void timer_loop(); void timer_loop();
@ -85,7 +85,7 @@ struct Thread {
volatile int activeSplitPoints; volatile int activeSplitPoints;
volatile bool is_searching; volatile bool is_searching;
volatile bool do_sleep; volatile bool do_sleep;
volatile bool do_terminate; volatile bool do_exit;
}; };
@ -110,7 +110,6 @@ public:
void set_size(int cnt); void set_size(int cnt);
void read_uci_options(); void read_uci_options();
bool available_slave_exists(int master) const; bool available_slave_exists(int master) const;
bool split_point_finished(SplitPoint* sp) const;
void set_timer(int msec); void set_timer(int msec);
void wait_for_stop_or_ponderhit(); void wait_for_stop_or_ponderhit();
void stop_thinking(); void stop_thinking();