From: Marco Costalba Date: Mon, 26 Mar 2012 18:55:32 +0000 (-0700) Subject: Merge pull request #9 from glinscott/master X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=a56322fde813094afd8ffa60d12761f94e0bd3ef;hp=dbe5e28eaa284aeaa4927ddde8a4341200e0e601 Merge pull request #9 from glinscott/master Penalty for undefended rook Almost no change at longer TC, but perhaps there is a tiny increase.... After 17522 games at 10"+0.05 Mod vs Orig 3064 - 2967 - 11491 ELO +2 Signed-off-by: Marco Costalba --- diff --git a/src/benchmark.cpp b/src/benchmark.cpp index 4124899b..35fd7254 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -118,7 +118,8 @@ void benchmark(int argc, char* argv[]) { } else { - Threads.start_thinking(pos, limits); + Threads.start_searching(pos, limits); + Threads.wait_for_search_finished(); nodes += Search::RootPosition.nodes_searched(); } } diff --git a/src/evaluate.cpp b/src/evaluate.cpp index c03aa99f..6e515d88 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -357,13 +357,12 @@ namespace { template Value do_evaluate(const Position& pos, Value& margin) { + assert(!pos.in_check()); + EvalInfo ei; Value margins[2]; Score score, mobilityWhite, mobilityBlack; - assert(pos.thread() >= 0 && pos.thread() < MAX_THREADS); - assert(!pos.in_check()); - // Initialize score by reading the incrementally updated scores included // in the position object (material + piece square tables). score = pos.value(); @@ -679,13 +678,13 @@ Value do_evaluate(const Position& pos, Value& margin) { const Color Them = (Us == WHITE ? BLACK : WHITE); - Bitboard b; + Bitboard b, undefended, undefendedMinors, weakEnemies; Score score = SCORE_ZERO; // Undefended pieces get penalized even if not under attack - Bitboard undefended = pos.pieces(Them) & ~ei.attackedBy[Them][0]; - const Bitboard undefendedMinors = undefended & (pos.pieces(BISHOP) | pos.pieces(KNIGHT)); - + undefended = pos.pieces(Them) & ~ei.attackedBy[Them][0]; + undefendedMinors = undefended & (pos.pieces(BISHOP) | pos.pieces(KNIGHT)); + if (undefendedMinors) score += single_bit(undefendedMinors) ? UndefendedPiecePenalty : UndefendedPiecePenalty * 2; @@ -693,9 +692,10 @@ Value do_evaluate(const Position& pos, Value& margin) { score += UndefendedPiecePenalty; // Enemy pieces not defended by a pawn and under our attack - Bitboard weakEnemies = pos.pieces(Them) - & ~ei.attackedBy[Them][PAWN] - & ei.attackedBy[Us][0]; + weakEnemies = pos.pieces(Them) + & ~ei.attackedBy[Them][PAWN] + & ei.attackedBy[Us][0]; + if (!weakEnemies) return score; diff --git a/src/main.cpp b/src/main.cpp index 1d5c6ea7..3dcb3f6d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,6 +55,4 @@ int main(int argc, char* argv[]) { cerr << "\nUsage: stockfish bench [hash size = 128] [threads = 1] " << "[limit = 12] [fen positions file = default] " << "[limited by depth, time, nodes or perft = depth]" << endl; - - Threads.exit(); } diff --git a/src/material.cpp b/src/material.cpp index 7369bca9..e2c64ff7 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -84,12 +84,6 @@ namespace { } // namespace -/// MaterialInfoTable c'tor and d'tor allocate and free the space for Endgames - -void MaterialInfoTable::init() { Base::init(); if (!funcs) funcs = new Endgames(); } -MaterialInfoTable::~MaterialInfoTable() { delete funcs; } - - /// MaterialInfoTable::material_info() takes a position object as input, /// computes or looks up a MaterialInfo object, and returns a pointer to it. /// If the material configuration is not already present in the table, it diff --git a/src/material.h b/src/material.h index 45bfe8b0..6f844926 100644 --- a/src/material.h +++ b/src/material.h @@ -72,8 +72,9 @@ private: class MaterialInfoTable : public SimpleHash { public: - ~MaterialInfoTable(); - void init(); + MaterialInfoTable() : funcs(new Endgames()) {} + ~MaterialInfoTable() { delete funcs; } + MaterialInfo* material_info(const Position& pos) const; static Phase game_phase(const Position& pos); diff --git a/src/platform.h b/src/platform.h index 26c3abfb..e002d218 100644 --- a/src/platform.h +++ b/src/platform.h @@ -53,8 +53,8 @@ inline uint64_t time_to_msec(const sys_time_t& t) { return t.tv_sec * 1000LL + t # include typedef pthread_mutex_t Lock; typedef pthread_cond_t WaitCondition; -typedef pthread_t ThreadHandle; -typedef void*(*start_fn)(void*); +typedef pthread_t NativeHandle; +typedef void*(*pt_start_fn)(void*); # define lock_init(x) pthread_mutex_init(&(x), NULL) # define lock_grab(x) pthread_mutex_lock(&(x)) @@ -65,7 +65,7 @@ typedef void*(*start_fn)(void*); # define cond_signal(x) pthread_cond_signal(&(x)) # define cond_wait(x,y) pthread_cond_wait(&(x),&(y)) # define cond_timedwait(x,y,z) pthread_cond_timedwait(&(x),&(y),z) -# define thread_create(x,f,id) !pthread_create(&(x),NULL,(start_fn)f,&(id)) +# define thread_create(x,f,t) !pthread_create(&(x),NULL,(pt_start_fn)f,t) # define thread_join(x) pthread_join(x, NULL) #else // Windows and MinGW @@ -90,7 +90,7 @@ inline uint64_t time_to_msec(const sys_time_t& t) { return t.time * 1000LL + t.m // but apart from this they have the same speed performance of SRW locks. typedef CRITICAL_SECTION Lock; typedef HANDLE WaitCondition; -typedef HANDLE ThreadHandle; +typedef HANDLE NativeHandle; # define lock_init(x) InitializeCriticalSection(&(x)) # define lock_grab(x) EnterCriticalSection(&(x)) @@ -101,7 +101,7 @@ typedef HANDLE ThreadHandle; # define cond_signal(x) SetEvent(x) # define cond_wait(x,y) { lock_release(y); WaitForSingleObject(x, INFINITE); lock_grab(y); } # define cond_timedwait(x,y,z) { lock_release(y); WaitForSingleObject(x,z); lock_grab(y); } -# define thread_create(x,f,id) (x = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)f,&(id),0,NULL), x != NULL) +# define thread_create(x,f,t) (x = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)f,t,0,NULL), x != NULL) # define thread_join(x) { WaitForSingleObject(x, INFINITE); CloseHandle(x); } #endif diff --git a/src/search.cpp b/src/search.cpp index fb5d375e..a76a9521 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -298,7 +298,7 @@ void Search::think() { << endl; } - Threads.set_size(Options["Threads"]); + Threads.wake_up(); // Set best timer interval to avoid lagging under time pressure. Timer is // used to check for remaining available thinking time. @@ -310,9 +310,8 @@ void Search::think() { // We're ready to start searching. Call the iterative deepening loop function id_loop(pos); - // Stop timer and send all the slaves to sleep, if not already sleeping - Threads.set_timer(0); - Threads.set_size(1); + Threads.set_timer(0); // Stop timer + Threads.sleep(); if (Options["Use Search Log"]) { diff --git a/src/thread.cpp b/src/thread.cpp index 5c23aa50..10f432bd 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -32,29 +32,61 @@ ThreadsManager Threads; // Global object namespace { extern "C" { // start_routine() is the C function which is called when a new thread - // is launched. It simply calls idle_loop() of the supplied thread. The first - // and last thread are special. First one is the main search thread while the - // last one mimics a timer, they run in main_loop() and timer_loop(). + // is launched. It is a wrapper to member function pointed by start_fn. - long start_routine(Thread* th) { + long start_routine(Thread* th) { (th->*(th->start_fn))(); return 0; } - if (th->threadID == 0) - th->main_loop(); +} } + + +// Thread c'tor starts a newly-created thread of execution that will call +// the idle loop function pointed by start_fn going immediately to sleep. + +Thread::Thread(Fn fn) { + + is_searching = do_exit = false; + maxPly = splitPointsCnt = 0; + curSplitPoint = NULL; + start_fn = fn; + threadID = Threads.size(); - else if (th->threadID == MAX_THREADS) - th->timer_loop(); + do_sleep = (fn != &Thread::main_loop); // Avoid a race with start_searching() - else - th->idle_loop(NULL); + lock_init(sleepLock); + cond_init(sleepCond); + + for (int j = 0; j < MAX_SPLITPOINTS_PER_THREAD; j++) + lock_init(splitPoints[j].lock); - return 0; + if (!thread_create(handle, start_routine, this)) + { + std::cerr << "Failed to create thread number " << threadID << std::endl; + ::exit(EXIT_FAILURE); } +} -} } + +// Thread d'tor waits for thread termination before to return. + +Thread::~Thread() { + + assert(do_sleep); + + do_exit = true; // Search must be already finished + wake_up(); + + thread_join(handle); // Wait for thread termination + + lock_destroy(sleepLock); + cond_destroy(sleepCond); + + for (int j = 0; j < MAX_SPLITPOINTS_PER_THREAD; j++) + lock_destroy(splitPoints[j].lock); +} // Thread::timer_loop() is where the timer thread waits maxPly milliseconds and -// then calls do_timer_event(). If maxPly is 0 thread sleeps until is woken up. +// then calls check_time(). If maxPly is 0 thread sleeps until is woken up. extern void check_time(); void Thread::timer_loop() { @@ -100,11 +132,12 @@ void Thread::main_loop() { // Thread::wake_up() wakes up the thread, normally at the beginning of the search -// or, if "sleeping threads" is used, when there is some work to do. +// or, if "sleeping threads" is used at split time. void Thread::wake_up() { lock_grab(sleepLock); + do_sleep = false; cond_signal(sleepCond); lock_release(sleepLock); } @@ -122,16 +155,13 @@ void Thread::wait_for_stop_or_ponderhit() { Signals.stopOnPonderhit = true; lock_grab(sleepLock); - - while (!Signals.stop) - cond_wait(sleepCond, sleepLock); - + while (!Signals.stop) cond_wait(sleepCond, sleepLock); lock_release(sleepLock); } -// cutoff_occurred() checks whether a beta cutoff has occurred in the current -// active split point, or in some ancestor of the split point. +// Thread::cutoff_occurred() checks whether a beta cutoff has occurred in the +// current active split point, or in some ancestor of the split point. bool Thread::cutoff_occurred() const { @@ -143,12 +173,12 @@ bool Thread::cutoff_occurred() const { } -// is_available_to() checks whether the thread is available to help the thread with -// threadID "master" at a split point. An obvious requirement is that thread must be -// idle. With more than two threads, this is not by itself sufficient: If the thread -// is the master of some active split point, it is only available as a slave to the -// threads which are busy searching the split point at the top of "slave"'s split -// point stack (the "helpful master concept" in YBWC terminology). +// Thread::is_available_to() checks whether the thread is available to help the +// thread with threadID "master" at a split point. An obvious requirement is that +// thread must be idle. With more than two threads, this is not sufficient: If +// the thread is the master of some active split point, it is only available as a +// slave to the threads which are busy searching the split point at the top of +// "slave"'s split point stack (the "helpful master concept" in YBWC terminology). bool Thread::is_available_to(int master) const { @@ -165,104 +195,82 @@ bool Thread::is_available_to(int master) const { } -// read_uci_options() updates internal threads parameters from the corresponding -// UCI options. It is called before to start a new search. +// init() is called at startup. Initializes lock and condition variable and +// launches requested threads sending them immediately to sleep. We cannot use +// a c'tor becuase Threads is a static object and we need a fully initialized +// engine at this point due to allocation of endgames in Thread c'tor. -void ThreadsManager::read_uci_options() { +void ThreadsManager::init() { - maxThreadsPerSplitPoint = Options["Max Threads per Split Point"]; - minimumSplitDepth = Options["Min Split Depth"] * ONE_PLY; - useSleepingThreads = Options["Use Sleeping Threads"]; + cond_init(sleepCond); + lock_init(splitLock); + timer = new Thread(&Thread::timer_loop); + threads.push_back(new Thread(&Thread::main_loop)); + read_uci_options(); } -// set_size() changes the number of active threads and raises do_sleep flag for -// all the unused threads that will go immediately to sleep. +// d'tor cleanly terminates the threads when the program exits. -void ThreadsManager::set_size(int cnt) { +ThreadsManager::~ThreadsManager() { - assert(cnt > 0 && cnt < MAX_THREADS); + for (int i = 0; i < size(); i++) + delete threads[i]; - activeThreads = cnt; - - for (int i = 0; i < MAX_THREADS; i++) - if (i < activeThreads) - { - // Dynamically allocate pawn and material hash tables according to the - // number of active threads. This avoids preallocating memory for all - // possible threads if only few are used. - threads[i].pawnTable.init(); - threads[i].materialTable.init(); - threads[i].maxPly = 0; - - threads[i].do_sleep = false; - - if (!useSleepingThreads) - threads[i].wake_up(); - } - else - threads[i].do_sleep = true; + delete timer; + lock_destroy(splitLock); + cond_destroy(sleepCond); } -// init() is called during startup. Initializes locks and condition variables -// and launches all threads sending them immediately to sleep. +// read_uci_options() updates internal threads parameters from the corresponding +// UCI options and creates/destroys threads to match the requested number. Thread +// objects are dynamically allocated to avoid creating in advance all possible +// threads, with included pawns and material tables, if only few are used. -void ThreadsManager::init() { +void ThreadsManager::read_uci_options() { - read_uci_options(); + maxThreadsPerSplitPoint = Options["Max Threads per Split Point"]; + minimumSplitDepth = Options["Min Split Depth"] * ONE_PLY; + useSleepingThreads = Options["Use Sleeping Threads"]; + int requested = Options["Threads"]; - cond_init(sleepCond); - lock_init(splitLock); + assert(requested > 0); - // Allocate main thread tables to call evaluate() also when not searching - threads[0].pawnTable.init(); - threads[0].materialTable.init(); + while (size() < requested) + threads.push_back(new Thread(&Thread::idle_loop)); - // Create and launch all the threads, threads will go immediately to sleep - for (int i = 0; i <= MAX_THREADS; i++) + while (size() > requested) { - threads[i].is_searching = false; - threads[i].do_sleep = (i != 0); // Avoid a race with start_thinking() - threads[i].threadID = i; - - lock_init(threads[i].sleepLock); - cond_init(threads[i].sleepCond); - - for (int j = 0; j < MAX_SPLITPOINTS_PER_THREAD; j++) - lock_init(threads[i].splitPoints[j].lock); - - if (!thread_create(threads[i].handle, start_routine, threads[i])) - { - std::cerr << "Failed to create thread number " << i << std::endl; - ::exit(EXIT_FAILURE); - } + delete threads.back(); + threads.pop_back(); } } -// exit() is called to cleanly terminate the threads when the program finishes +// wake_up() is called before a new search to start the threads that are waiting +// on the sleep condition and to reset maxPly. When useSleepingThreads is set +// threads will be woken up at split time. -void ThreadsManager::exit() { +void ThreadsManager::wake_up() const { - for (int i = 0; i <= MAX_THREADS; i++) + for (int i = 0; i < size(); i++) { - assert(threads[i].do_sleep); + threads[i]->maxPly = 0; - threads[i].do_exit = true; // Search must be already finished - threads[i].wake_up(); + if (!useSleepingThreads) + threads[i]->wake_up(); + } +} - thread_join(threads[i].handle); // Wait for thread termination - lock_destroy(threads[i].sleepLock); - cond_destroy(threads[i].sleepCond); +// sleep() is called after the search finishes to ask all the threads but the +// main one to go waiting on a sleep condition. - for (int j = 0; j < MAX_SPLITPOINTS_PER_THREAD; j++) - lock_destroy(threads[i].splitPoints[j].lock); - } +void ThreadsManager::sleep() const { - lock_destroy(splitLock); - cond_destroy(sleepCond); + for (int i = 1; i < size(); i++) // Main thread will go to sleep by itself + threads[i]->do_sleep = true; // to avoid a race with start_searching() } @@ -271,10 +279,10 @@ void ThreadsManager::exit() { bool ThreadsManager::available_slave_exists(int master) const { - assert(master >= 0 && master < activeThreads); + assert(master >= 0 && master < size()); - for (int i = 0; i < activeThreads; i++) - if (threads[i].is_available_to(master)) + for (int i = 0; i < size(); i++) + if (threads[i]->is_available_to(master)) return true; return false; @@ -300,11 +308,9 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, assert(alpha < beta); assert(beta <= VALUE_INFINITE); assert(depth > DEPTH_ZERO); - assert(pos.thread() >= 0 && pos.thread() < activeThreads); - assert(activeThreads > 1); int master = pos.thread(); - Thread& masterThread = threads[master]; + Thread& masterThread = *threads[master]; if (masterThread.splitPointsCnt >= MAX_SPLITPOINTS_PER_THREAD) return bestValue; @@ -340,15 +346,15 @@ Value ThreadsManager::split(Position& pos, Stack* ss, Value alpha, Value beta, lock_grab(sp->lock); lock_grab(splitLock); - for (int i = 0; i < activeThreads && !Fake; i++) - if (threads[i].is_available_to(master)) + for (int i = 0; i < size() && !Fake; ++i) + if (threads[i]->is_available_to(master)) { sp->slavesMask |= 1ULL << i; - threads[i].curSplitPoint = sp; - threads[i].is_searching = true; // Slave leaves idle_loop() + threads[i]->curSplitPoint = sp; + threads[i]->is_searching = true; // Slave leaves idle_loop() if (useSleepingThreads) - threads[i].wake_up(); + threads[i]->wake_up(); if (++slavesCnt + 1 >= maxThreadsPerSplitPoint) // Master is always included break; @@ -399,72 +405,42 @@ template Value ThreadsManager::split(Position&, Stack*, Value, Value, Valu void ThreadsManager::set_timer(int msec) { - Thread& timer = threads[MAX_THREADS]; - - lock_grab(timer.sleepLock); - timer.maxPly = msec; - cond_signal(timer.sleepCond); // Wake up and restart the timer - lock_release(timer.sleepLock); + lock_grab(timer->sleepLock); + timer->maxPly = msec; + cond_signal(timer->sleepCond); // Wake up and restart the timer + lock_release(timer->sleepLock); } -// ThreadsManager::start_thinking() is used by UI thread to wake up the main -// thread parked in main_loop() and starting a new search. If asyncMode is true -// then function returns immediately, otherwise caller is blocked waiting for -// the search to finish. +// ThreadsManager::wait_for_search_finished() waits for main thread to go to +// sleep, this means search is finished. Then returns. -void ThreadsManager::start_thinking(const Position& pos, const LimitsType& limits, - const std::set& searchMoves, bool async) { - Thread& main = threads[0]; +void ThreadsManager::wait_for_search_finished() { + + Thread* main = threads[0]; + lock_grab(main->sleepLock); + while (!main->do_sleep) cond_wait(sleepCond, main->sleepLock); + lock_release(main->sleepLock); +} - lock_grab(main.sleepLock); - // Wait main thread has finished before to launch a new search - while (!main.do_sleep) - cond_wait(sleepCond, main.sleepLock); +// ThreadsManager::start_searching() wakes up the main thread sleeping in +// main_loop() so to start a new search, then returns immediately. + +void ThreadsManager::start_searching(const Position& pos, const LimitsType& limits, + const std::set& searchMoves) { + wait_for_search_finished(); + + Signals.stopOnPonderhit = Signals.firstRootMove = false; + Signals.stop = Signals.failedLowAtRoot = false; - // Copy input arguments to initialize the search RootPosition.copy(pos, 0); Limits = limits; RootMoves.clear(); - // Populate RootMoves with all the legal moves (default) or, if a searchMoves - // set is given, with the subset of legal moves to search. for (MoveList ml(pos); !ml.end(); ++ml) if (searchMoves.empty() || searchMoves.count(ml.move())) RootMoves.push_back(RootMove(ml.move())); - // Reset signals before to start the new search - Signals.stopOnPonderhit = Signals.firstRootMove = false; - Signals.stop = Signals.failedLowAtRoot = false; - - main.do_sleep = false; - cond_signal(main.sleepCond); // Wake up main thread and start searching - - if (!async) - while (!main.do_sleep) - cond_wait(sleepCond, main.sleepLock); - - lock_release(main.sleepLock); -} - - -// ThreadsManager::stop_thinking() is used by UI thread to raise a stop request -// and to wait for the main thread finishing the search. Needed to wait exiting -// and terminate the threads after a 'quit' command. - -void ThreadsManager::stop_thinking() { - - Thread& main = threads[0]; - - Search::Signals.stop = true; - - lock_grab(main.sleepLock); - - cond_signal(main.sleepCond); // In case is waiting for stop or ponderhit - - while (!main.do_sleep) - cond_wait(sleepCond, main.sleepLock); - - lock_release(main.sleepLock); + threads[0]->wake_up(); } diff --git a/src/thread.h b/src/thread.h index e71db835..9b0a8bcf 100644 --- a/src/thread.h +++ b/src/thread.h @@ -21,6 +21,7 @@ #define THREAD_H_INCLUDED #include +#include #include "material.h" #include "movepick.h" @@ -46,7 +47,6 @@ struct SplitPoint { MovePicker* mp; SplitPoint* parent; - // Shared data Lock lock; volatile uint64_t slavesMask; @@ -64,12 +64,22 @@ struct SplitPoint { /// tables so that once we get a pointer to an entry its life time is unlimited /// and we don't have to care about someone changing the entry under our feet. -struct Thread { +class Thread { + + Thread(const Thread&); // Only declared to disable the default ones + Thread& operator=(const Thread&); // that are not suitable in this case. + + typedef void (Thread::* Fn) (); + +public: + Thread(Fn fn); + ~Thread(); void wake_up(); bool cutoff_occurred() const; bool is_available_to(int master) const; void idle_loop(SplitPoint* sp_master); + void idle_loop() { idle_loop(NULL); } // Hack to allow storing in start_fn void main_loop(); void timer_loop(); void wait_for_stop_or_ponderhit(); @@ -81,7 +91,8 @@ struct Thread { int maxPly; Lock sleepLock; WaitCondition sleepCond; - ThreadHandle handle; + NativeHandle handle; + Fn start_fn; SplitPoint* volatile curSplitPoint; volatile int splitPointsCnt; volatile bool is_searching; @@ -100,34 +111,35 @@ class ThreadsManager { static storage duration are automatically set to zero before enter main() */ public: - Thread& operator[](int threadID) { return threads[threadID]; } - void init(); - void exit(); + void init(); // No c'tor becuase Threads is static and we need stuff initialized + ~ThreadsManager(); + Thread& operator[](int id) { return *threads[id]; } bool use_sleeping_threads() const { return useSleepingThreads; } int min_split_depth() const { return minimumSplitDepth; } - int size() const { return activeThreads; } + int size() const { return (int)threads.size(); } - void set_size(int cnt); + void wake_up() const; + void sleep() const; void read_uci_options(); bool available_slave_exists(int master) const; void set_timer(int msec); - void stop_thinking(); - void start_thinking(const Position& pos, const Search::LimitsType& limits, - const std::set& = std::set(), bool async = false); + void wait_for_search_finished(); + void start_searching(const Position& pos, const Search::LimitsType& limits, + const std::set& = std::set()); template Value split(Position& pos, Search::Stack* ss, Value alpha, Value beta, Value bestValue, Move* bestMove, Depth depth, Move threatMove, int moveCount, MovePicker* mp, int nodeType); private: - friend struct Thread; + friend class Thread; - Thread threads[MAX_THREADS + 1]; // Last one is used as a timer + std::vector threads; + Thread* timer; Lock splitLock; WaitCondition sleepCond; Depth minimumSplitDepth; int maxThreadsPerSplitPoint; - int activeThreads; bool useSleepingThreads; }; diff --git a/src/tt.h b/src/tt.h index 39c161df..ae530c2a 100644 --- a/src/tt.h +++ b/src/tt.h @@ -139,24 +139,21 @@ inline void TranspositionTable::refresh(const TTEntry* tte) const { /// A simple fixed size hash table used to store pawns and material /// configurations. It is basically just an array of Entry objects. -/// Without cluster concept or overwrite policy. +/// Without cluster concept, overwrite policy nor resizing. template struct SimpleHash { typedef SimpleHash Base; - void init() { - - if (entries) - return; + SimpleHash() { entries = new (std::nothrow) Entry[HashSize]; if (!entries) { std::cerr << "Failed to allocate " << HashSize * sizeof(Entry) << " bytes for hash table." << std::endl; - exit(EXIT_FAILURE); + ::exit(EXIT_FAILURE); } memset(entries, 0, HashSize * sizeof(Entry)); } diff --git a/src/uci.cpp b/src/uci.cpp index 718c7875..7c2bd1e5 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -67,7 +67,12 @@ void uci_loop() { is >> skipws >> token; if (token == "quit" || token == "stop") - Threads.stop_thinking(); + { + Search::Signals.stop = true; + + if (token == "quit") // Cannot quit while threads are still running + Threads.wait_for_search_finished(); + } else if (token == "ponderhit") { @@ -77,7 +82,7 @@ void uci_loop() { Search::Limits.ponder = false; if (Search::Signals.stopOnPonderhit) - Threads.stop_thinking(); + Search::Signals.stop = true; } else if (token == "go") @@ -223,7 +228,7 @@ namespace { limits.time = time[pos.side_to_move()]; limits.increment = inc[pos.side_to_move()]; - Threads.start_thinking(pos, limits, searchMoves, true); + Threads.start_searching(pos, limits, searchMoves); } diff --git a/src/ucioption.cpp b/src/ucioption.cpp index df73670b..4be580fc 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -73,7 +73,7 @@ OptionsMap::OptionsMap() { o["Cowardice"] = UCIOption(100, 0, 200, on_eval); o["Min Split Depth"] = UCIOption(msd, 4, 7, on_threads); o["Max Threads per Split Point"] = UCIOption(5, 4, 8, on_threads); - o["Threads"] = UCIOption(cpus, 1, MAX_THREADS); + o["Threads"] = UCIOption(cpus, 1, MAX_THREADS, on_threads); o["Use Sleeping Threads"] = UCIOption(true, on_threads); o["Hash"] = UCIOption(32, 4, 8192, on_hash_size); o["Clear Hash"] = UCIOption(on_clear_hash);