X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=e5c485fce59d368dc5fb227dd3851084baa0da37;hp=eb9a0891d697edd3d827556bbd5e1fbcf7ef1a15;hb=69240a982d8c3a2d01fab04c284be43853ab2bc9;hpb=9c9205860c5ab0e4f3180298e3f7082be259772c diff --git a/src/search.cpp b/src/search.cpp index eb9a0891..e5c485fc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -127,6 +127,7 @@ namespace { }; EasyMoveManager EasyMove; + bool easyPlayed, failedLow; double BestMoveChanges; Value DrawValue[COLOR_NB]; CounterMovesHistoryStats CounterMovesHistory; @@ -220,11 +221,11 @@ uint64_t Search::perft(Position& pos, Depth depth) { template uint64_t Search::perft(Position&, Depth); -/// MainThread::think() is called by the main thread when the program receives +/// MainThread::search() is called by the main thread when the program receives /// the UCI 'go' command. It searches from root position and at the end prints /// the "bestmove" to output. -void MainThread::think() { +void MainThread::search() { Color us = rootPos.side_to_move(); Time.init(Limits, us, rootPos.game_ply()); @@ -290,24 +291,15 @@ void MainThread::think() { { th->maxPly = 0; th->rootDepth = DEPTH_ZERO; - th->searching = true; if (th != this) { th->rootPos = Position(rootPos, th); th->rootMoves = rootMoves; - th->notify_one(); // Wake up the thread and start searching + th->start_searching(); } } - search(true); // Let's start searching! - - // Stop the threads - Signals.stop = true; - - // Wait until all threads have finished - for (Thread* th : Threads) - if (th != this) - th->wait_while(th->searching); + Thread::search(); // Let's start searching! } // When playing in 'nodes as time' mode, subtract the searched nodes from @@ -326,12 +318,21 @@ void MainThread::think() { wait(Signals.stop); } + // Stop the threads if not already stopped + Signals.stop = true; + + // Wait until all threads have finished + for (Thread* th : Threads) + if (th != this) + th->wait_for_search_finished(); + // Check if there are threads with a better score than main thread. Thread* bestThread = this; - for (Thread* th : Threads) - if ( th->completedDepth > bestThread->completedDepth - && th->rootMoves[0].score > bestThread->rootMoves[0].score) - bestThread = th; + if (Options["MultiPV"] == 1 && !Skill(Options["Skill Level"]).enabled()) + for (Thread* th : Threads) + if ( th->completedDepth > bestThread->completedDepth + && th->rootMoves[0].score > bestThread->rootMoves[0].score) + bestThread = th; // Send new PV when needed. // FIXME: Breaks multiPV, and skill levels @@ -351,11 +352,12 @@ void MainThread::think() { // repeatedly with increasing depth until the allocated thinking time has been // consumed, user stops the search, or the maximum search depth is reached. -void Thread::search(bool isMainThread) { +void Thread::search() { Stack stack[MAX_PLY+4], *ss = stack+2; // To allow referencing (ss-2) and (ss+2) Value bestValue, alpha, beta, delta; Move easyMove = MOVE_NONE; + bool isMainThread = (this == Threads.main()); std::memset(ss-2, 0, 5 * sizeof(Stack)); @@ -367,6 +369,7 @@ void Thread::search(bool isMainThread) { { easyMove = EasyMove.get(rootPos.key()); EasyMove.clear(); + easyPlayed = false; BestMoveChanges = 0; TT.new_search(); } @@ -386,11 +389,11 @@ void Thread::search(bool isMainThread) { { // Set up the new depth for the helper threads if (!isMainThread) - rootDepth = Threads.main()->rootDepth + Depth(int(2.2 * log(1 + this->idx))); + rootDepth = std::min(DEPTH_MAX - ONE_PLY, Threads.main()->rootDepth + Depth(int(2.2 * log(1 + this->idx)))); // Age out PV variability metric if (isMainThread) - BestMoveChanges *= 0.5; + BestMoveChanges *= 0.505, failedLow = false; // Save the last iteration's scores before first PV line is searched and // all the move scores except the (new) PV are set to -VALUE_INFINITE. @@ -451,7 +454,7 @@ void Thread::search(bool isMainThread) { if (isMainThread) { - Signals.failedLowAtRoot = true; + failedLow = true; Signals.stopOnPonderhit = false; } } @@ -511,10 +514,10 @@ void Thread::search(bool isMainThread) { // of the available time has been used or we matched an easyMove // from the previous search and just did a fast verification. if ( rootMoves.size() == 1 - || Time.elapsed() > Time.available() - || ( rootMoves[0].pv[0] == easyMove + || Time.elapsed() > Time.available() * (failedLow? 641 : 315)/640 + || ( easyPlayed = ( rootMoves[0].pv[0] == easyMove && BestMoveChanges < 0.03 - && Time.elapsed() > Time.available() / 10)) + && Time.elapsed() > Time.available() / 8))) { // If we are allowed to ponder do not stop the search now but // keep pondering until the GUI sends "ponderhit" or "stop". @@ -532,15 +535,12 @@ void Thread::search(bool isMainThread) { } } - searching = false; - notify_one(); // Wake up main thread if is sleeping waiting for us - if (!isMainThread) return; // Clear any candidate easy move that wasn't stable for the last search // iterations; the second condition prevents consecutive fast moves. - if (EasyMove.stableCnt < 6 || Time.elapsed() < Time.available()) + if (EasyMove.stableCnt < 6 || easyPlayed) EasyMove.clear(); // If skill level is enabled, swap best PV line with the sub-optimal one @@ -562,7 +562,7 @@ namespace { assert(-VALUE_INFINITE <= alpha && alpha < beta && beta <= VALUE_INFINITE); assert(PvNode || (alpha == beta - 1)); - assert(depth > DEPTH_ZERO); + assert(DEPTH_ZERO < depth && depth < DEPTH_MAX); Move pv[MAX_PLY+1], quietsSearched[64]; StateInfo st; @@ -583,15 +583,15 @@ namespace { ss->ply = (ss-1)->ply + 1; // Check for available remaining time - if (thisThread->resetCallsCnt.load(std::memory_order_relaxed)) + if (thisThread->resetCalls.load(std::memory_order_relaxed)) { - thisThread->resetCallsCnt = false; + thisThread->resetCalls = false; thisThread->callsCnt = 0; } if (++thisThread->callsCnt > 4096) { for (Thread* th : Threads) - th->resetCallsCnt = true; + th->resetCalls = true; check_time(); } @@ -861,15 +861,10 @@ moves_loop: // When in check search starts from here ss->moveCount = ++moveCount; - if (RootNode && thisThread == Threads.main()) - { - Signals.firstRootMove = (moveCount == 1); - - if (Time.elapsed() > 3000) - sync_cout << "info depth " << depth / ONE_PLY - << " currmove " << UCI::move(move, pos.is_chess960()) - << " currmovenumber " << moveCount + thisThread->PVIdx << sync_endl; - } + if (RootNode && thisThread == Threads.main() && Time.elapsed() > 3000) + sync_cout << "info depth " << depth / ONE_PLY + << " currmove " << UCI::move(move, pos.is_chess960()) + << " currmovenumber " << moveCount + thisThread->PVIdx << sync_endl; if (PvNode) (ss+1)->pv = nullptr; @@ -923,7 +918,8 @@ moves_loop: // When in check search starts from here continue; // History based pruning - if ( depth <= 3 * ONE_PLY + if ( depth <= 4 * ONE_PLY + && move != ss->killers[0] && thisThread->history[pos.moved_piece(move)][to_sq(move)] < VALUE_ZERO && cmh[pos.moved_piece(move)][to_sq(move)] < VALUE_ZERO) continue; @@ -1487,19 +1483,9 @@ moves_loop: // When in check search starts from here if (Limits.ponder) return; - if (Limits.use_time_management()) - { - bool stillAtFirstMove = Signals.firstRootMove.load(std::memory_order_relaxed) - && !Signals.failedLowAtRoot.load(std::memory_order_relaxed) - && elapsed > Time.available() * 3 / 4; - - if (stillAtFirstMove || elapsed > Time.maximum() - 10) - Signals.stop = true; - } - else if (Limits.movetime && elapsed >= Limits.movetime) - Signals.stop = true; - - else if (Limits.nodes && Threads.nodes_searched() >= Limits.nodes) + if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10) + || (Limits.movetime && elapsed >= Limits.movetime) + || (Limits.nodes && Threads.nodes_searched() >= Limits.nodes)) Signals.stop = true; }