X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fsearch.cpp;h=4654256065bd54612ff03e1c2a6778e65a7f169c;hb=fb5ba1d32912a3b5fc405511fc34d504df5393b9;hp=4eabb59f385ce597707139544c861008778b0a83;hpb=8261f619644aa50213deb8368094004d0a3be00f;p=stockfish diff --git a/src/search.cpp b/src/search.cpp index 4eabb59f..46542560 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -164,8 +164,8 @@ namespace { int32_t FutilityMarginsMatrix[14][64]; // [depth][moveNumber] int FutilityMoveCountArray[32]; // [depth] - inline Value futility_margin(Depth d, int mn) { return (Value) (d < 14? FutilityMarginsMatrix[Max(d, 0)][Min(mn, 63)] : 2*VALUE_INFINITE); } - inline int futility_move_count(Depth d) { return (d < 32? FutilityMoveCountArray[d] : 512); } + 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 @@ -219,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; @@ -281,6 +280,7 @@ namespace { const Value futilityValue, Depth depth, int *moves, MovePicker *mp, int master, bool pvNode); void wake_sleeping_threads(); + void put_threads_to_sleep(); #if !defined(_MSC_VER) void *init_thread(void *threadID); @@ -336,7 +336,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; + StopOnPonderhit = AbortSearch = Quit = false; AspirationFailLow = false; NodesSincePoll = 0; SearchStartTime = get_system_time(); @@ -522,26 +522,18 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move, if (UseLogFile) LogFile.close(); - Idle = true; + put_threads_to_sleep(); + 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. +/// init_search() is called during startup. It initializes various lookup tables -void init_threads() { - - 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,18 +543,30 @@ void init_threads() { } // Init futility margins array - for (i = 0; i < 14; i++) // i == depth (OnePly = 2) + 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 } // Init futility move count array - for (i = 0; i < 32; i++) // i == depth (OnePly = 2) + 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); @@ -578,14 +582,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++) @@ -603,19 +608,19 @@ void init_threads() { Application::exit_with_failure(); } - // Wait until the thread has finished launching - while (!Threads[i].running); + // Wait until the thread has finished launching and is gone to sleep + while (!Threads[i].running || !Threads[i].sleeping); } } -/// stop_threads() is called when the program exits. It makes all the +/// exit_threads() is called when the program exits. It makes all the /// helper threads exit cleanly. -void stop_threads() { +void exit_threads() { ActiveThreads = THREAD_MAX; // HACK - Idle = false; // HACK + AllThreadsShouldSleep = true; // HACK wake_sleeping_threads(); AllThreadsShouldExit = true; for (int i = 1; i < THREAD_MAX; i++) @@ -647,7 +652,6 @@ void SearchStack::init(int ply) { currentMove = threatMove = MOVE_NONE; reduction = Depth(0); eval = VALUE_NONE; - evalInfo = NULL; } void SearchStack::initKillers() { @@ -1380,10 +1384,7 @@ namespace { 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 + futility_margin(depth, 0); //FIXME: Remove me, only for split @@ -1537,7 +1538,8 @@ namespace { // Value based pruning 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; + futilityValueScaled = ss[ply].eval + futility_margin(predictedDepth, moveCount) + + H.gain(pos.piece_on(move_from(move)), move_to(move)) + 45; if (futilityValueScaled < beta) { @@ -2773,19 +2775,20 @@ 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) + if (AllThreadsShouldSleep || threadID >= ActiveThreads) pthread_cond_wait(&WaitCond, &WaitLock); pthread_mutex_unlock(&WaitLock); @@ -2794,6 +2797,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) { @@ -3045,10 +3052,16 @@ namespace { void wake_sleeping_threads() { + assert(AllThreadsShouldSleep); + + AllThreadsShouldSleep = false; + if (ActiveThreads > 1) { for (int i = 1; i < ActiveThreads; i++) { + assert(Threads[i].sleeping == true); + Threads[i].idle = true; Threads[i].workIsWaiting = false; } @@ -3061,10 +3074,30 @@ 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); } } + // 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 put_threads_to_sleep() { + + assert(!AllThreadsShouldSleep); + + AllThreadsShouldSleep = true; + + // Wait for the threads to be all sleeping + for (int i = 1; i < ActiveThreads; i++) + while (!Threads[i].sleeping); + } + + // init_thread() is the function which is called when a new thread is // launched. It simply calls the idle_loop() function with the supplied // threadID. There are two versions of this function; one for POSIX