// used to check for remaining available thinking time.
if (Limits.use_time_management())
Threads.set_timer(std::min(100, std::max(TimeMgr.available_time() / 16, TimerResolution)));
+ else if (Limits.nodes)
+ Threads.set_timer(2 * TimerResolution);
else
Threads.set_timer(100);
(ss+2)->killers[0] = (ss+2)->killers[1] = MOVE_NONE;
}
- // Enforce node limit here. FIXME: This only works with 1 search thread.
- if (Limits.nodes && pos.nodes_searched() >= Limits.nodes)
- Signals.stop = true;
-
if (!RootNode)
{
// Step 2. Check for aborted search and immediate draw
sp->mutex.lock();
+ assert(sp->activePositions[idx] == NULL);
+
+ sp->activePositions[idx] = &pos;
+
if (sp->nodeType == Root)
search<SplitPointRoot>(pos, ss+1, sp->alpha, sp->beta, sp->depth);
else if (sp->nodeType == PV)
assert(is_searching);
is_searching = false;
+ sp->activePositions[idx] = NULL;
sp->slavesMask &= ~(1ULL << idx);
sp->nodes += pos.nodes_searched();
void check_time() {
static Time::point lastInfoTime = Time::now();
+ int64_t nodes = 0; // Workaround silly 'uninitialized' gcc warning
if (Time::now() - lastInfoTime >= 1000)
{
if (Limits.ponder)
return;
+ if (Limits.nodes)
+ {
+ Threads.mutex.lock();
+
+ nodes = RootPosition.nodes_searched();
+
+ // Loop across all split points and sum accumulated SplitPoint nodes plus
+ // all the currently active slaves positions.
+ for (size_t i = 0; i < Threads.size(); i++)
+ for (int j = 0; j < Threads[i].splitPointsCnt; j++)
+ {
+ SplitPoint& sp = Threads[i].splitPoints[j];
+
+ sp.mutex.lock();
+
+ nodes += sp.nodes;
+ Bitboard sm = sp.slavesMask;
+ while (sm)
+ {
+ Position* pos = sp.activePositions[pop_lsb(&sm)];
+ nodes += pos ? pos->nodes_searched() : 0;
+ }
+
+ sp.mutex.unlock();
+ }
+
+ Threads.mutex.unlock();
+ }
+
Time::point elapsed = Time::now() - SearchTime;
bool stillAtFirstMove = Signals.firstRootMove
&& !Signals.failedLowAtRoot
|| stillAtFirstMove;
if ( (Limits.use_time_management() && noMoreTime)
- || (Limits.movetime && elapsed >= Limits.movetime))
+ || (Limits.movetime && elapsed >= Limits.movetime)
+ || (Limits.nodes && nodes >= Limits.nodes))
Signals.stop = true;
}
// 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) {
+Thread::Thread(Fn fn) : splitPoints() {
is_searching = do_exit = false;
maxPly = splitPointsCnt = 0;
void ThreadPool::exit() {
+ delete timer; // As first becuase check_time() accesses threads data
+
for (size_t i = 0; i < threads.size(); i++)
delete threads[i];
-
- delete timer;
}
// Try to allocate available threads and ask them to start searching setting
// is_searching flag. This must be done under lock protection to avoid concurrent
// allocation of the same slave by another master.
- sp.mutex.lock();
mutex.lock();
+ sp.mutex.lock();
for (size_t i = 0; i < threads.size() && !Fake; ++i)
if (threads[i]->is_available_to(master))
master->splitPointsCnt++;
- mutex.unlock();
sp.mutex.unlock();
+ mutex.unlock();
// Everything is set up. The master thread enters the idle loop, from which
// it will instantly launch a search, because its is_searching flag is set.
// We have returned from the idle loop, which means that all threads are
// finished. Note that setting is_searching and decreasing splitPointsCnt is
// done under lock protection to avoid a race with Thread::is_available_to().
- sp.mutex.lock(); // To protect sp.nodes
mutex.lock();
+ sp.mutex.lock();
master->is_searching = true;
master->splitPointsCnt--;
pos.set_nodes_searched(pos.nodes_searched() + sp.nodes);
*bestMove = sp.bestMove;
- mutex.unlock();
sp.mutex.unlock();
+ mutex.unlock();
return sp.bestValue;
}