]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Allow split point master to sleep (take 2)
[stockfish] / src / search.cpp
index 59c717caa9700e5412b9de78101d791dcd42c6d5..5a4b56ba45ae2383bed345969d93432db8442f98 100644 (file)
@@ -259,6 +259,7 @@ namespace {
   // Multi-threads related variables
   Depth MinimumSplitDepth;
   int MaxThreadsPerSplitPoint;
+  bool UseSleepingMaster;
   ThreadsManager ThreadsMgr;
 
   // Node counters, used only by thread[0] but try to keep in different cache
@@ -451,6 +452,7 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
   MaxThreadsPerSplitPoint = Options["Maximum Number of Threads per Split Point"].value<int>();
   MultiPV                 = Options["MultiPV"].value<int>();
   UseLogFile              = Options["Use Search Log"].value<bool>();
+  UseSleepingMaster       = Options["Use Sleeping Master"].value<bool>();
 
   if (UseLogFile)
       LogFile.open(Options["Search Log Filename"].value<std::string>().c_str(), std::ios::out | std::ios::app);
@@ -2178,6 +2180,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,
@@ -2193,23 +2198,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 && (!sp || UseSleepingMaster)))
         {
-            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 && (!sp || UseSleepingMaster))))
             {
                 lock_release(&MPLock);
-                continue;
+                break;
             }
 
             // Put thread to sleep
@@ -2239,14 +2244,19 @@ split_point_start: // At split points actual search starts from here
             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 (UseSleepingMaster && 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.
@@ -2454,6 +2464,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;