Detach search arguments from UI thread
authorMarco Costalba <mcostalba@gmail.com>
Sun, 27 Nov 2011 16:07:17 +0000 (17:07 +0100)
committerMarco Costalba <mcostalba@gmail.com>
Sun, 27 Nov 2011 16:46:18 +0000 (17:46 +0100)
Detach from the UI thread the input arguments used by
the search threads so that the UI thread is able to receive
and process any command sent by the GUI while other threads
keep searching.

With this patch there is no more need to block the UI
thread after a "stop", so it is a more reliable and
robust solution than the previous patch.

No functional change.

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

index 45304671993c1d49c07cae6899bac14fa920a965..ee1128043f32f9b94f20f1722f2df55bc074ae5b 100644 (file)
@@ -59,7 +59,9 @@ static const string Defaults[] = {
 
 void benchmark(int argc, char* argv[]) {
 
+  std::vector<Move> searchMoves(1, MOVE_NONE);
   vector<string> fenList;
+  Search::LimitsType limits;
   int64_t totalNodes;
   int time;
 
@@ -76,11 +78,11 @@ void benchmark(int argc, char* argv[]) {
 
   // Search should be limited by nodes, time or depth ?
   if (valType == "nodes")
-      Search::Limits.maxNodes = atoi(valStr.c_str());
+      limits.maxNodes = atoi(valStr.c_str());
   else if (valType == "time")
-      Search::Limits.maxTime = 1000 * atoi(valStr.c_str()); // maxTime is in ms
+      limits.maxTime = 1000 * atoi(valStr.c_str()); // maxTime is in ms
   else
-      Search::Limits.maxDepth = atoi(valStr.c_str());
+      limits.maxDepth = atoi(valStr.c_str());
 
   // Do we need to load positions from a given FEN file?
   if (fenFile != "default")
@@ -105,30 +107,28 @@ void benchmark(int argc, char* argv[]) {
           fenList.push_back(Defaults[i]);
 
   // Ok, let's start the benchmark !
-  Search::RootMoves.push_back(MOVE_NONE);
   totalNodes = 0;
   time = get_system_time();
 
   for (size_t i = 0; i < fenList.size(); i++)
   {
       Position pos(fenList[i], false, 0);
-      Search::RootPosition = &pos;
 
       cerr << "\nBench position: " << i + 1 << '/' << fenList.size() << endl;
 
       if (valType == "perft")
       {
-          int64_t cnt = Search::perft(pos, Search::Limits.maxDepth * ONE_PLY);
+          int64_t cnt = Search::perft(pos, limits.maxDepth * ONE_PLY);
 
-          cerr << "\nPerft " << Search::Limits.maxDepth
+          cerr << "\nPerft " << limits.maxDepth
                << " nodes counted: " << cnt << endl;
 
           totalNodes += cnt;
       }
       else
       {
-          Threads.start_thinking(false);
-          totalNodes += pos.nodes_searched();
+          Threads.start_thinking(pos, limits, searchMoves, false);
+          totalNodes += Search::RootPosition.nodes_searched();
       }
   }
 
index 0f6a3febeb98d92a8e50232fcb16df4e1bd98716..2f18427d827f8111d0357416d92525bb4ad7bb72 100644 (file)
@@ -97,7 +97,7 @@ CheckInfo::CheckInfo(const Position& pos) {
 /// or the FEN string, we want the new born Position object do not depend
 /// on any external data so we detach state pointer from the source one.
 
-Position::Position(const Position& pos, int th) {
+void Position::copy(const Position& pos, int th) {
 
   memcpy(this, &pos, sizeof(Position));
   threadID = th;
index 7842ed8b337254ea5d2db61f537644056146e212..e4b6bd0f06123453a006abd6c1be70d67bbbe10c 100644 (file)
@@ -84,16 +84,17 @@ struct StateInfo {
 
 class Position {
 
-  // No defaul, copy c'tor or assignment allowed, default c'tor will not be
-  // generated anyhow because of user-defined c'tors.
+  // No copy c'tor or assignment operator allowed
   Position(const Position&);
   Position& operator=(const Position&);
 
 public:
-  Position(const Position& pos, int threadID);
-  Position(const std::string& fen, bool isChess960, int threadID);
+  Position() {}
+  Position(const Position& pos, int th) { copy(pos, th); }
+  Position(const std::string& fen, bool isChess960, int th);
 
   // Text input/output
+  void copy(const Position& pos, int th);
   void from_fen(const std::string& fen, bool isChess960);
   const std::string to_fen() const;
   void print(Move m = MOVE_NONE) const;
index 6615a1efacbc2bc1454ad0732568ab3c2716a8c1..037c44ddfe37a483a373c34c8b9eed1f3246c4e5 100644 (file)
@@ -50,7 +50,7 @@ namespace Search {
   volatile SignalsType Signals;
   LimitsType Limits;
   std::vector<Move> RootMoves;
-  Position* RootPosition;
+  Position RootPosition;
 }
 
 namespace {
@@ -362,7 +362,7 @@ void Search::think() {
 
   static Book book; // Defined static to initialize the PRNG only once
 
-  Position& pos = *RootPosition;
+  Position& pos = RootPosition;
 
   // Save "search start" time and reset elapsed time to zero
   elapsed_search_time(get_system_time());
index 4f98cc762fb041a0dac265a81cc9b1336b401150..abf7221d8a33bbbe9f22a66db31e4995932d0c3c 100644 (file)
@@ -54,6 +54,7 @@ namespace Search {
 
 struct LimitsType {
 
+  LimitsType() {  memset(this, 0, sizeof(LimitsType)); }
   bool useTimeManagement() const { return !(maxTime | maxDepth | maxNodes | infinite); }
 
   int time, increment, movesToGo, maxTime, maxDepth, maxNodes, infinite, ponder;
@@ -66,7 +67,7 @@ struct SignalsType {
 extern volatile SignalsType Signals;
 extern LimitsType Limits;
 extern std::vector<Move> RootMoves;
-extern Position* RootPosition;
+extern Position RootPosition;
 
 extern void init();
 extern int64_t perft(Position& pos, Depth depth);
index 536f22c1194cf6912eb578f550cf1d298d21d959..06646a7b99b131d9751ccdc7b951dd9f6a631bb5 100644 (file)
@@ -423,36 +423,25 @@ void Thread::main_loop() {
 }
 
 
-// ThreadsManager::wait_end_of_search() blocks UI thread until main thread has
-// returned to sleep in main_loop(). It is needed becuase xboard sends immediately
-// new position to search after a "stop" due to ponder miss.
-
-void ThreadsManager::wait_end_of_search() {
-
-  Thread& main = threads[0];
-
-  lock_grab(&main.sleepLock);
-
-  while (!main.do_sleep)
-      cond_wait(&sleepCond, &main.sleepLock);
-
-  lock_release(&main.sleepLock);
-}
-
-
 // ThreadsManager::start_thinking() is used by UI thread to wake up the main
 // thread parked in main_loop() and starting a new search. If asyncMode is true
 // then function returns immediately, otherwise caller is blocked waiting for
 // the search to finish.
 
-void ThreadsManager::start_thinking(bool asyncMode) {
-
+void ThreadsManager::start_thinking(const Position& pos, const Search::LimitsType& limits,
+                                    const std::vector<Move>& searchMoves, bool asyncMode) {
   Thread& main = threads[0];
 
+  lock_grab(&main.sleepLock);
+
   // Wait main thread has finished before to launch a new search
-  wait_end_of_search();
+  while (!main.do_sleep)
+      cond_wait(&sleepCond, &main.sleepLock);
 
-  lock_grab(&main.sleepLock);
+  // Copy input arguments to Search global variables
+  Search::RootPosition.copy(pos, 0);
+  Search::Limits = limits;
+  Search::RootMoves = searchMoves;
 
   // Reset signals before to start the search
   memset((void*)&Search::Signals, 0, sizeof(Search::Signals));
index 95ec1292ea0aa86c1abd93d6e3f11f7ba09e2c56..0a38caae57c0bed68c0b5fac4b29704633e24ec5 100644 (file)
@@ -116,11 +116,10 @@ public:
   void read_uci_options();
   bool available_slave_exists(int master) const;
   bool split_point_finished(SplitPoint* sp) const;
-
-  void start_thinking(bool asyncMode = true);
   void set_timer(int msec);
   void wait_for_stop_or_ponderhit();
-  void wait_end_of_search();
+  void start_thinking(const Position& pos, const Search::LimitsType& limits,
+                      const std::vector<Move>& searchMoves, bool asyncMode);
 
   template <bool Fake>
   Value split(Position& pos, SearchStack* ss, Value alpha, Value beta, Value bestValue,
index 57a31ad64f11f4bb0ef788a374ba67a3bd76e150..306819bb3e46f680544f4a0b0fea69a9f6921782 100644 (file)
@@ -72,7 +72,6 @@ void uci_loop() {
           quit = (token == "quit");
           Search::Signals.stop = true;
           Threads[0].wake_up(); // In case is waiting for stop or ponderhit
-          Threads.wait_end_of_search(); // Block here until search finishes
       }
 
       else if (cmd == "ponderhit")
@@ -206,18 +205,16 @@ namespace {
   void go(Position& pos, istringstream& is) {
 
     string token;
+    Search::LimitsType limits;
+    std::vector<Move> searchMoves;
     int time[] = { 0, 0 }, inc[] = { 0, 0 };
 
-    memset(&Search::Limits, 0, sizeof(Search::Limits));
-    Search::RootMoves.clear();
-    Search::RootPosition = &pos;
-
     while (is >> token)
     {
         if (token == "infinite")
-            Search::Limits.infinite = true;
+            limits.infinite = true;
         else if (token == "ponder")
-            Search::Limits.ponder = true;
+            limits.ponder = true;
         else if (token == "wtime")
             is >> time[WHITE];
         else if (token == "btime")
@@ -227,23 +224,22 @@ namespace {
         else if (token == "binc")
             is >> inc[BLACK];
         else if (token == "movestogo")
-            is >> Search::Limits.movesToGo;
+            is >> limits.movesToGo;
         else if (token == "depth")
-            is >> Search::Limits.maxDepth;
+            is >> limits.maxDepth;
         else if (token == "nodes")
-            is >> Search::Limits.maxNodes;
+            is >> limits.maxNodes;
         else if (token == "movetime")
-            is >> Search::Limits.maxTime;
+            is >> limits.maxTime;
         else if (token == "searchmoves")
             while (is >> token)
-                Search::RootMoves.push_back(move_from_uci(pos, token));
+                searchMoves.push_back(move_from_uci(pos, token));
     }
+    searchMoves.push_back(MOVE_NONE);
+    limits.time = time[pos.side_to_move()];
+    limits.increment = inc[pos.side_to_move()];
 
-    Search::RootMoves.push_back(MOVE_NONE);
-    Search::Limits.time = time[pos.side_to_move()];
-    Search::Limits.increment = inc[pos.side_to_move()];
-
-    Threads.start_thinking();
+    Threads.start_thinking(pos, limits, searchMoves, true);
   }