00001
00002
00003 #include "osl/game_playing/threadForEachMove.h"
00004 #include "osl/game_playing/gameState.h"
00005 #include "osl/game_playing/searchPlayer.h"
00006 #include "osl/search/timeControl.h"
00007 #include "osl/search/searchRecorder.h"
00008 #include "osl/misc/realTime.h"
00009 #include "osl/record/csa.h"
00010 #include "osl/sennichite.h"
00011 #include <boost/thread.hpp>
00012 #include <exception>
00013 #include <iostream>
00014 #include <ctime>
00015 #include <unistd.h>
00016
00017 #define DEBUG_SPECULATIVE_EXECUTION
00018 #define EXTRA_DEBUG_SPECULATIVE_EXECUTION
00019
00020 struct osl::game_playing::ThreadForEachMove::SpeculativeThread
00021 {
00022 boost::shared_ptr<boost::thread> thread;
00023 boost::shared_ptr<GameState> state;
00024 boost::shared_ptr<SearchPlayer> player;
00025 bool parent_is_verbose;
00026 volatile bool thread_finished;
00027 Move predicted_move;
00028 MoveWithComment next_move;
00029 bool verbose;
00030
00031 MoveWithComment *next_move_for_thread;
00032 volatile bool *thread_finished_for_thread;
00033
00034 SpeculativeThread() : player(), parent_is_verbose(false),
00035 thread_finished(true),
00036 verbose(false),
00037 next_move_for_thread(&next_move),
00038 thread_finished_for_thread(&thread_finished)
00039 {
00040 }
00041 private:
00042 void errorInThread()
00043 {
00044 std::cerr << "caught exception in thread" << std::cerr;
00045 *next_move_for_thread = MoveWithComment(Move::INVALID());
00046 *thread_finished_for_thread = true;
00047 }
00048 public:
00049 void operator()()
00050 {
00051
00052
00053
00054
00055 assert(predicted_move.isNormal());
00056 *thread_finished_for_thread = false;
00057 try
00058 {
00059 state->pushMove(predicted_move);
00060 player->pushMove(predicted_move);
00061 player->setVerbose(verbose);
00062 *next_move_for_thread = MoveWithComment(Move::INVALID());
00063 *next_move_for_thread = player->selectBestMove(*state, -1, -1);
00064 }
00065 catch (std::exception& e)
00066 {
00067 errorInThread();
00068 std::cerr << e.what() << std::endl;
00069 return;
00070 }
00071 catch (...)
00072 {
00073 errorInThread();
00074 std::cerr << "unknown exception" << std::endl;
00075 return;
00076 }
00077 *thread_finished_for_thread = true;
00078 #ifdef DEBUG_SPECULATIVE_EXECUTION
00079 time_t now = time(0);
00080 char ctime_buf[64];
00081 std::cerr << "if " << record::csa::show(predicted_move)
00082 << " then " << record::csa::show(next_move_for_thread->move)
00083 << " " << ctime_r(&now, ctime_buf);
00084 #endif
00085 if (parent_is_verbose)
00086 player->recorder().reportCount(std::cerr);
00087 }
00088 void run(Move prediction, const GameState& main_state,
00089 const SearchPlayer& main_player, bool verbose);
00090 private:
00091 void spawnFailed()
00092 {
00093 char ctime_buf[64];
00094 time_t now = time(0);
00095 std::cerr << "thread creation failure " << ctime_r(&now, ctime_buf);
00096 thread.reset();
00097 player.reset();
00098 predicted_move = Move::INVALID();
00099 }
00100 public:
00101 void join()
00102 {
00103 if (thread.get())
00104 {
00105 thread->join();
00106 thread.reset();
00107 }
00108 predicted_move = Move::INVALID();
00109 }
00110 void waitRunning() const
00111 {
00112 if (thread_finished)
00113 return;
00114 while ((! thread_finished)
00115 && (! player->canStopSearch()))
00116 {
00117 timespec rq = { 0, 20000000 }, rm;
00118 while (nanosleep(&rq, &rm) == -1)
00119 {
00120 rq = rm;
00121 }
00122 }
00123 }
00124 void changeTimer(const misc::RealTime& timer)
00125 {
00126 waitRunning();
00127 if (! thread_finished)
00128 player->setStopSchedule(timer);
00129 }
00130 void stopSearchNow()
00131 {
00132 char ctime_buf[64];
00133 if (! thread_finished)
00134 {
00135 #ifdef EXTRA_DEBUG_SPECULATIVE_EXECUTION
00136 time_t now = time(0);
00137 std::cerr << "need to call stopSearchNow " << ctime_r(&now, ctime_buf);
00138 #endif
00139 waitRunning();
00140 if (! thread_finished)
00141 {
00142 #ifdef EXTRA_DEBUG_SPECULATIVE_EXECUTION
00143 time_t now = time(0);
00144 std::cerr << "calling stopSearchNow " << ctime_r(&now, ctime_buf);
00145 #endif
00146 const bool success
00147 = player->stopSearchNow();
00148 if (! success)
00149 {
00150 std::cerr << "stop search failed" << this << "\n";
00151 }
00152 }
00153 }
00154 join();
00155 }
00156 };
00157
00158 void osl::game_playing::ThreadForEachMove::SpeculativeThread::
00159 run(Move prediction, const GameState& main_state,
00160 const SearchPlayer& main_player, bool verbose)
00161 {
00162 try
00163 {
00164 player.reset();
00165 player.reset(dynamic_cast<SearchPlayer*>(main_player.clone()));
00166 parent_is_verbose = player->getConfig().verbose;
00167 assert(! thread.get());
00168 predicted_move = prediction;
00169 state = main_state.clone();
00170 this->verbose = verbose;
00171 thread.reset(new boost::thread(*this));
00172 #ifdef DEBUG_SPECULATIVE_EXECUTION
00173 char ctime_buf[64];
00174 time_t now = time(0);
00175 std::cerr << "speculative search for " << record::csa::show(predicted_move)
00176 << " " << ctime_r(&now, ctime_buf);
00177 #endif
00178 }
00179 catch (boost::thread_resource_error&)
00180 {
00181 spawnFailed();
00182 }
00183 catch (std::exception& e)
00184 {
00185 spawnFailed();
00186 std::cerr << e.what() << std::endl;
00187 }
00188 catch (...)
00189 {
00190 spawnFailed();
00191 std::cerr << "unknown exception" << std::endl;
00192 }
00193 }
00194
00195 osl::game_playing::ThreadForEachMove::
00196 ThreadForEachMove(int threads)
00197 : speculative_thread0(new SpeculativeThread()),
00198 speculative_thread1(new SpeculativeThread()),
00199 max_threads(threads)
00200 {
00201 }
00202 osl::game_playing::
00203 ThreadForEachMove::~ThreadForEachMove()
00204 {
00205 stopAll();
00206 selectBestMoveCleanUp();
00207 }
00208
00209 void osl::game_playing::ThreadForEachMove::
00210 startSpeculative(const boost::shared_ptr<GameState> state,
00211 const SearchPlayer& main_player)
00212 {
00213 assert(speculative_thread0.get());
00214 assert(speculative_thread1.get());
00215 MoveVector moves;
00216 main_player.pickUpBestMoves(*state, moves);
00217 const bool run_thread0 = moves.size() > 0 && max_threads > 0;
00218 const bool run_thread1 = moves.size() > 1 && max_threads > 1;
00219 if (run_thread0)
00220 speculative_thread0->run(moves[0], *state, main_player,
00221 (! run_thread1));
00222 if (run_thread1)
00223 speculative_thread1->run(moves[1], *state, main_player,
00224 false);
00225 }
00226
00227 void osl::game_playing::ThreadForEachMove::
00228 stopOtherThan(Move m)
00229 {
00230 char ctime_buf[64];
00231 if (speculative_thread0->predicted_move != m)
00232 {
00233 #ifdef EXTRA_DEBUG_SPECULATIVE_EXECUTION
00234 if (max_threads > 0)
00235 {
00236 time_t now = time(0);
00237 std::cerr << "stop thread0 " << ctime_r(&now, ctime_buf);
00238 }
00239 #endif
00240 speculative_thread0->stopSearchNow();
00241 }
00242 if (speculative_thread1->predicted_move != m)
00243 {
00244 #ifdef EXTRA_DEBUG_SPECULATIVE_EXECUTION
00245 if (max_threads > 1)
00246 {
00247 time_t now = time(0);
00248 std::cerr << "stop thread1 " << ctime_r(&now, ctime_buf);
00249 }
00250 #endif
00251 speculative_thread1->stopSearchNow();
00252 }
00253 }
00254
00255 void osl::game_playing::ThreadForEachMove::
00256 stopAll()
00257 {
00258 if (! speculative_thread0->thread_finished)
00259 speculative_thread0->stopSearchNow();
00260 if (! speculative_thread1->thread_finished)
00261 speculative_thread1->stopSearchNow();
00262 }
00263
00264 const osl::game_playing::MoveWithComment
00265 osl::game_playing::ThreadForEachMove::
00266 waitResult(Move last_move, const int wait_for,
00267 SearchPlayer& main_player, int )
00268 {
00269 const time_t start_time = time(0);
00270 assert(last_move.isNormal());
00271 SpeculativeThread *match = 0;
00272 MoveWithComment result = MoveWithComment(Move::INVALID());
00273
00274 if (speculative_thread0->predicted_move == last_move)
00275 match = speculative_thread0.get();
00276 else if (speculative_thread1->predicted_move == last_move)
00277 match = speculative_thread1.get();
00278
00279 if (! match)
00280 {
00281 #ifdef DEBUG_SPECULATIVE_EXECUTION
00282 time_t now = time(0);
00283 char ctime_buf[64];
00284 std::cerr << "unexpected " << record::csa::show(last_move)
00285 << " " << ctime_r(&now, ctime_buf);
00286 #endif
00287 return result;
00288 }
00289
00290 const time_t stop_time = start_time + wait_for;
00291 match->changeTimer(misc::RealTime(wait_for));
00292 #ifdef DEBUG_SPECULATIVE_EXECUTION
00293 char ctime_buf[64];
00294 std::cerr << "match " << ctime_r(&start_time, ctime_buf);
00295 std::cerr << "wait for " << ctime_r(&stop_time, ctime_buf);
00296 #endif
00297 match->player->setVerbose(main_player.getConfig().verbose);
00298 while (true)
00299 {
00300 if (match->thread_finished)
00301 break;
00302
00303 time_t now = time(0);
00304 if (now >= stop_time)
00305 {
00306 match->stopSearchNow();
00307 #ifdef EXTRA_DEBUG_SPECULATIVE_EXECUTION
00308 std::cerr << "stop search (match): " << ctime_r(&now, ctime_buf);
00309 #endif
00310 break;
00311 }
00312 timespec rq = { 1, 0 }, rm;
00313 nanosleep(&rq, &rm);
00314 }
00315 result = match->next_move;
00316 if (result.move.isNormal()) {
00317 main_player.swapTable(*match->player);
00318 }
00319 return result;
00320 }
00321
00322 void osl::game_playing::ThreadForEachMove::
00323 selectBestMoveCleanUp()
00324 {
00325 speculative_thread0->join();
00326 speculative_thread1->join();
00327 }
00328
00329
00330
00331
00332
00333