Skip to content

Commit 763d364

Browse files
igchorbyrnedj
authored andcommitted
Initial multi-tier support implementation
Part 1. ----------------------------------------- This includes the following: - Multi-tier allocator with TierId - allocateInternalTier - creating multi-tier allocator on shared memory - serialization - some basic tests - Add option to insert items to first free tier, this enables an interleaving approach. Ther is no data movement among the tiers. Use `insertToFirstFreeTier` option to control. In order to evict data from the second tier, you will need to have the background movers enabled.
1 parent 56bb608 commit 763d364

24 files changed

+969
-307
lines changed

cachelib/allocator/BackgroundMover.h

+21-12
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,34 @@ template <typename C>
2727
struct BackgroundMoverAPIWrapper {
2828
// traverse the cache and move items from one tier to another
2929
// @param cache the cache interface
30+
// @param tid the tier to traverse
3031
// @param pid the pool id to traverse
3132
// @param cid the class id to traverse
3233
// @param evictionBatch number of items to evict in one go
3334
// @param promotionBatch number of items to promote in one go
3435
// @return pair of number of items evicted and promoted
3536
static std::pair<size_t, size_t> traverseAndMoveItems(C& cache,
37+
TierId tid,
3638
PoolId pid,
3739
ClassId cid,
3840
size_t evictionBatch,
3941
size_t promotionBatch) {
40-
return cache.traverseAndMoveItems(pid, cid, evictionBatch, promotionBatch);
42+
return cache.traverseAndMoveItems(tid, pid, cid, evictionBatch, promotionBatch);
4143
}
4244
static std::pair<size_t, double> getApproxUsage(C& cache,
45+
TierId tid,
4346
PoolId pid,
4447
ClassId cid) {
45-
const auto& pool = cache.getPool(pid);
48+
const auto& pool = cache.getPoolByTid(pid, tid);
4649
// we wait until all slabs are allocated before we start evicting
4750
if (!pool.allSlabsAllocated()) {
4851
return {0, 0.0};
4952
}
5053
return pool.getApproxUsage(cid);
5154
}
55+
static unsigned int getNumTiers(C& cache) {
56+
return cache.getNumTiers();
57+
}
5258
};
5359

5460
// Periodic worker that evicts items from tiers in batches
@@ -78,7 +84,7 @@ class BackgroundMover : public PeriodicWorker {
7884

7985
// return id of the worker responsible for promoting/evicting from particlar
8086
// pool and allocation calss (id is in range [0, numWorkers))
81-
static size_t workerId(PoolId pid, ClassId cid, size_t numWorkers);
87+
static size_t workerId(TierId tid, PoolId pid, ClassId cid, size_t numWorkers);
8288

8389
private:
8490
struct TraversalStats {
@@ -135,7 +141,9 @@ BackgroundMover<CacheT>::BackgroundMover(Cache& cache,
135141
: cache_(cache),
136142
evictionBatch_(evictionBatch),
137143
promotionBatch_(promotionBatch),
138-
targetFree_(targetFree) {}
144+
targetFree_(targetFree) {
145+
numTiers_ = BackgroundMoverAPIWrapper<CacheT>::getNumTiers(cache_);
146+
}
139147

140148
template <typename CacheT>
141149
void BackgroundMover<CacheT>::TraversalStats::recordTraversalTime(
@@ -170,8 +178,8 @@ template <typename CacheT>
170178
void BackgroundMover<CacheT>::setAssignedMemory(
171179
std::vector<MemoryDescriptorType>&& assignedMemory) {
172180
XLOG(INFO, "Class assigned to background worker:");
173-
for (auto [pid, cid] : assignedMemory) {
174-
XLOGF(INFO, "Pid: {}, Cid: {}", pid, cid);
181+
for (auto [tid, pid, cid] : assignedMemory) {
182+
XLOGF(INFO, "Tid: {}, Pid: {}, Cid: {}", tid, pid, cid);
175183
}
176184

177185
mutex_.lock_combine([this, &assignedMemory] {
@@ -185,10 +193,10 @@ BackgroundMover<CacheT>::getNumItemsToFree(
185193
const std::vector<MemoryDescriptorType>& assignedMemory) {
186194
std::map<MemoryDescriptorType, size_t> toFree;
187195
for (const auto& md : assignedMemory) {
188-
const auto [pid, cid] = md;
196+
const auto [tid, pid, cid] = md;
189197
const auto& pool = cache_.getPool(pid);
190198
const auto [activeItems, usage] =
191-
BackgroundMoverAPIWrapper<CacheT>::getApproxUsage(cache_, pid, cid);
199+
BackgroundMoverAPIWrapper<CacheT>::getApproxUsage(cache_, tid, pid, cid);
192200
if (usage < 1 - targetFree_) {
193201
toFree[md] = 0;
194202
} else {
@@ -210,7 +218,7 @@ void BackgroundMover<CacheT>::checkAndRun() {
210218
while (true) {
211219
bool allDone = true;
212220
for (auto md : assignedMemory) {
213-
const auto [pid, cid] = md;
221+
const auto [tid, pid, cid] = md;
214222
size_t evictionBatch = evictionBatch_;
215223
size_t promotionBatch = 0; // will enable with multi-tier support
216224
if (toFree[md] == 0) {
@@ -224,7 +232,7 @@ void BackgroundMover<CacheT>::checkAndRun() {
224232
const auto begin = util::getCurrentTimeNs();
225233
// try moving BATCH items from the class in order to reach free target
226234
auto moved = BackgroundMoverAPIWrapper<CacheT>::traverseAndMoveItems(
227-
cache_, pid, cid, evictionBatch, promotionBatch);
235+
cache_, tid, pid, cid, evictionBatch, promotionBatch);
228236
numEvictedItems_ += moved.first;
229237
toFree[md] > moved.first ? toFree[md] -= moved.first : toFree[md] = 0;
230238
numPromotedItems_ += moved.second;
@@ -263,12 +271,13 @@ BackgroundMoverStats BackgroundMover<CacheT>::getStats() const noexcept {
263271
}
264272

265273
template <typename CacheT>
266-
size_t BackgroundMover<CacheT>::workerId(PoolId pid,
274+
size_t BackgroundMover<CacheT>::workerId(TierId tid,
275+
PoolId pid,
267276
ClassId cid,
268277
size_t numWorkers) {
269278
XDCHECK(numWorkers);
270279

271280
// TODO: came up with some better sharding (use hashing?)
272-
return (pid + cid) % numWorkers;
281+
return (tid + pid + cid) % numWorkers;
273282
}
274283
}; // namespace facebook::cachelib

cachelib/allocator/Cache.h

+14-4
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,20 @@ enum class DestructorContext {
7575

7676
// a tuple that describes the memory pool and allocation class
7777
struct MemoryDescriptorType {
78-
MemoryDescriptorType(PoolId pid, ClassId cid) : pid_(pid), cid_(cid) {}
78+
MemoryDescriptorType(TierId tid, PoolId pid, ClassId cid) :
79+
tid_(tid), pid_(pid), cid_(cid) {}
80+
TierId tid_;
7981
PoolId pid_;
8082
ClassId cid_;
8183

8284
bool operator<(const MemoryDescriptorType& rhs) const {
83-
return std::make_tuple(pid_, cid_) < std::make_tuple(rhs.pid_, rhs.cid_);
85+
return std::make_tuple(tid_, pid_, cid_) <
86+
std::make_tuple(rhs.tid_, rhs.pid_, rhs.cid_);
8487
}
8588

8689
bool operator==(const MemoryDescriptorType& rhs) const {
87-
return std::make_tuple(pid_, cid_) == std::make_tuple(rhs.pid_, rhs.cid_);
90+
return std::make_tuple(tid_, pid_, cid_) ==
91+
std::make_tuple(rhs.tid_, rhs.pid_, rhs.cid_);
8892
}
8993
};
9094

@@ -111,6 +115,12 @@ class CacheBase {
111115
// @param poolId The pool id to query
112116
virtual const MemoryPool& getPool(PoolId poolId) const = 0;
113117

118+
// Get the reference to a memory pool using a tier id, for stats purposes
119+
//
120+
// @param poolId The pool id to query
121+
// @param tierId The tier of the pool id
122+
virtual const MemoryPool& getPoolByTid(PoolId poolId, TierId tid) const = 0;
123+
114124
// Get Pool specific stats (regular pools). This includes stats from the
115125
// Memory Pool and also the cache.
116126
//
@@ -121,7 +131,7 @@ class CacheBase {
121131
//
122132
// @param poolId the pool id
123133
// @param classId the class id
124-
virtual ACStats getACStats(PoolId poolId, ClassId classId) const = 0;
134+
virtual ACStats getACStats(TierId tid,PoolId poolId, ClassId classId) const = 0;
125135

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

0 commit comments

Comments
 (0)