]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Correctly implementg selDepth feature
[stockfish] / src / search.cpp
index 516f2d051cc503f058d2f541a7d46ef9fcb8800e..21db685285972f12c571078dec42751d76201228 100644 (file)
@@ -64,6 +64,7 @@ namespace {
        static storage duration are automatically set to zero before enter main()
     */
   public:
+    Thread& operator[](int threadID) { return threads[threadID]; }
     void init_threads();
     void exit_threads();
 
@@ -83,14 +84,13 @@ namespace {
                Depth depth, Move threatMove, int moveCount, MovePicker* mp, bool pvNode);
 
   private:
+    Lock mpLock;
     Depth minimumSplitDepth;
     int maxThreadsPerSplitPoint;
     bool useSleepingThreads;
     int activeThreads;
     volatile bool allThreadsShouldExit;
     Thread threads[MAX_THREADS];
-    Lock mpLock, sleepLock[MAX_THREADS];
-    WaitCondition sleepCond[MAX_THREADS];
   };
 
 
@@ -118,7 +118,7 @@ namespace {
 
     void extract_pv_from_tt(Position& pos);
     void insert_pv_in_tt(Position& pos);
-    std::string pv_info_to_uci(Position& pos, int depth, Value alpha, Value beta, int pvIdx);
+    std::string pv_info_to_uci(Position& pos, int depth, int selDepth, Value alpha, Value beta, int pvIdx);
 
     int64_t nodes;
     Value pv_score;
@@ -506,9 +506,12 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[
   ThreadsMgr.read_uci_options();
   init_eval(ThreadsMgr.active_threads());
 
-  // Wake up needed threads. Main thread, with threadID == 0, is always active
-  for (int i = 1; i < ThreadsMgr.active_threads(); i++)
+  // Wake up needed threads and reset maxPly counter
+  for (int i = 0; i < ThreadsMgr.active_threads(); i++)
+  {
       ThreadsMgr.wake_sleeping_thread(i);
+      ThreadsMgr[i].maxPly = 0;
+  }
 
   // Set thinking time
   int myTime = time[pos.side_to_move()];
@@ -596,7 +599,7 @@ namespace {
     SearchStack ss[PLY_MAX_PLUS_2];
     Value bestValues[PLY_MAX_PLUS_2];
     int bestMoveChanges[PLY_MAX_PLUS_2];
-    int depth, aspirationDelta, skillSamplingDepth;
+    int depth, selDepth, aspirationDelta;
     Value value, alpha, beta;
     Move bestMove, easyMove, skillBest, skillPonder;
 
@@ -605,7 +608,7 @@ namespace {
     TT.new_search();
     H.clear();
     *ponderMove = bestMove = easyMove = skillBest = skillPonder = MOVE_NONE;
-    depth = aspirationDelta = skillSamplingDepth = 0;
+    depth = aspirationDelta = 0;
     alpha = -VALUE_INFINITE, beta = VALUE_INFINITE;
     ss->currentMove = MOVE_NULL; // Hack to skip update_gains()
 
@@ -622,11 +625,6 @@ namespace {
         return MOVE_NONE;
     }
 
-    // Choose a random sampling depth according to SkillLevel so that at low
-    // skills there is an higher risk to pick up a blunder.
-    if (SkillLevelEnabled)
-        skillSamplingDepth = 4 + SkillLevel + (RK.rand<unsigned>() % 4);
-
     // Iterative deepening loop
     while (++depth <= PLY_MAX && (!MaxDepth || depth <= MaxDepth) && !StopRequest)
     {
@@ -690,12 +688,18 @@ namespace {
         bestMoveChanges[depth] = Rml.bestMoveChanges;
 
         // Do we need to pick now the best and the ponder moves ?
-        if (SkillLevelEnabled && depth == skillSamplingDepth)
+        if (SkillLevelEnabled && depth == 1 + SkillLevel)
             do_skill_level(&skillBest, &skillPonder);
 
+        // Retrieve max searched depth among threads
+        selDepth = 0;
+        for (int i = 0; i < ThreadsMgr.active_threads(); i++)
+            if (ThreadsMgr[i].maxPly > selDepth)
+                selDepth = ThreadsMgr[i].maxPly;
+
         // Send PV line to GUI and to log file
         for (int i = 0; i < Min(UCIMultiPV, (int)Rml.size()); i++)
-            cout << Rml[i].pv_info_to_uci(pos, depth, alpha, beta, i) << endl;
+            cout << Rml[i].pv_info_to_uci(pos, depth, selDepth, alpha, beta, i) << endl;
 
         if (UseLogFile)
             LogFile << pretty_pv(pos, depth, value, current_search_time(), Rml[0].pv) << endl;
@@ -798,6 +802,10 @@ namespace {
     isCheck = pos.is_check();
     ss->ply = (ss-1)->ply + 1;
 
+    // Used to send selDepth info to GUI
+    if (PvNode && ThreadsMgr[threadID].maxPly < ss->ply)
+        ThreadsMgr[threadID].maxPly = ss->ply;
+
     if (SpNode)
     {
         sp = ss->sp;
@@ -2052,7 +2060,7 @@ split_point_start: // At split points actual search starts from here
                 threads[threadID].state = THREAD_AVAILABLE;
 
             // Grab the lock to avoid races with wake_sleeping_thread()
-            lock_grab(&sleepLock[threadID]);
+            lock_grab(&threads[threadID].sleepLock);
 
             // If we are master and all slaves have finished do not go to sleep
             for (i = 0; sp && i < activeThreads && !sp->slaves[i]; i++) {}
@@ -2060,15 +2068,15 @@ split_point_start: // At split points actual search starts from here
 
             if (allFinished || allThreadsShouldExit)
             {
-                lock_release(&sleepLock[threadID]);
+                lock_release(&threads[threadID].sleepLock);
                 break;
             }
 
             // Do sleep here after retesting sleep conditions
             if (threadID >= activeThreads || threads[threadID].state == THREAD_AVAILABLE)
-                cond_wait(&sleepCond[threadID], &sleepLock[threadID]);
+                cond_wait(&threads[threadID].sleepCond, &threads[threadID].sleepLock);
 
-            lock_release(&sleepLock[threadID]);
+            lock_release(&threads[threadID].sleepLock);
         }
 
         // If this thread has been assigned work, launch a search
@@ -2139,8 +2147,8 @@ split_point_start: // At split points actual search starts from here
 
     for (i = 0; i < MAX_THREADS; i++)
     {
-        lock_init(&sleepLock[i]);
-        cond_init(&sleepCond[i]);
+        lock_init(&threads[i].sleepLock);
+        cond_init(&threads[i].sleepCond);
     }
 
     // Initialize splitPoints[] locks
@@ -2207,8 +2215,8 @@ split_point_start: // At split points actual search starts from here
     // Now we can safely destroy the wait conditions
     for (int i = 0; i < MAX_THREADS; i++)
     {
-        lock_destroy(&sleepLock[i]);
-        cond_destroy(&sleepCond[i]);
+        lock_destroy(&threads[i].sleepLock);
+        cond_destroy(&threads[i].sleepCond);
     }
   }
 
@@ -2397,9 +2405,9 @@ split_point_start: // At split points actual search starts from here
 
   void ThreadsManager::wake_sleeping_thread(int threadID) {
 
-     lock_grab(&sleepLock[threadID]);
-     cond_signal(&sleepCond[threadID]);
-     lock_release(&sleepLock[threadID]);
+     lock_grab(&threads[threadID].sleepLock);
+     cond_signal(&threads[threadID].sleepCond);
+     lock_release(&threads[threadID].sleepLock);
   }
 
 
@@ -2489,21 +2497,20 @@ split_point_start: // At split points actual search starts from here
   // pv_info_to_uci() returns a string with information on the current PV line
   // formatted according to UCI specification.
 
-  std::string RootMove::pv_info_to_uci(Position& pos, int depth, Value alpha,
+  std::string RootMove::pv_info_to_uci(Position& pos, int depth, int selDepth, Value alpha,
                                        Value beta, int pvIdx) {
-    std::stringstream s, l;
-    Move* m = pv;
-
-    while (*m != MOVE_NONE)
-        l << *m++ << " ";
+    std::stringstream s;
 
     s << "info depth " << depth
-      << " seldepth " << int(m - pv)
+      << " seldepth " << selDepth
       << " multipv " << pvIdx + 1
       << " score " << value_to_uci(pv_score)
       << (pv_score >= beta ? " lowerbound" : pv_score <= alpha ? " upperbound" : "")
       << speed_to_uci(pos.nodes_searched())
-      << " pv "    << l.str();
+      << " pv ";
+
+    for (Move* m = pv; *m != MOVE_NONE; m++)
+        s << *m << " ";
 
     return s.str();
   }