kernel/thread: Use a rw_spinlock for the sThreadHashLock.

On a dual-core system with no other applications but the standard ones
running, my standard "compile HaikuDepot with hot disk cache" benchmark
shows a consistent ~5% improvement after this patch (~33.7s -> ~31.9s sys).
On systems with higher core and thread counts, these numbers are probably
very much larger (I'd imagine it could be up to even 10 or 15%.)

Change-Id: I5df2a075bae7c71b84c6fcd33ead60df8e844757
Reviewed-on: https://review.haiku-os.org/c/861
Reviewed-by: Adrien Destugues <pulkomandy@gmail.com>
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Augustin Cavalier 2019-01-09 00:57:21 -05:00 committed by waddlesplash
parent e6bb34532a
commit 568bb7eeab

View File

@ -73,7 +73,7 @@ typedef BKernel::TeamThreadTable<Thread> ThreadHashTable;
// thread list
static Thread sIdleThreads[SMP_MAX_CPUS];
static ThreadHashTable sThreadHash;
static spinlock sThreadHashLock = B_SPINLOCK_INITIALIZER;
static rw_spinlock sThreadHashLock = B_RW_SPINLOCK_INITIALIZER;
static thread_id sNextThreadID = 2;
// ID 1 is allocated for the kernel by Team::Team() behind our back
@ -227,7 +227,7 @@ Thread::Thread(const char* name, thread_id threadID, struct cpu_ent* cpu)
msg.read_sem = -1;
// add to thread table -- yet invisible
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
InterruptsWriteSpinLocker threadHashLocker(sThreadHashLock);
sThreadHash.Insert(this);
}
@ -261,7 +261,7 @@ Thread::~Thread()
mutex_destroy(&fLock);
// remove from thread table
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
InterruptsWriteSpinLocker threadHashLocker(sThreadHashLock);
sThreadHash.Remove(this);
}
@ -287,7 +287,7 @@ Thread::Create(const char* name, Thread*& _thread)
/*static*/ Thread*
Thread::Get(thread_id id)
{
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
Thread* thread = sThreadHash.Lookup(id);
if (thread != NULL)
thread->AcquireReference();
@ -299,7 +299,7 @@ Thread::Get(thread_id id)
Thread::GetAndLock(thread_id id)
{
// look it up and acquire a reference
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
Thread* thread = sThreadHash.Lookup(id);
if (thread == NULL)
return NULL;
@ -333,7 +333,7 @@ Thread::GetDebug(thread_id id)
/*static*/ bool
Thread::IsAlive(thread_id id)
{
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
return sThreadHash.Lookup(id) != NULL;
}
@ -395,7 +395,7 @@ Thread::Init(bool idleThread)
bool
Thread::IsAlive() const
{
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
return sThreadHash.Lookup(id) != NULL;
}
@ -486,7 +486,7 @@ Thread::DeactivateCPUTimeUserTimers()
ThreadListIterator::ThreadListIterator()
{
// queue the entry
InterruptsSpinLocker locker(sThreadHashLock);
InterruptsWriteSpinLocker locker(sThreadHashLock);
sThreadHash.InsertIteratorEntry(&fEntry);
}
@ -494,7 +494,7 @@ ThreadListIterator::ThreadListIterator()
ThreadListIterator::~ThreadListIterator()
{
// remove the entry
InterruptsSpinLocker locker(sThreadHashLock);
InterruptsWriteSpinLocker locker(sThreadHashLock);
sThreadHash.RemoveIteratorEntry(&fEntry);
}
@ -503,7 +503,7 @@ Thread*
ThreadListIterator::Next()
{
// get the next team -- if there is one, get reference for it
InterruptsSpinLocker locker(sThreadHashLock);
InterruptsWriteSpinLocker locker(sThreadHashLock);
Thread* thread = sThreadHash.NextElement(&fEntry);
if (thread != NULL)
thread->AcquireReference();
@ -1016,7 +1016,7 @@ thread_create_thread(const ThreadCreationAttributes& attributes, bool kernel)
ThreadLocker threadLocker(thread);
InterruptsSpinLocker threadCreationLocker(gThreadCreationLock);
SpinLocker threadHashLocker(sThreadHashLock);
WriteSpinLocker threadHashLocker(sThreadHashLock);
// check the thread limit
if (sUsedThreads >= sMaxThreads) {
@ -2164,7 +2164,7 @@ thread_exit(void)
SpinLocker threadCreationLocker(gThreadCreationLock);
// mark invisible in global hash/list, so it's no longer accessible
SpinLocker threadHashLocker(sThreadHashLock);
WriteSpinLocker threadHashLocker(sThreadHashLock);
thread->visible = false;
sUsedThreads--;
threadHashLocker.Unlock();
@ -2375,7 +2375,7 @@ thread_reset_for_exec(void)
thread_id
allocate_thread_id()
{
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
InterruptsWriteSpinLocker threadHashLocker(sThreadHashLock);
// find the next unused ID
thread_id id;
@ -2396,7 +2396,7 @@ allocate_thread_id()
thread_id
peek_next_thread_id()
{
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
return sNextThreadID;
}
@ -2423,7 +2423,7 @@ thread_yield(void)
void
thread_map(void (*function)(Thread* thread, void* data), void* data)
{
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
InterruptsWriteSpinLocker threadHashLocker(sThreadHashLock);
for (ThreadHashTable::Iterator it = sThreadHash.GetIterator();
Thread* thread = it.Next();) {
@ -2609,7 +2609,7 @@ thread_max_threads(void)
int32
thread_used_threads(void)
{
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
return sUsedThreads;
}
@ -3153,10 +3153,11 @@ find_thread(const char* name)
if (name == NULL)
return thread_get_current_thread_id();
InterruptsSpinLocker threadHashLocker(sThreadHashLock);
InterruptsReadSpinLocker threadHashLocker(sThreadHashLock);
// TODO: Scanning the whole hash with the thread hash lock held isn't
// exactly cheap -- although this function is probably used very rarely.
// Scanning the whole hash with the thread hash lock held isn't exactly
// cheap, but since this function is probably used very rarely, and we
// only need a read lock, it's probably acceptable.
for (ThreadHashTable::Iterator it = sThreadHash.GetIterator();
Thread* thread = it.Next();) {