Skip to content

Commit a834f16

Browse files
committed
added per tier pool class rolling average latency
1 parent 57a3d1c commit a834f16

File tree

7 files changed

+129
-17
lines changed

7 files changed

+129
-17
lines changed

cachelib/allocator/Cache.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class CacheBase {
8484
CacheBase& operator=(CacheBase&&) = default;
8585

8686
// TODO: come up with some reasonable number
87-
static constexpr unsigned kMaxTiers = 8;
87+
static constexpr unsigned kMaxTiers = 2;
8888

8989
// Get a string referring to the cache name for this cache
9090
virtual const std::string getCacheName() const = 0;
@@ -100,8 +100,8 @@ class CacheBase {
100100
// @param poolId the pool id
101101
virtual PoolStats getPoolStats(PoolId poolId) const = 0;
102102

103-
virtual AllocationClassBaseStat getAllocationClassStats(TierId, PoolId pid, ClassId cid)
104-
const = 0;
103+
virtual AllocationClassBaseStat getAllocationClassStats(
104+
TierId, PoolId pid, ClassId cid) const = 0;
105105

106106
// @param poolId the pool id
107107
virtual AllSlabReleaseEvents getAllSlabReleaseEvents(PoolId poolId) const = 0;

cachelib/allocator/CacheAllocator-inl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ 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{(*stats_.classAllocLatency)[tid][pid][cid]};
385386

386387
// TODO: per-tier
387388
(*stats_.allocAttempts)[pid][cid].inc();
@@ -480,6 +481,8 @@ CacheAllocator<CacheTrait>::allocateChainedItemInternal(
480481
const auto pid = allocator_[tid]->getAllocInfo(parent->getMemory()).poolId;
481482
const auto cid = allocator_[tid]->getAllocationClassId(pid, requiredSize);
482483

484+
util::RollingLatencyTracker rollTracker{(*stats_.classAllocLatency)[tid][pid][cid]};
485+
483486
// TODO: per-tier? Right now stats_ are not used in any public periodic
484487
// worker
485488
(*stats_.allocAttempts)[pid][cid].inc();
@@ -2540,6 +2543,7 @@ AllocationClassBaseStat CacheAllocator<CacheTrait>::getAllocationClassStats(
25402543
} else {
25412544
stats.approxFreePercent = ac.approxFreePercentage();
25422545
}
2546+
stats.allocLatencyNs = (*stats_.classAllocLatency)[tid][pid][cid];
25432547

25442548
return stats;
25452549
}

cachelib/allocator/CacheStats.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ void Stats::init() {
4242
initToZero(*fragmentationSize);
4343
initToZero(*chainedItemEvictions);
4444
initToZero(*regularItemEvictions);
45+
46+
classAllocLatency = std::make_unique<PerTierPoolClassRollingStats>();
4547
}
4648

4749
template <int>

cachelib/allocator/CacheStats.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "cachelib/allocator/memory/Slab.h"
2626
#include "cachelib/common/FastStats.h"
2727
#include "cachelib/common/PercentileStats.h"
28+
#include "cachelib/common/RollingStats.h"
2829
#include "cachelib/common/Time.h"
2930

3031
namespace facebook {
@@ -107,6 +108,9 @@ struct AllocationClassBaseStat {
107108

108109
// percent of free memory in this class
109110
double approxFreePercent{0.0};
111+
112+
// Rolling allocation latency (in ns)
113+
util::RollingStats allocLatencyNs;
110114
};
111115

112116
// cache related stats for a given allocation class.

cachelib/allocator/CacheStatsInternal.h

Lines changed: 9 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 {
@@ -221,6 +222,14 @@ struct Stats {
221222
std::unique_ptr<PerPoolClassAtomicCounters> chainedItemEvictions{};
222223
std::unique_ptr<PerPoolClassAtomicCounters> regularItemEvictions{};
223224

225+
using PerTierPoolClassRollingStats = std::array<
226+
std::array<std::array<util::RollingStats, MemoryAllocator::kMaxClasses>,
227+
MemoryPoolManager::kMaxPools>,
228+
CacheBase::kMaxTiers>;
229+
230+
// rolling latency tracking for every alloc class in every pool
231+
std::unique_ptr<PerTierPoolClassRollingStats> classAllocLatency{};
232+
224233
// Eviction failures due to parent cannot be removed from access container
225234
AtomicCounter evictFailParentAC{0};
226235

cachelib/cachebench/cache/CacheStats.h

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ struct Stats {
9696
uint64_t invalidDestructorCount{0};
9797
int64_t unDestructedItemCount{0};
9898

99-
std::map<TierId, std::map<PoolId, std::map<ClassId, AllocationClassBaseStat>>> allocationClassStats;
99+
std::map<TierId, std::map<PoolId, std::map<ClassId, AllocationClassBaseStat>>>
100+
allocationClassStats;
100101

101102
std::vector<double> slabsApproxFreePercentages;
102103

@@ -122,7 +123,9 @@ struct Stats {
122123

123124
if (FLAGS_report_memory_usage_stats) {
124125
for (TierId tid = 0; tid < slabsApproxFreePercentages.size(); tid++) {
125-
out << folly::sformat("tid{:2} free slabs : {:.2f}%", tid, slabsApproxFreePercentages[tid]) << std::endl;
126+
out << folly::sformat("tid{:2} free slabs : {:.2f}%", tid,
127+
slabsApproxFreePercentages[tid])
128+
<< std::endl;
126129
}
127130

128131
auto formatMemory = [](size_t bytes) -> std::tuple<std::string, double> {
@@ -142,26 +145,25 @@ struct Stats {
142145
};
143146

144147
auto foreachAC = [&](auto cb) {
145-
for (auto &tidStats : allocationClassStats) {
146-
for (auto &pidStat : tidStats.second) {
147-
for (auto &cidStat : pidStat.second) {
148+
for (auto& tidStats : allocationClassStats) {
149+
for (auto& pidStat : tidStats.second) {
150+
for (auto& cidStat : pidStat.second) {
148151
cb(tidStats.first, pidStat.first, cidStat.first, cidStat.second);
149152
}
150153
}
151154
}
152155
};
153156

154-
foreachAC([&](auto tid, auto pid, auto cid, auto stats){
157+
foreachAC([&](auto tid, auto pid, auto cid, auto stats) {
155158
auto [allocSizeSuffix, allocSize] = formatMemory(stats.allocSize);
156159
auto [memorySizeSuffix, memorySize] = formatMemory(stats.memorySize);
157-
out << folly::sformat("tid{:2} pid{:2} cid{:4} {:8.2f}{} memorySize: {:8.2f}{}",
158-
tid, pid, cid, allocSize, allocSizeSuffix, memorySize, memorySizeSuffix) << std::endl;
159-
});
160-
161-
foreachAC([&](auto tid, auto pid, auto cid, auto stats){
162-
auto [allocSizeSuffix, allocSize] = formatMemory(stats.allocSize);
163-
out << folly::sformat("tid{:2} pid{:2} cid{:4} {:8.2f}{} free: {:4.2f}%",
164-
tid, pid, cid, allocSize, allocSizeSuffix, stats.approxFreePercent) << std::endl;
160+
out << folly::sformat(
161+
"tid{:2} pid{:2} cid{:4} {:8.2f}{} memorySize:{:8.2f}{} "
162+
"free:{:4.2f}% rollingAvgLatency:{:8.2f}ns",
163+
tid, pid, cid, allocSize, allocSizeSuffix, memorySize,
164+
memorySizeSuffix, stats.approxFreePercent,
165+
stats.allocLatencyNs.estimate())
166+
<< std::endl;
165167
});
166168
}
167169

cachelib/common/RollingStats.h

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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+
try {
33+
auto ratio = static_cast<double>(cnt_) / (cnt_ + 1);
34+
avg_ *= ratio;
35+
++cnt_;
36+
avg_ += value / cnt_;
37+
}
38+
// This is a highly unlikely scenario where
39+
// cnt_ reaches numerical limits. Don't update
40+
// the rolling average anymore.
41+
catch (std::runtime_error& e) {
42+
return {};
43+
}
44+
}
45+
46+
// Return the rolling average.
47+
double estimate() { return avg_; }
48+
49+
private:
50+
double avg_ = 0;
51+
uint64_t cnt_ = 0;
52+
};
53+
54+
class RollingLatencyTracker {
55+
public:
56+
explicit RollingLatencyTracker(RollingStats& stats)
57+
: stats_(&stats), begin_(std::chrono::steady_clock::now()) {}
58+
RollingLatencyTracker() {}
59+
~RollingLatencyTracker() {
60+
if (stats_) {
61+
auto tp = std::chrono::steady_clock::now();
62+
auto diffNanos =
63+
std::chrono::duration_cast<std::chrono::nanoseconds>(tp - begin_)
64+
.count();
65+
stats_->trackValue(static_cast<double>(diffNanos));
66+
}
67+
}
68+
69+
RollingLatencyTracker(const RollingLatencyTracker&) = delete;
70+
RollingLatencyTracker& operator=(const RollingLatencyTracker&) = delete;
71+
72+
RollingLatencyTracker(RollingLatencyTracker&& rhs) noexcept
73+
: stats_(rhs.stats_), begin_(rhs.begin_) {
74+
rhs.stats_ = nullptr;
75+
}
76+
77+
RollingLatencyTracker& operator=(RollingLatencyTracker&& rhs) noexcept {
78+
if (this != &rhs) {
79+
this->~RollingLatencyTracker();
80+
new (this) RollingLatencyTracker(std::move(rhs));
81+
}
82+
return *this;
83+
}
84+
85+
private:
86+
RollingStats* stats_{nullptr};
87+
std::chrono::time_point<std::chrono::steady_clock> begin_;
88+
};
89+
} // namespace util
90+
} // namespace cachelib
91+
} // namespace facebook

0 commit comments

Comments
 (0)