X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=22bc0156705121a9a02adfcd8b59c1ff66e21997;hp=6982082252c66a0a2434e916faa32d181b3f506a;hb=8a504d36f9b740c6d4c5bba6855148c5be40556e;hpb=69644d3f734ec97e8448383f9a91ae8cebf83e9c diff --git a/src/search.cpp b/src/search.cpp index 69820822..22bc0156 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -126,9 +126,6 @@ namespace { // Search depth at iteration 1 const Depth InitialDepth = OnePly; - // Depth limit for selective search - const Depth SelectiveDepth = 7 * OnePly; - // Use internal iterative deepening? const bool UseIIDAtPVNodes = true; const bool UseIIDAtNonPVNodes = true; @@ -150,17 +147,25 @@ namespace { // remaining ones we will extend it. const Value SingleReplyMargin = Value(0x20); - // Margins for futility pruning in the quiescence search, and at frontier - // and near frontier nodes. - const Value FutilityMarginQS = Value(0x80); + // Depth limit for razoring + const Depth RazorDepth = 4 * OnePly; - Value FutilityMargins[2 * PLY_MAX_PLUS_2]; // Initialized at startup. + /// Lookup tables initialized at startup - // Each move futility margin is decreased - const Value IncrementalFutilityMargin = Value(0x8); + // Reduction lookup tables and their getter functions + int8_t PVReductionMatrix[64][64]; // [depth][moveNumber] + int8_t NonPVReductionMatrix[64][64]; // [depth][moveNumber] - // Depth limit for razoring - const Depth RazorDepth = 4 * OnePly; + inline Depth pv_reduction(Depth d, int mn) { return (Depth) PVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; } + inline Depth nonpv_reduction(Depth d, int mn) { return (Depth) NonPVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; } + + // Futility lookup tables and their getter functions + const Value FutilityMarginQS = Value(0x80); + int32_t FutilityMarginsMatrix[14][64]; // [depth][moveNumber] + int FutilityMoveCountArray[32]; // [depth] + + inline Value futility_margin(Depth d, int mn) { return Value(d < 7*OnePly ? FutilityMarginsMatrix[Max(d, 0)][Min(mn, 63)] : 2 * VALUE_INFINITE); } + inline int futility_move_count(Depth d) { return d < 16*OnePly ? FutilityMoveCountArray[d] : 512; } /// Variables initialized by UCI options @@ -207,14 +212,6 @@ namespace { bool UseLogFile; std::ofstream LogFile; - // Reduction lookup tables and their getter functions - // Initialized at startup - int8_t PVReductionMatrix[64][64]; // [depth][moveNumber] - int8_t NonPVReductionMatrix[64][64]; // [depth][moveNumber] - - inline Depth pv_reduction(Depth d, int mn) { return (Depth) PVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; } - inline Depth nonpv_reduction(Depth d, int mn) { return (Depth) NonPVReductionMatrix[Min(d / 2, 63)][Min(mn, 63)]; } - // MP related variables int ActiveThreads = 1; Depth MinimumSplitDepth; @@ -222,9 +219,8 @@ namespace { Thread Threads[THREAD_MAX]; Lock MPLock; Lock IOLock; - bool AllThreadsShouldExit = false; + bool AllThreadsShouldExit, AllThreadsShouldSleep; SplitPoint SplitPointStack[THREAD_MAX][ACTIVE_SPLIT_POINTS_MAX]; - bool Idle = true; #if !defined(_MSC_VER) pthread_cond_t WaitCond; @@ -339,7 +335,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move, int maxNodes, int maxTime, Move searchMoves[]) { // Initialize global search variables - Idle = StopOnPonderhit = AbortSearch = Quit = false; + AllThreadsShouldSleep = StopOnPonderhit = AbortSearch = Quit = false; AspirationFailLow = false; NodesSincePoll = 0; SearchStartTime = get_system_time(); @@ -351,7 +347,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move, UseTimeManagement = !ExactMaxTime && !MaxDepth && !MaxNodes && !InfiniteSearch; // Look for a book move, only during games, not tests - if (UseTimeManagement && !ponder && get_option_value_bool("OwnBook")) + if (UseTimeManagement && get_option_value_bool("OwnBook")) { Move bookMove; if (get_option_value_string("Book File") != OpeningBook.file_name()) @@ -360,6 +356,9 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move, bookMove = OpeningBook.get_move(pos); if (bookMove != MOVE_NONE) { + if (PonderSearch) + wait_for_stop_or_ponderhit(); + cout << "bestmove " << bookMove << endl; return true; } @@ -522,26 +521,17 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move, if (UseLogFile) LogFile.close(); - Idle = true; + AllThreadsShouldSleep = true; return !Quit; } -/// init_threads() is called during startup. It launches all helper threads, -/// and initializes the split point stack and the global locks and condition -/// objects. - -void init_threads() { +/// init_search() is called during startup. It initializes various lookup tables - volatile int i; - bool ok; - -#if !defined(_MSC_VER) - pthread_t pthread[1]; -#endif +void init_search() { // Init our reduction lookup tables - for (i = 1; i < 64; i++) // i == depth + for (int i = 1; i < 64; i++) // i == depth (OnePly = 1) for (int j = 1; j < 64; j++) // j == moveNumber { double pvRed = 0.5 + log(double(i)) * log(double(j)) / 6.0; @@ -551,15 +541,30 @@ void init_threads() { } // Init futility margins array - FutilityMargins[0] = FutilityMargins[1] = Value(0); + for (int i = 0; i < 14; i++) // i == depth (OnePly = 2) + for (int j = 0; j < 64; j++) // j == moveNumber + { + FutilityMarginsMatrix[i][j] = (i < 2 ? 0 : 112 * bitScanReverse32(i * i / 2)) - 8 * j; // FIXME: test using log instead of BSR + } - for (i = 2; i < 2 * PLY_MAX_PLUS_2; i++) - { - FutilityMargins[i] = Value(112 * bitScanReverse32(i * i / 2)); // FIXME: test using log instead of BSR - } + // Init futility move count array + for (int i = 0; i < 32; i++) // i == depth (OnePly = 2) + FutilityMoveCountArray[i] = 3 + (1 << (3 * i / 8)); +} - for (i = 0; i < THREAD_MAX; i++) - Threads[i].activeSplitPoints = 0; + +/// init_threads() is called during startup. It launches all helper threads, +/// and initializes the split point stack and the global locks and condition +/// objects. + +void init_threads() { + + volatile int i; + bool ok; + +#if !defined(_MSC_VER) + pthread_t pthread[1]; +#endif // Initialize global locks lock_init(&MPLock, NULL); @@ -575,14 +580,15 @@ void init_threads() { SitIdleEvent[i] = CreateEvent(0, FALSE, FALSE, 0); #endif + // Will be set just before program exits to properly end the threads + AllThreadsShouldExit = false; + + // Threads will be put to sleep as soon as created + AllThreadsShouldSleep = true; + // All threads except the main thread should be initialized to idle state for (i = 1; i < THREAD_MAX; i++) - { - Threads[i].stop = false; - Threads[i].workIsWaiting = false; Threads[i].idle = true; - Threads[i].running = false; - } // Launch the helper threads for (i = 1; i < THREAD_MAX; i++) @@ -612,7 +618,7 @@ void init_threads() { void stop_threads() { ActiveThreads = THREAD_MAX; // HACK - Idle = false; // HACK + AllThreadsShouldSleep = false; // HACK wake_sleeping_threads(); AllThreadsShouldExit = true; for (int i = 1; i < THREAD_MAX; i++) @@ -644,7 +650,6 @@ void SearchStack::init(int ply) { currentMove = threatMove = MOVE_NONE; reduction = Depth(0); eval = VALUE_NONE; - evalInfo = NULL; } void SearchStack::initKillers() { @@ -1371,22 +1376,16 @@ namespace { isCheck = pos.is_check(); - // Calculate depth dependant futility pruning parameters - const int FutilityMoveCountMargin = 3 + (1 << (3 * int(depth) / 8)); - // Evaluate the position statically if (!isCheck) { if (tte && (tte->type() & VALUE_TYPE_EVAL)) staticValue = value_from_tt(tte->value(), ply); else - { staticValue = evaluate(pos, ei, threadID); - ss[ply].evalInfo = &ei; - } ss[ply].eval = staticValue; - futilityValue = staticValue + FutilityMargins[int(depth)]; //FIXME: Remove me, only for split + futilityValue = staticValue + futility_margin(depth, 0); //FIXME: Remove me, only for split staticValue = refine_eval(tte, staticValue, ply); // Enhance accuracy with TT value if possible update_gains(pos, ss[ply - 1].currentMove, ss[ply - 1].eval, ss[ply].eval); } @@ -1397,8 +1396,8 @@ namespace { if ( !isCheck && allowNullmove && depth < RazorDepth - && staticValue - FutilityMargins[int(depth)] >= beta) - return staticValue - FutilityMargins[int(depth)]; + && staticValue - futility_margin(depth, 0) >= beta) + return staticValue - futility_margin(depth, 0); // Null move search if ( allowNullmove @@ -1470,7 +1469,7 @@ namespace { { search(pos, ss, beta, Min(depth/2, depth-2*OnePly), ply, false, threadID); ttMove = ss[ply].pv[ply]; - tte = TT.retrieve(pos.get_key()); + tte = TT.retrieve(posKey); } // Initialize a MovePicker object for the current position, and prepare @@ -1530,35 +1529,21 @@ namespace { && move != ttMove) { // Move count based pruning - if ( moveCount >= FutilityMoveCountMargin + if ( moveCount >= futility_move_count(depth) && ok_to_prune(pos, move, ss[ply].threatMove) && bestValue > value_mated_in(PLY_MAX)) continue; // Value based pruning - Depth predictedDepth = newDepth; - - //FIXME: We are ignoring condition: depth >= 3*OnePly, BUG?? - ss[ply].reduction = nonpv_reduction(depth, moveCount); - if (ss[ply].reduction) - predictedDepth -= ss[ply].reduction; + Depth predictedDepth = newDepth - nonpv_reduction(depth, moveCount); //FIXME: We are ignoring condition: depth >= 3*OnePly, BUG?? + futilityValueScaled = ss[ply].eval + futility_margin(predictedDepth, moveCount) + + H.gain(pos.piece_on(move_from(move)), move_to(move)) + 45; - if (predictedDepth < SelectiveDepth) + if (futilityValueScaled < beta) { - int preFutilityValueMargin = 0; - if (predictedDepth >= OnePly) - preFutilityValueMargin = FutilityMargins[int(predictedDepth)]; - - preFutilityValueMargin += H.gain(pos.piece_on(move_from(move)), move_to(move)) + 45; - - futilityValueScaled = ss[ply].eval + preFutilityValueMargin - moveCount * IncrementalFutilityMargin; - - if (futilityValueScaled < beta) - { - if (futilityValueScaled > bestValue) - bestValue = futilityValueScaled; - continue; - } + if (futilityValueScaled > bestValue) + bestValue = futilityValueScaled; + continue; } } @@ -1857,11 +1842,9 @@ namespace { Move move; int moveCount; bool isCheck = pos.is_check(); - bool useFutilityPruning = sp->depth < SelectiveDepth + bool useFutilityPruning = sp->depth < 7 * OnePly //FIXME: sync with search && !isCheck; - const int FutilityMoveCountMargin = 3 + (1 << (3 * int(sp->depth) / 8)); - while ( lock_grab_bool(&(sp->lock)) && sp->bestValue < sp->beta && !thread_should_stop(threadID) @@ -1888,13 +1871,13 @@ namespace { && !captureOrPromotion) { // Move count based pruning - if ( moveCount >= FutilityMoveCountMargin + if ( moveCount >= futility_move_count(sp->depth) && ok_to_prune(pos, move, ss[sp->ply].threatMove) && sp->bestValue > value_mated_in(PLY_MAX)) continue; // Value based pruning - Value futilityValueScaled = sp->futilityValue - moveCount * IncrementalFutilityMargin; + Value futilityValueScaled = sp->futilityValue - moveCount * 8; //FIXME: sync with search if (futilityValueScaled < sp->beta) { @@ -2790,16 +2773,17 @@ namespace { Threads[threadID].running = true; - while (true) + while (!AllThreadsShouldExit || threadID == 0) { - if (AllThreadsShouldExit && threadID != 0) - break; - // If we are not thinking, wait for a condition to be signaled // instead of wasting CPU time polling for work. - while (threadID != 0 && (Idle || threadID >= ActiveThreads)) + while ( threadID != 0 + && !AllThreadsShouldExit + && (AllThreadsShouldSleep || threadID >= ActiveThreads)) { + Threads[threadID].sleeping = true; + #if !defined(_MSC_VER) pthread_mutex_lock(&WaitLock); if (Idle || threadID >= ActiveThreads) @@ -2811,6 +2795,10 @@ namespace { #endif } + // Out of the while loop to avoid races in case thread is woken up but + // while condition still holds true so that is put to sleep again. + Threads[threadID].sleeping = false; + // If this thread has been assigned work, launch a search if (Threads[threadID].workIsWaiting) { @@ -3066,6 +3054,8 @@ namespace { { for (int i = 1; i < ActiveThreads; i++) { + assert(Threads[i].sleeping == true); + Threads[i].idle = true; Threads[i].workIsWaiting = false; } @@ -3078,6 +3068,10 @@ namespace { for (int i = 1; i < THREAD_MAX; i++) SetEvent(SitIdleEvent[i]); #endif + + // Wait for the threads to be all woken up + for (int i = 1; i < ActiveThreads; i++) + while (Threads[i].sleeping); } }