@@ -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
448457namespace {
0 commit comments