From: Marco Costalba Date: Wed, 4 Apr 2012 06:54:02 +0000 (+0100) Subject: Use a Thread instead of an array index X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=673bc5526fa3d352f823ad144fb521b5dc98f45c Use a Thread instead of an array index No functional change. Signed-off-by: Marco Costalba --- diff --git a/src/benchmark.cpp b/src/benchmark.cpp index b9cd4058..f42c0e6c 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -107,7 +107,7 @@ void benchmark(istringstream& is) { for (size_t i = 0; i < fens.size(); i++) { - Position pos(fens[i], false, 0); + Position pos(fens[i], false, NULL); cerr << "\nPosition: " << i + 1 << '/' << fens.size() << endl; diff --git a/src/endgame.cpp b/src/endgame.cpp index 0e70efe1..5e021f11 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -77,7 +77,7 @@ namespace { string fen = sides[0] + char('0' + int(8 - code.length())) + sides[1] + "/8/8/8/8/8/8/8 w - - 0 10"; - return Position(fen, false, 0).material_key(); + return Position(fen, false, NULL).material_key(); } template diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 4d47b7e6..db5e3fc2 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -371,7 +371,7 @@ Value do_evaluate(const Position& pos, Value& margin) { margins[WHITE] = margins[BLACK] = VALUE_ZERO; // Probe the material hash table - ei.mi = Threads[pos.this_thread()].materialTable.probe(pos); + ei.mi = pos.this_thread().materialTable.probe(pos); score += ei.mi->material_value(); // If we have a specialized evaluation function for the current material @@ -383,7 +383,7 @@ Value do_evaluate(const Position& pos, Value& margin) { } // Probe the pawn hash table - ei.pi = Threads[pos.this_thread()].pawnTable.probe(pos); + ei.pi = pos.this_thread().pawnTable.probe(pos); score += ei.pi->pawns_value(); // Initialize attack and king safety bitboards diff --git a/src/position.cpp b/src/position.cpp index 57d6dc09..72a261d4 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -92,33 +92,27 @@ CheckInfo::CheckInfo(const Position& pos) { } -/// Position c'tors. Here we always create a copy of the original position -/// or the FEN string, we want the new born Position object do not depend -/// on any external data so we detach state pointer from the source one. +/// Position::copy() creates a copy of 'pos'. We want the new born Position +/// object do not depend on any external data so we detach state pointer from +/// the source one. -void Position::copy(const Position& pos, int th) { +void Position::copy(const Position& pos, Thread* th) { memcpy(this, &pos, sizeof(Position)); startState = *st; st = &startState; - threadID = th; + thisThread = th; nodes = 0; assert(pos_is_ok()); } -Position::Position(const string& fen, bool isChess960, int th) { - - from_fen(fen, isChess960); - threadID = th; -} - /// Position::from_fen() initializes the position object with the given FEN /// string. This function is not very robust - make sure that input FENs are /// correct (this is assumed to be the responsibility of the GUI). -void Position::from_fen(const string& fenStr, bool isChess960) { +void Position::from_fen(const string& fenStr, bool isChess960, Thread* th) { /* A FEN string defines a particular position using only the ASCII character set. @@ -234,6 +228,7 @@ void Position::from_fen(const string& fenStr, bool isChess960) { st->npMaterial[BLACK] = compute_non_pawn_material(BLACK); st->checkersBB = attackers_to(king_square(sideToMove)) & pieces(~sideToMove); chess960 = isChess960; + thisThread = th; assert(pos_is_ok()); } @@ -336,7 +331,7 @@ void Position::print(Move move) const { if (move) { - Position p(*this, this_thread()); + Position p(*this, thisThread); cout << "\nMove is: " << (sideToMove == BLACK ? ".." : "") << move_to_san(p, move); } @@ -903,8 +898,8 @@ void Position::do_move(Move m, StateInfo& newSt, const CheckInfo& ci, bool moveI } // Prefetch pawn and material hash tables - prefetch((char*)Threads[threadID].pawnTable.entries[st->pawnKey]); - prefetch((char*)Threads[threadID].materialTable.entries[st->materialKey]); + prefetch((char*)thisThread->pawnTable.entries[st->pawnKey]); + prefetch((char*)thisThread->materialTable.entries[st->materialKey]); // Update incremental scores st->psqScore += psq_delta(piece, from, to); @@ -1546,10 +1541,10 @@ void Position::init() { void Position::flip() { // Make a copy of current position before to start changing - const Position pos(*this, threadID); + const Position pos(*this, thisThread); clear(); - threadID = pos.this_thread(); + thisThread = &pos.this_thread(); // Board for (Square s = SQ_A1; s <= SQ_H8; s++) diff --git a/src/position.h b/src/position.h index b51002eb..4713094d 100644 --- a/src/position.h +++ b/src/position.h @@ -29,6 +29,7 @@ /// The checkInfo struct is initialized at c'tor time and keeps info used /// to detect if a move gives check. class Position; +class Thread; struct CheckInfo { @@ -90,12 +91,12 @@ class Position { public: Position() {} - Position(const Position& pos, int th) { copy(pos, th); } - Position(const std::string& fen, bool isChess960, int th); + Position(const Position& p, Thread* t) { copy(p, t); } + Position(const std::string& f, bool c960, Thread* t) { from_fen(f, c960, t); } // Text input/output - void copy(const Position& pos, int th); - void from_fen(const std::string& fen, bool isChess960); + void copy(const Position& pos, Thread* th); + void from_fen(const std::string& fen, bool isChess960, Thread* th); const std::string to_fen() const; void print(Move m = MOVE_NONE) const; @@ -175,7 +176,7 @@ public: Color side_to_move() const; int startpos_ply_counter() const; bool is_chess960() const; - int this_thread() const; + Thread& this_thread() const; int64_t nodes_searched() const; void set_nodes_searched(int64_t n); template bool is_draw() const; @@ -223,7 +224,7 @@ private: int64_t nodes; int startPosPly; Color sideToMove; - int threadID; + Thread* thisThread; StateInfo* st; int chess960; @@ -433,8 +434,8 @@ inline PieceType Position::captured_piece_type() const { return st->capturedType; } -inline int Position::this_thread() const { - return threadID; +inline Thread& Position::this_thread() const { + return *thisThread; } #endif // !defined(POSITION_H_INCLUDED) diff --git a/src/search.cpp b/src/search.cpp index da70c122..94fa063f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -332,7 +332,7 @@ finalize: // but if we are pondering or in infinite search, we shouldn't print the best // move before we are told to do so. if (!Signals.stop && (Limits.ponder || Limits.infinite)) - Threads[pos.this_thread()].wait_for_stop_or_ponderhit(); + pos.this_thread().wait_for_stop_or_ponderhit(); // Best move could be MOVE_NONE when searching on a stalemate position cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], Chess960) @@ -530,7 +530,6 @@ namespace { assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); assert((alpha == beta - 1) || PvNode); assert(depth > DEPTH_ZERO); - assert(pos.this_thread() >= 0 && pos.this_thread() < Threads.size()); Move movesSearched[MAX_MOVES]; StateInfo st; @@ -544,7 +543,7 @@ namespace { bool isPvMove, inCheck, singularExtensionNode, givesCheck; bool captureOrPromotion, dangerous, doFullDepthSearch; int moveCount = 0, playedMoveCount = 0; - Thread& thread = Threads[pos.this_thread()]; + Thread& thread = pos.this_thread(); SplitPoint* sp = NULL; refinedValue = bestValue = value = -VALUE_INFINITE; @@ -847,7 +846,7 @@ split_point_start: // At split points actual search starts from here { Signals.firstRootMove = (moveCount == 1); - if (pos.this_thread() == 0 && SearchTime.elapsed() > 2000) + if (&thread == Threads.main_thread() && SearchTime.elapsed() > 2000) cout << "info depth " << depth / ONE_PLY << " currmove " << move_to_uci(move, Chess960) << " currmovenumber " << moveCount + PVIdx << endl; @@ -1054,7 +1053,7 @@ split_point_start: // At split points actual search starts from here if ( !SpNode && depth >= Threads.min_split_depth() && bestValue < beta - && Threads.available_slave_exists(pos.this_thread()) + && Threads.available_slave_exists(thread) && !Signals.stop && !thread.cutoff_occurred()) bestValue = Threads.split(pos, ss, alpha, beta, bestValue, &bestMove, @@ -1131,7 +1130,6 @@ split_point_start: // At split points actual search starts from here assert(alpha >= -VALUE_INFINITE && alpha < beta && beta <= VALUE_INFINITE); assert((alpha == beta - 1) || PvNode); assert(depth <= DEPTH_ZERO); - assert(pos.this_thread() >= 0 && pos.this_thread() < Threads.size()); StateInfo st; Move ttMove, move, bestMove; @@ -1827,8 +1825,8 @@ void Thread::idle_loop(SplitPoint* sp_master) { lock_release(Threads.splitLock); Stack ss[MAX_PLY_PLUS_2]; - Position pos(*sp->pos, threadID); - int master = sp->master; + Position pos(*sp->pos, this); + Thread* master = sp->master; memcpy(ss, sp->ss - 1, 4 * sizeof(Stack)); (ss+1)->sp = sp; @@ -1847,7 +1845,7 @@ void Thread::idle_loop(SplitPoint* sp_master) { assert(is_searching); is_searching = false; - sp->slavesMask &= ~(1ULL << threadID); + sp->slavesMask &= ~(1ULL << idx); sp->nodes += pos.nodes_searched(); // After releasing the lock we cannot access anymore any SplitPoint @@ -1858,9 +1856,9 @@ void Thread::idle_loop(SplitPoint* sp_master) { // 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 ( Threads.use_sleeping_threads() - && threadID != master - && !Threads[master].is_searching) - Threads[master].wake_up(); + && this != master + && !master->is_searching) + master->wake_up(); } } } diff --git a/src/thread.cpp b/src/thread.cpp index 4ae268eb..54b42d46 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -48,7 +48,7 @@ Thread::Thread(Fn fn) { maxPly = splitPointsCnt = 0; curSplitPoint = NULL; start_fn = fn; - threadID = Threads.size(); + idx = Threads.size(); do_sleep = (fn != &Thread::main_loop); // Avoid a race with start_searching() @@ -60,7 +60,7 @@ Thread::Thread(Fn fn) { if (!thread_create(handle, start_routine, this)) { - std::cerr << "Failed to create thread number " << threadID << std::endl; + std::cerr << "Failed to create thread number " << idx << std::endl; ::exit(EXIT_FAILURE); } } @@ -173,13 +173,13 @@ bool Thread::cutoff_occurred() const { // Thread::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 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). +// thread 'master' at a split point. An obvious requirement is that thread must +// be idle. With more than two threads, this is not sufficient: If the thread is +// the master of some active split point, it is only available as a slave to the +// slaves which are busy searching the split point at the top of slaves split +// point stack (the "helpful master concept" in YBWC terminology). -bool Thread::is_available_to(int master) const { +bool Thread::is_available_to(const Thread& master) const { if (is_searching) return false; @@ -190,7 +190,7 @@ bool Thread::is_available_to(int master) const { // 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. - return !spCnt || (splitPoints[spCnt - 1].slavesMask & (1ULL << master)); + return !spCnt || (splitPoints[spCnt - 1].slavesMask & (1ULL << master.idx)); } @@ -275,11 +275,9 @@ void ThreadsManager::sleep() const { // available_slave_exists() tries to find an idle thread which is available as -// a slave for the thread with threadID 'master'. +// a slave for the thread 'master'. -bool ThreadsManager::available_slave_exists(int master) const { - - assert(master >= 0 && master < size()); +bool ThreadsManager::available_slave_exists(const Thread& master) const { for (int i = 0; i < size(); i++) if (threads[i]->is_available_to(master)) @@ -309,19 +307,18 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, assert(beta <= VALUE_INFINITE); assert(depth > DEPTH_ZERO); - int master = pos.this_thread(); - Thread& masterThread = *threads[master]; + Thread& master = pos.this_thread(); - if (masterThread.splitPointsCnt >= MAX_SPLITPOINTS_PER_THREAD) + if (master.splitPointsCnt >= MAX_SPLITPOINTS_PER_THREAD) return bestValue; // Pick the next available split point from the split point stack - SplitPoint* sp = &masterThread.splitPoints[masterThread.splitPointsCnt++]; + SplitPoint* sp = &master.splitPoints[master.splitPointsCnt++]; - sp->parent = masterThread.curSplitPoint; - sp->master = master; + sp->parent = master.curSplitPoint; + sp->master = &master; sp->cutoff = false; - sp->slavesMask = 1ULL << master; + sp->slavesMask = 1ULL << master.idx; sp->depth = depth; sp->bestMove = *bestMove; sp->threatMove = threatMove; @@ -335,9 +332,9 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, sp->nodes = 0; sp->ss = ss; - assert(masterThread.is_searching); + assert(master.is_searching); - masterThread.curSplitPoint = sp; + master.curSplitPoint = sp; int slavesCnt = 0; // Try to allocate available threads and ask them to start searching setting @@ -370,11 +367,11 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, // their work at this split point. if (slavesCnt || Fake) { - masterThread.idle_loop(sp); + master.idle_loop(sp); // In helpful master concept a master can help only a sub-tree of its split // point, and because here is all finished is not possible master is booked. - assert(!masterThread.is_searching); + assert(!master.is_searching); } // We have returned from the idle loop, which means that all threads are @@ -383,9 +380,9 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, lock_grab(sp->lock); // To protect sp->nodes lock_grab(splitLock); - masterThread.is_searching = true; - masterThread.splitPointsCnt--; - masterThread.curSplitPoint = sp->parent; + master.is_searching = true; + master.splitPointsCnt--; + master.curSplitPoint = sp->parent; pos.set_nodes_searched(pos.nodes_searched() + sp->nodes); *bestMove = sp->bestMove; @@ -417,11 +414,11 @@ void ThreadsManager::set_timer(int msec) { void ThreadsManager::wait_for_search_finished() { - Thread* main = threads[0]; - lock_grab(main->sleepLock); - cond_signal(main->sleepCond); // In case is waiting for stop or ponderhit - while (!main->do_sleep) cond_wait(sleepCond, main->sleepLock); - lock_release(main->sleepLock); + Thread* t = main_thread(); + lock_grab(t->sleepLock); + cond_signal(t->sleepCond); // In case is waiting for stop or ponderhit + while (!t->do_sleep) cond_wait(sleepCond, t->sleepLock); + lock_release(t->sleepLock); } @@ -437,7 +434,7 @@ void ThreadsManager::start_searching(const Position& pos, const LimitsType& limi Signals.stopOnPonderhit = Signals.firstRootMove = false; Signals.stop = Signals.failedLowAtRoot = false; - RootPosition.copy(pos, 0); + RootPosition.copy(pos, main_thread()); Limits = limits; RootMoves.clear(); @@ -445,6 +442,6 @@ void ThreadsManager::start_searching(const Position& pos, const LimitsType& limi if (searchMoves.empty() || count(searchMoves.begin(), searchMoves.end(), ml.move())) RootMoves.push_back(RootMove(ml.move())); - threads[0]->do_sleep = false; - threads[0]->wake_up(); + main_thread()->do_sleep = false; + main_thread()->wake_up(); } diff --git a/src/thread.h b/src/thread.h index fe2cf425..12fc4f23 100644 --- a/src/thread.h +++ b/src/thread.h @@ -31,6 +31,8 @@ const int MAX_THREADS = 32; const int MAX_SPLITPOINTS_PER_THREAD = 8; +class Thread; + struct SplitPoint { // Const data after split point has been setup @@ -39,7 +41,7 @@ struct SplitPoint { Depth depth; Value beta; int nodeType; - int master; + Thread* master; Move threatMove; // Const pointers to shared data @@ -76,7 +78,7 @@ public: void wake_up(); bool cutoff_occurred() const; - bool is_available_to(int master) const; + bool is_available_to(const Thread& master) const; void idle_loop(SplitPoint* sp_master); void idle_loop() { idle_loop(NULL); } // Hack to allow storing in start_fn void main_loop(); @@ -86,7 +88,7 @@ public: SplitPoint splitPoints[MAX_SPLITPOINTS_PER_THREAD]; MaterialTable materialTable; PawnTable pawnTable; - int threadID; + int idx; int maxPly; Lock sleepLock; WaitCondition sleepCond; @@ -117,11 +119,12 @@ public: bool use_sleeping_threads() const { return useSleepingThreads; } int min_split_depth() const { return minimumSplitDepth; } int size() const { return (int)threads.size(); } + Thread* main_thread() { return threads[0]; } void wake_up() const; void sleep() const; void read_uci_options(); - bool available_slave_exists(int master) const; + bool available_slave_exists(const Thread& master) const; void set_timer(int msec); void wait_for_search_finished(); void start_searching(const Position& pos, const Search::LimitsType& limits, diff --git a/src/uci.cpp b/src/uci.cpp index 4c3faf05..c6da2fc4 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -56,7 +56,7 @@ namespace { void uci_loop(const string& args) { - Position pos(StartFEN, false, 0); // The root position + Position pos(StartFEN, false, Threads.main_thread()); // The root position string cmd, token; while (token != "quit") @@ -167,7 +167,7 @@ namespace { else return; - pos.from_fen(fen, Options["UCI_Chess960"]); + pos.from_fen(fen, Options["UCI_Chess960"], Threads.main_thread()); // Parse move list (if any) while (is >> token && (m = move_from_uci(pos, token)) != MOVE_NONE)