Skip to content

Commit ab892ba

Browse files
generatedunixname1395027625275998meta-codesync[bot]
authored andcommitted
Add per-thread single-entry name cache to fb303 getStats to skip F14 lookup
Reviewed By: yfeldblum Differential Revision: D115968601 fbshipit-source-id: ec8afd2ae00eb23b9e8b7dc7c3997b4bd98d154b
1 parent 55d95fd commit ab892ba

2 files changed

Lines changed: 29 additions & 8 deletions

File tree

fb303/TFunctionStatHandler.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ int32_t TFunctionStatHandler::consolidateThread(
282282
time_t now,
283283
TStatsAggregator& functionMap) {
284284
auto calls = 0;
285-
for (auto& stats : functionMap) {
285+
for (auto& stats : functionMap.map) {
286286
if (!stats.second) {
287287
continue;
288288
}
@@ -426,11 +426,16 @@ TStatsPerThread* TFunctionStatHandler::getStats(std::string_view fnName) {
426426
std::unique_lock lock(statMutex_);
427427
tlFunctionMap_.reset(mapPtr, deleter);
428428
}
429+
// Single-entry cache: repeated lookups of the same function name skip the
430+
// map find. Matched by content, so any caller name buffer is safe.
431+
if (mapPtr->cachedStats != nullptr && fnName == mapPtr->cachedFnName) {
432+
return mapPtr->cachedStats;
433+
}
429434
// Find TStatsPerThread in TStatsAggregator's map - the map is only updated
430435
// from one thread (the current one, owner of the TStatsAggregator); no
431436
// update should be needed in the common case, so we just use statMutex_
432437
// to guard it
433-
auto& map = *mapPtr;
438+
auto& map = mapPtr->map;
434439
auto it = map.find(fnName);
435440
if (it == map.end()) {
436441
auto stats = createStatsPerThread(fnName);
@@ -439,10 +444,14 @@ TStatsPerThread* TFunctionStatHandler::getStats(std::string_view fnName) {
439444

440445
// we're going to be writing the map, so lock out stat aggregation ftm
441446
std::unique_lock lock(statMutex_);
442-
map[fnName] = stats;
443-
return stats.get();
447+
it = map.emplace(fnName, std::move(stats)).first;
444448
}
445-
return it->second.get();
449+
// Cache a view of the owning map key (no copy) and the raw stats pointer.
450+
// Both stay valid until the next getStats() call on this thread, the only
451+
// path that mutates the map.
452+
mapPtr->cachedFnName = it->first;
453+
mapPtr->cachedStats = it->second.get();
454+
return mapPtr->cachedStats;
446455
}
447456

448457
namespace {

fb303/TFunctionStatHandler.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,22 @@ class TFunctionStatHandler
189189

190190
/**
191191
* Mapping from thrift functions to their respective
192-
* TStatsPerThread objects for a single thread
192+
* TStatsPerThread objects for a single thread, plus a single-entry
193+
* cache (a view of the most recent getStats() lookup).
193194
*/
194-
using TStatsAggregator =
195-
folly::F14FastMap<std::string, std::shared_ptr<TStatsPerThread>>;
195+
struct TStatsAggregator {
196+
folly::F14FastMap<std::string, std::shared_ptr<TStatsPerThread>> map;
197+
198+
// Single-entry cache of the last getStats() lookup. cachedFnName is a
199+
// non-owning view of the map key (no per-call string copy). Both members
200+
// stay valid because the map is only ever mutated by getStats() on this
201+
// same thread and the cache is refreshed immediately after any insert, so
202+
// no rehash can invalidate them between calls. cachedStats points at the
203+
// heap-allocated TStatsPerThread owned by the map's shared_ptr, which never
204+
// moves.
205+
std::string_view cachedFnName;
206+
TStatsPerThread* cachedStats = nullptr;
207+
};
196208

197209
class Tag;
198210
folly::ThreadLocalPtr<TStatsAggregator, Tag> tlFunctionMap_;

0 commit comments

Comments
 (0)