Skip to content

Commit 18ad985

Browse files
igchorfacebook-github-bot
authored andcommitted
Initial framework for background item eviction/promotion (facebook#213)
Summary: Implements stubs for periodic workers for item eviction/promotion. The actual implementation of eviction and promotion is not part of this PR. The idea behind introducing those workers is the following: - BG eviction: to keep certain amount of free memory and decrease allocate latency - BG promotion: to move hot items to memory and decrease read latency Each BG worker can be customized with an eviction/promotion strategy (not part of this PR). One such strategy is implemented here: https://github.com/intel/CacheLib/blob/develop/cachelib/allocator/FreeThresholdStrategy.cpp BG promotion is only helpful for multi-tier setup (unless we would have some way of predicting which NVM items are going to be accessed), but BG eviction can be useful for single-tier configuration as well to decrease allocate latency. Pull Request resolved: facebook#213 Reviewed By: therealgymmy Differential Revision: D47106337 Pulled By: haowu14 fbshipit-source-id: 8c8a178e625b7601dd96694068066420a90dbb87
1 parent ff26d5d commit 18ad985

14 files changed

+818
-13
lines changed
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and 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+
namespace facebook {
18+
namespace cachelib {
19+
20+
template <typename CacheT>
21+
BackgroundMover<CacheT>::BackgroundMover(
22+
Cache& cache,
23+
std::shared_ptr<BackgroundMoverStrategy> strategy,
24+
MoverDir direction)
25+
: cache_(cache), strategy_(strategy), direction_(direction) {
26+
if (direction_ == MoverDir::Evict) {
27+
moverFunc = BackgroundMoverAPIWrapper<CacheT>::traverseAndEvictItems;
28+
29+
} else if (direction_ == MoverDir::Promote) {
30+
moverFunc = BackgroundMoverAPIWrapper<CacheT>::traverseAndPromoteItems;
31+
}
32+
}
33+
34+
template <typename CacheT>
35+
BackgroundMover<CacheT>::~BackgroundMover() {
36+
stop(std::chrono::seconds(0));
37+
}
38+
39+
template <typename CacheT>
40+
void BackgroundMover<CacheT>::work() {
41+
try {
42+
checkAndRun();
43+
} catch (const std::exception& ex) {
44+
XLOGF(ERR, "BackgroundMover interrupted due to exception: {}", ex.what());
45+
}
46+
}
47+
48+
template <typename CacheT>
49+
void BackgroundMover<CacheT>::setAssignedMemory(
50+
std::vector<MemoryDescriptorType>&& assignedMemory) {
51+
XLOG(INFO, "Class assigned to background worker:");
52+
for (auto [pid, cid] : assignedMemory) {
53+
XLOGF(INFO, "Pid: {}, Cid: {}", pid, cid);
54+
}
55+
56+
mutex_.lock_combine([this, &assignedMemory] {
57+
this->assignedMemory_ = std::move(assignedMemory);
58+
});
59+
}
60+
61+
// Look for classes that exceed the target memory capacity
62+
// and return those for eviction
63+
template <typename CacheT>
64+
void BackgroundMover<CacheT>::checkAndRun() {
65+
auto assignedMemory = mutex_.lock_combine([this] { return assignedMemory_; });
66+
67+
unsigned int moves = 0;
68+
auto batches = strategy_->calculateBatchSizes(cache_, assignedMemory);
69+
70+
for (size_t i = 0; i < batches.size(); i++) {
71+
const auto [pid, cid] = assignedMemory[i];
72+
const auto batch = batches[i];
73+
74+
if (batch == 0) {
75+
continue;
76+
}
77+
78+
// try moving BATCH items from the class in order to reach free target
79+
auto moved = moverFunc(cache_, pid, cid, batch);
80+
moves += moved;
81+
movesPerClass_[pid][cid] += moved;
82+
totalBytesMoved_.add(moved * cache_.getPool(pid).getAllocSizes()[cid]);
83+
}
84+
85+
numTraversals_.inc();
86+
numMovedItems_.add(moves);
87+
}
88+
89+
template <typename CacheT>
90+
BackgroundMoverStats BackgroundMover<CacheT>::getStats() const noexcept {
91+
BackgroundMoverStats stats;
92+
stats.numMovedItems = numMovedItems_.get();
93+
stats.runCount = numTraversals_.get();
94+
stats.totalBytesMoved = totalBytesMoved_.get();
95+
96+
return stats;
97+
}
98+
99+
template <typename CacheT>
100+
std::map<PoolId, std::map<ClassId, uint64_t>>
101+
BackgroundMover<CacheT>::getClassStats() const noexcept {
102+
return movesPerClass_;
103+
}
104+
105+
template <typename CacheT>
106+
size_t BackgroundMover<CacheT>::workerId(PoolId pid,
107+
ClassId cid,
108+
size_t numWorkers) {
109+
XDCHECK(numWorkers);
110+
111+
// TODO: came up with some better sharding (use hashing?)
112+
return (pid + cid) % numWorkers;
113+
}
114+
115+
} // namespace cachelib
116+
} // namespace facebook

cachelib/allocator/BackgroundMover.h

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and 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 "cachelib/allocator/BackgroundMoverStrategy.h"
20+
#include "cachelib/allocator/CacheStats.h"
21+
#include "cachelib/common/AtomicCounter.h"
22+
#include "cachelib/common/PeriodicWorker.h"
23+
24+
namespace facebook {
25+
namespace cachelib {
26+
27+
// wrapper that exposes the private APIs of CacheType that are specifically
28+
// needed for the cache api
29+
template <typename C>
30+
struct BackgroundMoverAPIWrapper {
31+
static size_t traverseAndEvictItems(C& cache,
32+
unsigned int pid,
33+
unsigned int cid,
34+
size_t batch) {
35+
return cache.traverseAndEvictItems(pid, cid, batch);
36+
}
37+
38+
static size_t traverseAndPromoteItems(C& cache,
39+
unsigned int pid,
40+
unsigned int cid,
41+
size_t batch) {
42+
return cache.traverseAndPromoteItems(pid, cid, batch);
43+
}
44+
};
45+
46+
enum class MoverDir { Evict = 0, Promote };
47+
48+
// Periodic worker that evicts items from tiers in batches
49+
// The primary aim is to reduce insertion times for new items in the
50+
// cache
51+
template <typename CacheT>
52+
class BackgroundMover : public PeriodicWorker {
53+
public:
54+
using Cache = CacheT;
55+
// @param cache the cache interface
56+
// @param strategy the stragey class that defines how objects are
57+
// moved (promoted vs. evicted and how much)
58+
BackgroundMover(Cache& cache,
59+
std::shared_ptr<BackgroundMoverStrategy> strategy,
60+
MoverDir direction_);
61+
62+
~BackgroundMover() override;
63+
64+
BackgroundMoverStats getStats() const noexcept;
65+
std::map<PoolId, std::map<ClassId, uint64_t>> getClassStats() const noexcept;
66+
67+
void setAssignedMemory(std::vector<MemoryDescriptorType>&& assignedMemory);
68+
69+
// return id of the worker responsible for promoting/evicting from particlar
70+
// pool and allocation calss (id is in range [0, numWorkers))
71+
static size_t workerId(PoolId pid, ClassId cid, size_t numWorkers);
72+
73+
private:
74+
std::map<PoolId, std::map<ClassId, uint64_t>> movesPerClass_;
75+
// cache allocator's interface for evicting
76+
using Item = typename Cache::Item;
77+
78+
Cache& cache_;
79+
std::shared_ptr<BackgroundMoverStrategy> strategy_;
80+
MoverDir direction_;
81+
82+
std::function<size_t(Cache&, unsigned int, unsigned int, size_t)> moverFunc;
83+
84+
// implements the actual logic of running the background evictor
85+
void work() override final;
86+
void checkAndRun();
87+
88+
AtomicCounter numMovedItems_{0};
89+
AtomicCounter numTraversals_{0};
90+
AtomicCounter totalBytesMoved_{0};
91+
92+
std::vector<MemoryDescriptorType> assignedMemory_;
93+
folly::DistributedMutex mutex_;
94+
};
95+
} // namespace cachelib
96+
} // namespace facebook
97+
98+
#include "cachelib/allocator/BackgroundMover-inl.h"
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and 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 "cachelib/allocator/Cache.h"
20+
21+
namespace facebook {
22+
namespace cachelib {
23+
24+
struct MemoryDescriptorType {
25+
MemoryDescriptorType(PoolId pid, ClassId cid) : pid_(pid), cid_(cid) {}
26+
PoolId pid_;
27+
ClassId cid_;
28+
};
29+
30+
// Base class for background eviction strategy.
31+
class BackgroundMoverStrategy {
32+
public:
33+
// Calculate how many items should be moved by the background mover
34+
//
35+
// @param cache Cache allocator that implements CacheBase
36+
// @param acVec vector of memory descriptors for which batch sizes should
37+
// be calculated
38+
//
39+
// @return vector of batch sizes, where each element in the vector specifies
40+
// batch size for the memory descriptor in acVec
41+
virtual std::vector<size_t> calculateBatchSizes(
42+
const CacheBase& cache, std::vector<MemoryDescriptorType> acVec) = 0;
43+
44+
virtual ~BackgroundMoverStrategy() = default;
45+
};
46+
47+
} // namespace cachelib
48+
} // namespace facebook

cachelib/allocator/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ add_library (cachelib_allocator
3535
CCacheManager.cpp
3636
ContainerTypes.cpp
3737
FreeMemStrategy.cpp
38+
FreeThresholdStrategy.cpp
3839
HitsPerSlabStrategy.cpp
3940
LruTailAgeStrategy.cpp
4041
MarginalHitsOptimizeStrategy.cpp

0 commit comments

Comments
 (0)