X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=aa63fcb4392d2fbe839b91b2c3bdfc1e764dd69d;hp=fbe6b2c052fa3fee50e7f98bcf37639134e438a1;hb=5ec63eb6b6f43cbd4e25b8f8b97bc8980dbbabef;hpb=b8e6f83cfb913fa079edd3690a8720f09eb7b388 diff --git a/src/search.cpp b/src/search.cpp index fbe6b2c0..aa63fcb4 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -94,7 +94,7 @@ namespace { void id_loop(Position& pos); Value value_to_tt(Value v, int ply); Value value_from_tt(Value v, int ply); - void update_stats(Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt); + void update_stats(const Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt); string uci_pv(const Position& pos, int depth, Value alpha, Value beta); struct Skill { @@ -226,14 +226,12 @@ void Search::think() { for (size_t i = 0; i < Threads.size(); ++i) Threads[i]->maxPly = 0; - Threads.sleepWhileIdle = Options["Idle Threads Sleep"]; Threads.timer->run = true; Threads.timer->notify_one(); // Wake up the recurring timer id_loop(RootPos); // Let's start searching ! Threads.timer->run = false; // Stop the timer - Threads.sleepWhileIdle = true; // Send idle threads to sleep if (Options["Write Search Log"]) { @@ -584,6 +582,10 @@ namespace { && abs(beta) < VALUE_MATE_IN_MAX_PLY && !pos.pawn_on_7th(pos.side_to_move())) { + if ( depth <= ONE_PLY + && eval + razor_margin(3 * ONE_PLY) <= alpha) + return qsearch(pos, ss, alpha, beta, DEPTH_ZERO); + Value ralpha = alpha - razor_margin(depth); Value v = qsearch(pos, ss, ralpha, ralpha+1, DEPTH_ZERO); if (v <= ralpha) @@ -885,7 +887,7 @@ moves_loop: // When in check and at SpNode search starts from here value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); - // Research at intermediate depth if reduction is very high + // Re-search at intermediate depth if reduction is very high if (value > alpha && ss->reduction >= 4 * ONE_PLY) { Depth d2 = std::max(newDepth - 2 * ONE_PLY, ONE_PLY); @@ -984,8 +986,10 @@ moves_loop: // When in check and at SpNode search starts from here // Step 19. Check for splitting the search if ( !SpNode + && Threads.size() >= 2 && depth >= Threads.minimumSplitDepth - && Threads.available_slave(thisThread) + && ( !thisThread->activeSplitPoint + || !thisThread->activeSplitPoint->allSlavesSearching) && thisThread->splitPointsSize < MAX_SPLITPOINTS_PER_THREAD) { assert(bestValue > -VALUE_INFINITE && bestValue < beta); @@ -1017,18 +1021,18 @@ moves_loop: // When in check and at SpNode search starts from here // must be mate or stalemate. If we are in a singular extension search then // return a fail low score. if (!moveCount) - return excludedMove ? alpha - : inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()]; + bestValue = excludedMove ? alpha + : inCheck ? mated_in(ss->ply) : DrawValue[pos.side_to_move()]; + + // Quiet best move: update killers, history, countermoves and followupmoves + else if (bestValue >= beta && !pos.capture_or_promotion(bestMove) && !inCheck) + update_stats(pos, ss, bestMove, depth, quietsSearched, quietCount - 1); TT.store(posKey, value_to_tt(bestValue, ss->ply), bestValue >= beta ? BOUND_LOWER : PvNode && bestMove ? BOUND_EXACT : BOUND_UPPER, depth, bestMove, ss->staticEval); - // Quiet best move: update killers, history, countermoves and followupmoves - if (bestValue >= beta && !pos.capture_or_promotion(bestMove) && !inCheck) - update_stats(pos, ss, bestMove, depth, quietsSearched, quietCount - 1); - assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); return bestValue; @@ -1265,7 +1269,7 @@ moves_loop: // When in check and at SpNode search starts from here // update_stats() updates killers, history, countermoves and followupmoves stats after a fail-high // of a quiet move. - void update_stats(Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt) { + void update_stats(const Position& pos, Stack* ss, Move move, Depth depth, Move* quiets, int quietsCnt) { if (ss->killers[0] != move) { @@ -1460,7 +1464,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 ((!searching && Threads.sleepWhileIdle) || exit) + while (!searching || exit) { if (exit) { @@ -1530,12 +1534,12 @@ void Thread::idle_loop() { searching = false; activePosition = NULL; 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 ( Threads.sleepWhileIdle - && this != sp->masterThread + if ( this != sp->masterThread && sp->slavesMask.none()) { assert(!sp->masterThread->searching); @@ -1544,9 +1548,39 @@ void Thread::idle_loop() { // 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. Also accessing other Thread objects is unsafe because - // if we are exiting there is a chance that they are already freed. + // 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) + { + int size = Threads[i]->splitPointsSize; // Local copy + sp = size ? &Threads[i]->splitPoints[size - 1] : NULL; + + 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 + } + } } // If this thread is the master of a split point and all slaves have finished