]> git.sesse.net Git - stockfish/blobdiff - src/search.cpp
Retire Time::restart()
[stockfish] / src / search.cpp
index df09007f1538f8f15134e6df34edbc8dafacb93e..53a99f66036f66932ccc6e01b1ade81f81b51ca3 100644 (file)
@@ -21,7 +21,6 @@
 #include <cassert>
 #include <cmath>
 #include <cstring>
-#include <iomanip>
 #include <iostream>
 #include <sstream>
 
@@ -30,6 +29,7 @@
 #include "history.h"
 #include "movegen.h"
 #include "movepick.h"
+#include "notation.h"
 #include "search.h"
 #include "timeman.h"
 #include "thread.h"
@@ -43,19 +43,13 @@ namespace Search {
   std::vector<RootMove> RootMoves;
   Position RootPosition;
   Time SearchTime;
+  StateStackPtr SetupStates;
 }
 
 using std::string;
-using std::cout;
-using std::endl;
 using Eval::evaluate;
 using namespace Search;
 
-// For some reason argument-dependent lookup (ADL) doesn't work for Android's
-// STLPort, so explicitly qualify following functions.
-using std::count;
-using std::find;
-
 namespace {
 
   // Set to true to force running with one thread. Used for debugging
@@ -144,29 +138,8 @@ namespace {
   bool connected_threat(const Position& pos, Move m, Move threat);
   Value refine_eval(const TTEntry* tte, Value ttValue, Value defaultEval);
   Move do_skill_level();
-  string score_to_uci(Value v, Value alpha = -VALUE_INFINITE, Value beta = VALUE_INFINITE);
-  string pretty_pv(Position& pos, int depth, Value score, int time, Move pv[]);
   string uci_pv(const Position& pos, int depth, Value alpha, Value beta);
 
-  // MovePickerExt class template extends MovePicker and allows to choose at
-  // compile time the proper moves source according to the type of node. In the
-  // default case we simply create and use a standard MovePicker object.
-  template<bool SpNode> struct MovePickerExt : public MovePicker {
-
-    MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, Stack* ss, Value b)
-                  : MovePicker(p, ttm, d, h, ss, b) {}
-  };
-
-  // In case of a SpNode we use split point's shared MovePicker object as moves source
-  template<> struct MovePickerExt<true> : public MovePicker {
-
-    MovePickerExt(const Position& p, Move ttm, Depth d, const History& h, Stack* ss, Value b)
-                  : MovePicker(p, ttm, d, h, ss, b), mp(ss->sp->mp) {}
-
-    Move next_move() { return mp->next_move(); }
-    MovePicker* mp;
-  };
-
   // is_dangerous() checks whether a move belongs to some classes of known
   // 'dangerous' moves so that we avoid to prune it.
   FORCE_INLINE bool is_dangerous(const Position& pos, Move m, bool captureOrPromotion) {
@@ -185,7 +158,7 @@ namespace {
         &&  type_of(pos.piece_on(to_sq(m))) != PAWN
         &&  type_of(m) == NORMAL
         && (  pos.non_pawn_material(WHITE) + pos.non_pawn_material(BLACK)
-            - PieceValueMidgame[pos.piece_on(to_sq(m))] == VALUE_ZERO))
+            - PieceValue[Mg][pos.piece_on(to_sq(m))] == VALUE_ZERO))
         return true;
 
     return false;
@@ -224,24 +197,23 @@ void Search::init() {
 /// Search::perft() is our utility to verify move generation. All the leaf nodes
 /// up to the given depth are generated and counted and the sum returned.
 
-int64_t Search::perft(Position& pos, Depth depth) {
-
-  StateInfo st;
-  int64_t cnt = 0;
-
-  MoveList<LEGAL> ml(pos);
+size_t Search::perft(Position& pos, Depth depth) {
 
-  // At the last ply just return the number of moves (leaf nodes)
+  // At the last ply just return the number of legal moves (leaf nodes)
   if (depth == ONE_PLY)
-      return ml.size();
+      return MoveList<LEGAL>(pos).size();
 
+  StateInfo st;
+  size_t cnt = 0;
   CheckInfo ci(pos);
-  for ( ; !ml.end(); ++ml)
+
+  for (MoveList<LEGAL> ml(pos); !ml.end(); ++ml)
   {
       pos.do_move(ml.move(), st, ci, pos.move_gives_check(ml.move(), ci));
       cnt += perft(pos, depth - ONE_PLY);
       pos.undo_move(ml.move());
   }
+
   return cnt;
 }
 
@@ -263,8 +235,8 @@ void Search::think() {
 
   if (RootMoves.empty())
   {
-      cout << "info depth 0 score "
-           << score_to_uci(pos.in_check() ? -VALUE_MATE : VALUE_DRAW) << endl;
+      sync_cout << "info depth 0 score "
+                << score_to_uci(pos.in_check() ? -VALUE_MATE : VALUE_DRAW) << sync_endl;
 
       RootMoves.push_back(MOVE_NONE);
       goto finalize;
@@ -274,9 +246,9 @@ void Search::think() {
   {
       Move bookMove = book.probe(pos, Options["Book File"], Options["Best Book Move"]);
 
-      if (bookMove && count(RootMoves.begin(), RootMoves.end(), bookMove))
+      if (bookMove && std::count(RootMoves.begin(), RootMoves.end(), bookMove))
       {
-          std::swap(RootMoves[0], *find(RootMoves.begin(), RootMoves.end(), bookMove));
+          std::swap(RootMoves[0], *std::find(RootMoves.begin(), RootMoves.end(), bookMove));
           goto finalize;
       }
   }
@@ -298,7 +270,7 @@ void Search::think() {
           << " time: "        << Limits.time[pos.side_to_move()]
           << " increment: "   << Limits.inc[pos.side_to_move()]
           << " moves to go: " << Limits.movestogo
-          << endl;
+          << std::endl;
   }
 
   Threads.wake_up();
@@ -327,7 +299,7 @@ void Search::think() {
 
       StateInfo st;
       pos.do_move(RootMoves[0].pv[0], st);
-      log << "\nPonder move: " << move_to_san(pos, RootMoves[0].pv[1]) << endl;
+      log << "\nPonder move: " << move_to_san(pos, RootMoves[0].pv[1]) << std::endl;
       pos.undo_move(RootMoves[0].pv[0]);
   }
 
@@ -340,8 +312,8 @@ finalize:
       pos.this_thread()->wait_for_stop_or_ponderhit();
 
   // Best move could be MOVE_NONE when searching on a stalemate position
-  cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], Chess960)
-       << " ponder "  << move_to_uci(RootMoves[0].pv[1], Chess960) << endl;
+  sync_cout << "bestmove " << move_to_uci(RootMoves[0].pv[0], Chess960)
+            << " ponder "  << move_to_uci(RootMoves[0].pv[1], Chess960) << sync_endl;
 }
 
 
@@ -427,7 +399,7 @@ namespace {
                 // Send full PV info to GUI if we are going to leave the loop or
                 // if we have a fail high/low and we are deep in the search.
                 if ((bestValue > alpha && bestValue < beta) || SearchTime.elapsed() > 2000)
-                    cout << uci_pv(pos, depth, alpha, beta) << endl;
+                    sync_cout << uci_pv(pos, depth, alpha, beta) << sync_endl;
 
                 // In case of failing high/low increase aspiration window and
                 // research, otherwise exit the fail high/low loop.
@@ -460,7 +432,7 @@ namespace {
         {
             Log log(Options["Search Log Filename"]);
             log << pretty_pv(pos, depth, bestValue, SearchTime.elapsed(), &RootMoves[0].pv[0])
-                << endl;
+                << std::endl;
         }
 
         // Filter out startup noise when monitoring best move stability
@@ -517,7 +489,7 @@ namespace {
         if (skillBest == MOVE_NONE) // Still unassigned ?
             skillBest = do_skill_level();
 
-        std::swap(RootMoves[0], *find(RootMoves.begin(), RootMoves.end(), skillBest));
+        std::swap(RootMoves[0], *std::find(RootMoves.begin(), RootMoves.end(), skillBest));
     }
   }
 
@@ -715,7 +687,7 @@ namespace {
         Depth R = 3 * ONE_PLY + depth / 4;
 
         // Null move dynamic reduction based on value
-        if (refinedValue - PawnValueMidgame > beta)
+        if (refinedValue - PawnValueMg > beta)
             R += ONE_PLY;
 
         pos.do_null_move<true>(st);
@@ -781,7 +753,7 @@ namespace {
         MovePicker mp(pos, ttMove, H, pos.captured_piece_type());
         CheckInfo ci(pos);
 
-        while ((move = mp.next_move()) != MOVE_NONE)
+        while ((move = mp.next_move<false>()) != MOVE_NONE)
             if (pos.pl_move_is_legal(move, ci.pinned))
             {
                 ss->currentMove = move;
@@ -810,7 +782,7 @@ namespace {
 
 split_point_start: // At split points actual search starts from here
 
-    MovePickerExt<SpNode> mp(pos, ttMove, depth, H, ss, PvNode ? -VALUE_INFINITE : beta);
+    MovePicker mp(pos, ttMove, depth, H, ss, PvNode ? -VALUE_INFINITE : beta);
     CheckInfo ci(pos);
     futilityBase = ss->eval + ss->evalMargin;
     singularExtensionNode =   !RootNode
@@ -824,7 +796,7 @@ split_point_start: // At split points actual search starts from here
     // Step 11. Loop through moves
     // Loop through all pseudo-legal moves until no moves remain or a beta cutoff occurs
     while (    bestValue < beta
-           && (move = mp.next_move()) != MOVE_NONE
+           && (move = mp.next_move<SpNode>()) != MOVE_NONE
            && !thisThread->cutoff_occurred()
            && !Signals.stop)
     {
@@ -836,7 +808,7 @@ split_point_start: // At split points actual search starts from here
       // At root obey the "searchmoves" option and skip moves not listed in Root
       // Move List, as a consequence any illegal move is also skipped. In MultiPV
       // mode we also skip PV moves which have been already searched.
-      if (RootNode && !count(RootMoves.begin() + PVIdx, RootMoves.end(), move))
+      if (RootNode && !std::count(RootMoves.begin() + PVIdx, RootMoves.end(), move))
           continue;
 
       // At PV and SpNode nodes we want all moves to be legal since the beginning
@@ -846,7 +818,7 @@ split_point_start: // At split points actual search starts from here
       if (SpNode)
       {
           moveCount = ++sp->moveCount;
-          lock_release(sp->lock);
+          sp->mutex.unlock();
       }
       else
           moveCount++;
@@ -856,9 +828,9 @@ split_point_start: // At split points actual search starts from here
           Signals.firstRootMove = (moveCount == 1);
 
           if (thisThread == Threads.main_thread() && SearchTime.elapsed() > 2000)
-              cout << "info depth " << depth / ONE_PLY
-                   << " currmove " << move_to_uci(move, Chess960)
-                   << " currmovenumber " << moveCount + PVIdx << endl;
+              sync_cout << "info depth " << depth / ONE_PLY
+                        << " currmove " << move_to_uci(move, Chess960)
+                        << " currmovenumber " << moveCount + PVIdx << sync_endl;
       }
 
       isPvMove = (PvNode && moveCount <= 1);
@@ -912,7 +884,7 @@ split_point_start: // At split points actual search starts from here
               && (!threatMove || !connected_threat(pos, move, threatMove)))
           {
               if (SpNode)
-                  lock_grab(sp->lock);
+                  sp->mutex.lock();
 
               continue;
           }
@@ -927,7 +899,7 @@ split_point_start: // At split points actual search starts from here
           if (futilityValue < beta)
           {
               if (SpNode)
-                  lock_grab(sp->lock);
+                  sp->mutex.lock();
 
               continue;
           }
@@ -937,7 +909,7 @@ split_point_start: // At split points actual search starts from here
               && pos.see_sign(move) < 0)
           {
               if (SpNode)
-                  lock_grab(sp->lock);
+                  sp->mutex.lock();
 
               continue;
           }
@@ -1001,7 +973,7 @@ split_point_start: // At split points actual search starts from here
       // Step 18. Check for new best move
       if (SpNode)
       {
-          lock_grab(sp->lock);
+          sp->mutex.lock();
           bestValue = sp->bestValue;
           alpha = sp->alpha;
       }
@@ -1012,7 +984,7 @@ split_point_start: // At split points actual search starts from here
       // be trusted, and we don't update the best move and/or PV.
       if (RootNode && !Signals.stop)
       {
-          RootMove& rm = *find(RootMoves.begin(), RootMoves.end(), move);
+          RootMove& rm = *std::find(RootMoves.begin(), RootMoves.end(), move);
 
           // PV move or new best move ?
           if (isPvMove || value > alpha)
@@ -1203,7 +1175,7 @@ split_point_start: // At split points actual search starts from here
             alpha = bestValue;
 
         futilityBase = ss->eval + evalMargin + FutilityMarginQS;
-        enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMidgame;
+        enoughMaterial = pos.non_pawn_material(pos.side_to_move()) > RookValueMg;
     }
 
     // Initialize a MovePicker object for the current position, and prepare
@@ -1215,7 +1187,7 @@ split_point_start: // At split points actual search starts from here
 
     // Loop through the moves until no moves remain or a beta cutoff occurs
     while (   bestValue < beta
-           && (move = mp.next_move()) != MOVE_NONE)
+           && (move = mp.next_move<false>()) != MOVE_NONE)
     {
       assert(is_ok(move));
 
@@ -1231,8 +1203,8 @@ split_point_start: // At split points actual search starts from here
           && !pos.is_passed_pawn_push(move))
       {
           futilityValue =  futilityBase
-                         + PieceValueEndgame[pos.piece_on(to_sq(move))]
-                         + (type_of(move) == ENPASSANT ? PawnValueEndgame : VALUE_ZERO);
+                         + PieceValue[Eg][pos.piece_on(to_sq(move))]
+                         + (type_of(move) == ENPASSANT ? PawnValueEg : VALUE_ZERO);
 
           if (futilityValue < beta)
           {
@@ -1270,7 +1242,7 @@ split_point_start: // At split points actual search starts from here
           &&  givesCheck
           &&  move != ttMove
           && !pos.is_capture_or_promotion(move)
-          &&  ss->eval + PawnValueMidgame / 4 < beta
+          &&  ss->eval + PawnValueMg / 4 < beta
           && !check_is_dangerous(pos, move, futilityBase, beta))
           continue;
 
@@ -1355,7 +1327,7 @@ split_point_start: // At split points actual search starts from here
     while (b)
     {
         // Note that here we generate illegal "double move"!
-        if (futilityBase + PieceValueEndgame[pos.piece_on(pop_lsb(&b))] >= beta)
+        if (futilityBase + PieceValue[Eg][pos.piece_on(pop_lsb(&b))] >= beta)
             return true;
     }
 
@@ -1467,7 +1439,7 @@ split_point_start: // At split points actual search starts from here
     // Case 2: If the threatened piece has value less than or equal to the
     // value of the threatening piece, don't prune moves which defend it.
     if (   pos.is_capture(threat)
-        && (   PieceValueMidgame[pos.piece_on(tfrom)] >= PieceValueMidgame[pos.piece_on(tto)]
+        && (   PieceValue[Mg][pos.piece_on(tfrom)] >= PieceValue[Mg][pos.piece_on(tto)]
             || type_of(pos.piece_on(tfrom)) == KING)
         && pos.move_attacks_square(m, tto))
         return true;
@@ -1512,25 +1484,48 @@ split_point_start: // At split points actual search starts from here
   }
 
 
-  // score_to_uci() converts a value to a string suitable for use with the UCI
-  // protocol specifications:
-  //
-  // cp <x>     The score from the engine's point of view in centipawns.
-  // mate <y>   Mate in y moves, not plies. If the engine is getting mated
-  //            use negative values for y.
+  // When playing with strength handicap choose best move among the MultiPV set
+  // using a statistical rule dependent on SkillLevel. Idea by Heinz van Saanen.
 
-  string score_to_uci(Value v, Value alpha, Value beta) {
+  Move do_skill_level() {
 
-    std::stringstream s;
+    assert(MultiPV > 1);
 
-    if (abs(v) < VALUE_MATE_IN_MAX_PLY)
-        s << "cp " << v * 100 / int(PawnValueMidgame);
-    else
-        s << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2;
+    static RKISS rk;
 
-    s << (v >= beta ? " lowerbound" : v <= alpha ? " upperbound" : "");
+    // PRNG sequence should be not deterministic
+    for (int i = Time::current_time().msec() % 50; i > 0; i--)
+        rk.rand<unsigned>();
 
-    return s.str();
+    // RootMoves are already sorted by score in descending order
+    size_t size = std::min(MultiPV, RootMoves.size());
+    int variance = std::min(RootMoves[0].score - RootMoves[size - 1].score, PawnValueMg);
+    int weakness = 120 - 2 * SkillLevel;
+    int max_s = -VALUE_INFINITE;
+    Move best = MOVE_NONE;
+
+    // Choose best move. For each move score we add two terms both dependent on
+    // weakness, one deterministic and bigger for weaker moves, and one random,
+    // then we choose the move with the resulting highest score.
+    for (size_t i = 0; i < size; i++)
+    {
+        int s = RootMoves[i].score;
+
+        // Don't allow crazy blunders even at very low skills
+        if (i > 0 && RootMoves[i-1].score > s + EasyMoveMargin)
+            break;
+
+        // This is our magic formula
+        s += (  weakness * int(RootMoves[0].score - s)
+              + variance * (rk.rand<unsigned>() % weakness)) / 128;
+
+        if (s > max_s)
+        {
+            max_s = s;
+            best = RootMoves[i].pv[0];
+        }
+    }
+    return best;
   }
 
 
@@ -1544,7 +1539,7 @@ split_point_start: // At split points actual search starts from here
     int t = SearchTime.elapsed();
     int selDepth = 0;
 
-    for (int i = 0; i < Threads.size(); i++)
+    for (size_t i = 0; i < Threads.size(); i++)
         if (Threads[i].maxPly > selDepth)
             selDepth = Threads[i].maxPly;
 
@@ -1577,141 +1572,6 @@ split_point_start: // At split points actual search starts from here
     return s.str();
   }
 
-
-  // pretty_pv() formats human-readable search information, typically to be
-  // appended to the search log file. It uses the two helpers below to pretty
-  // format time and score respectively.
-
-  string time_to_string(int millisecs) {
-
-    const int MSecMinute = 1000 * 60;
-    const int MSecHour   = 1000 * 60 * 60;
-
-    int hours = millisecs / MSecHour;
-    int minutes =  (millisecs % MSecHour) / MSecMinute;
-    int seconds = ((millisecs % MSecHour) % MSecMinute) / 1000;
-
-    std::stringstream s;
-
-    if (hours)
-        s << hours << ':';
-
-    s << std::setfill('0') << std::setw(2) << minutes << ':'
-                           << std::setw(2) << seconds;
-    return s.str();
-  }
-
-  string score_to_string(Value v) {
-
-    std::stringstream s;
-
-    if (v >= VALUE_MATE_IN_MAX_PLY)
-        s << "#" << (VALUE_MATE - v + 1) / 2;
-
-    else if (v <= VALUE_MATED_IN_MAX_PLY)
-        s << "-#" << (VALUE_MATE + v) / 2;
-
-    else
-        s << std::setprecision(2) << std::fixed << std::showpos
-          << float(v) / PawnValueMidgame;
-
-    return s.str();
-  }
-
-  string pretty_pv(Position& pos, int depth, Value value, int time, Move pv[]) {
-
-    const int64_t K = 1000;
-    const int64_t M = 1000000;
-
-    StateInfo state[MAX_PLY_PLUS_2], *st = state;
-    Move* m = pv;
-    string san, padding;
-    size_t length;
-    std::stringstream s;
-
-    s << std::setw(2) << depth
-      << std::setw(8) << score_to_string(value)
-      << std::setw(8) << time_to_string(time);
-
-    if (pos.nodes_searched() < M)
-        s << std::setw(8) << pos.nodes_searched() / 1 << "  ";
-
-    else if (pos.nodes_searched() < K * M)
-        s << std::setw(7) << pos.nodes_searched() / K << "K  ";
-
-    else
-        s << std::setw(7) << pos.nodes_searched() / M << "M  ";
-
-    padding = string(s.str().length(), ' ');
-    length = padding.length();
-
-    while (*m != MOVE_NONE)
-    {
-        san = move_to_san(pos, *m);
-
-        if (length + san.length() > 80)
-        {
-            s << "\n" + padding;
-            length = padding.length();
-        }
-
-        s << san << ' ';
-        length += san.length() + 1;
-
-        pos.do_move(*m++, *st++);
-    }
-
-    while (m != pv)
-        pos.undo_move(*--m);
-
-    return s.str();
-  }
-
-
-  // When playing with strength handicap choose best move among the MultiPV set
-  // using a statistical rule dependent on SkillLevel. Idea by Heinz van Saanen.
-
-  Move do_skill_level() {
-
-    assert(MultiPV > 1);
-
-    static RKISS rk;
-
-    // PRNG sequence should be not deterministic
-    for (int i = Time::current_time().msec() % 50; i > 0; i--)
-        rk.rand<unsigned>();
-
-    // RootMoves are already sorted by score in descending order
-    size_t size = std::min(MultiPV, RootMoves.size());
-    int variance = std::min(RootMoves[0].score - RootMoves[size - 1].score, PawnValueMidgame);
-    int weakness = 120 - 2 * SkillLevel;
-    int max_s = -VALUE_INFINITE;
-    Move best = MOVE_NONE;
-
-    // Choose best move. For each move score we add two terms both dependent on
-    // weakness, one deterministic and bigger for weaker moves, and one random,
-    // then we choose the move with the resulting highest score.
-    for (size_t i = 0; i < size; i++)
-    {
-        int s = RootMoves[i].score;
-
-        // Don't allow crazy blunders even at very low skills
-        if (i > 0 && RootMoves[i-1].score > s + EasyMoveMargin)
-            break;
-
-        // This is our magic formula
-        s += (  weakness * int(RootMoves[0].score - s)
-              + variance * (rk.rand<unsigned>() % weakness)) / 128;
-
-        if (s > max_s)
-        {
-            max_s = s;
-            best = RootMoves[i].pv[0];
-        }
-    }
-    return best;
-  }
-
 } // namespace
 
 
@@ -1782,11 +1642,15 @@ void RootMove::insert_pv_in_tt(Position& pos) {
 }
 
 
-/// Thread::idle_loop() is where the thread is parked when it has no work to do.
-/// The parameter 'master_sp', if non-NULL, is a pointer to an active SplitPoint
-/// object for which the thread is the master.
+/// Thread::idle_loop() is where the thread is parked when it has no work to do
 
-void Thread::idle_loop(SplitPoint* sp_master) {
+void Thread::idle_loop() {
+
+  // Pointer 'sp_master', if non-NULL, points to the active SplitPoint
+  // object for which the thread is the master.
+  const SplitPoint* sp_master = splitPointsCnt ? curSplitPoint : NULL;
+
+  assert(!sp_master || (sp_master->master == this && is_searching));
 
   // If this thread is the master of a split point and all slaves have
   // finished their work at this split point, return from the idle loop.
@@ -1805,12 +1669,12 @@ void Thread::idle_loop(SplitPoint* sp_master) {
           }
 
           // Grab the lock to avoid races with Thread::wake_up()
-          lock_grab(sleepLock);
+          mutex.lock();
 
           // If we are master and all slaves have finished don't go to sleep
           if (sp_master && !sp_master->slavesMask)
           {
-              lock_release(sleepLock);
+              mutex.unlock();
               break;
           }
 
@@ -1819,9 +1683,9 @@ void Thread::idle_loop(SplitPoint* sp_master) {
           // in the meanwhile, allocated us and sent the wake_up() call before we
           // had the chance to grab the lock.
           if (do_sleep || !is_searching)
-              cond_wait(sleepCond, sleepLock);
+              sleepCondition.wait(mutex);
 
-          lock_release(sleepLock);
+          mutex.unlock();
       }
 
       // If this thread has been assigned work, launch a search
@@ -1829,12 +1693,12 @@ void Thread::idle_loop(SplitPoint* sp_master) {
       {
           assert(!do_sleep && !do_exit);
 
-          lock_grab(Threads.splitLock);
+          Threads.mutex.lock();
 
           assert(is_searching);
           SplitPoint* sp = curSplitPoint;
 
-          lock_release(Threads.splitLock);
+          Threads.mutex.unlock();
 
           Stack ss[MAX_PLY_PLUS_2];
           Position pos(*sp->pos, this);
@@ -1842,7 +1706,7 @@ void Thread::idle_loop(SplitPoint* sp_master) {
           memcpy(ss, sp->ss - 1, 4 * sizeof(Stack));
           (ss+1)->sp = sp;
 
-          lock_grab(sp->lock);
+          sp->mutex.lock();
 
           if (sp->nodeType == Root)
               search<SplitPointRoot>(pos, ss+1, sp->alpha, sp->beta, sp->depth);
@@ -1863,14 +1727,17 @@ void Thread::idle_loop(SplitPoint* sp_master) {
           // case we are the last slave of the split point.
           if (    Threads.use_sleeping_threads()
               &&  this != sp->master
-              && !sp->master->is_searching)
+              && !sp->slavesMask)
+          {
+              assert(!sp->master->is_searching);
               sp->master->wake_up();
+          }
 
           // After releasing the lock we cannot access anymore any SplitPoint
           // related data in a safe way becuase it could have been released under
           // our feet by the sp master. Also accessing other Thread objects is
           // unsafe because if we are exiting there is a chance are already freed.
-          lock_release(sp->lock);
+          sp->mutex.unlock();
       }
   }
 }
@@ -1886,7 +1753,7 @@ void check_time() {
 
   if (lastInfoTime.elapsed() >= 1000)
   {
-      lastInfoTime.restart();
+      lastInfoTime = Time::current_time();
       dbg_print();
   }