X-Git-Url: https://git.sesse.net/?p=stockfish;a=blobdiff_plain;f=src%2Fsearch.cpp;h=ac870f5bf617aa8d75fbdede2e5e04048eaf970c;hp=4bacbef01b6c813a9cd2ec6b1354e3b20b32b909;hb=4ad03c9bad914b337fb6431c4bcbc1d909a1a841;hpb=d0dc05ad419902d869efdec012a1d82a7b34ff92 diff --git a/src/search.cpp b/src/search.cpp index 4bacbef0..ac870f5b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -94,8 +94,8 @@ namespace { int ActiveThreads; volatile bool AllThreadsShouldExit; Thread threads[MAX_THREADS]; - Lock MPLock, WaitLock; - WaitCondition WaitCond[MAX_THREADS]; + Lock MPLock, SleepLock[MAX_THREADS]; + WaitCondition SleepCond[MAX_THREADS]; }; @@ -263,6 +263,7 @@ namespace { // Multi-threads related variables Depth MinimumSplitDepth; int MaxThreadsPerSplitPoint; + bool UseSleepingThreads; ThreadsManager ThreadsMgr; // Node counters, used only by thread[0] but try to keep in different cache @@ -347,7 +348,7 @@ void init_search() { // Init reductions array for (hd = 1; hd < 64; hd++) for (mc = 1; mc < 64; mc++) { - double pvRed = 0.33 + log(double(hd)) * log(double(mc)) / 4.5; + double pvRed = log(double(hd)) * log(double(mc)) / 3.0; double nonPVRed = 0.33 + log(double(hd)) * log(double(mc)) / 2.25; ReductionMatrix[PV][hd][mc] = (int8_t) ( pvRed >= 1.0 ? floor( pvRed * int(ONE_PLY)) : 0); ReductionMatrix[NonPV][hd][mc] = (int8_t) (nonPVRed >= 1.0 ? floor(nonPVRed * int(ONE_PLY)) : 0); @@ -455,6 +456,7 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[ MaxThreadsPerSplitPoint = Options["Maximum Number of Threads per Split Point"].value(); MultiPV = Options["MultiPV"].value(); UseLogFile = Options["Use Search Log"].value(); + UseSleepingThreads = Options["Use Sleeping Threads"].value(); if (UseLogFile) LogFile.open(Options["Search Log Filename"].value().c_str(), std::ios::out | std::ios::app); @@ -466,7 +468,7 @@ bool think(Position& pos, bool infinite, bool ponder, int time[], int increment[ if (newActiveThreads != ThreadsMgr.active_threads()) { ThreadsMgr.set_active_threads(newActiveThreads); - init_eval(ThreadsMgr.active_threads()); + init_eval(newActiveThreads); } // Wake up needed threads @@ -661,7 +663,7 @@ namespace { << " time " << current_search_time() << endl; // Print the best move and the ponder move to the standard output - if (pv[0] == MOVE_NONE) + if (pv[0] == MOVE_NONE || MultiPV > 1) { pv[0] = rml.move(0); pv[1] = MOVE_NONE; @@ -1070,7 +1072,6 @@ namespace { && !isCheck && refinedValue < beta - razor_margin(depth) && ttMove == MOVE_NONE - && (ss-1)->currentMove != MOVE_NULL && !value_is_mate(beta) && !pos.has_pawn_on_7th(pos.side_to_move())) { @@ -1287,6 +1288,17 @@ split_point_start: // At split points actual search starts from here continue; } + + // Prune neg. see moves at low depths + if ( predictedDepth < 2 * ONE_PLY + && bestValue > value_mated_in(PLY_MAX) + && pos.see_sign(move) < 0) + { + if (SpNode) + lock_grab(&(sp->lock)); + + continue; + } } // Step 13. Make the move @@ -2189,6 +2201,9 @@ split_point_start: // At split points actual search starts from here assert(threadID >= 0 && threadID < MAX_THREADS); + int i; + bool allFinished = false; + while (true) { // Slave threads can exit as soon as AllThreadsShouldExit raises, @@ -2202,22 +2217,33 @@ 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); - assert(threadID != 0); + assert(!sp || UseSleepingThreads); + assert(threadID != 0 || UseSleepingThreads); - if (AllThreadsShouldExit) - break; + if (threads[threadID].state == THREAD_INITIALIZING) + threads[threadID].state = THREAD_AVAILABLE; - threads[threadID].state = THREAD_AVAILABLE; + // Grab the lock to avoid races with wake_sleeping_thread() + lock_grab(&SleepLock[threadID]); + + // If we are master and all slaves have finished do not go to sleep + for (i = 0; sp && i < ActiveThreads && !sp->slaves[i]; i++) {} + allFinished = (i == ActiveThreads); - lock_grab(&WaitLock); + if (allFinished || AllThreadsShouldExit) + { + lock_release(&SleepLock[threadID]); + break; + } - if (threadID >= ActiveThreads || threads[threadID].state == THREAD_INITIALIZING) - cond_wait(&WaitCond[threadID], &WaitLock); + // Do sleep here after retesting sleep conditions + if (threadID >= ActiveThreads || threads[threadID].state == THREAD_AVAILABLE) + cond_wait(&SleepCond[threadID], &SleepLock[threadID]); - lock_release(&WaitLock); + lock_release(&SleepLock[threadID]); } // If this thread has been assigned work, launch a search @@ -2235,20 +2261,25 @@ 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; + + // 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 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. - int i = 0; - for ( ; sp && i < ActiveThreads && !sp->slaves[i]; i++) {} + for (i = 0; sp && i < ActiveThreads && !sp->slaves[i]; i++) {} + allFinished = (i == ActiveThreads); - if (i == ActiveThreads) + if (allFinished) { // Because sp->slaves[] is reset under lock protection, // be sure sp->lock has been released before to return. @@ -2277,10 +2308,12 @@ 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++) - cond_init(&WaitCond[i]); + { + lock_init(&SleepLock[i]); + cond_init(&SleepCond[i]); + } // Initialize splitPoints[] locks for (i = 0; i < MAX_THREADS; i++) @@ -2341,12 +2374,14 @@ 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 for (int i = 0; i < MAX_THREADS; i++) - cond_destroy(&WaitCond[i]); + { + lock_destroy(&SleepLock[i]); + cond_destroy(&SleepCond[i]); + } } @@ -2458,6 +2493,7 @@ split_point_start: // At split points actual search starts from here // Initialize the split point object splitPoint.parent = masterThread.splitPoint; + splitPoint.master = master; splitPoint.stopRequest = false; splitPoint.ply = ply; splitPoint.depth = depth; @@ -2507,6 +2543,9 @@ 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 (UseSleepingThreads && i != master) + wake_sleeping_thread(i); } // Everything is set up. The master thread enters the idle loop, from @@ -2530,14 +2569,14 @@ split_point_start: // At split points actual search starts from here } - // wake_sleeping_thread() wakes up all sleeping threads when it is time - // to start a new search from the root. + // 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(&WaitLock); - cond_signal(&WaitCond[threadID]); - lock_release(&WaitLock); + lock_grab(&SleepLock[threadID]); + cond_signal(&SleepCond[threadID]); + lock_release(&SleepLock[threadID]); }