Rewrite async I/O

Use the starting thread to wait for GUI input and instead use
the other threads to search. The consequence is that now think()
is alwasy started on a differnt thread than the caller that
returns immediately waiting for input. This reformat greatly
simplifies the code and is more in line with the common way
to implement this feature.

As a side effect now we don't need anymore Makefile tricks
with sleep() to allow profile builds.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
This commit is contained in:
Marco Costalba
2011-11-23 20:07:29 +01:00
parent e9dc2e9e1e
commit ed04c010eb
7 changed files with 134 additions and 203 deletions
+39 -46
View File
@@ -43,6 +43,10 @@ using std::cout;
using std::endl;
using std::string;
SearchLimits Limits;
std::vector<Move> SearchMoves;
Position* RootPosition;
namespace {
// Set to true to force running with one thread. Used for debugging
@@ -162,9 +166,8 @@ namespace {
int MultiPV, UCIMultiPV, MultiPVIdx;
// Time management variables
volatile bool StopOnPonderhit, FirstRootMove, StopRequest, QuitRequest, AspirationFailLow;
volatile bool StopOnPonderhit, FirstRootMove, StopRequest, AspirationFailLow;
TimeManager TimeMgr;
SearchLimits Limits;
// Skill level adjustment
int SkillLevel;
@@ -200,7 +203,6 @@ namespace {
string pv_to_uci(const Move pv[], int pvNum, bool chess960);
string pretty_pv(Position& pos, int depth, Value score, int time, Move pv[]);
string depth_to_uci(Depth depth);
void wait_for_stop_or_ponderhit();
// MovePickerExt template class extends MovePicker and allows to choose at compile
// time the proper moves source according to the type of node. In the default case
@@ -351,16 +353,17 @@ int64_t perft(Position& pos, Depth depth) {
/// variables, and calls id_loop(). It returns false when a "quit" command is
/// received during the search.
bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
void think() {
static Book book; // Defined static to initialize the PRNG only once
Position& pos = *RootPosition;
// Save "search start" time and reset elapsed time to zero
elapsed_search_time(get_system_time());
// Initialize global search-related variables
StopOnPonderhit = StopRequest = QuitRequest = AspirationFailLow = false;
Limits = limits;
StopOnPonderhit = StopRequest = AspirationFailLow = false;
// Set output stream mode: normal or chess960. Castling notation is different
cout << set960(pos.is_chess960());
@@ -374,11 +377,11 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
Move bookMove = book.probe(pos, Options["Best Book Move"].value<bool>());
if (bookMove != MOVE_NONE)
{
if (Limits.ponder)
wait_for_stop_or_ponderhit();
if (!StopRequest && (Limits.ponder || Limits.infinite))
Threads.wait_for_stop_or_ponderhit();
cout << "bestmove " << bookMove << endl;
return !QuitRequest;
return;
}
}
@@ -432,16 +435,9 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
else
Threads.set_timer(100);
// Start async mode to catch UCI commands sent to us while searching,
// like "quit", "stop", etc.
Threads.start_listener();
// We're ready to start thinking. Call the iterative deepening loop function
Move ponderMove = MOVE_NONE;
Move bestMove = id_loop(pos, searchMoves, &ponderMove);
// From now on any UCI command will be read in-sync with Threads.getline()
Threads.stop_listener();
Move bestMove = id_loop(pos, &SearchMoves[0], &ponderMove);
// Stop timer, no need to check for available time any more
Threads.set_timer(0);
@@ -469,7 +465,7 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
// we are pondering or in infinite search, we shouldn't print the best move
// before we are told to do so.
if (!StopRequest && (Limits.ponder || Limits.infinite))
wait_for_stop_or_ponderhit();
Threads.wait_for_stop_or_ponderhit();
// Could be MOVE_NONE when searching on a stalemate position
cout << "bestmove " << bestMove;
@@ -480,8 +476,6 @@ bool think(Position& pos, const SearchLimits& limits, Move searchMoves[]) {
cout << " ponder " << ponderMove;
cout << endl;
return !QuitRequest;
}
@@ -1902,26 +1896,6 @@ split_point_start: // At split points actual search starts from here
}
// wait_for_stop_or_ponderhit() is called when the maximum depth is reached
// while the program is pondering. The point is to work around a wrinkle in
// the UCI protocol: When pondering, the engine is not allowed to give a
// "bestmove" before the GUI sends it a "stop" or "ponderhit" command.
// We simply wait here until one of these commands (that raise StopRequest) is
// sent, and return, after which the bestmove and pondermove will be printed.
void wait_for_stop_or_ponderhit() {
string cmd;
StopOnPonderhit = true;
while (!StopRequest)
{
Threads.getline(cmd);
do_uci_async_cmd(cmd);
}
}
// When playing with strength handicap choose best move among the MultiPV set
// using a statistical rule dependent on SkillLevel. Idea by Heinz van Saanen.
@@ -2164,15 +2138,34 @@ void Thread::idle_loop(SplitPoint* sp) {
}
// do_uci_async_cmd() is called by listener thread when in async mode and 'cmd'
// input line is received from the GUI.
// ThreadsManager::wait_for_stop_or_ponderhit() is called when the maximum depth
// is reached while the program is pondering. The point is to work around a wrinkle
// in the UCI protocol: When pondering, the engine is not allowed to give a
// "bestmove" before the GUI sends it a "stop" or "ponderhit" command.
// We simply wait here until one of these commands (that raise StopRequest) is
// sent, and return, after which the bestmove and pondermove will be printed.
void do_uci_async_cmd(const std::string& cmd) {
void ThreadsManager::wait_for_stop_or_ponderhit() {
if (cmd == "quit")
QuitRequest = StopRequest = true;
StopOnPonderhit = true;
else if (cmd == "stop")
Thread& main = threads[0];
lock_grab(&main.sleepLock);
while (!StopRequest)
cond_wait(&main.sleepCond, &main.sleepLock);
lock_release(&main.sleepLock);
}
// uci_async_command() is called when a 'cmd' input line is received from the
// GUI while searching.
void uci_async_command(const std::string& cmd) {
if (cmd == "quit" || cmd == "stop")
StopRequest = true;
else if (cmd == "ponderhit")