namespace Search {
- SignalsType Signals;
LimitsType Limits;
}
void update_pv(Move* pv, Move move, Move* childPv);
void update_cm_stats(Stack* ss, Piece pc, Square s, int bonus);
void update_stats(const Position& pos, Stack* ss, Move move, Move* quiets, int quietsCnt, int bonus);
- void check_time();
} // namespace
for (Thread* th : Threads)
{
- th->resetCalls = true;
th->counterMoves.fill(MOVE_NONE);
th->history.fill(0);
th->counterMoveHistory[NO_PIECE][0].fill(CounterMovePruneThreshold - 1);
}
+ Threads.main()->callsCnt = 0;
Threads.main()->previousScore = VALUE_INFINITE;
}
Time.availableNodes += Limits.inc[us] - Threads.nodes_searched();
// When we reach the maximum depth, we can arrive here without a raise of
- // Signals.stop. However, if we are pondering or in an infinite search,
+ // Threads.stop. However, if we are pondering or in an infinite search,
// the UCI protocol states that we shouldn't print the best move before the
// GUI sends a "stop" or "ponderhit" command. We therefore simply wait here
- // until the GUI sends one of those commands (which also raises Signals.stop).
- if (!Signals.stop && (Limits.ponder || Limits.infinite))
+ // until the GUI sends one of those commands (which also raises Threads.stop).
+ if (!Threads.stop && (Limits.ponder || Limits.infinite))
{
- Signals.stopOnPonderhit = true;
- wait(Signals.stop);
+ Threads.stopOnPonderhit = true;
+ wait(Threads.stop);
}
// Stop the threads if not already stopped
- Signals.stop = true;
+ Threads.stop = true;
// Wait until all threads have finished
for (Thread* th : Threads)
multiPV = std::min(multiPV, rootMoves.size());
// Iterative deepening loop until requested to stop or the target depth is reached
- while ( (rootDepth = rootDepth + ONE_PLY) < DEPTH_MAX
- && !Signals.stop
- && (!Limits.depth || Threads.main()->rootDepth / ONE_PLY <= Limits.depth))
+ while ( (rootDepth += ONE_PLY) < DEPTH_MAX
+ && !Threads.stop
+ && !(Limits.depth && mainThread && rootDepth / ONE_PLY > Limits.depth))
{
// Distribute search depths across the threads
if (idx)
rm.previousScore = rm.score;
// MultiPV loop. We perform a full root search for each PV line
- for (PVIdx = 0; PVIdx < multiPV && !Signals.stop; ++PVIdx)
+ for (PVIdx = 0; PVIdx < multiPV && !Threads.stop; ++PVIdx)
{
+ // Reset UCI info selDepth for each depth and each PV line
+ selDepth = 0;
+
// Reset aspiration window starting size
if (rootDepth >= 5 * ONE_PLY)
{
{
bestValue = ::search<PV>(rootPos, ss, alpha, beta, rootDepth, false, false);
- this->tbHits = rootPos.tb_hits();
- this->nodes = rootPos.nodes_searched();
-
// Bring the best move to the front. It is critical that sorting
// is done with a stable algorithm because all the values but the
// first and eventually the new best one are set to -VALUE_INFINITE
// If search has been stopped, we break immediately. Sorting and
// writing PV back to TT is safe because RootMoves is still
// valid, although it refers to the previous iteration.
- if (Signals.stop)
+ if (Threads.stop)
break;
// When failing high/low give some update (without cluttering
if (mainThread)
{
mainThread->failedLow = true;
- Signals.stopOnPonderhit = false;
+ Threads.stopOnPonderhit = false;
}
}
else if (bestValue >= beta)
- {
- alpha = (alpha + beta) / 2;
beta = std::min(bestValue + delta, VALUE_INFINITE);
- }
else
break;
if (!mainThread)
continue;
- if (Signals.stop || PVIdx + 1 == multiPV || Time.elapsed() > 3000)
+ if (Threads.stop || PVIdx + 1 == multiPV || Time.elapsed() > 3000)
sync_cout << UCI::pv(rootPos, rootDepth, alpha, beta) << sync_endl;
}
- if (!Signals.stop)
+ if (!Threads.stop)
completedDepth = rootDepth;
if (!mainThread)
if ( Limits.mate
&& bestValue >= VALUE_MATE_IN_MAX_PLY
&& VALUE_MATE - bestValue <= 2 * Limits.mate)
- Signals.stop = true;
+ Threads.stop = true;
// Do we have time for the next iteration? Can we stop searching now?
if (Limits.use_time_management())
{
- if (!Signals.stop && !Signals.stopOnPonderhit)
+ if (!Threads.stop && !Threads.stopOnPonderhit)
{
// Stop the search if only one legal move is available, or if all
// of the available time has been used, or if we matched an easyMove
// If we are allowed to ponder do not stop the search now but
// keep pondering until the GUI sends "ponderhit" or "stop".
if (Limits.ponder)
- Signals.stopOnPonderhit = true;
+ Threads.stopOnPonderhit = true;
else
- Signals.stop = true;
+ Threads.stop = true;
}
}
ss->ply = (ss-1)->ply + 1;
// Check for the available remaining time
- if (thisThread->resetCalls.load(std::memory_order_relaxed))
- {
- thisThread->resetCalls = false;
-
- thisThread->tbHits = pos.tb_hits();
- thisThread->nodes = pos.nodes_searched();
-
- // At low node count increase the checking rate to about 0.1% of nodes
- // otherwise use a default value.
- thisThread->callsCnt = Limits.nodes ? std::min(4096, int(Limits.nodes / 1024))
- : 4096;
- }
-
- if (--thisThread->callsCnt <= 0)
- {
- for (Thread* th : Threads)
- th->resetCalls = true;
-
- check_time();
- }
+ if (thisThread == Threads.main())
+ static_cast<MainThread*>(thisThread)->check_time();
// Used to send selDepth info to GUI
- if (PvNode && thisThread->maxPly < ss->ply)
- thisThread->maxPly = ss->ply;
+ if (PvNode && thisThread->selDepth < ss->ply)
+ thisThread->selDepth = ss->ply;
if (!rootNode)
{
// Step 2. Check for aborted search and immediate draw
- if (Signals.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
+ if (Threads.stop.load(std::memory_order_relaxed) || pos.is_draw(ss->ply) || ss->ply >= MAX_PLY)
return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos)
: DrawValue[pos.side_to_move()];
if (err != TB::ProbeState::FAIL)
{
- pos.increment_tbHits();
+ thisThread->tbHits.fetch_add(1, std::memory_order_relaxed);
int drawScore = TB::UseRule50 ? 1 : 0;
eval = ss->staticEval = evaluate(pos);
// Can ttValue be used as a better position evaluation?
- if (ttValue != VALUE_NONE)
- if (tte->bound() & (ttValue > eval ? BOUND_LOWER : BOUND_UPPER))
- eval = ttValue;
+ if ( ttValue != VALUE_NONE
+ && (tte->bound() & (ttValue > eval ? BOUND_LOWER : BOUND_UPPER)))
+ eval = ttValue;
}
else
{
ss->moveCount = --moveCount;
continue;
}
-
+
if (move == ttMove && captureOrPromotion)
ttCapture = true;
r -= r ? ONE_PLY : DEPTH_ZERO;
else
{
-
// Increase reduction if ttMove is a capture
if (ttCapture)
r += ONE_PLY;
-
+
// Increase reduction for cut nodes
if (cutNode)
r += 2 * ONE_PLY;
// Finished searching the move. If a stop occurred, the return value of
// the search cannot be trusted, and we return immediately without
// updating best move, PV and TT.
- if (Signals.stop.load(std::memory_order_relaxed))
+ if (Threads.stop.load(std::memory_order_relaxed))
return VALUE_ZERO;
if (rootNode)
if (moveCount == 1 || value > alpha)
{
rm.score = value;
+ rm.selDepth = thisThread->selDepth;
rm.pv.resize(1);
assert((ss+1)->pv);
++static_cast<MainThread*>(thisThread)->bestMoveChanges;
}
else
- // All other moves but the PV are set to the lowest value: this is
- // not a problem when sorting because the sort is stable and the
+ // All other moves but the PV are set to the lowest value: this
+ // is not a problem when sorting because the sort is stable and the
// move position in the list is preserved - just the PV is pushed up.
rm.score = -VALUE_INFINITE;
}
// completed. But in this case bestValue is valid because we have fully
// searched our subtree, and we can anyhow save the result in TT.
/*
- if (Signals.stop)
+ if (Threads.stop)
return VALUE_DRAW;
*/
ss->staticEval = bestValue = evaluate(pos);
// Can ttValue be used as a better position evaluation?
- if (ttValue != VALUE_NONE)
- if (tte->bound() & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER))
- bestValue = ttValue;
+ if ( ttValue != VALUE_NONE
+ && (tte->bound() & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER)))
+ bestValue = ttValue;
}
else
ss->staticEval = bestValue =
return best;
}
+} // namespace
// check_time() 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() {
+ void MainThread::check_time() {
- static std::atomic<TimePoint> lastInfoTime = { now() };
+ if (--callsCnt > 0)
+ return;
+
+ // At low node count increase the checking rate to about 0.1% of nodes
+ // otherwise use a default value.
+ callsCnt = Limits.nodes ? std::min(4096, int(Limits.nodes / 1024)) : 4096;
+
+ static TimePoint lastInfoTime = now();
int elapsed = Time.elapsed();
TimePoint tick = Limits.startTime + elapsed;
if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10)
|| (Limits.movetime && elapsed >= Limits.movetime)
|| (Limits.nodes && Threads.nodes_searched() >= (uint64_t)Limits.nodes))
- Signals.stop = true;
+ Threads.stop = true;
}
-} // namespace
-
/// UCI::pv() formats PV information according to the UCI protocol. UCI requires
/// that all (if any) unsearched PV lines are sent using a previous search score.
ss << "info"
<< " depth " << d / ONE_PLY
- << " seldepth " << pos.this_thread()->maxPly
+ << " seldepth " << rootMoves[i].selDepth
<< " multipv " << i + 1
<< " score " << UCI::value(v);