Use a Thread instead of an array index
authorMarco Costalba <mcostalba@gmail.com>
Wed, 4 Apr 2012 06:54:02 +0000 (07:54 +0100)
committerMarco Costalba <mcostalba@gmail.com>
Wed, 4 Apr 2012 11:12:08 +0000 (12:12 +0100)
No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
src/benchmark.cpp
src/endgame.cpp
src/evaluate.cpp
src/position.cpp
src/position.h
src/search.cpp
src/thread.cpp
src/thread.h
src/uci.cpp

index b9cd4058aca8296eca14d9fe18aa7b2242a0e1a4..f42c0e6c312460742dd944d1765398bd2f001788 100644 (file)
@@ -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;
 
index 0e70efe1d386fd387018d787be94acce38bc7d25..5e021f1132917aa36d397a1f090f71938c72cb99 100644 (file)
@@ -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<typename M>
index 4d47b7e6df64a681bdc1b979626a04d942643d32..db5e3fc25e79a39a282e1f05098e352b40944c6a 100644 (file)
@@ -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
index 57d6dc09bce917c7d9014f1d31340b6ed6134dd8..72a261d4d09046cfe9617ac5e0a2084c50df984d 100644 (file)
@@ -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++)
index b51002eb5eb929253188db27072bc36101638539..4713094d537ea0f89b3ac44bc7cd3fe7e0f2ac21 100644 (file)
@@ -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 SkipRepetition> 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)
index da70c1221988d17e20452586415643e1382a9422..94fa063fa5274e6a1c3194597b1ceb10203d4978 100644 (file)
@@ -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<FakeSplit>(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();
       }
   }
 }
index 4ae268eb77b9ae885554bf4e60c78ef1e2ebf032..54b42d461ccad7db189d5f920084439bce20583f 100644 (file)
@@ -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();
 }
index fe2cf42592e4c88d50323b16f11daef000c1e135..12fc4f23a70e1c21d596f092b9b0a35932c0e9b8 100644 (file)
@@ -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,
index 4c3faf05c02c07999017594728c1249213dd4b2d..c6da2fc4851acee54e5b60f140cb054d3066e5f5 100644 (file)
@@ -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)