]> git.sesse.net Git - stockfish/commitdiff
Re-apply the fix for Limits::ponder race
authorMarco Costalba <mcostalba@gmail.com>
Thu, 10 Aug 2017 19:32:50 +0000 (12:32 -0700)
committerMarco Costalba <mcostalba@gmail.com>
Thu, 10 Aug 2017 19:47:31 +0000 (12:47 -0700)
But this time correctly set Threads.ponder

We avoid using 'limits' for passing pondering
flag because we don't want to have 2 ponder
variables in search scope: Search::Limits.ponder
and Threads.ponder. This would be confusing also
because limits.ponder is set at the beginning of
the search and never changes, instead Threads.ponder
can change value asynchronously during search.

No functional change.

src/search.cpp
src/search.h
src/thread.cpp
src/thread.h
src/uci.cpp

index 11dcdb34f13840a1b8ff43a7b08df4273fe972f9..3c638ca057f5e1c3c515498e005cecf88a111c8e 100644 (file)
@@ -277,7 +277,7 @@ void MainThread::search() {
   // the UCI protocol states that we shouldn't print the best move before the
   // GUI sends a "stop" or "ponderhit" command. We therefore simply wait here
   // until the GUI sends one of those commands (which also raises Threads.stop).
   // the UCI protocol states that we shouldn't print the best move before the
   // GUI sends a "stop" or "ponderhit" command. We therefore simply wait here
   // until the GUI sends one of those commands (which also raises Threads.stop).
-  if (!Threads.stop && (Limits.ponder || Limits.infinite))
+  if (!Threads.stop && (Threads.ponder || Limits.infinite))
   {
       Threads.stopOnPonderhit = true;
       wait(Threads.stop);
   {
       Threads.stopOnPonderhit = true;
       wait(Threads.stop);
@@ -499,7 +499,7 @@ void Thread::search() {
               {
                   // If we are allowed to ponder do not stop the search now but
                   // keep pondering until the GUI sends "ponderhit" or "stop".
               {
                   // If we are allowed to ponder do not stop the search now but
                   // keep pondering until the GUI sends "ponderhit" or "stop".
-                  if (Limits.ponder)
+                  if (Threads.ponder)
                       Threads.stopOnPonderhit = true;
                   else
                       Threads.stop = true;
                       Threads.stopOnPonderhit = true;
                   else
                       Threads.stop = true;
@@ -1489,7 +1489,7 @@ moves_loop: // When in check search starts from here
     }
 
     // An engine may not stop pondering until told so by the GUI
     }
 
     // An engine may not stop pondering until told so by the GUI
-    if (Limits.ponder)
+    if (Threads.ponder)
         return;
 
     if (   (Limits.use_time_management() && elapsed > Time.maximum() - 10)
         return;
 
     if (   (Limits.use_time_management() && elapsed > Time.maximum() - 10)
index 477570e3919e3d40c7d0092e44a61630a4357e61..bbdbdfd950e9409483ccdbf0056162f741d7c54c 100644 (file)
@@ -72,14 +72,13 @@ typedef std::vector<RootMove> RootMoves;
 
 
 /// LimitsType struct stores information sent by GUI about available time to
 
 
 /// LimitsType struct stores information sent by GUI about available time to
-/// search the current move, maximum depth/time, if we are in analysis mode or
-/// if we have to ponder while it's our opponent's turn to move.
+/// search the current move, maximum depth/time, or if we are in analysis mode.
 
 struct LimitsType {
 
   LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC
     nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] =
 
 struct LimitsType {
 
   LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC
     nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] =
-    npmsec = movestogo = depth = movetime = mate = infinite = ponder = 0;
+    npmsec = movestogo = depth = movetime = mate = infinite = 0;
   }
 
   bool use_time_management() const {
   }
 
   bool use_time_management() const {
@@ -87,7 +86,7 @@ struct LimitsType {
   }
 
   std::vector<Move> searchmoves;
   }
 
   std::vector<Move> searchmoves;
-  int time[COLOR_NB], inc[COLOR_NB], npmsec, movestogo, depth, movetime, mate, infinite, ponder;
+  int time[COLOR_NB], inc[COLOR_NB], npmsec, movestogo, depth, movetime, mate, infinite;
   int64_t nodes;
   TimePoint startTime;
 };
   int64_t nodes;
   TimePoint startTime;
 };
index 86fce6aa0c20020b6c54666c874a5231793d6c9e..6d3364d5c56525c1bdad9fc8af803ce8ed2234e2 100644 (file)
@@ -183,11 +183,12 @@ uint64_t ThreadPool::tb_hits() const {
 /// and starts a new search, then returns immediately.
 
 void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
 /// and starts a new search, then returns immediately.
 
 void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
-                                const Search::LimitsType& limits) {
+                                const Search::LimitsType& limits, bool ponderMode) {
 
   main()->wait_for_search_finished();
 
   stopOnPonderhit = stop = false;
 
   main()->wait_for_search_finished();
 
   stopOnPonderhit = stop = false;
+  ponder = ponderMode;
   Search::Limits = limits;
   Search::RootMoves rootMoves;
 
   Search::Limits = limits;
   Search::RootMoves rootMoves;
 
index c1b635b7ea4db61dfca33ed0ee3423e3eeefb862..ee43bfb5ba19f7afb7b43f50f45c6377d7574f55 100644 (file)
@@ -96,12 +96,12 @@ struct ThreadPool : public std::vector<Thread*> {
   void exit(); // be initialized and valid during the whole thread lifetime.
 
   MainThread* main() { return static_cast<MainThread*>(at(0)); }
   void exit(); // be initialized and valid during the whole thread lifetime.
 
   MainThread* main() { return static_cast<MainThread*>(at(0)); }
-  void start_thinking(Position&, StateListPtr&, const Search::LimitsType&);
+  void start_thinking(Position&, StateListPtr&, const Search::LimitsType&, bool = false);
   void read_uci_options();
   uint64_t nodes_searched() const;
   uint64_t tb_hits() const;
 
   void read_uci_options();
   uint64_t nodes_searched() const;
   uint64_t tb_hits() const;
 
-  std::atomic_bool stop, stopOnPonderhit;
+  std::atomic_bool stop, ponder, stopOnPonderhit;
 
 private:
   StateListPtr setupStates;
 
 private:
   StateListPtr setupStates;
index 8f6416bdcb7b866b984e53b5ac6be64c4a7e47b8..58b38779ee2bec226c5cd29002ef345ba3a221c0 100644 (file)
@@ -115,6 +115,7 @@ namespace {
 
     Search::LimitsType limits;
     string token;
 
     Search::LimitsType limits;
     string token;
+    bool ponderMode = false;
 
     limits.startTime = now(); // As early as possible!
 
 
     limits.startTime = now(); // As early as possible!
 
@@ -133,9 +134,9 @@ namespace {
         else if (token == "movetime")  is >> limits.movetime;
         else if (token == "mate")      is >> limits.mate;
         else if (token == "infinite")  limits.infinite = 1;
         else if (token == "movetime")  is >> limits.movetime;
         else if (token == "mate")      is >> limits.mate;
         else if (token == "infinite")  limits.infinite = 1;
-        else if (token == "ponder")    limits.ponder = 1;
+        else if (token == "ponder")    ponderMode = true;
 
 
-    Threads.start_thinking(pos, States, limits);
+    Threads.start_thinking(pos, States, limits, ponderMode);
   }
 
 } // namespace
   }
 
 } // namespace
@@ -167,11 +168,11 @@ void UCI::loop(int argc, char* argv[]) {
       token.clear(); // getline() could return empty or blank line
       is >> skipws >> token;
 
       token.clear(); // getline() could return empty or blank line
       is >> skipws >> token;
 
-      // The GUI sends 'ponderhit' to tell us to ponder on the same move the
-      // opponent has played. In case Threads.stopOnPonderhit is set we are
-      // waiting for 'ponderhit' to stop the search (for instance because we
-      // already ran out of time), otherwise we should continue searching but
-      // switching from pondering to normal search.
+      // The GUI sends 'ponderhit' to tell us the user has played the expected move.
+      // So 'ponderhit' will be sent if we were told to ponder on the same move the
+      // user has played. We should continue searching but switch from pondering to
+      // normal search. In case Threads.stopOnPonderhit is set we are waiting for
+      // 'ponderhit' to stop the search, for instance if max search depth is reached.
       if (    token == "quit"
           ||  token == "stop"
           || (token == "ponderhit" && Threads.stopOnPonderhit))
       if (    token == "quit"
           ||  token == "stop"
           || (token == "ponderhit" && Threads.stopOnPonderhit))
@@ -180,7 +181,7 @@ void UCI::loop(int argc, char* argv[]) {
           Threads.main()->start_searching(true); // Could be sleeping
       }
       else if (token == "ponderhit")
           Threads.main()->start_searching(true); // Could be sleeping
       }
       else if (token == "ponderhit")
-          Search::Limits.ponder = 0; // Switch to normal search
+          Threads.ponder = false; // Switch to normal search
 
       else if (token == "uci")
           sync_cout << "id name " << engine_info(true)
 
       else if (token == "uci")
           sync_cout << "id name " << engine_info(true)