mirror of
https://github.com/sockspls/badfish
synced 2025-04-30 16:53:09 +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;
|
||||
|
||||
// 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();
|
||||
|
||||
// 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
|
||||
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]);
|
||||
|
||||
// Initialize attack and king safety bitboards
|
||||
|
|
|
@ -55,7 +55,7 @@ int main(int argc, char* argv[]) {
|
|||
Position::init_piece_square_tables();
|
||||
init_kpk_bitbase();
|
||||
init_search();
|
||||
ThreadsMgr.init_threads();
|
||||
Threads.init();
|
||||
|
||||
#ifdef USE_CALLGRIND
|
||||
CALLGRIND_START_INSTRUMENTATION;
|
||||
|
@ -82,6 +82,6 @@ int main(int argc, char* argv[]) {
|
|||
<< "[limit = 12] [fen positions file = default] "
|
||||
<< "[depth, time, perft or node limited = depth]" << endl;
|
||||
|
||||
ThreadsMgr.exit_threads();
|
||||
Threads.exit();
|
||||
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
|
||||
ThreadsMgr[threadID].pawnTable.prefetch(st->pawnKey);
|
||||
ThreadsMgr[threadID].materialTable.prefetch(st->materialKey);
|
||||
Threads[threadID].pawnTable.prefetch(st->pawnKey);
|
||||
Threads[threadID].materialTable.prefetch(st->materialKey);
|
||||
|
||||
// Update incremental scores
|
||||
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>();
|
||||
|
||||
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
|
||||
ThreadsMgr.init_hash_tables();
|
||||
Threads.init_hash_tables();
|
||||
TT.set_size(Options["Hash"].value<int>());
|
||||
|
||||
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);
|
||||
|
||||
// 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();
|
||||
ThreadsMgr[i].maxPly = 0;
|
||||
Threads[i].wake_up();
|
||||
Threads[i].maxPly = 0;
|
||||
}
|
||||
|
||||
// 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
|
||||
ThreadsMgr.set_active_threads(1);
|
||||
Threads.set_size(1);
|
||||
|
||||
// If we are pondering or in infinite search, we shouldn't print the
|
||||
// best move before we are told to do so.
|
||||
|
@ -625,9 +625,9 @@ namespace {
|
|||
|
||||
// Retrieve max searched depth among threads
|
||||
selDepth = 0;
|
||||
for (int i = 0; i < ThreadsMgr.active_threads(); i++)
|
||||
if (ThreadsMgr[i].maxPly > selDepth)
|
||||
selDepth = ThreadsMgr[i].maxPly;
|
||||
for (int i = 0; i < Threads.size(); i++)
|
||||
if (Threads[i].maxPly > selDepth)
|
||||
selDepth = Threads[i].maxPly;
|
||||
|
||||
// Send PV line to GUI and to log file
|
||||
for (int i = 0; i < Min(UCIMultiPV, (int)Rml.size()); i++)
|
||||
|
@ -708,7 +708,7 @@ namespace {
|
|||
assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE);
|
||||
assert(beta > alpha && beta <= VALUE_INFINITE);
|
||||
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];
|
||||
int64_t nodes;
|
||||
|
@ -731,8 +731,8 @@ namespace {
|
|||
ss->ply = (ss-1)->ply + 1;
|
||||
|
||||
// Used to send selDepth info to GUI
|
||||
if (PvNode && ThreadsMgr[threadID].maxPly < ss->ply)
|
||||
ThreadsMgr[threadID].maxPly = ss->ply;
|
||||
if (PvNode && Threads[threadID].maxPly < ss->ply)
|
||||
Threads[threadID].maxPly = ss->ply;
|
||||
|
||||
if (SpNode)
|
||||
{
|
||||
|
@ -758,7 +758,7 @@ namespace {
|
|||
|
||||
// Step 2. Check for aborted search and immediate draw
|
||||
if (( StopRequest
|
||||
|| ThreadsMgr.cutoff_at_splitpoint(threadID)
|
||||
|| Threads[threadID].cutoff_occurred()
|
||||
|| pos.is_draw()
|
||||
|| ss->ply > PLY_MAX) && !Root)
|
||||
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
|
||||
while ( bestValue < beta
|
||||
&& (move = mp.get_next_move()) != MOVE_NONE
|
||||
&& !ThreadsMgr.cutoff_at_splitpoint(threadID))
|
||||
&& !Threads[threadID].cutoff_occurred())
|
||||
{
|
||||
assert(move_is_ok(move));
|
||||
|
||||
|
@ -1154,7 +1154,7 @@ split_point_start: // At split points actual search starts from here
|
|||
alpha = sp->alpha;
|
||||
}
|
||||
|
||||
if (value > bestValue && !(SpNode && ThreadsMgr.cutoff_at_splitpoint(threadID)))
|
||||
if (value > bestValue && !(SpNode && Threads[threadID].cutoff_occurred()))
|
||||
{
|
||||
bestValue = value;
|
||||
|
||||
|
@ -1171,7 +1171,7 @@ split_point_start: // At split points actual search starts from here
|
|||
sp->alpha = value;
|
||||
}
|
||||
else if (SpNode)
|
||||
sp->betaCutoff = true;
|
||||
sp->is_betaCutoff = true;
|
||||
|
||||
if (value == value_mate_in(ss->ply + 1))
|
||||
ss->mateKiller = move;
|
||||
|
@ -1227,14 +1227,13 @@ split_point_start: // At split points actual search starts from here
|
|||
// Step 18. Check for split
|
||||
if ( !Root
|
||||
&& !SpNode
|
||||
&& depth >= ThreadsMgr.min_split_depth()
|
||||
&& ThreadsMgr.active_threads() > 1
|
||||
&& depth >= Threads.min_split_depth()
|
||||
&& bestValue < beta
|
||||
&& ThreadsMgr.available_thread_exists(threadID)
|
||||
&& Threads.available_slave_exists(threadID)
|
||||
&& !StopRequest
|
||||
&& !ThreadsMgr.cutoff_at_splitpoint(threadID))
|
||||
ThreadsMgr.split<FakeSplit>(pos, ss, &alpha, beta, &bestValue, depth,
|
||||
threatMove, moveCount, &mp, PvNode);
|
||||
&& !Threads[threadID].cutoff_occurred())
|
||||
Threads.split<FakeSplit>(pos, ss, &alpha, beta, &bestValue, depth,
|
||||
threatMove, moveCount, &mp, PvNode);
|
||||
}
|
||||
|
||||
// Step 19. Check for mate and stalemate
|
||||
|
@ -1247,7 +1246,7 @@ split_point_start: // At split points actual search starts from here
|
|||
// Step 20. Update tables
|
||||
// If the search is not aborted, update the transposition table,
|
||||
// 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;
|
||||
vt = bestValue <= oldAlpha ? VALUE_TYPE_UPPER
|
||||
|
@ -1271,7 +1270,7 @@ split_point_start: // At split points actual search starts from here
|
|||
if (SpNode)
|
||||
{
|
||||
// Here we have the lock still grabbed
|
||||
sp->slaves[threadID] = 0;
|
||||
sp->is_slave[threadID] = false;
|
||||
sp->nodes += pos.nodes_searched();
|
||||
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(PvNode || alpha == beta - 1);
|
||||
assert(depth <= 0);
|
||||
assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads());
|
||||
assert(pos.thread() >= 0 && pos.thread() < Threads.size());
|
||||
|
||||
StateInfo st;
|
||||
Move ttMove, move;
|
||||
|
@ -2112,27 +2111,27 @@ void ThreadsManager::idle_loop(int threadID, SplitPoint* sp) {
|
|||
if (allThreadsShouldExit)
|
||||
{
|
||||
assert(!sp);
|
||||
threads[threadID].state = THREAD_TERMINATED;
|
||||
threads[threadID].state = Thread::TERMINATED;
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are not thinking, wait for a condition to be signaled
|
||||
// instead of wasting CPU time polling for work.
|
||||
while ( threadID >= activeThreads
|
||||
|| threads[threadID].state == THREAD_INITIALIZING
|
||||
|| (useSleepingThreads && threads[threadID].state == THREAD_AVAILABLE))
|
||||
|| threads[threadID].state == Thread::INITIALIZING
|
||||
|| (useSleepingThreads && threads[threadID].state == Thread::AVAILABLE))
|
||||
{
|
||||
assert(!sp || useSleepingThreads);
|
||||
assert(threadID != 0 || useSleepingThreads);
|
||||
|
||||
if (threads[threadID].state == THREAD_INITIALIZING)
|
||||
threads[threadID].state = THREAD_AVAILABLE;
|
||||
if (threads[threadID].state == Thread::INITIALIZING)
|
||||
threads[threadID].state = Thread::AVAILABLE;
|
||||
|
||||
// Grab the lock to avoid races with Thread::wake_up()
|
||||
lock_grab(&threads[threadID].sleepLock);
|
||||
|
||||
// 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);
|
||||
|
||||
if (allFinished || allThreadsShouldExit)
|
||||
|
@ -2142,18 +2141,18 @@ void ThreadsManager::idle_loop(int threadID, SplitPoint* sp) {
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
||||
lock_release(&threads[threadID].sleepLock);
|
||||
}
|
||||
|
||||
// If this thread has been assigned work, launch a search
|
||||
if (threads[threadID].state == THREAD_WORKISWAITING)
|
||||
if (threads[threadID].state == Thread::WORKISWAITING)
|
||||
{
|
||||
assert(!allThreadsShouldExit);
|
||||
|
||||
threads[threadID].state = THREAD_SEARCHING;
|
||||
threads[threadID].state = Thread::SEARCHING;
|
||||
|
||||
// Copy split point position and search stack and call search()
|
||||
// with SplitPoint template parameter set to true.
|
||||
|
@ -2169,21 +2168,21 @@ void ThreadsManager::idle_loop(int threadID, SplitPoint* sp) {
|
|||
else
|
||||
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
|
||||
// case we are the last slave of the split point.
|
||||
if ( useSleepingThreads
|
||||
&& threadID != tsp->master
|
||||
&& threads[tsp->master].state == THREAD_AVAILABLE)
|
||||
&& threads[tsp->master].state == Thread::AVAILABLE)
|
||||
threads[tsp->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.
|
||||
for (i = 0; sp && i < activeThreads && !sp->slaves[i]; i++) {}
|
||||
for (i = 0; sp && i < activeThreads && !sp->is_slave[i]; i++) {}
|
||||
allFinished = (i == activeThreads);
|
||||
|
||||
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
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
151
src/thread.cpp
151
src/thread.cpp
|
@ -22,7 +22,7 @@
|
|||
#include "thread.h"
|
||||
#include "ucioption.h"
|
||||
|
||||
ThreadsManager ThreadsMgr; // Global object definition
|
||||
ThreadsManager Threads; // Global object definition
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -35,7 +35,7 @@ namespace {
|
|||
|
||||
void* init_thread(void* threadID) {
|
||||
|
||||
ThreadsMgr.idle_loop(*(int*)threadID, NULL);
|
||||
Threads.idle_loop(*(int*)threadID, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ namespace {
|
|||
|
||||
DWORD WINAPI init_thread(LPVOID threadID) {
|
||||
|
||||
ThreadsMgr.idle_loop(*(int*)threadID, NULL);
|
||||
Threads.idle_loop(*(int*)threadID, NULL);
|
||||
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
|
||||
// parameters according to the UCI options values. It is called before
|
||||
// to start a new search.
|
||||
|
@ -68,7 +118,7 @@ void ThreadsManager::read_uci_options() {
|
|||
// init_threads() is called during startup. Initializes locks and condition
|
||||
// variables and launches all threads sending them immediately to sleep.
|
||||
|
||||
void ThreadsManager::init_threads() {
|
||||
void ThreadsManager::init() {
|
||||
|
||||
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
|
||||
activeThreads = 1;
|
||||
threads[0].state = THREAD_SEARCHING;
|
||||
threads[0].state = Thread::SEARCHING;
|
||||
|
||||
// Allocate pawn and material hash tables for main thread
|
||||
init_hash_tables();
|
||||
|
@ -97,7 +147,7 @@ void ThreadsManager::init_threads() {
|
|||
// Create and startup all the threads but the main that is already running
|
||||
for (int i = 1; i < MAX_THREADS; i++)
|
||||
{
|
||||
threads[i].state = THREAD_INITIALIZING;
|
||||
threads[i].state = Thread::INITIALIZING;
|
||||
arg[i] = i;
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
|
@ -110,11 +160,11 @@ void ThreadsManager::init_threads() {
|
|||
if (!ok)
|
||||
{
|
||||
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
|
||||
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
|
||||
// helper threads exit cleanly.
|
||||
|
||||
void ThreadsManager::exit_threads() {
|
||||
void ThreadsManager::exit() {
|
||||
|
||||
// Force the woken up threads to exit idle_loop() and hence terminate
|
||||
allThreadsShouldExit = true;
|
||||
|
@ -133,7 +183,7 @@ void ThreadsManager::exit_threads() {
|
|||
if (i != 0)
|
||||
{
|
||||
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
|
||||
|
@ -164,66 +214,15 @@ void ThreadsManager::init_hash_tables() {
|
|||
}
|
||||
|
||||
|
||||
// cutoff_at_splitpoint() 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 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
|
||||
// available_slave_exists() tries to find an idle thread which is available as
|
||||
// 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(activeThreads > 1);
|
||||
|
||||
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 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
|
||||
// active split points, don't split.
|
||||
if ( !available_thread_exists(master)
|
||||
if ( !available_slave_exists(master)
|
||||
|| masterThread.activeSplitPoints >= MAX_ACTIVE_SPLIT_POINTS)
|
||||
{
|
||||
lock_release(&mpLock);
|
||||
|
@ -272,7 +271,7 @@ void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const V
|
|||
// Initialize the split point object
|
||||
splitPoint.parent = masterThread.splitPoint;
|
||||
splitPoint.master = master;
|
||||
splitPoint.betaCutoff = false;
|
||||
splitPoint.is_betaCutoff = false;
|
||||
splitPoint.depth = depth;
|
||||
splitPoint.threatMove = threatMove;
|
||||
splitPoint.alpha = *alpha;
|
||||
|
@ -285,22 +284,22 @@ void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const V
|
|||
splitPoint.nodes = 0;
|
||||
splitPoint.ss = ss;
|
||||
for (i = 0; i < activeThreads; i++)
|
||||
splitPoint.slaves[i] = 0;
|
||||
splitPoint.is_slave[i] = false;
|
||||
|
||||
masterThread.splitPoint = &splitPoint;
|
||||
|
||||
// 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
|
||||
|
||||
// Allocate available threads setting state to THREAD_BOOKED
|
||||
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;
|
||||
splitPoint.slaves[i] = 1;
|
||||
splitPoint.is_slave[i] = true;
|
||||
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
|
||||
// their idle loop.
|
||||
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)
|
||||
threads[i].wake_up();
|
||||
|
@ -343,5 +342,5 @@ void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const V
|
|||
}
|
||||
|
||||
// Explicit template instantiations
|
||||
template void ThreadsManager::split<0>(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<false>(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 bestValue;
|
||||
volatile int moveCount;
|
||||
volatile bool betaCutoff;
|
||||
volatile int slaves[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
|
||||
volatile bool is_betaCutoff;
|
||||
volatile bool is_slave[MAX_THREADS];
|
||||
};
|
||||
|
||||
|
||||
// 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.
|
||||
/// Thread struct is used to keep together all the thread related stuff like locks,
|
||||
/// state and especially split points. We also 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.
|
||||
|
||||
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;
|
||||
PawnInfoTable pawnTable;
|
||||
int maxPly;
|
||||
|
@ -83,18 +88,12 @@ struct Thread {
|
|||
SplitPoint* volatile splitPoint;
|
||||
volatile int activeSplitPoints;
|
||||
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,
|
||||
// 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.
|
||||
/// 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
|
||||
/// point. All the access to shared thread data is done through this class.
|
||||
|
||||
class ThreadsManager {
|
||||
/* As long as the single ThreadsManager object is defined as a global we don't
|
||||
|
@ -103,18 +102,16 @@ class ThreadsManager {
|
|||
*/
|
||||
public:
|
||||
Thread& operator[](int threadID) { return threads[threadID]; }
|
||||
void init_threads();
|
||||
void exit_threads();
|
||||
void init();
|
||||
void exit();
|
||||
void init_hash_tables();
|
||||
|
||||
int min_split_depth() const { return minimumSplitDepth; }
|
||||
int active_threads() const { return activeThreads; }
|
||||
void set_active_threads(int cnt) { activeThreads = cnt; }
|
||||
int size() const { return activeThreads; }
|
||||
void set_size(int cnt) { activeThreads = cnt; }
|
||||
|
||||
void read_uci_options();
|
||||
bool available_thread_exists(int master) const;
|
||||
bool thread_is_available(int slave, int master) const;
|
||||
bool cutoff_at_splitpoint(int threadID) const;
|
||||
bool available_slave_exists(int master) const;
|
||||
void idle_loop(int threadID, SplitPoint* sp);
|
||||
|
||||
template <bool Fake>
|
||||
|
@ -130,6 +127,6 @@ private:
|
|||
Thread threads[MAX_THREADS];
|
||||
};
|
||||
|
||||
extern ThreadsManager ThreadsMgr;
|
||||
extern ThreadsManager Threads;
|
||||
|
||||
#endif // !defined(THREAD_H_INCLUDED)
|
||||
|
|
Loading…
Add table
Reference in a new issue