Skip to content

Commit 81c7975

Browse files
Joona Kiiskizamar
authored andcommitted
Use thread specific mutexes instead of a global one.
This is necessary to improve the scalability with high number of cores. There is no functional change in a single thread mode. Resolves official-stockfish#281
1 parent 4b59347 commit 81c7975

3 files changed

Lines changed: 34 additions & 33 deletions

File tree

src/search.cpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,13 +1526,12 @@ void Thread::idle_loop() {
15261526
// If this thread has been assigned work, launch a search
15271527
while (searching)
15281528
{
1529-
Threads.mutex.lock();
1529+
mutex.lock();
15301530

15311531
assert(activeSplitPoint);
1532-
15331532
SplitPoint* sp = activeSplitPoint;
15341533

1535-
Threads.mutex.unlock();
1534+
mutex.unlock();
15361535

15371536
Stack stack[MAX_PLY+4], *ss = stack+2; // To allow referencing (ss-2) and (ss+2)
15381537
Position pos(*sp->pos, this);
@@ -1618,20 +1617,24 @@ void Thread::idle_loop() {
16181617
sp = bestSp;
16191618

16201619
// Recheck the conditions under lock protection
1621-
Threads.mutex.lock();
16221620
sp->mutex.lock();
16231621

16241622
if ( sp->allSlavesSearching
1625-
&& sp->slavesMask.count() < MAX_SLAVES_PER_SPLITPOINT
1626-
&& can_join(sp))
1623+
&& sp->slavesMask.count() < MAX_SLAVES_PER_SPLITPOINT)
16271624
{
1628-
sp->slavesMask.set(idx);
1629-
activeSplitPoint = sp;
1630-
searching = true;
1625+
mutex.lock();
1626+
1627+
if (can_join(sp))
1628+
{
1629+
sp->slavesMask.set(idx);
1630+
activeSplitPoint = sp;
1631+
searching = true;
1632+
}
1633+
1634+
mutex.unlock();
16311635
}
16321636

16331637
sp->mutex.unlock();
1634-
Threads.mutex.unlock();
16351638
}
16361639
}
16371640

@@ -1687,12 +1690,11 @@ void check_time() {
16871690

16881691
else if (Limits.nodes)
16891692
{
1690-
Threads.mutex.lock();
1691-
16921693
int64_t nodes = RootPos.nodes_searched();
16931694

16941695
// Loop across all split points and sum accumulated SplitPoint nodes plus
16951696
// all the currently active positions nodes.
1697+
// FIXME: Racy...
16961698
for (Thread* th : Threads)
16971699
for (size_t i = 0; i < th->splitPointsSize; ++i)
16981700
{
@@ -1709,8 +1711,6 @@ void check_time() {
17091711
sp.mutex.unlock();
17101712
}
17111713

1712-
Threads.mutex.unlock();
1713-
17141714
if (nodes >= Limits.nodes)
17151715
Signals.stop = true;
17161716
}

src/thread.cpp

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ void Thread::split(Position& pos, Stack* ss, Value alpha, Value beta, Value* bes
144144
// Pick and init the next available split point
145145
SplitPoint& sp = splitPoints[splitPointsSize];
146146

147+
sp.mutex.lock(); // No contention here until we don't increment splitPointsSize
148+
147149
sp.master = this;
148150
sp.parentSplitPoint = activeSplitPoint;
149151
sp.slavesMask = 0, sp.slavesMask.set(idx);
@@ -160,35 +162,36 @@ void Thread::split(Position& pos, Stack* ss, Value alpha, Value beta, Value* bes
160162
sp.nodes = 0;
161163
sp.cutoff = false;
162164
sp.ss = ss;
163-
164-
// Try to allocate available threads and ask them to start searching setting
165-
// 'searching' flag. This must be done under lock protection to avoid concurrent
166-
// allocation of the same slave by another master.
167-
Threads.mutex.lock();
168-
sp.mutex.lock();
169-
170165
sp.allSlavesSearching = true; // Must be set under lock protection
166+
171167
++splitPointsSize;
172168
activeSplitPoint = &sp;
173169
activePosition = nullptr;
174170

171+
// Try to allocate available threads
175172
Thread* slave;
176173

177174
while ( sp.slavesMask.count() < MAX_SLAVES_PER_SPLITPOINT
178-
&& (slave = Threads.available_slave(activeSplitPoint)) != nullptr)
175+
&& (slave = Threads.available_slave(&sp)) != nullptr)
179176
{
180-
sp.slavesMask.set(slave->idx);
181-
slave->activeSplitPoint = activeSplitPoint;
182-
slave->searching = true; // Slave leaves idle_loop()
183-
slave->notify_one(); // Could be sleeping
177+
slave->mutex.lock();
178+
179+
if (slave->can_join(activeSplitPoint))
180+
{
181+
activeSplitPoint->slavesMask.set(slave->idx);
182+
slave->activeSplitPoint = activeSplitPoint;
183+
slave->searching = true;
184+
slave->sleepCondition.notify_one(); // Could be sleeping
185+
}
186+
187+
slave->mutex.unlock();
184188
}
185189

186190
// Everything is set up. The master thread enters the idle loop, from which
187191
// it will instantly launch a search, because its 'searching' flag is set.
188192
// The thread will return from the idle loop when all slaves have finished
189193
// their work at this split point.
190194
sp.mutex.unlock();
191-
Threads.mutex.unlock();
192195

193196
Thread::idle_loop(); // Force a call to base class idle_loop()
194197

@@ -198,13 +201,13 @@ void Thread::split(Position& pos, Stack* ss, Value alpha, Value beta, Value* bes
198201
assert(!searching);
199202
assert(!activePosition);
200203

204+
searching = true;
205+
201206
// We have returned from the idle loop, which means that all threads are
202-
// finished. Note that setting 'searching' and decreasing splitPointsSize must
203-
// be done under lock protection to avoid a race with Thread::available_to().
204-
Threads.mutex.lock();
207+
// finished. Note that decreasing splitPointsSize must be done under lock
208+
// protection to avoid a race with Thread::can_join().
205209
sp.mutex.lock();
206210

207-
searching = true;
208211
--splitPointsSize;
209212
activeSplitPoint = sp.parentSplitPoint;
210213
activePosition = &pos;
@@ -213,7 +216,6 @@ void Thread::split(Position& pos, Stack* ss, Value alpha, Value beta, Value* bes
213216
*bestValue = sp.bestValue;
214217

215218
sp.mutex.unlock();
216-
Threads.mutex.unlock();
217219
}
218220

219221

src/thread.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,6 @@ struct ThreadPool : public std::vector<Thread*> {
151151
void start_thinking(const Position&, const Search::LimitsType&, Search::StateStackPtr&);
152152

153153
Depth minimumSplitDepth;
154-
Mutex mutex;
155154
ConditionVariable sleepCondition;
156155
TimerThread* timer;
157156
};

0 commit comments

Comments
 (0)