Skip to content

Commit 00d9e9f

Browse files
lucasartzamar
authored andcommitted
Use atomics instead of volatile
Rely on well defined behaviour for message passing, instead of volatile. Three versions have been tested, to make sure this wouldn't cause a slowdown on any platform. v1: Sequentially consistent atomics No mesurable regression, despite the extra memory barriers on x86. Even with 15 threads and extreme time pressure, both acting as a magnifying glass: threads=15, tc=2+0.02 ELO: 2.59 +-3.4 (95%) LOS: 93.3% Total: 18132 W: 4113 L: 3978 D: 10041 threads=7, tc=2+0.02 ELO: -1.64 +-3.6 (95%) LOS: 18.8% Total: 16914 W: 4053 L: 4133 D: 8728 v2: Acquire/Release semantics This version generates no extra barriers for x86 (on the hot path). As expected, no regression either, under the same conditions: threads=15, tc=2+0.02 ELO: 2.85 +-3.3 (95%) LOS: 95.4% Total: 19661 W: 4640 L: 4479 D: 10542 threads=7, tc=2+0.02 ELO: 0.23 +-3.5 (95%) LOS: 55.1% Total: 18108 W: 4326 L: 4314 D: 9468 As suggested by Joona, another test at LTC: threads=15, tc=20+0.05 ELO: 0.64 +-2.6 (95%) LOS: 68.3% Total: 20000 W: 3053 L: 3016 D: 13931 v3: Final version: SeqCst/Relaxed threads=15, tc=10+0.1 ELO: 0.87 +-3.9 (95%) LOS: 67.1% Total: 9541 W: 1478 L: 1454 D: 6609 Resolves #474
1 parent 3428a28 commit 00d9e9f

File tree

4 files changed

+22
-20
lines changed

4 files changed

+22
-20
lines changed

src/search.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
namespace Search {
3939

40-
volatile SignalsType Signals;
40+
SignalsType Signals;
4141
LimitsType Limits;
4242
StateStackPtr SetupStates;
4343
}
@@ -581,8 +581,8 @@ namespace {
581581
if (!RootNode)
582582
{
583583
// Step 2. Check for aborted search and immediate draw
584-
if (Signals.stop || pos.is_draw() || ss->ply >= MAX_PLY)
585-
return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos)
584+
if (Signals.stop.load(std::memory_order_relaxed) || pos.is_draw() || ss->ply >= MAX_PLY)
585+
return ss->ply >= MAX_PLY && !inCheck ? evaluate(pos)
586586
: DrawValue[pos.side_to_move()];
587587

588588
// Step 3. Mate distance pruning. Even if we mate at the next move our score
@@ -841,7 +841,7 @@ namespace {
841841

842842
if (RootNode && thisThread == Threads.main())
843843
{
844-
Signals.firstRootMove = (moveCount == 1);
844+
Signals.firstRootMove = moveCount == 1;
845845

846846
if (Time.elapsed() > 3000)
847847
sync_cout << "info depth " << depth / ONE_PLY
@@ -1008,7 +1008,7 @@ namespace {
10081008
// Finished searching the move. If a stop occurred, the return value of
10091009
// the search cannot be trusted, and we return immediately without
10101010
// updating best move, PV and TT.
1011-
if (Signals.stop)
1011+
if (Signals.stop.load(std::memory_order_relaxed))
10121012
return VALUE_ZERO;
10131013

10141014
if (RootNode)
@@ -1577,7 +1577,7 @@ void check_time() {
15771577
{
15781578
bool stillAtFirstMove = Signals.firstRootMove
15791579
&& !Signals.failedLowAtRoot
1580-
&& elapsed > Time.available() * 75 / 100;
1580+
&& elapsed > Time.available() * 3 / 4;
15811581

15821582
if ( stillAtFirstMove
15831583
|| elapsed > Time.maximum() - 2 * TimerThread::Resolution)

src/search.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
#ifndef SEARCH_H_INCLUDED
2121
#define SEARCH_H_INCLUDED
2222

23-
#include <memory> // For std::auto_ptr
23+
#include <atomic>
24+
#include <memory> // For std::unique_ptr
2425
#include <stack>
2526
#include <vector>
2627

@@ -91,16 +92,16 @@ struct LimitsType {
9192
TimePoint startTime;
9293
};
9394

94-
/// The SignalsType struct stores volatile flags updated during the search
95+
/// The SignalsType struct stores atomic flags updated during the search
9596
/// typically in an async fashion e.g. to stop the search by the GUI.
9697

9798
struct SignalsType {
98-
bool stop, stopOnPonderhit, firstRootMove, failedLowAtRoot;
99+
std::atomic<bool> stop, stopOnPonderhit, firstRootMove, failedLowAtRoot;
99100
};
100101

101102
typedef std::unique_ptr<std::stack<StateInfo>> StateStackPtr;
102103

103-
extern volatile SignalsType Signals;
104+
extern SignalsType Signals;
104105
extern LimitsType Limits;
105106
extern StateStackPtr SetupStates;
106107

src/thread.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,15 @@ void ThreadBase::notify_one() {
6868

6969
// ThreadBase::wait() set the thread to sleep until 'condition' turns true
7070

71-
void ThreadBase::wait(volatile const bool& condition) {
71+
void ThreadBase::wait(std::atomic<bool>& condition) {
7272

7373
std::unique_lock<Mutex> lk(mutex);
74-
sleepCondition.wait(lk, [&]{ return condition; });
74+
sleepCondition.wait(lk, [&]{ return bool(condition); });
7575
}
7676

7777

7878
// ThreadBase::wait_while() set the thread to sleep until 'condition' turns false
79-
80-
void ThreadBase::wait_while(volatile const bool& condition) {
79+
void ThreadBase::wait_while(std::atomic<bool>& condition) {
8180

8281
std::unique_lock<Mutex> lk(mutex);
8382
sleepCondition.wait(lk, [&]{ return !condition; });
@@ -87,7 +86,7 @@ void ThreadBase::wait_while(volatile const bool& condition) {
8786
// Thread c'tor makes some init but does not launch any execution thread that
8887
// will be started only when c'tor returns.
8988

90-
Thread::Thread() /* : splitPoints() */ { // Initialization of non POD broken in MSVC
89+
Thread::Thread() {
9190

9291
searching = false;
9392
maxPly = 0;

src/thread.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,16 @@ const size_t MAX_THREADS = 128;
4444

4545
struct ThreadBase : public std::thread {
4646

47+
ThreadBase() { exit = false; }
4748
virtual ~ThreadBase() = default;
4849
virtual void idle_loop() = 0;
4950
void notify_one();
50-
void wait(volatile const bool& b);
51-
void wait_while(volatile const bool& b);
51+
void wait(std::atomic<bool>& b);
52+
void wait_while(std::atomic<bool>& b);
5253

5354
Mutex mutex;
5455
ConditionVariable sleepCondition;
55-
volatile bool exit = false;
56+
std::atomic<bool> exit;
5657
};
5758

5859

@@ -72,7 +73,7 @@ struct Thread : public ThreadBase {
7273
Endgames endgames;
7374
size_t idx, PVIdx;
7475
int maxPly;
75-
volatile bool searching;
76+
std::atomic<bool> searching;
7677

7778
Position rootPos;
7879
Search::RootMoveVector rootMoves;
@@ -87,10 +88,11 @@ struct Thread : public ThreadBase {
8788
/// special threads: the main one and the recurring timer.
8889

8990
struct MainThread : public Thread {
91+
MainThread() { thinking = true; } // Avoid a race with start_thinking()
9092
virtual void idle_loop();
9193
void join();
9294
void think();
93-
volatile bool thinking = true; // Avoid a race with start_thinking()
95+
std::atomic<bool> thinking;
9496
};
9597

9698
struct TimerThread : public ThreadBase {

0 commit comments

Comments
 (0)