X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=e2006425a3fefac5003f9c4865ed6ee89c2b61ef;hp=46dd53ebd1e7919bb937699d649f1996b7553939;hb=f6e11ee2a34fb074ebe588bd44a156b001d9b0d9;hpb=13d8231746686118f0175111c769b55f48a6592e diff --git a/src/search.cpp b/src/search.cpp index 46dd53eb..e2006425 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -83,7 +83,6 @@ namespace { bool thread_is_available(int slave, int master) const; bool thread_should_stop(int threadID) const; void wake_sleeping_thread(int threadID); - void put_threads_to_sleep(); void idle_loop(int threadID, SplitPoint* sp); template @@ -96,7 +95,7 @@ namespace { int ActiveThreads; volatile bool AllThreadsShouldExit; Thread threads[MAX_THREADS]; - Lock MPLock, WaitLock; + Lock MPLock; WaitCondition WaitCond[MAX_THREADS]; }; @@ -465,10 +464,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int time[], int incr init_eval(ThreadsMgr.active_threads()); } - // Wake up needed threads - for (int i = 1; i < newActiveThreads; i++) - ThreadsMgr.wake_sleeping_thread(i); - // Set thinking time int myTime = time[pos.side_to_move()]; int myIncrement = increment[pos.side_to_move()]; @@ -501,8 +496,6 @@ bool think(const Position& pos, bool infinite, bool ponder, int time[], int incr if (UseLogFile) LogFile.close(); - ThreadsMgr.put_threads_to_sleep(); - return !Quit; } @@ -707,7 +700,7 @@ namespace { int64_t nodes; Move move; Depth depth, ext, newDepth; - Value value, alpha, beta; + Value value, evalMargin, alpha, beta; bool isCheck, moveIsCheck, captureOrPromotion, dangerous; int researchCountFH, researchCountFL; @@ -726,8 +719,7 @@ namespace { // Step 5. Evaluate the position statically // At root we do this only to get reference value for child nodes - ss->evalMargin = VALUE_NONE; - ss->eval = isCheck ? VALUE_NONE : evaluate(pos, ss->evalMargin); + ss->eval = isCheck ? VALUE_NONE : evaluate(pos, evalMargin); // Step 6. Razoring (omitted at root) // Step 7. Static null move pruning (omitted at root) @@ -973,7 +965,7 @@ namespace { Key posKey; Move ttMove, move, excludedMove, threatMove; Depth ext, newDepth; - Value bestValue, value, oldAlpha; + Value bestValue, value, evalMargin, oldAlpha; Value refinedValue, nullValue, futilityBase, futilityValueScaled; // Non-PV specific bool isCheck, singleEvasion, singularExtensionNode, moveIsCheck, captureOrPromotion, dangerous; bool mateThreat = false; @@ -988,6 +980,7 @@ namespace { { sp = ss->sp; tte = NULL; + evalMargin = VALUE_ZERO; ttMove = excludedMove = MOVE_NONE; threatMove = sp->threatMove; mateThreat = sp->mateThreat; @@ -1048,19 +1041,19 @@ namespace { // Step 5. Evaluate the position statically and // update gain statistics of parent move. if (isCheck) - ss->eval = ss->evalMargin = VALUE_NONE; + ss->eval = evalMargin = VALUE_NONE; else if (tte) { assert(tte->static_value() != VALUE_NONE); ss->eval = tte->static_value(); - ss->evalMargin = tte->static_value_margin(); + evalMargin = tte->static_value_margin(); refinedValue = refine_eval(tte, ss->eval, ply); } else { - refinedValue = ss->eval = evaluate(pos, ss->evalMargin); - TT.store(posKey, VALUE_NONE, VALUE_TYPE_NONE, DEPTH_NONE, MOVE_NONE, ss->eval, ss->evalMargin); + refinedValue = ss->eval = evaluate(pos, evalMargin); + TT.store(posKey, VALUE_NONE, VALUE_TYPE_NONE, DEPTH_NONE, MOVE_NONE, ss->eval, evalMargin); } // Save gain for the parent non-capture move @@ -1186,7 +1179,7 @@ split_point_start: // At split points actual search starts from here CheckInfo ci(pos); ss->bestMove = MOVE_NONE; singleEvasion = !SpNode && isCheck && mp.number_of_evasions() == 1; - futilityBase = ss->eval + ss->evalMargin; + futilityBase = ss->eval + evalMargin; singularExtensionNode = !SpNode && depth >= SingularExtensionDepth[PvNode] && tte @@ -1250,7 +1243,10 @@ split_point_start: // At split points actual search starts from here newDepth = depth - ONE_PLY + ext; // Update current move (this must be done after singular extension search) - movesSearched[moveCount++] = ss->currentMove = move; + movesSearched[moveCount] = ss->currentMove = move; + + if (!SpNode) + moveCount++; // Step 12. Futility pruning (is omitted in PV nodes) if ( !PvNode @@ -1371,24 +1367,29 @@ split_point_start: // At split points actual search starts from here if (value > bestValue && !(SpNode && ThreadsMgr.thread_should_stop(threadID))) { bestValue = value; + + if (SpNode) + sp->bestValue = value; + if (value > alpha) { if (SpNode && (!PvNode || value >= beta)) sp->stopRequest = true; if (PvNode && value < beta) // We want always alpha < beta + { alpha = value; + if (SpNode) + sp->alpha = value; + } - if (value == value_mate_in(ply + 1)) + if (!SpNode && value == value_mate_in(ply + 1)) ss->mateKiller = move; ss->bestMove = move; - } - if (SpNode) - { - sp->bestValue = bestValue; - sp->alpha = alpha; - sp->parentSstack->bestMove = ss->bestMove; + + if (SpNode) + sp->parentSstack->bestMove = move; } } @@ -1428,7 +1429,7 @@ split_point_start: // At split points actual search starts from here ValueType vt = (bestValue <= oldAlpha ? VALUE_TYPE_UPPER : bestValue >= beta ? VALUE_TYPE_LOWER : VALUE_TYPE_EXACT); move = (bestValue <= oldAlpha ? MOVE_NONE : ss->bestMove); - TT.store(posKey, value_to_tt(bestValue, ply), vt, depth, move, ss->eval, ss->evalMargin); + TT.store(posKey, value_to_tt(bestValue, ply), vt, depth, move, ss->eval, evalMargin); // Update killers and history only for non capture moves that fails high if ( bestValue >= beta @@ -2225,7 +2226,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) + || threads[threadID].state == THREAD_INITIALIZING + || (!sp && threads[threadID].state == THREAD_AVAILABLE)) { assert(!sp); assert(threadID != 0); @@ -2233,16 +2235,21 @@ split_point_start: // At split points actual search starts from here if (AllThreadsShouldExit) break; - threads[threadID].state = THREAD_AVAILABLE; + lock_grab(&MPLock); -#if !defined(_MSC_VER) - lock_grab(&WaitLock); - if (threadID >= ActiveThreads) - pthread_cond_wait(&WaitCond[threadID], &WaitLock); - lock_release(&WaitLock); -#else - WaitForSingleObject(WaitCond[threadID], INFINITE); -#endif + // Retest condition under lock protection + if (!( threadID >= ActiveThreads + || threads[threadID].state == THREAD_INITIALIZING + || (!sp && threads[threadID].state == THREAD_AVAILABLE))) + { + lock_release(&MPLock); + continue; + } + + // Put thread to sleep + threads[threadID].state = THREAD_AVAILABLE; + cond_wait(&WaitCond[threadID], &MPLock); + lock_release(&MPLock); } // If this thread has been assigned work, launch a search @@ -2260,9 +2267,9 @@ split_point_start: // At split points actual search starts from here if (tsp->pvNode) search(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply); - else + else { search(pos, ss, tsp->alpha, tsp->beta, tsp->depth, tsp->ply); - + } assert(threads[threadID].state == THREAD_SEARCHING); threads[threadID].state = THREAD_AVAILABLE; @@ -2302,14 +2309,9 @@ split_point_start: // At split points actual search starts from here // Initialize global locks lock_init(&MPLock); - lock_init(&WaitLock); for (i = 0; i < MAX_THREADS; i++) -#if !defined(_MSC_VER) - pthread_cond_init(&WaitCond[i], NULL); -#else - WaitCond[i] = CreateEvent(0, FALSE, FALSE, 0); -#endif + cond_init(&WaitCond[i]); // Initialize splitPoints[] locks for (i = 0; i < MAX_THREADS; i++) @@ -2369,7 +2371,6 @@ split_point_start: // At split points actual search starts from here for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++) lock_destroy(&(threads[i].splitPoints[j].lock)); - lock_destroy(&WaitLock); lock_destroy(&MPLock); // Now we can safely destroy the wait conditions @@ -2450,9 +2451,8 @@ split_point_start: // At split points actual search starts from here // split point objects), the function immediately returns. If splitting is // possible, a SplitPoint object is initialized with all the data that must be // copied to the helper threads and we tell our helper threads that they have - // been assigned work. This will cause them to instantly leave their idle loops - // and call sp_search(). When all threads have returned from sp_search() then - // split() returns. + // been assigned work. This will cause them to instantly leave their idle loops and + // call search().When all threads have returned from search() then split() returns. template void ThreadsManager::split(const Position& p, SearchStack* ss, int ply, Value* alpha, @@ -2535,6 +2535,8 @@ split_point_start: // At split points actual search starts from here assert(i == master || threads[i].state == THREAD_BOOKED); threads[i].state = THREAD_WORKISWAITING; // This makes the slave to exit from idle_loop() + if (i != master) + wake_sleeping_thread(i); } // Everything is set up. The master thread enters the idle loop, from @@ -2562,29 +2564,12 @@ split_point_start: // At split points actual search starts from here void ThreadsManager::wake_sleeping_thread(int threadID) { - assert(threadID > 0); - assert(threads[threadID].state == THREAD_AVAILABLE); - -#if !defined(_MSC_VER) - pthread_mutex_lock(&WaitLock); - pthread_cond_signal(&WaitCond[threadID]); - pthread_mutex_unlock(&WaitLock); -#else - SetEvent(WaitCond[threadID]); -#endif + lock_grab(&MPLock); + cond_signal(&WaitCond[threadID]); + lock_release(&MPLock); } - // put_threads_to_sleep() makes all the threads go to sleep just before - // to leave think(), at the end of the search. Threads should have already - // finished the job and should be idle. - - void ThreadsManager::put_threads_to_sleep() { - - // This makes the threads to go to sleep - ActiveThreads = 1; - } - /// The RootMoveList class // RootMoveList c'tor @@ -2598,7 +2583,7 @@ split_point_start: // At split points actual search starts from here // Initialize search stack init_ss_array(ss, PLY_MAX_PLUS_2); - ss[0].eval = ss[0].evalMargin = VALUE_NONE; + ss[0].eval = VALUE_NONE; count = 0; // Generate all legal moves