X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=902049c351205e8f32405f999f978d8c21ef35e1;hp=07700c6c2dd6cbdd27dd0a48cf985e0f4ddf74aa;hb=8bf9dc825420bddb6d8425352e53a97a285027ec;hpb=54f1c383d36f461a740eeaa93856b408e8d3faa3 diff --git a/src/search.cpp b/src/search.cpp index 07700c6c..902049c3 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -64,6 +64,7 @@ namespace { static storage duration are automatically set to zero before enter main() */ public: + Thread& operator[](int threadID) { return threads[threadID]; } void init_threads(); void exit_threads(); @@ -75,22 +76,19 @@ namespace { bool available_thread_exists(int master) const; bool thread_is_available(int slave, int master) const; bool cutoff_at_splitpoint(int threadID) const; - void wake_sleeping_thread(int threadID); void idle_loop(int threadID, SplitPoint* sp); template - void split(Position& pos, SearchStack* ss, int ply, Value* alpha, const Value beta, Value* bestValue, + void split(Position& pos, SearchStack* ss, Value* alpha, const Value beta, Value* bestValue, Depth depth, Move threatMove, int moveCount, MovePicker* mp, bool pvNode); - private: + Lock mpLock; Depth minimumSplitDepth; int maxThreadsPerSplitPoint; bool useSleepingThreads; int activeThreads; volatile bool allThreadsShouldExit; Thread threads[MAX_THREADS]; - Lock mpLock, sleepLock[MAX_THREADS]; - WaitCondition sleepCond[MAX_THREADS]; }; @@ -118,7 +116,7 @@ namespace { void extract_pv_from_tt(Position& pos); void insert_pv_in_tt(Position& pos); - std::string pv_info_to_uci(Position& pos, int depth, Value alpha, Value beta, int pvIdx); + std::string pv_info_to_uci(Position& pos, int depth, int selDepth, Value alpha, Value beta, int pvIdx); int64_t nodes; Value pv_score; @@ -216,7 +214,7 @@ namespace { int8_t ReductionMatrix[2][64][64]; // [pv][depth][moveNumber] template - inline Depth reduction(Depth d, int mn) { return (Depth) ReductionMatrix[PV][Min(d / 2, 63)][Min(mn, 63)]; } + inline Depth reduction(Depth d, int mn) { return (Depth) ReductionMatrix[PV][Min(d / ONE_PLY, 63)][Min(mn, 63)]; } // Easy move margin. An easy move candidate must be at least this much // better than the second best move. @@ -235,7 +233,7 @@ namespace { int MultiPV, UCIMultiPV; // Time management variables - int SearchStartTime, MaxNodes, MaxDepth, ExactMaxTime; + int MaxNodes, MaxDepth, ExactMaxTime; bool UseTimeManagement, InfiniteSearch, Pondering, StopOnPonderhit; bool FirstRootMove, StopRequest, QuitRequest, AspirationFailLow; TimeManager TimeMgr; @@ -267,16 +265,16 @@ namespace { Move id_loop(Position& pos, Move searchMoves[], Move* ponderMove); template - Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply); + Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth); template - Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply); + Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth); template - inline Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply) { + inline Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth) { - return depth < ONE_PLY ? qsearch(pos, ss, alpha, beta, DEPTH_ZERO, ply) - : search(pos, ss, alpha, beta, depth, ply); + return depth < ONE_PLY ? qsearch(pos, ss, alpha, beta, DEPTH_ZERO) + : search(pos, ss, alpha, beta, depth); } template @@ -293,7 +291,7 @@ namespace { void update_gains(const Position& pos, Move move, Value before, Value after); void do_skill_level(Move* best, Move* ponder); - int current_search_time(); + int current_search_time(int set = 0); std::string value_to_uci(Value v); std::string speed_to_uci(int64_t nodes); void poll(const Position& pos); @@ -450,7 +448,7 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[ // Initialize global search-related variables StopOnPonderhit = StopRequest = QuitRequest = AspirationFailLow = SendSearchedNodes = false; NodesSincePoll = 0; - SearchStartTime = get_system_time(); + current_search_time(get_system_time()); ExactMaxTime = maxTime; MaxDepth = maxDepth; MaxNodes = maxNodes; @@ -506,9 +504,12 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[ ThreadsMgr.read_uci_options(); init_eval(ThreadsMgr.active_threads()); - // Wake up needed threads. Main thread, with threadID == 0, is always active - for (int i = 1; i < ThreadsMgr.active_threads(); i++) - ThreadsMgr.wake_sleeping_thread(i); + // Wake up needed threads and reset maxPly counter + for (int i = 0; i < ThreadsMgr.active_threads(); i++) + { + ThreadsMgr[i].wake_up(); + ThreadsMgr[i].maxPly = 0; + } // Set thinking time int myTime = time[pos.side_to_move()]; @@ -596,7 +597,7 @@ namespace { SearchStack ss[PLY_MAX_PLUS_2]; Value bestValues[PLY_MAX_PLUS_2]; int bestMoveChanges[PLY_MAX_PLUS_2]; - int depth, aspirationDelta, skillSamplingDepth; + int depth, selDepth, aspirationDelta; Value value, alpha, beta; Move bestMove, easyMove, skillBest, skillPonder; @@ -605,7 +606,7 @@ namespace { TT.new_search(); H.clear(); *ponderMove = bestMove = easyMove = skillBest = skillPonder = MOVE_NONE; - depth = aspirationDelta = skillSamplingDepth = 0; + depth = aspirationDelta = 0; alpha = -VALUE_INFINITE, beta = VALUE_INFINITE; ss->currentMove = MOVE_NULL; // Hack to skip update_gains() @@ -622,11 +623,6 @@ namespace { return MOVE_NONE; } - // Choose a random sampling depth according to SkillLevel so that at low - // skills there is an higher risk to pick up a blunder. - if (SkillLevelEnabled) - skillSamplingDepth = 4 + SkillLevel + (RK.rand() % 4); - // Iterative deepening loop while (++depth <= PLY_MAX && (!MaxDepth || depth <= MaxDepth) && !StopRequest) { @@ -650,7 +646,7 @@ namespace { // research with bigger window until not failing high/low anymore. do { // Search starting from ss+1 to allow calling update_gains() - value = search(pos, ss+1, alpha, beta, depth * ONE_PLY, 0); + value = search(pos, ss+1, alpha, beta, depth * ONE_PLY); // Write PV back to transposition table in case the relevant entries // have been overwritten during the search. @@ -690,12 +686,18 @@ namespace { bestMoveChanges[depth] = Rml.bestMoveChanges; // Do we need to pick now the best and the ponder moves ? - if (SkillLevelEnabled && depth == skillSamplingDepth) + if (SkillLevelEnabled && depth == 1 + SkillLevel) do_skill_level(&skillBest, &skillPonder); + // Retrieve max searched depth among threads + selDepth = 0; + for (int i = 0; i < ThreadsMgr.active_threads(); i++) + if (ThreadsMgr[i].maxPly > selDepth) + selDepth = ThreadsMgr[i].maxPly; + // Send PV line to GUI and to log file for (int i = 0; i < Min(UCIMultiPV, (int)Rml.size()); i++) - cout << Rml[i].pv_info_to_uci(pos, depth, alpha, beta, i) << endl; + cout << Rml[i].pv_info_to_uci(pos, depth, selDepth, alpha, beta, i) << endl; if (UseLogFile) LogFile << pretty_pv(pos, depth, value, current_search_time(), Rml[0].pv) << endl; @@ -771,12 +773,11 @@ namespace { // here: This is taken care of after we return from the split point. template - Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply) { + Value search(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth) { assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE); assert(beta > alpha && beta <= VALUE_INFINITE); assert(PvNode || alpha == beta - 1); - assert((Root || ply > 0) && ply < PLY_MAX); assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads()); Move movesSearched[MOVES_MAX]; @@ -797,6 +798,11 @@ namespace { refinedValue = bestValue = value = -VALUE_INFINITE; oldAlpha = alpha; isCheck = pos.is_check(); + ss->ply = (ss-1)->ply + 1; + + // Used to send selDepth info to GUI + if (PvNode && ThreadsMgr[threadID].maxPly < ss->ply) + ThreadsMgr[threadID].maxPly = ss->ply; if (SpNode) { @@ -824,12 +830,12 @@ namespace { if (( StopRequest || ThreadsMgr.cutoff_at_splitpoint(threadID) || pos.is_draw() - || ply >= PLY_MAX - 1) && !Root) + || ss->ply > PLY_MAX) && !Root) return VALUE_DRAW; // Step 3. Mate distance pruning - alpha = Max(value_mated_in(ply), alpha); - beta = Min(value_mate_in(ply+1), beta); + alpha = Max(value_mated_in(ss->ply), alpha); + beta = Min(value_mate_in(ss->ply+1), beta); if (alpha >= beta) return alpha; @@ -848,11 +854,11 @@ namespace { if ( !Root && tte && (PvNode ? tte->depth() >= depth && tte->type() == VALUE_TYPE_EXACT - : ok_to_use_TT(tte, depth, beta, ply))) + : ok_to_use_TT(tte, depth, beta, ss->ply))) { TT.refresh(tte); ss->bestMove = ttMove; // Can be MOVE_NONE - return value_from_tt(tte->value(), ply); + return value_from_tt(tte->value(), ss->ply); } // Step 5. Evaluate the position statically and update parent's gain statistics @@ -864,7 +870,7 @@ namespace { ss->eval = tte->static_value(); ss->evalMargin = tte->static_value_margin(); - refinedValue = refine_eval(tte, ss->eval, ply); + refinedValue = refine_eval(tte, ss->eval, ss->ply); } else { @@ -885,7 +891,7 @@ namespace { && !pos.has_pawn_on_7th(pos.side_to_move())) { Value rbeta = beta - razor_margin(depth); - Value v = qsearch(pos, ss, rbeta-1, rbeta, DEPTH_ZERO, ply); + Value v = qsearch(pos, ss, rbeta-1, rbeta, DEPTH_ZERO); if (v < rbeta) // Logically we should return (v + razor_margin(depth)), but // surprisingly this did slightly weaker in tests. @@ -924,7 +930,7 @@ namespace { pos.do_null_move(st); (ss+1)->skipNullMove = true; - nullValue = -search(pos, ss+1, -beta, -alpha, depth-R*ONE_PLY, ply+1); + nullValue = -search(pos, ss+1, -beta, -alpha, depth-R*ONE_PLY); (ss+1)->skipNullMove = false; pos.undo_null_move(); @@ -939,7 +945,7 @@ namespace { // Do verification search at high depths ss->skipNullMove = true; - Value v = search(pos, ss, alpha, beta, depth-R*ONE_PLY, ply); + Value v = search(pos, ss, alpha, beta, depth-R*ONE_PLY); ss->skipNullMove = false; if (v >= beta) @@ -971,7 +977,7 @@ namespace { Depth d = (PvNode ? depth - 2 * ONE_PLY : depth / 2); ss->skipNullMove = true; - search(pos, ss, alpha, beta, d, ply); + search(pos, ss, alpha, beta, d); ss->skipNullMove = false; ttMove = ss->bestMove; @@ -1055,14 +1061,14 @@ split_point_start: // At split points actual search starts from here && move == tte->move() && ext < ONE_PLY) { - Value ttValue = value_from_tt(tte->value(), ply); + Value ttValue = value_from_tt(tte->value(), ss->ply); if (abs(ttValue) < VALUE_KNOWN_WIN) { Value rBeta = ttValue - int(depth); ss->excludedMove = move; ss->skipNullMove = true; - Value v = search(pos, ss, rBeta - 1, rBeta, depth / 2, ply); + Value v = search(pos, ss, rBeta - 1, rBeta, depth / 2); ss->skipNullMove = false; ss->excludedMove = MOVE_NONE; ss->bestMove = MOVE_NONE; @@ -1151,7 +1157,7 @@ split_point_start: // At split points actual search starts from here if (Root && MultiPV > 1) alpha = -VALUE_INFINITE; - value = -search(pos, ss+1, -beta, -alpha, newDepth, ply+1); + value = -search(pos, ss+1, -beta, -alpha, newDepth); } else { @@ -1172,7 +1178,7 @@ split_point_start: // At split points actual search starts from here { alpha = SpNode ? sp->alpha : alpha; Depth d = newDepth - ss->reduction; - value = -search(pos, ss+1, -(alpha+1), -alpha, d, ply+1); + value = -search(pos, ss+1, -(alpha+1), -alpha, d); doFullDepthSearch = (value > alpha); } @@ -1186,7 +1192,7 @@ split_point_start: // At split points actual search starts from here ss->reduction = 3 * ONE_PLY; Value rAlpha = alpha - 300; Depth d = newDepth - ss->reduction; - value = -search(pos, ss+1, -(rAlpha+1), -rAlpha, d, ply+1); + value = -search(pos, ss+1, -(rAlpha+1), -rAlpha, d); doFullDepthSearch = (value > rAlpha); ss->reduction = DEPTH_ZERO; // Restore original reduction } @@ -1195,13 +1201,13 @@ split_point_start: // At split points actual search starts from here if (doFullDepthSearch) { alpha = SpNode ? sp->alpha : alpha; - value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth, ply+1); + value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth); // Step extra. pv search (only in PV nodes) // Search only for possible new PV nodes, if instead value >= beta then // parent node fails low with value <= alpha and tries another move. if (PvNode && value > alpha && (Root || value < beta)) - value = -search(pos, ss+1, -beta, -alpha, newDepth, ply+1); + value = -search(pos, ss+1, -beta, -alpha, newDepth); } } @@ -1237,7 +1243,7 @@ split_point_start: // At split points actual search starts from here else if (SpNode) sp->betaCutoff = true; - if (value == value_mate_in(ply + 1)) + if (value == value_mate_in(ss->ply + 1)) ss->mateKiller = move; ss->bestMove = move; @@ -1297,7 +1303,7 @@ split_point_start: // At split points actual search starts from here && ThreadsMgr.available_thread_exists(threadID) && !StopRequest && !ThreadsMgr.cutoff_at_splitpoint(threadID)) - ThreadsMgr.split(pos, ss, ply, &alpha, beta, &bestValue, depth, + ThreadsMgr.split(pos, ss, &alpha, beta, &bestValue, depth, threatMove, moveCount, &mp, PvNode); } @@ -1306,7 +1312,7 @@ split_point_start: // At split points actual search starts from here // no legal moves, it must be mate or stalemate. // If one move was excluded return fail low score. if (!SpNode && !moveCount) - return excludedMove ? oldAlpha : isCheck ? value_mated_in(ply) : VALUE_DRAW; + return excludedMove ? oldAlpha : isCheck ? value_mated_in(ss->ply) : VALUE_DRAW; // Step 20. Update tables // If the search is not aborted, update the transposition table, @@ -1317,7 +1323,7 @@ split_point_start: // At split points actual search starts from here vt = bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT; - TT.store(posKey, value_to_tt(bestValue, ply), vt, depth, move, ss->eval, ss->evalMargin); + TT.store(posKey, value_to_tt(bestValue, ss->ply), vt, depth, move, ss->eval, ss->evalMargin); // Update killers and history only for non capture moves that fails high if ( bestValue >= beta @@ -1350,13 +1356,12 @@ split_point_start: // At split points actual search starts from here // less than ONE_PLY). template - Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth, int ply) { + Value qsearch(Position& pos, SearchStack* ss, Value alpha, Value beta, Depth depth) { assert(alpha >= -VALUE_INFINITE && alpha <= VALUE_INFINITE); assert(beta >= -VALUE_INFINITE && beta <= VALUE_INFINITE); assert(PvNode || alpha == beta - 1); assert(depth <= 0); - assert(ply > 0 && ply < PLY_MAX); assert(pos.thread() >= 0 && pos.thread() < ThreadsMgr.active_threads()); StateInfo st; @@ -1368,9 +1373,10 @@ split_point_start: // At split points actual search starts from here Value oldAlpha = alpha; ss->bestMove = ss->currentMove = MOVE_NONE; + ss->ply = (ss-1)->ply + 1; // Check for an instant draw or maximum ply reached - if (pos.is_draw() || ply >= PLY_MAX - 1) + if (ss->ply > PLY_MAX || pos.is_draw()) return VALUE_DRAW; // Decide whether or not to include checks, this fixes also the type of @@ -1384,10 +1390,10 @@ split_point_start: // At split points actual search starts from here tte = TT.retrieve(pos.get_key()); ttMove = (tte ? tte->move() : MOVE_NONE); - if (!PvNode && tte && ok_to_use_TT(tte, ttDepth, beta, ply)) + if (!PvNode && tte && ok_to_use_TT(tte, ttDepth, beta, ss->ply)) { ss->bestMove = ttMove; // Can be MOVE_NONE - return value_from_tt(tte->value(), ply); + return value_from_tt(tte->value(), ss->ply); } // Evaluate the position statically @@ -1415,7 +1421,7 @@ split_point_start: // At split points actual search starts from here if (bestValue >= beta) { if (!tte) - TT.store(pos.get_key(), value_to_tt(bestValue, ply), VALUE_TYPE_LOWER, DEPTH_NONE, MOVE_NONE, ss->eval, evalMargin); + TT.store(pos.get_key(), value_to_tt(bestValue, ss->ply), VALUE_TYPE_LOWER, DEPTH_NONE, MOVE_NONE, ss->eval, evalMargin); return bestValue; } @@ -1504,7 +1510,7 @@ split_point_start: // At split points actual search starts from here // Make and search the move pos.do_move(move, st, ci, moveIsCheck); - value = -qsearch(pos, ss+1, -beta, -alpha, depth-ONE_PLY, ply+1); + value = -qsearch(pos, ss+1, -beta, -alpha, depth-ONE_PLY); pos.undo_move(move); assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); @@ -1524,11 +1530,11 @@ split_point_start: // At split points actual search starts from here // All legal moves have been searched. A special case: If we're in check // and no legal moves were found, it is checkmate. if (isCheck && bestValue == -VALUE_INFINITE) - return value_mated_in(ply); + return value_mated_in(ss->ply); // Update transposition table ValueType vt = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT); - TT.store(pos.get_key(), value_to_tt(bestValue, ply), vt, ttDepth, ss->bestMove, ss->eval, evalMargin); + TT.store(pos.get_key(), value_to_tt(bestValue, ss->ply), vt, ttDepth, ss->bestMove, ss->eval, evalMargin); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); @@ -1837,9 +1843,14 @@ split_point_start: // At split points actual search starts from here // current_search_time() returns the number of milliseconds which have passed // since the beginning of the current search. - int current_search_time() { + int current_search_time(int set) { + + static int searchStartTime; + + if (set) + searchStartTime = set; - return get_system_time() - SearchStartTime; + return get_system_time() - searchStartTime; } @@ -1855,9 +1866,9 @@ split_point_start: // At split points actual search starts from here std::stringstream s; if (abs(v) < VALUE_MATE - PLY_MAX * ONE_PLY) - s << "cp " << int(v) * 100 / int(PawnValueMidgame); // Scale to centipawns + s << "cp " << int(v) * 100 / int(PawnValueMidgame); // Scale to centipawns else - s << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; + s << "mate " << (v > 0 ? VALUE_MATE - v + 1 : -VALUE_MATE - v) / 2; return s.str(); } @@ -1933,11 +1944,8 @@ split_point_start: // At split points actual search starts from here { lastInfoTime = t; - if (dbg_show_mean) - dbg_print_mean(); - - if (dbg_show_hit_rate) - dbg_print_hit_rate(); + dbg_print_mean(); + dbg_print_hit_rate(); // Send info on searched nodes as soon as we return to root SendSearchedNodes = true; @@ -2030,7 +2038,7 @@ split_point_start: // At split points actual search starts from here assert(threadID >= 0 && threadID < MAX_THREADS); int i; - bool allFinished = false; + bool allFinished; while (true) { @@ -2045,7 +2053,8 @@ split_point_start: // At split points actual search starts from here // If we are not thinking, wait for a condition to be signaled // instead of wasting CPU time polling for work. - while ( threadID >= activeThreads || threads[threadID].state == THREAD_INITIALIZING + while ( threadID >= activeThreads + || threads[threadID].state == THREAD_INITIALIZING || (useSleepingThreads && threads[threadID].state == THREAD_AVAILABLE)) { assert(!sp || useSleepingThreads); @@ -2054,8 +2063,8 @@ split_point_start: // At split points actual search starts from here if (threads[threadID].state == THREAD_INITIALIZING) threads[threadID].state = THREAD_AVAILABLE; - // Grab the lock to avoid races with wake_sleeping_thread() - lock_grab(&sleepLock[threadID]); + // Grab the lock to avoid races with Thread::wake_up() + lock_grab(&threads[threadID].sleepLock); // If we are master and all slaves have finished do not go to sleep for (i = 0; sp && i < activeThreads && !sp->slaves[i]; i++) {} @@ -2063,15 +2072,15 @@ split_point_start: // At split points actual search starts from here if (allFinished || allThreadsShouldExit) { - lock_release(&sleepLock[threadID]); + lock_release(&threads[threadID].sleepLock); break; } // Do sleep here after retesting sleep conditions if (threadID >= activeThreads || threads[threadID].state == THREAD_AVAILABLE) - cond_wait(&sleepCond[threadID], &sleepLock[threadID]); + cond_wait(&threads[threadID].sleepCond, &threads[threadID].sleepLock); - lock_release(&sleepLock[threadID]); + lock_release(&threads[threadID].sleepLock); } // If this thread has been assigned work, launch a search @@ -2081,7 +2090,7 @@ split_point_start: // At split points actual search starts from here threads[threadID].state = THREAD_SEARCHING; - // Copy SplitPoint position and search stack and call search() + // Copy split point position and search stack and call search() // with SplitPoint template parameter set to true. SearchStack ss[PLY_MAX_PLUS_2]; SplitPoint* tsp = threads[threadID].splitPoint; @@ -2091,9 +2100,9 @@ split_point_start: // At split points actual search starts from here (ss+1)->sp = tsp; if (tsp->pvNode) - search(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth, tsp->ply); + search(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth); else - search(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth, tsp->ply); + search(pos, ss+1, tsp->alpha, tsp->beta, tsp->depth); assert(threads[threadID].state == THREAD_SEARCHING); @@ -2101,8 +2110,10 @@ split_point_start: // At split points actual search starts from here // Wake up master thread so to allow it to return from the idle loop in // case we are the last slave of the split point. - if (useSleepingThreads && threadID != tsp->master && threads[tsp->master].state == THREAD_AVAILABLE) - wake_sleeping_thread(tsp->master); + if ( useSleepingThreads + && threadID != tsp->master + && threads[tsp->master].state == THREAD_AVAILABLE) + threads[tsp->master].wake_up(); } // If this thread is the master of a split point and all slaves have @@ -2128,41 +2139,36 @@ split_point_start: // At split points actual search starts from here } - // init_threads() is called during startup. It launches all helper threads, - // and initializes the split point stack and the global locks and condition - // objects. + // init_threads() is called during startup. Initializes locks and condition + // variables and launches all threads sending them immediately to sleep. void ThreadsManager::init_threads() { int i, arg[MAX_THREADS]; bool ok; - // Initialize global locks + // This flag is needed to properly end the threads when program exits + allThreadsShouldExit = false; + + // Threads will sent to sleep as soon as created, only main thread is kept alive + activeThreads = 1; + lock_init(&mpLock); for (i = 0; i < MAX_THREADS; i++) { - lock_init(&sleepLock[i]); - cond_init(&sleepCond[i]); - } + // Initialize thread and split point locks + lock_init(&threads[i].sleepLock); + cond_init(&threads[i].sleepCond); - // Initialize splitPoints[] locks - for (i = 0; i < MAX_THREADS; i++) for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++) lock_init(&(threads[i].splitPoints[j].lock)); - // Will be set just before program exits to properly end the threads - allThreadsShouldExit = false; - - // Threads will be put all threads to sleep as soon as created - activeThreads = 1; - - // All threads except the main thread should be initialized to THREAD_INITIALIZING - threads[0].state = THREAD_SEARCHING; - for (i = 1; i < MAX_THREADS; i++) - threads[i].state = THREAD_INITIALIZING; + // All threads but first should be set to THREAD_INITIALIZING + threads[i].state = (i == 0 ? THREAD_SEARCHING : THREAD_INITIALIZING); + } - // Launch the helper threads + // Create and startup the threads for (i = 1; i < MAX_THREADS; i++) { arg[i] = i; @@ -2191,28 +2197,27 @@ split_point_start: // At split points actual search starts from here void ThreadsManager::exit_threads() { - allThreadsShouldExit = true; // Let the woken up threads to exit idle_loop() + // Force the woken up threads to exit idle_loop() and hence terminate + allThreadsShouldExit = true; - // Wake up all the threads and waits for termination - for (int i = 1; i < MAX_THREADS; i++) + for (int i = 0; i < MAX_THREADS; i++) { - wake_sleeping_thread(i); - while (threads[i].state != THREAD_TERMINATED) {} - } + // Wake up all the threads and waits for termination + if (i != 0) + { + threads[i].wake_up(); + while (threads[i].state != THREAD_TERMINATED) {} + } + + // Now we can safely destroy the locks and wait conditions + lock_destroy(&threads[i].sleepLock); + cond_destroy(&threads[i].sleepCond); - // Now we can safely destroy the locks - for (int i = 0; i < MAX_THREADS; i++) for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++) lock_destroy(&(threads[i].splitPoints[j].lock)); + } lock_destroy(&mpLock); - - // Now we can safely destroy the wait conditions - for (int i = 0; i < MAX_THREADS; i++) - { - lock_destroy(&sleepLock[i]); - cond_destroy(&sleepCond[i]); - } } @@ -2292,11 +2297,10 @@ split_point_start: // At split points actual search starts from here // call search().When all threads have returned from search() then split() returns. template - void ThreadsManager::split(Position& pos, SearchStack* ss, int ply, Value* alpha, - const Value beta, Value* bestValue, Depth depth, Move threatMove, + void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const Value beta, + Value* bestValue, Depth depth, Move threatMove, int moveCount, MovePicker* mp, bool pvNode) { assert(pos.is_ok()); - assert(ply > 0 && ply < PLY_MAX); assert(*bestValue >= -VALUE_INFINITE); assert(*bestValue <= *alpha); assert(*alpha < beta); @@ -2326,7 +2330,6 @@ split_point_start: // At split points actual search starts from here splitPoint.parent = masterThread.splitPoint; splitPoint.master = master; splitPoint.betaCutoff = false; - splitPoint.ply = ply; splitPoint.depth = depth; splitPoint.threatMove = threatMove; splitPoint.alpha = *alpha; @@ -2373,7 +2376,7 @@ split_point_start: // At split points actual search starts from here threads[i].state = THREAD_WORKISWAITING; // This makes the slave to exit from idle_loop() if (useSleepingThreads && i != master) - wake_sleeping_thread(i); + threads[i].wake_up(); } // Everything is set up. The master thread enters the idle loop, from @@ -2397,17 +2400,6 @@ split_point_start: // At split points actual search starts from here } - // wake_sleeping_thread() wakes up the thread with the given threadID - // when it is time to start a new search. - - void ThreadsManager::wake_sleeping_thread(int threadID) { - - lock_grab(&sleepLock[threadID]); - cond_signal(&sleepCond[threadID]); - lock_release(&sleepLock[threadID]); - } - - /// RootMove and RootMoveList method's definitions RootMove::RootMove() { @@ -2494,21 +2486,20 @@ split_point_start: // At split points actual search starts from here // pv_info_to_uci() returns a string with information on the current PV line // formatted according to UCI specification. - std::string RootMove::pv_info_to_uci(Position& pos, int depth, Value alpha, + std::string RootMove::pv_info_to_uci(Position& pos, int depth, int selDepth, Value alpha, Value beta, int pvIdx) { - std::stringstream s, l; - Move* m = pv; - - while (*m != MOVE_NONE) - l << *m++ << " "; + std::stringstream s; s << "info depth " << depth - << " seldepth " << int(m - pv) + << " seldepth " << selDepth << " multipv " << pvIdx + 1 << " score " << value_to_uci(pv_score) << (pv_score >= beta ? " lowerbound" : pv_score <= alpha ? " upperbound" : "") << speed_to_uci(pos.nodes_searched()) - << " pv " << l.str(); + << " pv "; + + for (Move* m = pv; *m != MOVE_NONE; m++) + s << *m << " "; return s.str(); }