]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Do not wait for threads falling asleep
[stockfish] / src / search.cpp
index 38e2ac14084a26442fdafa19581f5843ec1dc897..2e3f9d5663718ad4cac483c1d46b630cc5888d36 100644 (file)
@@ -84,7 +84,7 @@ namespace {
     void wake_sleeping_threads();
     void put_threads_to_sleep();
     void idle_loop(int threadID, SplitPoint* waitSp);
-    bool split(const Position& pos, SearchStack* ss, int ply, Value* alpha, Value* beta, Value* bestValue,
+    bool split(const Position& pos, SearchStack* ss, int ply, Value* alpha, const Value beta, Value* bestValue,
                const Value futilityValue, Depth depth, int* moves, MovePicker* mp, int master, bool pvNode);
 
   private:
@@ -442,9 +442,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
   // Wake up sleeping threads
   TM.wake_sleeping_threads();
 
-  for (int i = 1; i < TM.active_threads(); i++)
-      assert(TM.thread_is_available(i, 0));
-
   // Set thinking time
   int myTime = time[side_to_move];
   int myIncrement = increment[side_to_move];
@@ -1210,7 +1207,7 @@ namespace {
           && TM.available_thread_exists(threadID)
           && !AbortSearch
           && !TM.thread_should_stop(threadID)
-          && TM.split(pos, ss, ply, &alpha, &beta, &bestValue, VALUE_NONE,
+          && TM.split(pos, ss, ply, &alpha, beta, &bestValue, VALUE_NONE,
                       depth, &moveCount, &mp, threadID, true))
           break;
     }
@@ -1524,7 +1521,7 @@ namespace {
           && TM.available_thread_exists(threadID)
           && !AbortSearch
           && !TM.thread_should_stop(threadID)
-          && TM.split(pos, ss, ply, &beta, &beta, &bestValue, futilityValue, //FIXME: SMP & futilityValue
+          && TM.split(pos, ss, ply, NULL, beta, &bestValue, futilityValue, //FIXME: SMP & futilityValue
                       depth, &moveCount, &mp, threadID, false))
           break;
     }
@@ -1851,25 +1848,10 @@ namespace {
 
       assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
 
-      if (TM.thread_should_stop(threadID))
-      {
-          lock_grab(&(sp->lock));
-          break;
-      }
-
       // New best move?
       if (value > sp->bestValue) // Less then 2% of cases
       {
-          // Recursive locking, lock current split point and its ancestors to
-          // guarantee thread_should_stop() and sp_update_pv() are race free.
-          SplitPoint* spChain[MAX_THREADS * ACTIVE_SPLIT_POINTS_MAX];
-          int cnt = 0;
-          for (spChain[cnt] = sp; spChain[cnt]; )
-          {
-              lock_grab(&(spChain[cnt++]->lock));
-              spChain[cnt] = spChain[cnt - 1]->parent;
-          }
-
+          lock_grab(&(sp->lock));
           if (value > sp->bestValue && !TM.thread_should_stop(threadID))
           {
               sp->bestValue = value;
@@ -1879,10 +1861,7 @@ namespace {
                   sp_update_pv(sp->parentSstack, ss, sp->ply);
               }
           }
-
-          // Release locks in reverse order
-          while (cnt > 0)
-              lock_release(&(spChain[--cnt]->lock));
+          lock_release(&(sp->lock));
       }
     }
 
@@ -1978,25 +1957,10 @@ namespace {
 
       assert(value > -VALUE_INFINITE && value < VALUE_INFINITE);
 
-      if (TM.thread_should_stop(threadID))
-      {
-          lock_grab(&(sp->lock));
-          break;
-      }
-
       // New best move?
       if (value > sp->bestValue) // Less then 2% of cases
       {
-          // Recursive locking, lock current split point and its ancestors to
-          // guarantee thread_should_stop() and sp_update_pv() are race free.
-          SplitPoint* spChain[MAX_THREADS * ACTIVE_SPLIT_POINTS_MAX];
-          int cnt = 0;
-          for (spChain[cnt] = sp; spChain[cnt]; )
-          {
-              lock_grab(&(spChain[cnt++]->lock));
-              spChain[cnt] = spChain[cnt - 1]->parent;
-          }
-
+          lock_grab(&(sp->lock));
           if (value > sp->bestValue && !TM.thread_should_stop(threadID))
           {
               sp->bestValue = value;
@@ -2013,10 +1977,7 @@ namespace {
                       ss[sp->ply].mateKiller = move;
               }
           }
-
-          // Release locks in reverse order
-          while (cnt > 0)
-              lock_release(&(spChain[--cnt]->lock));
+          lock_release(&(sp->lock));
       }
     }
 
@@ -2622,34 +2583,39 @@ namespace {
     {
         // Slave threads can exit as soon as AllThreadsShouldExit raises,
         // master should exit as last one.
-        if (AllThreadsShouldExit && !waitSp)
+        if (AllThreadsShouldExit)
         {
+            assert(!waitSp);
             threads[threadID].state = THREAD_TERMINATED;
             return;
         }
 
         // If we are not thinking, wait for a condition to be signaled
         // instead of wasting CPU time polling for work.
-        while (    threadID != 0
-               && !AllThreadsShouldExit
-               && (AllThreadsShouldSleep || threadID >= ActiveThreads))
+        while (AllThreadsShouldSleep || threadID >= ActiveThreads)
         {
+            assert(threadID != 0);
             threads[threadID].state = THREAD_SLEEPING;
 
 #if !defined(_MSC_VER)
             pthread_mutex_lock(&WaitLock);
-            pthread_cond_wait(&WaitCond, &WaitLock);
+            if (AllThreadsShouldSleep || threadID >= ActiveThreads)
+                pthread_cond_wait(&WaitCond, &WaitLock);
             pthread_mutex_unlock(&WaitLock);
 #else
             WaitForSingleObject(SitIdleEvent[threadID], INFINITE);
 #endif
-            // State is already changed by wake_sleeping_threads()
-            assert(threads[threadID].state == THREAD_AVAILABLE || threadID >= ActiveThreads);
         }
 
+        // If thread has just woken up, mark it as available
+        if (threads[threadID].state == THREAD_SLEEPING)
+            threads[threadID].state = THREAD_AVAILABLE;
+
         // If this thread has been assigned work, launch a search
         if (threads[threadID].state == THREAD_WORKISWAITING)
         {
+            assert(!AllThreadsShouldExit && !AllThreadsShouldSleep);
+
             threads[threadID].state = THREAD_SEARCHING;
 
             if (threads[threadID].splitPoint->pvNode)
@@ -2659,21 +2625,14 @@ namespace {
 
             assert(threads[threadID].state == THREAD_SEARCHING);
 
-            // If this is a slave thread reset to available, instead
-            // if it is a master thread and all slaves have finished
-            // then leave as is to avoid booking by another master,
-            // we will leave idle loop shortly anyhow.
-            if (   !AllThreadsShouldExit
-                && (!waitSp || waitSp->cpus > 0))
-                threads[threadID].state = THREAD_AVAILABLE;
+            threads[threadID].state = THREAD_AVAILABLE;
         }
 
         // If this thread is the master of a split point and all threads have
         // finished their work at this split point, return from the idle loop.
         if (waitSp != NULL && waitSp->cpus == 0)
         {
-            assert(   threads[threadID].state == THREAD_AVAILABLE
-                   || threads[threadID].state == THREAD_SEARCHING);
+            assert(threads[threadID].state == THREAD_AVAILABLE);
 
             threads[threadID].state = THREAD_SEARCHING;
             return;
@@ -2700,7 +2659,7 @@ namespace {
     lock_init(&IOLock, NULL);
 
     // Initialize SplitPointStack locks
-    for (int i = 0; i < MAX_THREADS; i++)
+    for (i = 0; i < MAX_THREADS; i++)
         for (int j = 0; j < ACTIVE_SPLIT_POINTS_MAX; j++)
         {
             SplitPointStack[i][j].parent = NULL;
@@ -2855,15 +2814,17 @@ namespace {
   // splitPoint->cpus becomes 0), split() returns true.
 
   bool ThreadsManager::split(const Position& p, SearchStack* sstck, int ply,
-             Value* alpha, Value* beta, Value* bestValue, const Value futilityValue,
+             Value* alpha, const Value beta, Value* bestValue, const Value futilityValue,
              Depth depth, int* moves, MovePicker* mp, int master, bool pvNode) {
 
     assert(p.is_ok());
     assert(sstck != NULL);
     assert(ply >= 0 && ply < PLY_MAX);
-    assert(*bestValue >= -VALUE_INFINITE && *bestValue <= *alpha);
-    assert(!pvNode || *alpha < *beta);
-    assert(*beta <= VALUE_INFINITE);
+    assert(*bestValue >= -VALUE_INFINITE);
+    assert(   ( pvNode && *bestValue <= *alpha)
+           || (!pvNode && *bestValue <   beta ));
+    assert(!pvNode || *alpha < beta);
+    assert(beta <= VALUE_INFINITE);
     assert(depth > Depth(0));
     assert(master >= 0 && master < ActiveThreads);
     assert(ActiveThreads > 1);
@@ -2882,16 +2843,15 @@ namespace {
     }
 
     // Pick the next available split point object from the split point stack
-    splitPoint = SplitPointStack[master] + threads[master].activeSplitPoints;
-    threads[master].activeSplitPoints++;
+    splitPoint = &SplitPointStack[master][threads[master].activeSplitPoints];
 
     // Initialize the split point object
     splitPoint->parent = threads[master].splitPoint;
     splitPoint->stopRequest = false;
     splitPoint->ply = ply;
     splitPoint->depth = depth;
-    splitPoint->alpha = pvNode ? *alpha : (*beta - 1);
-    splitPoint->beta = *beta;
+    splitPoint->alpha = pvNode ? *alpha : beta - 1;
+    splitPoint->beta = beta;
     splitPoint->pvNode = pvNode;
     splitPoint->bestValue = *bestValue;
     splitPoint->futilityValue = futilityValue;
@@ -2905,6 +2865,7 @@ namespace {
         splitPoint->slaves[i] = 0;
 
     threads[master].splitPoint = splitPoint;
+    threads[master].activeSplitPoints++;
 
     // If we are here it means we are not available
     assert(threads[master].state != THREAD_AVAILABLE);
@@ -2951,7 +2912,6 @@ namespace {
     if (pvNode)
         *alpha = splitPoint->alpha;
 
-    *beta = splitPoint->beta;
     *bestValue = splitPoint->bestValue;
     threads[master].activeSplitPoints--;
     threads[master].splitPoint = splitPoint->parent;
@@ -2975,12 +2935,8 @@ namespace {
         return;
 
     for (int i = 1; i < ActiveThreads; i++)
-    {
         assert(threads[i].state == THREAD_SLEEPING);
 
-        threads[i].state = THREAD_AVAILABLE;
-    }
-
 #if !defined(_MSC_VER)
     pthread_mutex_lock(&WaitLock);
     pthread_cond_broadcast(&WaitCond);
@@ -3004,12 +2960,9 @@ namespace {
     // This makes the threads to go to sleep
     AllThreadsShouldSleep = true;
 
-    // Wait for the threads to be all sleeping and reset flags
-    // to a known state.
+    // Reset flags to a known state.
     for (int i = 1; i < ActiveThreads; i++)
     {
-        while (threads[i].state != THREAD_SLEEPING);
-
         // This flag can be in a random state
         threads[i].printCurrentLineRequest = false;
     }