Skip to content

Commit 0a81319

Browse files
pbhandar2meta-codesync[bot]
authored andcommitted
Fix redundant sampleKey() in NvmCache event tracking
Summary: NvmCache::recordEvent() calls sampleKey(), then routes through CacheAPIWrapperForNvm::recordEvent() → CacheAllocator::recordEvent() which calls sampleKey() again on the same key. Since sampleKey() is deterministic for a given key, the second call always produces the same result as the first making it redundant CPU work (hashing + comparison) on every NVM event. Fix by adding recordEventWithoutSampling() to CacheAllocator and its CacheApiWrapper, which skips the redundant sampleKey() check and goes directly to eventTracker->recordWithoutSampling(). NvmCache::recordEvent() now calls sampleKey() once, then uses the no-sampling path downstream. Reviewed By: rlyerly Differential Revision: D100874852 fbshipit-source-id: 60205bb38eb086e82beed82edb7a5797243ba35d
1 parent ca1b53e commit 0a81319

3 files changed

Lines changed: 53 additions & 26 deletions

File tree

cachelib/allocator/CacheAllocator.h

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1876,32 +1876,45 @@ class CacheAllocator : public CacheBase {
18761876
AllocatorApiResult result,
18771877
EventRecordParams params = {}) const {
18781878
if (auto* eventTracker = getEventTracker()) {
1879-
if (eventTracker->sampleKey(key)) {
1880-
EventInfo eventInfo;
1881-
eventInfo.eventTimestamp = util::getCurrentTimeSec();
1882-
eventInfo.event = event;
1883-
eventInfo.result = result;
1884-
eventInfo.key = key;
1885-
if (params.size) {
1886-
eventInfo.size = *params.size;
1887-
}
1888-
if (params.expiryTime) {
1889-
eventInfo.expiryTime = *params.expiryTime;
1890-
eventInfo.timeToExpire = calculateTimeToExpire(
1891-
*params.expiryTime, eventInfo.eventTimestamp);
1892-
}
1893-
if (params.ttlSecs && *params.ttlSecs > 0) {
1894-
eventInfo.ttlSecs = *params.ttlSecs;
1895-
}
1896-
if (params.allocSize) {
1897-
eventInfo.allocSize = *params.allocSize;
1898-
}
1899-
if (params.poolId) {
1900-
eventInfo.poolId = *params.poolId;
1901-
}
1879+
if (!eventTracker->sampleKey(key)) {
1880+
return;
1881+
}
1882+
}
1883+
recordEventWithoutSampling(event, key, result, std::move(params));
1884+
}
19021885

1903-
eventTracker->recordWithoutSampling(eventInfo);
1886+
// Record event without calling sampleKey(). Use when the caller has already
1887+
// determined that the key should be sampled (e.g., NvmCache::recordEvent()
1888+
// calls sampleKey() once and then uses this to avoid double-sampling).
1889+
void recordEventWithoutSampling(AllocatorApiEvent event,
1890+
Key key,
1891+
AllocatorApiResult result,
1892+
EventRecordParams params = {}) const {
1893+
if (auto* eventTracker = getEventTracker()) {
1894+
EventInfo eventInfo;
1895+
eventInfo.eventTimestamp = util::getCurrentTimeSec();
1896+
eventInfo.event = event;
1897+
eventInfo.result = result;
1898+
eventInfo.key = key;
1899+
if (params.size) {
1900+
eventInfo.size = *params.size;
1901+
}
1902+
if (params.expiryTime) {
1903+
eventInfo.expiryTime = *params.expiryTime;
1904+
eventInfo.timeToExpire =
1905+
calculateTimeToExpire(*params.expiryTime, eventInfo.eventTimestamp);
1906+
}
1907+
if (params.ttlSecs && *params.ttlSecs > 0) {
1908+
eventInfo.ttlSecs = *params.ttlSecs;
19041909
}
1910+
if (params.allocSize) {
1911+
eventInfo.allocSize = *params.allocSize;
1912+
}
1913+
if (params.poolId) {
1914+
eventInfo.poolId = *params.poolId;
1915+
}
1916+
1917+
eventTracker->recordWithoutSampling(eventInfo);
19051918
} else if (auto legacyEventTracker = getLegacyEventTracker()) {
19061919
folly::Optional<uint32_t> size =
19071920
params.size

cachelib/allocator/nvmcache/CacheApiWrapper.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,17 @@ class CacheAPIWrapperForNvm {
172172
typename C::EventRecordParams params = {}) {
173173
cache.recordEvent(event, key, result, params);
174174
}
175+
176+
// Record event without sampling. Use when the caller has already called
177+
// sampleKey() and determined the key should be sampled.
178+
static void recordEventWithoutSampling(
179+
C& cache,
180+
AllocatorApiEvent event,
181+
Key key,
182+
AllocatorApiResult result,
183+
typename C::EventRecordParams params = {}) {
184+
cache.recordEventWithoutSampling(event, key, result, std::move(params));
185+
}
175186
};
176187

177188
} // namespace cachelib

cachelib/allocator/nvmcache/NvmCache.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,8 @@ class NvmCache {
321321
folly::StringPiece key,
322322
AllocatorApiResult result,
323323
const NvmItem* nvmItem = nullptr) {
324+
// Sample the key once here. Use recordEventWithoutSampling() downstream
325+
// to avoid double/triple-sampling through CacheAllocator::recordEvent().
324326
if (auto eventTracker = CacheAPIWrapperForNvm<C>::getEventTracker(cache_)) {
325327
if (!eventTracker->sampleKey(key)) {
326328
return;
@@ -330,7 +332,8 @@ class NvmCache {
330332
}
331333

332334
if (!nvmItem) {
333-
CacheAPIWrapperForNvm<C>::recordEvent(cache_, event, key, result);
335+
CacheAPIWrapperForNvm<C>::recordEventWithoutSampling(cache_, event, key,
336+
result);
334337
return;
335338
}
336339

@@ -343,7 +346,7 @@ class NvmCache {
343346
ttlSecs = expiryTime - nvmItem->getCreationTime();
344347
}
345348

346-
CacheAPIWrapperForNvm<C>::recordEvent(
349+
CacheAPIWrapperForNvm<C>::recordEventWithoutSampling(
347350
cache_, event, key, result,
348351
typename C::EventRecordParams{.size = itemSize,
349352
.ttlSecs = ttlSecs,

0 commit comments

Comments
 (0)