Skip to content

Commit

Permalink
Re-apply the fix for Limits::ponder race
Browse files Browse the repository at this point in the history
But this time correctly set Threads.ponder

We avoid using 'limits' for passing pondering
flag because we don't want to have 2 ponder
variables in search scope: Search::Limits.ponder
and Threads.ponder. This would be confusing also
because limits.ponder is set at the beginning of
the search and never changes, instead Threads.ponder
can change value asynchronously during search.

No functional change.
  • Loading branch information
mcostalba committed Aug 10, 2017
1 parent 44236f4 commit 66c5eae
Show file tree
Hide file tree
Showing 5 changed files with 19 additions and 18 deletions.
6 changes: 3 additions & 3 deletions src/search.cpp
Expand Up @@ -277,7 +277,7 @@ void MainThread::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 Threads.stop).
if (!Threads.stop && (Limits.ponder || Limits.infinite))
if (!Threads.stop && (Threads.ponder || Limits.infinite))
{
Threads.stopOnPonderhit = true;
wait(Threads.stop);
Expand Down Expand Up @@ -499,7 +499,7 @@ void Thread::search() {
{
// 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)
if (Threads.ponder)
Threads.stopOnPonderhit = true;
else
Threads.stop = true;
Expand Down Expand Up @@ -1489,7 +1489,7 @@ namespace {
}

// An engine may not stop pondering until told so by the GUI
if (Limits.ponder)
if (Threads.ponder)
return;

if ( (Limits.use_time_management() && elapsed > Time.maximum() - 10)
Expand Down
7 changes: 3 additions & 4 deletions src/search.h
Expand Up @@ -72,22 +72,21 @@ typedef std::vector<RootMove> RootMoves;


/// LimitsType struct stores information sent by GUI about available time to
/// search the current move, maximum depth/time, if we are in analysis mode or
/// if we have to ponder while it's our opponent's turn to move.
/// search the current move, maximum depth/time, or if we are in analysis mode.

struct LimitsType {

LimitsType() { // Init explicitly due to broken value-initialization of non POD in MSVC
nodes = time[WHITE] = time[BLACK] = inc[WHITE] = inc[BLACK] =
npmsec = movestogo = depth = movetime = mate = infinite = ponder = 0;
npmsec = movestogo = depth = movetime = mate = infinite = 0;
}

bool use_time_management() const {
return !(mate | movetime | depth | nodes | infinite);
}

std::vector<Move> searchmoves;
int time[COLOR_NB], inc[COLOR_NB], npmsec, movestogo, depth, movetime, mate, infinite, ponder;
int time[COLOR_NB], inc[COLOR_NB], npmsec, movestogo, depth, movetime, mate, infinite;
int64_t nodes;
TimePoint startTime;
};
Expand Down
3 changes: 2 additions & 1 deletion src/thread.cpp
Expand Up @@ -183,11 +183,12 @@ uint64_t ThreadPool::tb_hits() const {
/// and starts a new search, then returns immediately.

void ThreadPool::start_thinking(Position& pos, StateListPtr& states,
const Search::LimitsType& limits) {
const Search::LimitsType& limits, bool ponderMode) {

main()->wait_for_search_finished();

stopOnPonderhit = stop = false;
ponder = ponderMode;
Search::Limits = limits;
Search::RootMoves rootMoves;

Expand Down
4 changes: 2 additions & 2 deletions src/thread.h
Expand Up @@ -96,12 +96,12 @@ struct ThreadPool : public std::vector<Thread*> {
void exit(); // be initialized and valid during the whole thread lifetime.

MainThread* main() { return static_cast<MainThread*>(at(0)); }
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&);
void start_thinking(Position&, StateListPtr&, const Search::LimitsType&, bool = false);
void read_uci_options();
uint64_t nodes_searched() const;
uint64_t tb_hits() const;

std::atomic_bool stop, stopOnPonderhit;
std::atomic_bool stop, ponder, stopOnPonderhit;

private:
StateListPtr setupStates;
Expand Down
17 changes: 9 additions & 8 deletions src/uci.cpp
Expand Up @@ -115,6 +115,7 @@ namespace {

Search::LimitsType limits;
string token;
bool ponderMode = false;

limits.startTime = now(); // As early as possible!

Expand All @@ -133,9 +134,9 @@ namespace {
else if (token == "movetime") is >> limits.movetime;
else if (token == "mate") is >> limits.mate;
else if (token == "infinite") limits.infinite = 1;
else if (token == "ponder") limits.ponder = 1;
else if (token == "ponder") ponderMode = true;

Threads.start_thinking(pos, States, limits);
Threads.start_thinking(pos, States, limits, ponderMode);
}

} // namespace
Expand Down Expand Up @@ -167,11 +168,11 @@ void UCI::loop(int argc, char* argv[]) {
token.clear(); // getline() could return empty or blank line
is >> skipws >> token;

// The GUI sends 'ponderhit' to tell us to ponder on the same move the
// opponent has played. In case Threads.stopOnPonderhit is set we are
// waiting for 'ponderhit' to stop the search (for instance because we
// already ran out of time), otherwise we should continue searching but
// switching from pondering to normal search.
// The GUI sends 'ponderhit' to tell us the user has played the expected move.
// So 'ponderhit' will be sent if we were told to ponder on the same move the
// user has played. We should continue searching but switch from pondering to
// normal search. In case Threads.stopOnPonderhit is set we are waiting for
// 'ponderhit' to stop the search, for instance if max search depth is reached.
if ( token == "quit"
|| token == "stop"
|| (token == "ponderhit" && Threads.stopOnPonderhit))
Expand All @@ -180,7 +181,7 @@ void UCI::loop(int argc, char* argv[]) {
Threads.main()->start_searching(true); // Could be sleeping
}
else if (token == "ponderhit")
Search::Limits.ponder = 0; // Switch to normal search
Threads.ponder = false; // Switch to normal search

else if (token == "uci")
sync_cout << "id name " << engine_info(true)
Expand Down

0 comments on commit 66c5eae

Please sign in to comment.