X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=6232f0cbf3ab8477ff5bc10f5973a3b1a134341b;hp=df74d580ec2b954cd346b310438a976b9819bbca;hb=cfe59de27ddc42ac555187ae68879f2bc7bd7936;hpb=5ed0a60203c1c93c5630894b4eca1f801241fe27 diff --git a/src/search.cpp b/src/search.cpp index df74d580..6232f0cb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -32,6 +32,7 @@ #include "book.h" #include "evaluate.h" #include "history.h" +#include "maxgain.h" #include "misc.h" #include "movegen.h" #include "movepick.h" @@ -263,6 +264,8 @@ namespace { // History table History H; + // MaxGain table + MaxGain MG; /// Functions @@ -841,7 +844,7 @@ namespace { // If we are pondering or in infinite search, we shouldn't print the // best move before we are told to do so. - if (!AbortSearch && !ExactMaxTime && (PonderSearch || InfiniteSearch)) + if (!AbortSearch && (PonderSearch || InfiniteSearch)) wait_for_stop_or_ponderhit(); else // Print final search statistics @@ -1643,7 +1646,7 @@ namespace { StateInfo st; Move ttMove, move; Value staticValue, bestValue, value, futilityBase, futilityValue; - bool isCheck, enoughMaterial, moveIsCheck; + bool isCheck, enoughMaterial, moveIsCheck, evasionPrunable; const TTEntry* tte = NULL; int moveCount = 0; bool pvNode = (beta - alpha != 1); @@ -1744,8 +1747,15 @@ namespace { } } - // Don't search captures and checks with negative SEE values - if ( !isCheck + // Detect blocking evasions that are candidate to be pruned + evasionPrunable = isCheck + && bestValue != -VALUE_INFINITE + && !pos.move_is_capture(move) + && pos.type_of_piece_on(move_from(move)) != KING + && !pos.can_castle(pos.side_to_move()); + + // Don't search moves with negative SEE values + if ( (!isCheck || evasionPrunable) && move != ttMove && !move_is_promotion(move) && pos.see_sign(move) < 0) @@ -1813,7 +1823,7 @@ namespace { assert(threadID >= 0 && threadID < ActiveThreads); assert(ActiveThreads > 1); - Position pos = Position(sp->pos); + Position pos(*sp->pos); CheckInfo ci(pos); SearchStack* ss = sp->sstack[threadID]; Value value = -VALUE_INFINITE; @@ -1955,7 +1965,7 @@ namespace { assert(threadID >= 0 && threadID < ActiveThreads); assert(ActiveThreads > 1); - Position pos = Position(sp->pos); + Position pos(*sp->pos); CheckInfo ci(pos); SearchStack* ss = sp->sstack[threadID]; Value value = -VALUE_INFINITE; @@ -2039,37 +2049,40 @@ namespace { break; // New best move? - lock_grab(&(sp->lock)); - if (value > sp->bestValue && !thread_should_stop(threadID)) + if (value > sp->bestValue) // Less then 2% of cases { - sp->bestValue = value; - if (value > sp->alpha) + lock_grab(&(sp->lock)); + if (value > sp->bestValue && !thread_should_stop(threadID)) { - // Ask threads to stop before to modify sp->alpha - if (value >= sp->beta) + sp->bestValue = value; + if (value > sp->alpha) { - for (int i = 0; i < ActiveThreads; i++) - if (i != threadID && (i == sp->master || sp->slaves[i])) - Threads[i].stop = true; + // Ask threads to stop before to modify sp->alpha + if (value >= sp->beta) + { + for (int i = 0; i < ActiveThreads; i++) + if (i != threadID && (i == sp->master || sp->slaves[i])) + Threads[i].stop = true; - sp->finished = true; - } + sp->finished = true; + } - sp->alpha = value; + sp->alpha = value; - sp_update_pv(sp->parentSstack, ss, sp->ply); - if (value == value_mate_in(sp->ply + 1)) - ss[sp->ply].mateKiller = move; - } - // If we are at ply 1, and we are searching the first root move at - // ply 0, set the 'Problem' variable if the score has dropped a lot - // (from the computer's point of view) since the previous iteration. - if ( sp->ply == 1 - && Iteration >= 2 - && -value <= IterationInfo[Iteration-1].value - ProblemMargin) - Problem = true; + sp_update_pv(sp->parentSstack, ss, sp->ply); + if (value == value_mate_in(sp->ply + 1)) + ss[sp->ply].mateKiller = move; + } + // If we are at ply 1, and we are searching the first root move at + // ply 0, set the 'Problem' variable if the score has dropped a lot + // (from the computer's point of view) since the previous iteration. + if ( sp->ply == 1 + && Iteration >= 2 + && -value <= IterationInfo[Iteration-1].value - ProblemMargin) + Problem = true; + } + lock_release(&(sp->lock)); } - lock_release(&(sp->lock)); } lock_grab(&(sp->lock)); @@ -2891,7 +2904,10 @@ namespace { if (!Threads[slave].idle || slave == master) return false; - if (Threads[slave].activeSplitPoints == 0) + // Make a local copy to be sure doesn't change under our feet + int localActiveSplitPoints = Threads[slave].activeSplitPoints; + + if (localActiveSplitPoints == 0) // No active split points means that the thread is available as // a slave for any other thread. return true; @@ -2899,8 +2915,10 @@ namespace { if (ActiveThreads == 2) return true; - // Apply the "helpful master" concept if possible - if (SplitPointStack[slave][Threads[slave].activeSplitPoints - 1].slaves[master]) + // Apply the "helpful master" concept if possible. Use localActiveSplitPoints + // that is known to be > 0, instead of Threads[slave].activeSplitPoints that + // could have been set to 0 by another thread leading to an out of bound access. + if (SplitPointStack[slave][localActiveSplitPoints - 1].slaves[master]) return true; return false; @@ -2950,7 +2968,6 @@ namespace { assert(ActiveThreads > 1); SplitPoint* splitPoint; - int i; lock_grab(&MPLock); @@ -2967,7 +2984,7 @@ namespace { splitPoint = SplitPointStack[master] + Threads[master].activeSplitPoints; Threads[master].activeSplitPoints++; - // Initialize the split point object and copy current position + // Initialize the split point object splitPoint->parent = Threads[master].splitPoint; splitPoint->finished = false; splitPoint->ply = ply; @@ -2981,37 +2998,40 @@ namespace { splitPoint->mp = mp; splitPoint->moves = *moves; splitPoint->cpus = 1; - splitPoint->pos.copy(p); + splitPoint->pos = &p; splitPoint->parentSstack = sstck; - for (i = 0; i < ActiveThreads; i++) + for (int i = 0; i < ActiveThreads; i++) splitPoint->slaves[i] = 0; - // Copy the current search stack to the master thread - memcpy(splitPoint->sstack[master], sstck, (ply+1) * sizeof(SearchStack)); + Threads[master].idle = false; + Threads[master].stop = false; Threads[master].splitPoint = splitPoint; - // Make copies of the current position and search stack for each thread - for (i = 0; i < ActiveThreads && splitPoint->cpus < MaxThreadsPerSplitPoint; i++) + // Allocate available threads setting idle flag to false + for (int i = 0; i < ActiveThreads && splitPoint->cpus < MaxThreadsPerSplitPoint; i++) if (thread_is_available(i, master)) { - memcpy(splitPoint->sstack[i], sstck, (ply+1) * sizeof(SearchStack)); + Threads[i].idle = false; + Threads[i].stop = false; Threads[i].splitPoint = splitPoint; splitPoint->slaves[i] = 1; splitPoint->cpus++; } + assert(splitPoint->cpus > 1); + + // We can release the lock because master and slave threads are already booked + lock_release(&MPLock); + // Tell the threads that they have work to do. This will make them leave - // their idle loop. - for (i = 0; i < ActiveThreads; i++) + // their idle loop. But before copy search stack tail for each thread. + for (int i = 0; i < ActiveThreads; i++) if (i == master || splitPoint->slaves[i]) { - Threads[i].workIsWaiting = true; - Threads[i].idle = false; - Threads[i].stop = false; + memcpy(splitPoint->sstack[i] + ply - 1, sstck + ply - 1, 3 * sizeof(SearchStack)); + Threads[i].workIsWaiting = true; // This makes the slave to exit from idle_loop() } - lock_release(&MPLock); - // Everything is set up. The master thread enters the idle loop, from // which it will instantly launch a search, because its workIsWaiting // slot is 'true'. We send the split point as a second parameter to the