]> git.sesse.net Git - stockfish/commitdiff
Allow threads to sleep when available
authorMarco Costalba <mcostalba@gmail.com>
Sun, 7 Nov 2010 22:45:13 +0000 (23:45 +0100)
committerMarco Costalba <mcostalba@gmail.com>
Sat, 11 Dec 2010 08:22:38 +0000 (09:22 +0100)
By mean of an an UCI option it is possible let the available
threads to sleep, this should help with Hyper Threading although
is not the best solution when number of threads equals number
of available cores.

Option is disabled by default.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
src/search.cpp
src/thread.h
src/ucioption.cpp

index 12481d4083bae3fc6d48cfb733938ec91acd595b..9252dfa6fa1d35724f94f4c32b62f5a24b7fb7c3 100644 (file)
@@ -263,6 +263,7 @@ namespace {
   // Multi-threads related variables
   Depth MinimumSplitDepth;
   int MaxThreadsPerSplitPoint;
   // Multi-threads related variables
   Depth MinimumSplitDepth;
   int MaxThreadsPerSplitPoint;
+  bool UseSleepingThreads;
   ThreadsManager ThreadsMgr;
 
   // Node counters, used only by thread[0] but try to keep in different cache
   ThreadsManager ThreadsMgr;
 
   // Node counters, used only by thread[0] but try to keep in different cache
@@ -455,6 +456,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>();
   MaxThreadsPerSplitPoint = Options["Maximum Number of Threads per Split Point"].value<int>();
   MultiPV                 = Options["MultiPV"].value<int>();
   UseLogFile              = Options["Use Search Log"].value<bool>();
+  UseSleepingThreads      = Options["Use Sleeping Threads"].value<bool>();
 
   if (UseLogFile)
       LogFile.open(Options["Search Log Filename"].value<std::string>().c_str(), std::ios::out | std::ios::app);
 
   if (UseLogFile)
       LogFile.open(Options["Search Log Filename"].value<std::string>().c_str(), std::ios::out | std::ios::app);
@@ -466,7 +468,7 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
   if (newActiveThreads != ThreadsMgr.active_threads())
   {
       ThreadsMgr.set_active_threads(newActiveThreads);
   if (newActiveThreads != ThreadsMgr.active_threads())
   {
       ThreadsMgr.set_active_threads(newActiveThreads);
-      init_eval(ThreadsMgr.active_threads());
+      init_eval(newActiveThreads);
   }
 
   // Wake up needed threads
   }
 
   // Wake up needed threads
@@ -2199,6 +2201,9 @@ split_point_start: // At split points actual search starts from here
 
     assert(threadID >= 0 && threadID < MAX_THREADS);
 
 
     assert(threadID >= 0 && threadID < MAX_THREADS);
 
+    int i;
+    bool allFinished = false;
+
     while (true)
     {
         // Slave threads can exit as soon as AllThreadsShouldExit raises,
     while (true)
     {
         // Slave threads can exit as soon as AllThreadsShouldExit raises,
@@ -2212,19 +2217,30 @@ split_point_start: // At split points actual search starts from here
 
         // If we are not thinking, wait for a condition to be signaled
         // instead of wasting CPU time polling for work.
 
         // 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)
+        while (   threadID >= ActiveThreads || threads[threadID].state == THREAD_INITIALIZING
+               || (UseSleepingThreads && threads[threadID].state == THREAD_AVAILABLE))
         {
         {
-            assert(!sp);
-            assert(threadID != 0);
-
-            if (AllThreadsShouldExit)
-                break;
+            assert(!sp || UseSleepingThreads);
+            assert(threadID != 0 || UseSleepingThreads);
 
 
-            threads[threadID].state = THREAD_AVAILABLE;
+            if (threads[threadID].state == THREAD_INITIALIZING)
+                threads[threadID].state = THREAD_AVAILABLE;
 
 
+            // Grab the lock to avoid races with wake_sleeping_thread()
             lock_grab(&WaitLock);
 
             lock_grab(&WaitLock);
 
-            if (threadID >= ActiveThreads || threads[threadID].state == THREAD_INITIALIZING)
+            // If we are master and all slaves have finished do not go to sleep
+            for (i = 0; sp && i < ActiveThreads && !sp->slaves[i]; i++) {}
+            allFinished = (i == ActiveThreads);
+
+            if (allFinished || AllThreadsShouldExit)
+            {
+                lock_release(&WaitLock);
+                break;
+            }
+
+            // Do sleep here after retesting sleep conditions
+            if (threadID >= ActiveThreads || threads[threadID].state == THREAD_AVAILABLE)
                 cond_wait(&WaitCond[threadID], &WaitLock);
 
             lock_release(&WaitLock);
                 cond_wait(&WaitCond[threadID], &WaitLock);
 
             lock_release(&WaitLock);
@@ -2245,20 +2261,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);
 
             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);
                 search<NonPV, true>(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply);
-            }
+
             assert(threads[threadID].state == THREAD_SEARCHING);
 
             threads[threadID].state = THREAD_AVAILABLE;
             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 (UseSleepingThreads && 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.
         }
 
         // 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.
         {
             // Because sp->slaves[] is reset under lock protection,
             // be sure sp->lock has been released before to return.
@@ -2468,6 +2489,7 @@ split_point_start: // At split points actual search starts from here
 
     // Initialize the split point object
     splitPoint.parent = masterThread.splitPoint;
 
     // Initialize the split point object
     splitPoint.parent = masterThread.splitPoint;
+    splitPoint.master = master;
     splitPoint.stopRequest = false;
     splitPoint.ply = ply;
     splitPoint.depth = depth;
     splitPoint.stopRequest = false;
     splitPoint.ply = ply;
     splitPoint.depth = depth;
@@ -2517,6 +2539,9 @@ split_point_start: // At split points actual search starts from here
             assert(i == master || threads[i].state == THREAD_BOOKED);
 
             threads[i].state = THREAD_WORKISWAITING; // This makes the slave to exit from idle_loop()
             assert(i == master || threads[i].state == THREAD_BOOKED);
 
             threads[i].state = THREAD_WORKISWAITING; // This makes the slave to exit from idle_loop()
+
+            if (UseSleepingThreads && i != master)
+                wake_sleeping_thread(i);
         }
 
     // Everything is set up. The master thread enters the idle loop, from
         }
 
     // Everything is set up. The master thread enters the idle loop, from
index 348e5f676d7096855b14a523bae295da6e62524e..ddcea17dd0963c7f0fb70bd12f9c8c60f2a0f8ad 100644 (file)
@@ -55,6 +55,7 @@ struct SplitPoint {
   bool pvNode, mateThreat;
   Value beta;
   int ply;
   bool pvNode, mateThreat;
   Value beta;
   int ply;
+  int master;
   Move threatMove;
   SearchStack sstack[MAX_THREADS][PLY_MAX_PLUS_2];
 
   Move threatMove;
   SearchStack sstack[MAX_THREADS][PLY_MAX_PLUS_2];
 
index 81dd0ca0a074fd15565a55f07408018ab02b45af..346fd42b89a5aa8a5ea988618e8640ce92b43e82 100644 (file)
@@ -94,6 +94,7 @@ void init_uci_options() {
   Options["Minimum Split Depth"] = Option(4, 4, 7);
   Options["Maximum Number of Threads per Split Point"] = Option(5, 4, 8);
   Options["Threads"] = Option(1, 1, MAX_THREADS);
   Options["Minimum Split Depth"] = Option(4, 4, 7);
   Options["Maximum Number of Threads per Split Point"] = Option(5, 4, 8);
   Options["Threads"] = Option(1, 1, MAX_THREADS);
+  Options["Use Sleeping Threads"] = Option(false);
   Options["Hash"] = Option(32, 4, 8192);
   Options["Clear Hash"] = Option(false, "button");
   Options["Ponder"] = Option(true);
   Options["Hash"] = Option(32, 4, 8192);
   Options["Clear Hash"] = Option(false, "button");
   Options["Ponder"] = Option(true);