This simple patch has devastating consequences ;-)
Now an available thread goes to sleep and is waked up after
being allocated.
This patch allows Stockfish to dramatically increase performances
on HyperThreading systems.
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
int ActiveThreads;
volatile bool AllThreadsShouldExit;
Thread threads[MAX_THREADS];
int ActiveThreads;
volatile bool AllThreadsShouldExit;
Thread threads[MAX_THREADS];
WaitCondition WaitCond[MAX_THREADS];
};
WaitCondition WaitCond[MAX_THREADS];
};
// If we are not thinking, wait for a condition to be signaled
// instead of wasting CPU time polling for work.
// If we are not thinking, wait for a condition to be signaled
// instead of wasting CPU time polling for work.
- while (threadID >= ActiveThreads || threads[threadID].state == THREAD_INITIALIZING)
+ while ( threadID >= ActiveThreads
+ || threads[threadID].state == THREAD_INITIALIZING
+ || (!sp && threads[threadID].state == THREAD_AVAILABLE))
{
assert(!sp);
assert(threadID != 0);
{
assert(!sp);
assert(threadID != 0);
if (AllThreadsShouldExit)
break;
if (AllThreadsShouldExit)
break;
- threads[threadID].state = THREAD_AVAILABLE;
-
- lock_grab(&WaitLock);
- if (threadID >= ActiveThreads || threads[threadID].state == THREAD_INITIALIZING)
- cond_wait(&WaitCond[threadID], &WaitLock);
+ // Retest condition under lock protection
+ if (!( threadID >= ActiveThreads
+ || threads[threadID].state == THREAD_INITIALIZING
+ || (!sp && threads[threadID].state == THREAD_AVAILABLE)))
+ {
+ lock_release(&MPLock);
+ continue;
+ }
- lock_release(&WaitLock);
+ // Put thread to sleep
+ threads[threadID].state = THREAD_AVAILABLE;
+ cond_wait(&WaitCond[threadID], &MPLock);
+ lock_release(&MPLock);
}
// If this thread has been assigned work, launch a search
}
// If this thread has been assigned work, launch a search
// Initialize global locks
lock_init(&MPLock);
// Initialize global locks
lock_init(&MPLock);
for (i = 0; i < MAX_THREADS; i++)
cond_init(&WaitCond[i]);
for (i = 0; i < MAX_THREADS; i++)
cond_init(&WaitCond[i]);
for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++)
lock_destroy(&(threads[i].splitPoints[j].lock));
for (int j = 0; j < MAX_ACTIVE_SPLIT_POINTS; j++)
lock_destroy(&(threads[i].splitPoints[j].lock));
- lock_destroy(&WaitLock);
lock_destroy(&MPLock);
// Now we can safely destroy the wait conditions
lock_destroy(&MPLock);
// Now we can safely destroy the wait conditions
assert(i == master || threads[i].state == THREAD_BOOKED);
threads[i].state = THREAD_WORKISWAITING; // This makes the slave to exit from idle_loop()
assert(i == master || threads[i].state == THREAD_BOOKED);
threads[i].state = THREAD_WORKISWAITING; // This makes the slave to exit from idle_loop()
+ if (i != master)
+ wake_sleeping_thread(i);
}
// Everything is set up. The master thread enters the idle loop, from
}
// Everything is set up. The master thread enters the idle loop, from
void ThreadsManager::wake_sleeping_thread(int threadID) {
void ThreadsManager::wake_sleeping_thread(int threadID) {
cond_signal(&WaitCond[threadID]);
cond_signal(&WaitCond[threadID]);
- lock_release(&WaitLock);