Try hard not to lose on time
authorMarco Costalba <mcostalba@gmail.com>
Mon, 2 Jan 2012 22:40:14 +0000 (23:40 +0100)
committerMarco Costalba <mcostalba@gmail.com>
Fri, 6 Jan 2012 00:41:45 +0000 (01:41 +0100)
We try hard not to lose on time even under extreme
time pressure. We achieve this through 3 different but
coordinated steps:

    1) Increase max frequency of timer events

    2) Quickly return after a stop signal

    3) Take in account timer resolution

With these SF played under LittleBlitzer at 1"+0.02 and 3"+0
without losing on time even one game.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
src/search.cpp
src/search.h
src/thread.cpp
src/ucioption.cpp

index 5e22ec4e806f769114521142a6ee249992a6bf32..9d29d2798737b81f76d8fa64ad130b97eac54ebd 100644 (file)
@@ -139,6 +139,9 @@ namespace {
   // better than the second best move.
   const Value EasyMoveMargin = Value(0x150);
 
+  // This is the minimum interval in msec between two check_time() calls
+  const int TimerResolution = 5;
+
 
   /// Namespace variables
 
@@ -343,8 +346,8 @@ void Search::think() {
 
   // Set best timer interval to avoid lagging under time pressure. Timer is
   // used to check for remaining available thinking time.
-  if (TimeMgr.available_time())
-      Threads.set_timer(std::min(100, std::max(TimeMgr.available_time() / 8, 20)));
+  if (Limits.use_time_management())
+      Threads.set_timer(std::min(100, std::max(TimeMgr.available_time() / 16, TimerResolution)));
   else
       Threads.set_timer(100);
 
@@ -513,7 +516,7 @@ namespace {
             bestMoveNeverChanged = false;
 
         // Do we have time for the next iteration? Can we stop searching now?
-        if (!Signals.stop && !Signals.stopOnPonderhit && Limits.useTimeManagement())
+        if (!Signals.stop && !Signals.stopOnPonderhit && Limits.use_time_management())
         {
             bool stop = false; // Local variable, not the volatile Signals.stop
 
@@ -865,7 +868,8 @@ split_point_start: // At split points actual search starts from here
     // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
     while (   bestValue < beta
            && (move = mp.next_move()) != MOVE_NONE
-           && !thread.cutoff_occurred())
+           && !thread.cutoff_occurred()
+           && !Signals.stop)
     {
       assert(is_ok(move));
 
@@ -1957,11 +1961,11 @@ void Thread::idle_loop(SplitPoint* sp) {
 }
 
 
-/// do_timer_event() is called by the timer thread when the timer triggers. It
-/// is used to print debug info and, more important, to detect when we are out of
+/// check_time() is called by the timer thread when the timer triggers. It is
+/// used to print debug info and, more important, to detect when we are out of
 /// available time and so stop the search.
 
-void do_timer_event() {
+void check_time() {
 
   static int lastInfoTime;
   int e = elapsed_time();
@@ -1979,10 +1983,10 @@ void do_timer_event() {
                          && !Signals.failedLowAtRoot
                          &&  e > TimeMgr.available_time();
 
-  bool noMoreTime =   e > TimeMgr.maximum_time()
+  bool noMoreTime =   e > TimeMgr.maximum_time() - TimerResolution
                    || stillAtFirstMove;
 
-  if (   (Limits.useTimeManagement() && noMoreTime)
+  if (   (Limits.use_time_management() && noMoreTime)
       || (Limits.maxTime && e >= Limits.maxTime)
          /* missing nodes limit */ ) // FIXME
       Signals.stop = true;
index c1b370d63070018c0d64feb99a6d48714945d306..8290b41a70f6a49f874df4c64c28341e5614d45f 100644 (file)
@@ -55,7 +55,7 @@ struct Stack {
 struct LimitsType {
 
   LimitsType() {  memset(this, 0, sizeof(LimitsType)); }
-  bool useTimeManagement() const { return !(maxTime | maxDepth | maxNodes | infinite); }
+  bool use_time_management() const { return !(maxTime | maxDepth | maxNodes | infinite); }
 
   int time, increment, movesToGo, maxTime, maxDepth, maxNodes, infinite, ponder;
 };
index 832648015cfd362cf9488cca93c663b005fc1af4..cb0ab5e9c258eea998fe9c5892e77e88562308c2 100644 (file)
@@ -367,7 +367,7 @@ template Value ThreadsManager::split<true>(Position&, Stack*, Value, Value, Valu
 
 // Thread::timer_loop() is where the timer thread waits maxPly milliseconds and
 // then calls do_timer_event(). If maxPly is 0 thread sleeps until is woken up.
-extern void do_timer_event();
+extern void check_time();
 
 void Thread::timer_loop() {
 
@@ -376,7 +376,7 @@ void Thread::timer_loop() {
       lock_grab(&sleepLock);
       timed_wait(&sleepCond, &sleepLock, maxPly ? maxPly : INT_MAX);
       lock_release(&sleepLock);
-      do_timer_event();
+      check_time();
   }
 }
 
index 132760c9499dd4fad6c282414ea7c5f1fc85e6e5..8162bc4294fa2870ad411b9814440f84b847cf24 100644 (file)
@@ -68,7 +68,7 @@ OptionsMap::OptionsMap() {
   o["OwnBook"]                     = UCIOption(true);
   o["MultiPV"]                     = UCIOption(1, 1, 500);
   o["Skill Level"]                 = UCIOption(20, 0, 20);
-  o["Emergency Move Horizon"]      = UCIOption(40, 0, 50);
+  o["Emergency Move Horizon"]      = UCIOption(30, 0, 50);
   o["Emergency Base Time"]         = UCIOption(200, 0, 30000);
   o["Emergency Move Time"]         = UCIOption(70, 0, 5000);
   o["Minimum Thinking Time"]       = UCIOption(20, 0, 5000);