]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Allow split point master to sleep
[stockfish] / src / search.cpp
index 24070b43df8d2e2a75b3bc72ee3055e10a0c9117..d022b3de738cd8f982d6edbd172dcc0e219c8392 100644 (file)
@@ -464,10 +464,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int time[], int incr
       init_eval(ThreadsMgr.active_threads());
   }
 
-  // Wake up needed threads
-  for (int i = 1; i < newActiveThreads; i++)
-      ThreadsMgr.wake_sleeping_thread(i);
-
   // Set thinking time
   int myTime = time[pos.side_to_move()];
   int myIncrement = increment[pos.side_to_move()];
@@ -500,9 +496,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int time[], int incr
   if (UseLogFile)
       LogFile.close();
 
-  // This makes all the threads to go to sleep
-  ThreadsMgr.set_active_threads(1);
-
   return !Quit;
 }
 
@@ -1181,7 +1174,7 @@ split_point_start: // At split points actual search starts from here
 
     // Initialize a MovePicker object for the current position
     // FIXME currently MovePicker() c'tor is needless called also in SplitPoint
-    MovePicker mpBase = MovePicker(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta));
+    MovePicker mpBase(pos, ttMove, depth, H, ss, (PvNode ? -VALUE_INFINITE : beta));
     MovePicker& mp = SpNode ? *sp->mp : mpBase;
     CheckInfo ci(pos);
     ss->bestMove = MOVE_NONE;
@@ -1250,7 +1243,10 @@ split_point_start: // At split points actual search starts from here
       newDepth = depth - ONE_PLY + ext;
 
       // Update current move (this must be done after singular extension search)
-      movesSearched[moveCount++] = ss->currentMove = move;
+      movesSearched[moveCount] = ss->currentMove = move;
+
+      if (!SpNode)
+          moveCount++;
 
       // Step 12. Futility pruning (is omitted in PV nodes)
       if (   !PvNode
@@ -1371,24 +1367,29 @@ split_point_start: // At split points actual search starts from here
       if (value > bestValue && !(SpNode && ThreadsMgr.thread_should_stop(threadID)))
       {
           bestValue = value;
+
+          if (SpNode)
+              sp->bestValue = value;
+
           if (value > alpha)
           {
               if (SpNode && (!PvNode || value >= beta))
                   sp->stopRequest = true;
 
               if (PvNode && value < beta) // We want always alpha < beta
+              {
                   alpha = value;
+                  if (SpNode)
+                      sp->alpha = value;
+              }
 
               if (value == value_mate_in(ply + 1))
                   ss->mateKiller = move;
 
               ss->bestMove = move;
-          }
-          if (SpNode)
-          {
-              sp->bestValue = bestValue;
-              sp->alpha = alpha;
-              sp->parentSstack->bestMove = ss->bestMove;
+
+              if (SpNode)
+                  sp->parentSstack->bestMove = move;
           }
       }
 
@@ -2211,6 +2212,9 @@ split_point_start: // At split points actual search starts from here
 
     assert(threadID >= 0 && threadID < MAX_THREADS);
 
+    int i;
+    bool allFinished = false;
+
     while (true)
     {
         // Slave threads can exit as soon as AllThreadsShouldExit raises,
@@ -2226,23 +2230,23 @@ split_point_start: // At split points actual search starts from here
         // instead of wasting CPU time polling for work.
         while (   threadID >= ActiveThreads
                || threads[threadID].state == THREAD_INITIALIZING
-               || (!sp && threads[threadID].state == THREAD_AVAILABLE))
+               || threads[threadID].state == THREAD_AVAILABLE)
         {
-            assert(!sp);
-            assert(threadID != 0);
-
-            if (AllThreadsShouldExit)
-                break;
-
             lock_grab(&MPLock);
 
-            // Retest condition under lock protection
-            if (!(   threadID >= ActiveThreads
-                  || threads[threadID].state == THREAD_INITIALIZING
-                  || (!sp && threads[threadID].state == THREAD_AVAILABLE)))
+            // Test with lock held to avoid races with wake_sleeping_thread()
+            for (i = 0; sp && i < ActiveThreads && !sp->slaves[i]; i++) {}
+            allFinished = (i == ActiveThreads);
+
+            // Retest sleep conditions under lock protection
+            if (   AllThreadsShouldExit
+                || allFinished
+                || !(   threadID >= ActiveThreads
+                     || threads[threadID].state == THREAD_INITIALIZING
+                     || threads[threadID].state == THREAD_AVAILABLE))
             {
                 lock_release(&MPLock);
-                continue;
+                break;
             }
 
             // Put thread to sleep
@@ -2266,20 +2270,25 @@ split_point_start: // At split points actual search starts from here
 
             if (tsp->pvNode)
                 search<PV, true>(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
-            else
+            else {
                 search<NonPV, true>(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
-
+            }
             assert(threads[threadID].state == THREAD_SEARCHING);
 
             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 (threadID != tsp->master && threads[tsp->master].state == THREAD_AVAILABLE)
+                wake_sleeping_thread(tsp->master);
         }
 
         // 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.
-        int i = 0;
-        for ( ; sp && i < ActiveThreads && !sp->slaves[i]; i++) {}
+        for (i = 0; sp && i < ActiveThreads && !sp->slaves[i]; i++) {}
+        allFinished = (i == ActiveThreads);
 
-        if (i == ActiveThreads)
+        if (allFinished)
         {
             // Because sp->slaves[] is reset under lock protection,
             // be sure sp->lock has been released before to return.
@@ -2450,9 +2459,8 @@ split_point_start: // At split points actual search starts from here
   // split point objects), the function immediately returns. If splitting is
   // possible, a SplitPoint object is initialized with all the data that must be
   // copied to the helper threads and we tell our helper threads that they have
-  // been assigned work. This will cause them to instantly leave their idle loops
-  // and call sp_search(). When all threads have returned from sp_search() then
-  // split() returns.
+  // been assigned work. This will cause them to instantly leave their idle loops and
+  // call search().When all threads have returned from search() then split() returns.
 
   template <bool Fake>
   void ThreadsManager::split(const Position& p, SearchStack* ss, int ply, Value* alpha,
@@ -2487,6 +2495,7 @@ split_point_start: // At split points actual search starts from here
 
     // Initialize the split point object
     splitPoint.parent = masterThread.splitPoint;
+    splitPoint.master = master;
     splitPoint.stopRequest = false;
     splitPoint.ply = ply;
     splitPoint.depth = depth;