Don't use do_sleep flag
authorMarco Costalba <mcostalba@gmail.com>
Sun, 13 Jan 2013 17:38:44 +0000 (18:38 +0100)
committerMarco Costalba <mcostalba@gmail.com>
Sun, 13 Jan 2013 23:02:32 +0000 (00:02 +0100)
Rename it is_finished and use it only in main
thread to signal search is finished. This allows
us to simplify the complex SMP logic.

Ultra tricky patch: deep test is required under
wide conditions like pondering on and option
"Use Sleeping Threads" set to false.

No functional change.

src/search.cpp
src/thread.cpp
src/thread.h
src/ucioption.cpp

index b18ae3539d68239259f82332ea12621b7ec90fba..0dbba7e0de5fbf836203bf2856f38effa614c788 100644 (file)
@@ -227,15 +227,11 @@ void Search::think() {
           << std::endl;
   }
 
-  // Reset and wake up the threads
+  // Reset the threads, still sleeping: will be wake up at split time
   for (size_t i = 0; i < Threads.size(); i++)
-  {
       Threads[i].maxPly = 0;
-      Threads[i].do_sleep = false;
 
-      if (!Threads.use_sleeping_threads())
-          Threads[i].notify_one();
-  }
+  Threads.sleepWhileIdle = Options["Use Sleeping Threads"];
 
   // Set best timer interval to avoid lagging under time pressure. Timer is
   // used to check for remaining available thinking time.
@@ -249,11 +245,7 @@ void Search::think() {
   id_loop(RootPos); // Let's start searching !
 
   Threads.timer_thread()->maxPly = 0; // Stop the timer
-
-  // Main thread will go to sleep by itself to avoid a race with start_searching()
-  for (size_t i = 0; i < Threads.size(); i++)
-      if (&Threads[i] != Threads.main_thread())
-          Threads[i].do_sleep = true;
+  Threads.sleepWhileIdle = true; // Send idle threads to sleep
 
   if (Options["Use Search Log"])
   {
@@ -1632,9 +1624,7 @@ void Thread::idle_loop() {
   {
       // If we are not searching, wait for a condition to be signaled
       // instead of wasting CPU time polling for work.
-      while (   do_sleep
-             || do_exit
-             || (!is_searching && Threads.use_sleeping_threads()))
+      while (do_exit || (!is_searching && Threads.sleepWhileIdle))
       {
           if (do_exit)
           {
@@ -1656,7 +1646,7 @@ void Thread::idle_loop() {
           // particular we need to avoid a deadlock in case a master thread has,
           // in the meanwhile, allocated us and sent the wake_up() call before we
           // had the chance to grab the lock.
-          if (do_sleep || !is_searching)
+          if (!is_searching && Threads.sleepWhileIdle)
               sleepCondition.wait(mutex);
 
           mutex.unlock();
@@ -1665,7 +1655,7 @@ void Thread::idle_loop() {
       // If this thread has been assigned work, launch a search
       if (is_searching)
       {
-          assert(!do_sleep && !do_exit);
+          assert(/*!is_finished &&*/ !do_exit);
 
           Threads.mutex.lock();
 
@@ -1704,7 +1694,7 @@ void Thread::idle_loop() {
 
           // 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 (    Threads.use_sleeping_threads()
+          if (    Threads.sleepWhileIdle
               &&  this != sp->master
               && !sp->slavesMask)
           {
index 1f5dc82350e50bdfbcbf0bc578a239d3314b7ea4..7f5ce7148f3fe25c5d243f7ff43d9b8cafc0a5b0 100644 (file)
@@ -50,7 +50,7 @@ Thread::Thread(Fn fn) : splitPoints() {
   start_fn = fn;
   idx = Threads.size();
 
-  do_sleep = (fn != &Thread::main_loop); // Avoid a race with start_searching()
+  is_finished = (fn != &Thread::main_loop); // Avoid a race with start_searching()
 
   if (!thread_create(handle, start_routine, this))
   {
@@ -64,7 +64,7 @@ Thread::Thread(Fn fn) : splitPoints() {
 
 Thread::~Thread() {
 
-  assert(do_sleep);
+  assert(is_finished);
 
   do_exit = true; // Search must be already finished
   notify_one();
@@ -98,10 +98,10 @@ void Thread::main_loop() {
   {
       mutex.lock();
 
-      do_sleep = true; // Always return to sleep after a search
+      is_finished = true; // Always return to sleep after a search
       is_searching = false;
 
-      while (do_sleep && !do_exit)
+      while (is_finished && !do_exit)
       {
           Threads.sleepCondition.notify_one(); // Wake up UI thread if needed
           sleepCondition.wait(mutex);
@@ -186,6 +186,7 @@ void ThreadPool::init() {
 
   timer = new Thread(&Thread::timer_loop);
   threads.push_back(new Thread(&Thread::main_loop));
+  sleepWhileIdle = true;
   read_uci_options();
 }
 
@@ -210,7 +211,6 @@ void ThreadPool::read_uci_options() {
 
   maxThreadsPerSplitPoint = Options["Max Threads per Split Point"];
   minimumSplitDepth       = Options["Min Split Depth"] * ONE_PLY;
-  useSleepingThreads      = Options["Use Sleeping Threads"];
   size_t requested        = Options["Threads"];
 
   assert(requested > 0);
@@ -302,9 +302,7 @@ Value ThreadPool::split(Position& pos, Stack* ss, Value alpha, Value beta,
           sp.slavesMask |= 1ULL << i;
           threads[i]->curSplitPoint = &sp;
           threads[i]->is_searching = true; // Slave leaves idle_loop()
-
-          if (useSleepingThreads)
-              threads[i]->notify_one();
+          threads[i]->notify_one(); // Could be sleeping
 
           if (++slavesCnt + 1 >= maxThreadsPerSplitPoint) // Master is always included
               break;
@@ -358,7 +356,7 @@ void ThreadPool::wait_for_search_finished() {
 
   Thread* t = main_thread();
   t->mutex.lock();
-  while (!t->do_sleep) sleepCondition.wait(t->mutex);
+  while (!t->is_finished) sleepCondition.wait(t->mutex);
   t->mutex.unlock();
 }
 
@@ -384,6 +382,6 @@ void ThreadPool::start_searching(const Position& pos, const LimitsType& limits,
       if (searchMoves.empty() || count(searchMoves.begin(), searchMoves.end(), ml.move()))
           RootMoves.push_back(RootMove(ml.move()));
 
-  main_thread()->do_sleep = false;
-  main_thread()->notify_one();
+  main_thread()->is_finished = false;
+  main_thread()->notify_one(); // Starts main thread
 }
index 12c64e80c7af58f8f33ef9b388b1ef7248494d70..2fc958c1ceb681c4b3652816ff0f8e1494e34130 100644 (file)
@@ -120,7 +120,7 @@ public:
   SplitPoint* volatile curSplitPoint;
   volatile int splitPointsCnt;
   volatile bool is_searching;
-  volatile bool do_sleep;
+  volatile bool is_finished;
   volatile bool do_exit;
 };
 
@@ -136,7 +136,6 @@ public:
   void exit(); // be initialized and valid during the whole thread lifetime.
 
   Thread& operator[](size_t id) { return *threads[id]; }
-  bool use_sleeping_threads() const { return useSleepingThreads; }
   int min_split_depth() const { return minimumSplitDepth; }
   size_t size() const { return threads.size(); }
   Thread* main_thread() { return threads[0]; }
@@ -161,7 +160,8 @@ private:
   ConditionVariable sleepCondition;
   Depth minimumSplitDepth;
   int maxThreadsPerSplitPoint;
-  bool useSleepingThreads;
+public:
+  bool sleepWhileIdle;
 };
 
 extern ThreadPool Threads;
index 6a194b3f60cb98d65597110ff76c7c3b656d1ff1..e59a43a9148f620c7ccbc7000bd0d806fc53eda0 100644 (file)
@@ -73,7 +73,7 @@ void init(OptionsMap& o) {
   o["Min Split Depth"]             = Option(msd, 4, 7, on_threads);
   o["Max Threads per Split Point"] = Option(5, 4, 8, on_threads);
   o["Threads"]                     = Option(cpus, 1, MAX_THREADS, on_threads);
-  o["Use Sleeping Threads"]        = Option(true, on_threads);
+  o["Use Sleeping Threads"]        = Option(true);
   o["Hash"]                        = Option(32, 4, 8192, on_hash_size);
   o["Clear Hash"]                  = Option(on_clear_hash);
   o["Ponder"]                      = Option(true);