From e70eae2c91840c06f69e900c231b6a8a9660b438 Mon Sep 17 00:00:00 2001 From: Marco Costalba Date: Sun, 13 Jan 2013 18:38:44 +0100 Subject: [PATCH] Don't use do_sleep flag 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 | 24 +++++++----------------- src/thread.cpp | 20 +++++++++----------- src/thread.h | 6 +++--- src/ucioption.cpp | 2 +- 4 files changed, 20 insertions(+), 32 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index b18ae353..0dbba7e0 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -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) { diff --git a/src/thread.cpp b/src/thread.cpp index 1f5dc823..7f5ce714 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -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 } diff --git a/src/thread.h b/src/thread.h index 12c64e80..2fc958c1 100644 --- a/src/thread.h +++ b/src/thread.h @@ -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; diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 6a194b3f..e59a43a9 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -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); -- 2.39.2