mirror of
https://github.com/HChaZZY/Stockfish.git
synced 2025-12-20 00:56:39 +08:00
Get rid of timer thread
Unfortunately std::condition_variable::wait_for() is not accurate in general case and the timer thread can wake up also after tens or even hundreds of millisecs after time has elapsded. CPU load, process priorities, number of concurrent threads, even from other processes, will have effect upon it. Even official documentation says: "This function may block for longer than timeout_duration due to scheduling or resource contention delays." So retire timer and use a polling scheme based on a local thread counter that counts search() calls and a small trick to keep polling frequency constant, independently from the number of threads. Tested for no regression at very fast TC 2+0.05 th 7: LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 32969 W: 6720 L: 6620 D: 19629 TC 2+0.05 th 1: LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 7765 W: 1917 L: 1765 D: 4083 And at STC TC, both single thread LLR: 2.96 (-2.94,2.94) [-3.00,1.00] Total: 15587 W: 3036 L: 2905 D: 9646 And with 7 threads LLR: 2.95 (-2.94,2.94) [-3.00,1.00] Total: 8149 W: 1367 L: 1227 D: 5555 bench: 8639247
This commit is contained in:
@@ -66,7 +66,7 @@ void ThreadBase::notify_one() {
|
||||
|
||||
// ThreadBase::wait() set the thread to sleep until 'condition' turns true
|
||||
|
||||
void ThreadBase::wait(std::atomic<bool>& condition) {
|
||||
void ThreadBase::wait(std::atomic_bool& condition) {
|
||||
|
||||
std::unique_lock<Mutex> lk(mutex);
|
||||
sleepCondition.wait(lk, [&]{ return bool(condition); });
|
||||
@@ -74,7 +74,7 @@ void ThreadBase::wait(std::atomic<bool>& condition) {
|
||||
|
||||
|
||||
// ThreadBase::wait_while() set the thread to sleep until 'condition' turns false
|
||||
void ThreadBase::wait_while(std::atomic<bool>& condition) {
|
||||
void ThreadBase::wait_while(std::atomic_bool& condition) {
|
||||
|
||||
std::unique_lock<Mutex> lk(mutex);
|
||||
sleepCondition.wait(lk, [&]{ return !condition; });
|
||||
@@ -86,34 +86,14 @@ void ThreadBase::wait_while(std::atomic<bool>& condition) {
|
||||
|
||||
Thread::Thread() {
|
||||
|
||||
searching = false;
|
||||
maxPly = 0;
|
||||
searching = resetCallsCnt = false;
|
||||
maxPly = callsCnt = 0;
|
||||
history.clear();
|
||||
counterMoves.clear();
|
||||
idx = Threads.size(); // Starts from 0
|
||||
}
|
||||
|
||||
|
||||
// TimerThread::idle_loop() is where the timer thread waits Resolution milliseconds
|
||||
// and then calls check_time(). When not searching, thread sleeps until it's woken up.
|
||||
|
||||
void TimerThread::idle_loop() {
|
||||
|
||||
while (!exit)
|
||||
{
|
||||
std::unique_lock<Mutex> lk(mutex);
|
||||
|
||||
if (!exit)
|
||||
sleepCondition.wait_for(lk, std::chrono::milliseconds(run ? Resolution : INT_MAX));
|
||||
|
||||
lk.unlock();
|
||||
|
||||
if (!exit && run)
|
||||
check_time();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Thread::idle_loop() is where the thread is parked when it has no work to do
|
||||
|
||||
void Thread::idle_loop() {
|
||||
@@ -174,7 +154,6 @@ void MainThread::join() {
|
||||
|
||||
void ThreadPool::init() {
|
||||
|
||||
timer = new_thread<TimerThread>();
|
||||
push_back(new_thread<MainThread>());
|
||||
read_uci_options();
|
||||
}
|
||||
@@ -185,9 +164,6 @@ void ThreadPool::init() {
|
||||
|
||||
void ThreadPool::exit() {
|
||||
|
||||
delete_thread(timer); // As first because check_time() accesses threads data
|
||||
timer = nullptr;
|
||||
|
||||
for (Thread* th : *this)
|
||||
delete_thread(th);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user