Skip to content

Commit

Permalink
in thread-local meta, iterate snapshot of atomic-grow-array
Browse files Browse the repository at this point in the history
Summary:
Iterate a snapshot of the id-to-thread-entry-set-map rather than iterating the map directly. Iterating a snapshot can avoid some extra loads and branches on every index being iterated as compared with iterating the map directly. A snapshot of an atomic-grow-array is always valid until the array is destroyed.

The typical way to iterate `atomic_grow_array` is to iterate a snapshot gotten via member `as_view`. This works when there is no externally-known array size, since the array does not internally track any actual size or other information about elements that have already been accessed. But in `StaticMeta` we do track an upper bound on elements that have already been accessed, so we may use `as_ptr_span` and then `subspan` on that.

Differential Revision: D66744595

fbshipit-source-id: 93f1d9693d998fb2c236594ac69f390f8c8bf0c5
  • Loading branch information
yfeldblum authored and facebook-github-bot committed Dec 5, 2024
1 parent 30b63c1 commit d8d0aa4
Showing 1 changed file with 15 additions and 9 deletions.
24 changes: 15 additions & 9 deletions folly/detail/ThreadLocalDetail.h
Original file line number Diff line number Diff line change
Expand Up @@ -505,9 +505,9 @@ struct StaticMetaBase {
* from the allId2ThreadEntrySets_.
*/
FOLLY_ALWAYS_INLINE void removeThreadEntryFromAllInMap(ThreadEntry* te) {
uint32_t maxId = nextId_.load();
for (uint32_t i = 0; i < maxId; ++i) {
allId2ThreadEntrySets_[i].wlock()->erase(te);
for (const auto ptr : getThreadEntrySetsPtrSpan()) {
auto& set = *ptr;
set.wlock()->erase(te);
}
}

Expand All @@ -520,9 +520,9 @@ struct StaticMetaBase {
if (needForkLock) {
rlocked.lock();
}
uint32_t maxId = nextId_.load();
for (uint32_t i = 0; i < maxId; ++i) {
if (allId2ThreadEntrySets_[i].rlock()->contains(te)) {
for (const auto ptr : getThreadEntrySetsPtrSpan()) {
auto& set = *ptr;
if (set.rlock()->contains(te)) {
return false;
}
}
Expand All @@ -536,6 +536,12 @@ struct StaticMetaBase {
static ElementWrapper* reallocate(
ThreadEntry* threadEntry, uint32_t idval, size_t& newCapacity);

span<SynchronizedThreadEntrySet* const> getThreadEntrySetsPtrSpan() {
const auto sets = allId2ThreadEntrySets_.as_view().as_ptr_span();
const size_t nextId = nextId_.load();
return sets.subspan(0, std::min(sets.size(), nextId));
}

relaxed_atomic_uint32_t nextId_;
std::vector<uint32_t> freeIds_;
std::mutex lock_;
Expand Down Expand Up @@ -774,9 +780,9 @@ struct FOLLY_EXPORT StaticMeta final : StaticMetaBase {
// Loop through allId2ThreadEntrySets_; Only keep ThreadEntry* in the map
// for ThreadEntry::elements that are still in use by the current thread.
// Evict all of the ThreadEntry* from other threads.
uint32_t maxId = meta.nextId_.load();
for (uint32_t id = 0; id < maxId; ++id) {
auto wlockedSet = meta.allId2ThreadEntrySets_[id].wlock();
for (const auto ptr : meta.getThreadEntrySetsPtrSpan()) {
auto& set = *ptr;
auto wlockedSet = set.wlock();
if (wlockedSet->contains(threadEntry)) {
wlockedSet->clear();
wlockedSet->insert(threadEntry);
Expand Down

0 comments on commit d8d0aa4

Please sign in to comment.