[hwasan] Fix lock contention on thread creation.

Do not hold the free/live thread list lock longer than necessary.
This change speeds up the following benchmark 10x.

constexpr int kTopThreads = 50;
constexpr int kChildThreads = 20;
constexpr int kChildIterations = 8;

void Thread() {
  for (int i = 0; i < kChildIterations; ++i) {
    std::vector<std::thread> threads;
    for (int i = 0; i < kChildThreads; ++i)
      threads.emplace_back([](){});
    for (auto& t : threads)
      t.join();
  }
}

int main() {
  std::vector<std::thread> threads;
  for (int i = 0; i < kTopThreads; ++i)
    threads.emplace_back(Thread);
  for (auto& t : threads)
    t.join();
}

Differential Revision: https://reviews.llvm.org/D100348
This commit is contained in:
Evgenii Stepanov
2021-04-12 13:35:32 -07:00
parent 1035123ac5
commit 51aa61e74b

View File

@@ -86,17 +86,22 @@ class HwasanThreadList {
}
Thread *CreateCurrentThread() {
Thread *t;
Thread *t = nullptr;
{
SpinMutexLock l(&list_mutex_);
SpinMutexLock l(&free_list_mutex_);
if (!free_list_.empty()) {
t = free_list_.back();
free_list_.pop_back();
uptr start = (uptr)t - ring_buffer_size_;
internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
} else {
t = AllocThread();
}
}
if (t) {
uptr start = (uptr)t - ring_buffer_size_;
internal_memset((void *)start, 0, ring_buffer_size_ + sizeof(Thread));
} else {
t = AllocThread();
}
{
SpinMutexLock l(&live_list_mutex_);
live_list_.push_back(t);
}
t->Init((uptr)t - ring_buffer_size_, ring_buffer_size_);
@@ -110,6 +115,7 @@ class HwasanThreadList {
}
void RemoveThreadFromLiveList(Thread *t) {
SpinMutexLock l(&live_list_mutex_);
for (Thread *&t2 : live_list_)
if (t2 == t) {
// To remove t2, copy the last element of the list in t2's position, and
@@ -124,10 +130,10 @@ class HwasanThreadList {
void ReleaseThread(Thread *t) {
RemoveThreadStats(t);
t->Destroy();
SpinMutexLock l(&list_mutex_);
RemoveThreadFromLiveList(t);
free_list_.push_back(t);
DontNeedThread(t);
RemoveThreadFromLiveList(t);
SpinMutexLock l(&free_list_mutex_);
free_list_.push_back(t);
}
Thread *GetThreadByBufferAddress(uptr p) {
@@ -144,7 +150,7 @@ class HwasanThreadList {
template <class CB>
void VisitAllLiveThreads(CB cb) {
SpinMutexLock l(&list_mutex_);
SpinMutexLock l(&live_list_mutex_);
for (Thread *t : live_list_) cb(t);
}
@@ -180,9 +186,10 @@ class HwasanThreadList {
uptr ring_buffer_size_;
uptr thread_alloc_size_;
SpinMutex free_list_mutex_;
InternalMmapVector<Thread *> free_list_;
SpinMutex live_list_mutex_;
InternalMmapVector<Thread *> live_list_;
SpinMutex list_mutex_;
ThreadStats stats_;
SpinMutex stats_mutex_;