Skip to content

Commit 4cefc44

Browse files
guptaskbyrnedj
authored andcommitted
added per pool class rolling average latency (upstream PR version)
fix for rolling stats (on multi-tier to be followed by multi-tier rolling stats implementation in the following commit)
1 parent c432df6 commit 4cefc44

File tree

6 files changed

+118
-6
lines changed

6 files changed

+118
-6
lines changed

cachelib/allocator/CacheAllocator-inl.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,8 @@ CacheAllocator<CacheTrait>::allocateInternalTier(TierId tid,
382382

383383
// the allocation class in our memory allocator.
384384
const auto cid = allocator_[tid]->getAllocationClassId(pid, requiredSize);
385+
util::RollingLatencyTracker rollTracker{
386+
(*stats_.classAllocLatency)[pid][cid]};
385387

386388
// TODO: per-tier
387389
(*stats_.allocAttempts)[pid][cid].inc();
@@ -478,8 +480,9 @@ CacheAllocator<CacheTrait>::allocateChainedItemInternal(
478480
const auto pid = allocator_[tid]->getAllocInfo(parent->getMemory()).poolId;
479481
const auto cid = allocator_[tid]->getAllocationClassId(pid, requiredSize);
480482

481-
// TODO: per-tier? Right now stats_ are not used in any public periodic
482-
// worker
483+
util::RollingLatencyTracker rollTracker{
484+
(*stats_.classAllocLatency)[pid][cid]};
485+
483486
(*stats_.allocAttempts)[pid][cid].inc();
484487

485488
void* memory = allocator_[tid]->allocate(pid, requiredSize);
@@ -2468,7 +2471,10 @@ ACStats CacheAllocator<CacheTrait>::getACStats(TierId tid,
24682471
ClassId classId) const {
24692472
const auto& pool = allocator_[tid]->getPool(poolId);
24702473
const auto& ac = pool.getAllocationClass(classId);
2471-
return ac.getStats();
2474+
2475+
auto stats = ac.getStats();
2476+
stats.allocLatencyNs = (*stats_.classAllocLatency)[poolId][classId];
2477+
return stats;
24722478
}
24732479

24742480
template <typename CacheTrait>

cachelib/allocator/CacheStats.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,16 @@ void Stats::init() {
4444
initToZero(*fragmentationSize);
4545
initToZero(*chainedItemEvictions);
4646
initToZero(*regularItemEvictions);
47+
48+
classAllocLatency = std::make_unique<PerPoolClassRollingStats>();
4749
}
4850

4951
template <int>
5052
struct SizeVerify {};
5153

5254
void Stats::populateGlobalCacheStats(GlobalCacheStats& ret) const {
5355
#ifndef SKIP_SIZE_VERIFY
54-
SizeVerify<sizeof(Stats)> a = SizeVerify<16176>{};
56+
SizeVerify<sizeof(Stats)> a = SizeVerify<16192>{};
5557
std::ignore = a;
5658
#endif
5759
ret.numCacheGets = numCacheGets.get();

cachelib/allocator/CacheStatsInternal.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "cachelib/allocator/Cache.h"
2222
#include "cachelib/allocator/memory/MemoryAllocator.h"
2323
#include "cachelib/common/AtomicCounter.h"
24+
#include "cachelib/common/RollingStats.h"
2425

2526
namespace facebook {
2627
namespace cachelib {
@@ -229,6 +230,13 @@ struct Stats {
229230
std::unique_ptr<PerPoolClassAtomicCounters> chainedItemEvictions{};
230231
std::unique_ptr<PerPoolClassAtomicCounters> regularItemEvictions{};
231232

233+
using PerPoolClassRollingStats =
234+
std::array<std::array<util::RollingStats, MemoryAllocator::kMaxClasses>,
235+
MemoryPoolManager::kMaxPools>;
236+
237+
// rolling latency tracking for every alloc class in every pool
238+
std::unique_ptr<PerPoolClassRollingStats> classAllocLatency{};
239+
232240
// Eviction failures due to parent cannot be removed from access container
233241
AtomicCounter evictFailParentAC{0};
234242

cachelib/allocator/memory/MemoryAllocatorStats.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <unordered_map>
2121

2222
#include "cachelib/allocator/memory/Slab.h"
23+
#include "cachelib/common/RollingStats.h"
2324

2425
namespace facebook {
2526
namespace cachelib {
@@ -47,6 +48,9 @@ struct ACStats {
4748
// true if the allocation class is full.
4849
bool full;
4950

51+
// Rolling allocation latency (in ns)
52+
util::RollingStats allocLatencyNs;
53+
5054
constexpr unsigned long long totalSlabs() const noexcept {
5155
return freeSlabs + usedSlabs;
5256
}

cachelib/cachebench/cache/CacheStats.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,10 @@ struct Stats {
184184
: stats.usageFraction();
185185

186186
out << folly::sformat(
187-
"pid{:2} cid{:4} {:8.2f}{} usageFraction: {:4.2f}", pid, cid,
188-
allocSize, allocSizeSuffix, acUsageFraction)
187+
"tid{:2} pid{:2} cid{:4} {:8.2f}{} usageFraction: {:4.2f} "
188+
"rollingAvgAllocLatency: {:8.2f}ns",
189+
tid, pid, cid, allocSize, allocSizeSuffix, acUsageFraction,
190+
stats.allocLatencyNs.estimate())
189191
<< std::endl;
190192
});
191193
}

cachelib/common/RollingStats.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <folly/Range.h>
20+
#include <folly/logging/xlog.h>
21+
22+
#include "cachelib/common/Utils.h"
23+
24+
namespace facebook {
25+
namespace cachelib {
26+
namespace util {
27+
28+
class RollingStats {
29+
public:
30+
// track latency by taking the value of duration directly.
31+
void trackValue(double value) {
32+
// This is a highly unlikely scenario where
33+
// cnt_ reaches numerical limits. Skip update
34+
// of the rolling average anymore.
35+
if (cnt_ == std::numeric_limits<uint64_t>::max()) {
36+
cnt_ = 0;
37+
return;
38+
}
39+
auto ratio = static_cast<double>(cnt_) / (cnt_ + 1);
40+
avg_ *= ratio;
41+
++cnt_;
42+
avg_ += value / cnt_;
43+
}
44+
45+
// Return the rolling average.
46+
double estimate() { return avg_; }
47+
48+
private:
49+
double avg_{0};
50+
uint64_t cnt_{0};
51+
};
52+
53+
class RollingLatencyTracker {
54+
public:
55+
explicit RollingLatencyTracker(RollingStats& stats)
56+
: stats_(&stats), begin_(std::chrono::steady_clock::now()) {}
57+
RollingLatencyTracker() {}
58+
~RollingLatencyTracker() {
59+
if (stats_) {
60+
auto tp = std::chrono::steady_clock::now();
61+
auto diffNanos =
62+
std::chrono::duration_cast<std::chrono::nanoseconds>(tp - begin_)
63+
.count();
64+
stats_->trackValue(static_cast<double>(diffNanos));
65+
}
66+
}
67+
68+
RollingLatencyTracker(const RollingLatencyTracker&) = delete;
69+
RollingLatencyTracker& operator=(const RollingLatencyTracker&) = delete;
70+
71+
RollingLatencyTracker(RollingLatencyTracker&& rhs) noexcept
72+
: stats_(rhs.stats_), begin_(rhs.begin_) {
73+
rhs.stats_ = nullptr;
74+
}
75+
76+
RollingLatencyTracker& operator=(RollingLatencyTracker&& rhs) noexcept {
77+
if (this != &rhs) {
78+
this->~RollingLatencyTracker();
79+
new (this) RollingLatencyTracker(std::move(rhs));
80+
}
81+
return *this;
82+
}
83+
84+
private:
85+
RollingStats* stats_{nullptr};
86+
std::chrono::time_point<std::chrono::steady_clock> begin_;
87+
};
88+
} // namespace util
89+
} // namespace cachelib
90+
} // namespace facebook

0 commit comments

Comments
 (0)