X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=53a99f66036f66932ccc6e01b1ade81f81b51ca3;hp=65f5a6add648b73274d2aa9ac7659d50d415a465;hb=831f91b859c43a5fa895ef0c955516ec8b7a8212;hpb=9de4ee6d329b6da4f6bda0387a8ce6918c4e5a99 diff --git a/src/search.cpp b/src/search.cpp index 65f5a6ad..53a99f66 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -43,19 +43,13 @@ namespace Search { std::vector 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 @@ -164,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; @@ -203,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 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(pos).size(); + StateInfo st; + size_t cnt = 0; CheckInfo ci(pos); - for ( ; !ml.end(); ++ml) + + for (MoveList 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; } @@ -242,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; @@ -253,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; } } @@ -277,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(); @@ -306,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]); } @@ -319,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; } @@ -406,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. @@ -439,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 @@ -496,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)); } } @@ -694,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(st); @@ -815,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 @@ -825,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++; @@ -835,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); @@ -891,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; } @@ -906,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; } @@ -916,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; } @@ -980,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; } @@ -991,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) @@ -1182,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 @@ -1210,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) { @@ -1249,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; @@ -1334,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; } @@ -1446,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; @@ -1506,7 +1499,7 @@ split_point_start: // At split points actual search starts from here // 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 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; @@ -1546,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; @@ -1649,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() { + + // 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; -void Thread::idle_loop(SplitPoint* sp_master) { + 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. @@ -1672,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; } @@ -1686,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 @@ -1696,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); @@ -1709,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(pos, ss+1, sp->alpha, sp->beta, sp->depth); @@ -1730,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(); } } } @@ -1753,7 +1753,7 @@ void check_time() { if (lastInfoTime.elapsed() >= 1000) { - lastInfoTime.restart(); + lastInfoTime = Time::current_time(); dbg_print(); }