1
0
Fork 0
mirror of https://github.com/sockspls/badfish synced 2025-05-02 01:29:36 +00:00

Large API rename in ThreadsManager

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
Marco Costalba 2011-04-25 00:22:48 +01:00
parent 339e1b49f6
commit 05cfb00f26
6 changed files with 150 additions and 155 deletions

View file

@ -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

View file

@ -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;
} }

View file

@ -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);

View file

@ -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;
} }
} }

View file

@ -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);

View file

@ -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)