Skip to content

Commit

Permalink
Active Reparenting
Browse files Browse the repository at this point in the history
In Young Brothers Wait Concept (YBWC) available slaves are
booked by the split point master, then start to search below
the assigned split point and, once finished, return in idle
state waiting to be booked by another master.

This patch introduces "Active Reparenting" so that when a
slave finishes its job on the assigned split point, instead
of passively waiting to be booked, searches a suitable active
split point and reprents itselfs to that split point. Then
immediately starts to search below the split point in exactly
the same way of the others split point's slaves. This reduces
to zero the time waiting in idle loop and should increase
scalability especially whit many (8 or more) cores.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
  • Loading branch information
mcostalba committed Apr 10, 2012
1 parent d66b765 commit 44432f6
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 1 deletion.
43 changes: 43 additions & 0 deletions src/search.cpp
Expand Up @@ -1859,6 +1859,49 @@ void Thread::idle_loop(SplitPoint* sp_master) {
// our feet by the sp master. Also accessing other Thread objects is
// unsafe because if we are exiting there is a chance are already freed.
lock_release(sp->lock);

// Try to reparent to another split point. Only for slave threads
// that are not master of any active split point.
if ( !sp_master
&& !is_searching
&& !do_sleep
&& !do_exit
&& !splitPointsCnt
&& Threads.size() > 2)
{
for (int i = 0; i < Threads.size(); i++)
{
SplitPoint* oldest = &Threads[i].splitPoints[0];

// Find the first oldest split point with still all slaves running
if ( Threads[i].splitPointsCnt
&& oldest->slavesMask == oldest->allSlavesMask
&& !single_bit(oldest->allSlavesMask))
{
lock_grab(oldest->lock);
lock_grab(Threads.splitLock); // Needed by is_searching

// Retest all under lock protection, we are in the middle
// of a race storm !
if ( !is_searching
&& !do_sleep
&& !do_exit
&& Threads[i].splitPointsCnt
&& oldest->slavesMask == oldest->allSlavesMask
&& !single_bit(oldest->allSlavesMask))
{
oldest->slavesMask |= 1ULL << idx; // allSlavesMask is not updated
curSplitPoint = oldest;
is_searching = true;
}

lock_release(Threads.splitLock);
lock_release(oldest->lock);

break; // Exit anyhow, only one try (enough in 99% of cases)
}
}
}
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions src/thread.cpp
Expand Up @@ -319,6 +319,7 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta,
sp->master = master;
sp->cutoff = false;
sp->slavesMask = 1ULL << master->idx;
sp->allSlavesMask = 1ULL << master->idx;
sp->depth = depth;
sp->bestMove = *bestMove;
sp->threatMove = threatMove;
Expand Down Expand Up @@ -347,14 +348,18 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta,
if (threads[i]->is_available_to(master))
{
sp->slavesMask |= 1ULL << i;
sp->allSlavesMask |= 1ULL << i;
threads[i]->curSplitPoint = sp;
threads[i]->is_searching = true; // Slave leaves idle_loop()

if (useSleepingThreads)
threads[i]->wake_up();

if (++slavesCnt + 1 >= maxThreadsPerSplitPoint) // Master is always included
{
sp->allSlavesMask = 0; // Disable reparenting to this split point
break;
}
}

lock_release(splitLock);
Expand Down
1 change: 1 addition & 0 deletions src/thread.h
Expand Up @@ -51,6 +51,7 @@ struct SplitPoint {
// Shared data
Lock lock;
volatile uint64_t slavesMask;
volatile uint64_t allSlavesMask;
volatile int64_t nodes;
volatile Value alpha;
volatile Value bestValue;
Expand Down
1 change: 0 additions & 1 deletion src/types.h
Expand Up @@ -325,7 +325,6 @@ const Value QueenValueEndgame = Value(0x9FE);
extern const Value PieceValueMidgame[17]; // Indexed by Piece or PieceType
extern const Value PieceValueEndgame[17];
extern int SquareDistance[64][64];
extern uint8_t BitCount8Bit[256];

inline Color operator~(Color c) {
return Color(c ^ 1);
Expand Down

0 comments on commit 44432f6

Please sign in to comment.