-
-
-/// Thread::idle_loop() is where the thread is parked when it has no work to do
-
-void Thread::idle_loop() {
-
- // Pointer 'this_sp' is not null only if we are called from split(), and not
- // at the thread creation. This means we are the split point's master.
- SplitPoint* this_sp = splitPointsSize ? activeSplitPoint : nullptr;
-
- assert(!this_sp || (this_sp->masterThread == this && searching));
-
- while (!exit)
- {
- // If this thread has been assigned work, launch a search
- while (searching)
- {
- Threads.mutex.lock();
-
- assert(activeSplitPoint);
- SplitPoint* sp = activeSplitPoint;
-
- Threads.mutex.unlock();
-
- Stack stack[MAX_PLY+4], *ss = stack+2; // To allow referencing (ss-2) and (ss+2)
- Position pos(*sp->pos, this);
-
- std::memcpy(ss-2, sp->ss-2, 5 * sizeof(Stack));
- ss->splitPoint = sp;
-
- sp->mutex.lock();
-
- assert(activePosition == nullptr);
-
- activePosition = &pos;
-
- if (sp->nodeType == NonPV)
- search<NonPV, true>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
-
- else if (sp->nodeType == PV)
- search<PV, true>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
-
- else if (sp->nodeType == Root)
- search<Root, true>(pos, ss, sp->alpha, sp->beta, sp->depth, sp->cutNode);
-
- else
- assert(false);
-
- assert(searching);
-
- searching = false;
- activePosition = nullptr;
- sp->slavesMask.reset(idx);
- sp->allSlavesSearching = false;
- sp->nodes += pos.nodes_searched();
-
- // Wake up the master thread so to allow it to return from the idle
- // loop in case we are the last slave of the split point.
- if ( this != sp->masterThread
- && sp->slavesMask.none())
- {
- assert(!sp->masterThread->searching);
- sp->masterThread->notify_one();
- }
-
- // After releasing the lock we can't access any SplitPoint related data
- // in a safe way because it could have been released under our feet by
- // the sp master.
- sp->mutex.unlock();
-
- // Try to late join to another split point if none of its slaves has
- // already finished.
- if (Threads.size() > 2)
- for (size_t i = 0; i < Threads.size(); ++i)
- {
- const int size = Threads[i]->splitPointsSize; // Local copy
- sp = size ? &Threads[i]->splitPoints[size - 1] : nullptr;
-
- if ( sp
- && sp->allSlavesSearching
- && available_to(Threads[i]))
- {
- // Recheck the conditions under lock protection
- Threads.mutex.lock();
- sp->mutex.lock();
-
- if ( sp->allSlavesSearching
- && available_to(Threads[i]))
- {
- sp->slavesMask.set(idx);
- activeSplitPoint = sp;
- searching = true;
- }
-
- sp->mutex.unlock();
- Threads.mutex.unlock();
-
- break; // Just a single attempt
- }
- }
- }
-
- // Grab the lock to avoid races with Thread::notify_one()
- std::unique_lock<std::mutex> lk(mutex);
-
- // If we are master and all slaves have finished then exit idle_loop
- if (this_sp && this_sp->slavesMask.none())
- {
- assert(!searching);
- break;
- }
-
- // If we are not searching, wait for a condition to be signaled instead of
- // wasting CPU time polling for work.
- if (!searching && !exit)
- sleepCondition.wait(lk);
- }
-}
-
-
-/// check_time() is called by the timer thread when the timer triggers. It is
-/// used to print debug info and, more importantly, to detect when we are out of
-/// available time and thus stop the search.
-
-void check_time() {
-
- static Time::point lastInfoTime = Time::now();
- Time::point elapsed = Time::now() - SearchTime;
-
- if (Time::now() - lastInfoTime >= 1000)
- {
- lastInfoTime = Time::now();
- dbg_print();
- }
-
- // An engine may not stop pondering until told so by the GUI
- if (Limits.ponder)
- return;
-
- if (Limits.use_time_management())
- {
- bool stillAtFirstMove = Signals.firstRootMove
- && !Signals.failedLowAtRoot
- && elapsed > TimeMgr.available_time() * 75 / 100;
-
- if ( stillAtFirstMove
- || elapsed > TimeMgr.maximum_time() - 2 * TimerThread::Resolution)
- Signals.stop = true;
- }
- else if (Limits.movetime && elapsed >= Limits.movetime)
- Signals.stop = true;
-
- else if (Limits.nodes)
- {
- Threads.mutex.lock();
-
- int64_t nodes = RootPos.nodes_searched();
-
- // Loop across all split points and sum accumulated SplitPoint nodes plus
- // all the currently active positions nodes.
- for (Thread* th : Threads)
- for (int i = 0; i < th->splitPointsSize; ++i)
- {
- SplitPoint& sp = th->splitPoints[i];
-
- sp.mutex.lock();
-
- nodes += sp.nodes;
-
- for (size_t idx = 0; idx < Threads.size(); ++idx)
- if (sp.slavesMask.test(idx) && Threads[idx]->activePosition)
- nodes += Threads[idx]->activePosition->nodes_searched();
-
- sp.mutex.unlock();
- }
-
- Threads.mutex.unlock();
-
- if (nodes >= Limits.nodes)
- Signals.stop = true;
- }
-}