From b25183f67337237c630290c0202fa7d78f6189b0 Mon Sep 17 00:00:00 2001 From: Andrii Grynenko Date: Thu, 14 Apr 2016 11:19:59 -0700 Subject: [PATCH] Improve folly::ThreadLocal perf Summary: This fixes folly::ThreadLocal perf after several refactorings which touched the code. Reviewed By: ericniebler Differential Revision: D3170761 fb-gh-sync-id: d44198f19aebc9f9f2588a65950efba0694e2a11 fbshipit-source-id: d44198f19aebc9f9f2588a65950efba0694e2a11 --- folly/detail/ThreadLocalDetail.cpp | 27 +++++++++++++-------------- folly/detail/ThreadLocalDetail.h | 26 ++++++++++++++++++++++---- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/folly/detail/ThreadLocalDetail.cpp b/folly/detail/ThreadLocalDetail.cpp index fcee5c7e..9e7fda68 100644 --- a/folly/detail/ThreadLocalDetail.cpp +++ b/folly/detail/ThreadLocalDetail.cpp @@ -26,12 +26,24 @@ StaticMetaBase::StaticMetaBase(ThreadEntry* (*threadEntry)()) } void StaticMetaBase::onThreadExit(void* ptr) { +#ifdef FOLLY_TLD_USE_FOLLY_TLS + auto threadEntry = static_cast(ptr); +#else std::unique_ptr threadEntry(static_cast(ptr)); +#endif DCHECK_GT(threadEntry->elementsCapacity, 0); auto& meta = *threadEntry->meta; + + // Make sure this ThreadEntry is available if ThreadLocal A is accessed in + // ThreadLocal B destructor. + pthread_setspecific(meta.pthreadKey_, threadEntry); + SCOPE_EXIT { + pthread_setspecific(meta.pthreadKey_, nullptr); + }; + { std::lock_guard g(meta.lock_); - meta.erase(threadEntry.get()); + meta.erase(&(*threadEntry)); // No need to hold the lock any longer; the ThreadEntry is private to this // thread now that it's been removed from meta. } @@ -210,19 +222,6 @@ void StaticMetaBase::reserve(EntryID* id) { free(reallocated); } -ElementWrapper& StaticMetaBase::get(EntryID* ent) { - ThreadEntry* threadEntry = (*threadEntry_)(); - uint32_t id = ent->getOrInvalid(); - // if id is invalid, it is equal to uint32_t's max value. - // x <= max value is always true - if (UNLIKELY(threadEntry->elementsCapacity <= id)) { - reserve(ent); - id = ent->getOrInvalid(); - assert(threadEntry->elementsCapacity > id); - } - return threadEntry->elements[id]; -} - FOLLY_STATIC_CTOR_PRIORITY_MAX PthreadKeyUnregister PthreadKeyUnregister::instance_; }} diff --git a/folly/detail/ThreadLocalDetail.h b/folly/detail/ThreadLocalDetail.h index 1fa4844d..65ecfc67 100644 --- a/folly/detail/ThreadLocalDetail.h +++ b/folly/detail/ThreadLocalDetail.h @@ -289,7 +289,7 @@ struct StaticMetaBase { // StaticMeta; you can specify multiple Tag types to break that lock. template struct StaticMeta : StaticMetaBase { - StaticMeta() : StaticMetaBase(&StaticMeta::getThreadEntry) { + StaticMeta() : StaticMetaBase(&StaticMeta::getThreadEntrySlow) { #if FOLLY_HAVE_PTHREAD_ATFORK int ret = pthread_atfork( /*prepare*/ &StaticMeta::preFork, @@ -313,13 +313,31 @@ struct StaticMeta : StaticMetaBase { return *instance; } + ElementWrapper& get(EntryID* ent) { + ThreadEntry* threadEntry = getThreadEntry(); + uint32_t id = ent->getOrInvalid(); + // if id is invalid, it is equal to uint32_t's max value. + // x <= max value is always true + if (UNLIKELY(threadEntry->elementsCapacity <= id)) { + reserve(ent); + id = ent->getOrInvalid(); + assert(threadEntry->elementsCapacity > id); + } + return threadEntry->elements[id]; + } + static ThreadEntry* getThreadEntrySlow() { auto& meta = instance(); auto key = meta.pthreadKey_; ThreadEntry* threadEntry = static_cast(pthread_getspecific(key)); if (!threadEntry) { +#ifdef FOLLY_TLD_USE_FOLLY_TLS + static FOLLY_TLS ThreadEntry threadEntrySingleton; + threadEntry = &threadEntrySingleton; +#else threadEntry = new ThreadEntry(); +#endif threadEntry->meta = &meta; int ret = pthread_setspecific(key, threadEntry); checkPosixError(ret, "pthread_setspecific failed"); @@ -327,15 +345,15 @@ struct StaticMeta : StaticMetaBase { return threadEntry; } - static ThreadEntry* getThreadEntry() { + inline static ThreadEntry* getThreadEntry() { #ifdef FOLLY_TLD_USE_FOLLY_TLS static FOLLY_TLS ThreadEntry* threadEntryCache{nullptr}; if (UNLIKELY(threadEntryCache == nullptr)) { - threadEntryCache = getThreadEntrySlow(); + threadEntryCache = instance().threadEntry_(); } return threadEntryCache; #else - return getThreadEntrySlow(); + return instance().threadEntry_(); #endif } -- 2.34.1