Commit b25183f6 authored by Andrii Grynenko's avatar Andrii Grynenko Committed by Facebook Github Bot 8

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
parent a6692f12
......@@ -26,12 +26,24 @@ StaticMetaBase::StaticMetaBase(ThreadEntry* (*threadEntry)())
}
void StaticMetaBase::onThreadExit(void* ptr) {
#ifdef FOLLY_TLD_USE_FOLLY_TLS
auto threadEntry = static_cast<ThreadEntry*>(ptr);
#else
std::unique_ptr<ThreadEntry> threadEntry(static_cast<ThreadEntry*>(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<std::mutex> 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_;
}}
......@@ -289,7 +289,7 @@ struct StaticMetaBase {
// StaticMeta; you can specify multiple Tag types to break that lock.
template <class Tag>
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<ThreadEntry*>(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
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment