Skip to content

Commit ffda92f

Browse files
committed
First set of changes to cache configuration API to enable multi-tier caches (facebook#138)
Summary: These changes introduce per-tier cache configuration required to implement features discussed here: facebook#102. These specific changes enable single DRAM tier configs only which are compatible with the current version of cachelib. Configuration API will be expanded as multi-tier changes in other parts of the library are introduced. Pull Request resolved: facebook#138 Reviewed By: therealgymmy Differential Revision: D36189766 Pulled By: jiayuebao fbshipit-source-id: 947aa0cd800ea6accffc1b7b6b0c9693aa7fc0a5
1 parent 434d77e commit ffda92f

File tree

11 files changed

+285
-284
lines changed

11 files changed

+285
-284
lines changed

cachelib/allocator/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ if (BUILD_TESTS)
121121
add_test (tests/MemoryTiersTest.cpp)
122122
add_test (tests/MultiAllocatorTest.cpp)
123123
add_test (tests/NvmAdmissionPolicyTest.cpp)
124+
add_test (tests/CacheAllocatorConfigTest.cpp)
124125
add_test (nvmcache/tests/NvmItemTests.cpp)
125126
add_test (nvmcache/tests/InFlightPutsTest.cpp)
126127
add_test (nvmcache/tests/TombStoneTests.cpp)

cachelib/allocator/CacheAllocator-inl.h

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,17 @@ ShmSegmentOpts CacheAllocator<CacheTrait>::createShmCacheOpts(TierId tid) {
206206
return opts;
207207
}
208208

209+
template <typename CacheTrait>
210+
size_t CacheAllocator<CacheTrait>::memoryTierSize(TierId tid) const
211+
{
212+
auto partitions = std::accumulate(memoryTierConfigs.begin(), memoryTierConfigs.end(), 0UL,
213+
[](const size_t i, const MemoryTierCacheConfig& config){
214+
return i + config.getRatio();
215+
});
216+
217+
return memoryTierConfigs[tid].calculateTierSize(config_.getCacheSize(), partitions);
218+
}
219+
209220
template <typename CacheTrait>
210221
std::unique_ptr<MemoryAllocator>
211222
CacheAllocator<CacheTrait>::createNewMemoryAllocator(TierId tid) {
@@ -216,7 +227,8 @@ CacheAllocator<CacheTrait>::createNewMemoryAllocator(TierId tid) {
216227
config_.getCacheSize(), config_.slabMemoryBaseAddr,
217228
createShmCacheOpts(tid))
218229
.addr,
219-
memoryTierConfigs[tid].getSize());
230+
memoryTierSize(tid)
231+
);
220232
}
221233

222234
template <typename CacheTrait>
@@ -227,7 +239,7 @@ CacheAllocator<CacheTrait>::restoreMemoryAllocator(TierId tid) {
227239
shmManager_
228240
->attachShm(detail::kShmCacheName + std::to_string(tid),
229241
config_.slabMemoryBaseAddr, createShmCacheOpts(tid)).addr,
230-
memoryTierConfigs[tid].getSize(),
242+
memoryTierSize(tid),
231243
config_.disableFullCoredump);
232244
}
233245

@@ -2365,38 +2377,25 @@ PoolId CacheAllocator<CacheTrait>::addPool(
23652377
folly::SharedMutex::WriteHolder w(poolsResizeAndRebalanceLock_);
23662378

23672379
PoolId pid = 0;
2368-
size_t remainingPoolSize = size;
23692380
std::vector<size_t> tierPoolSizes;
2370-
auto tierConfigs = config_.getMemoryTierConfigs();
2381+
const auto &tierConfigs = config_.getMemoryTierConfigs();
23712382
size_t totalCacheSize = 0;
23722383

23732384
for (TierId tid = 0; tid < numTiers_; tid++) {
23742385
totalCacheSize += allocator_[tid]->getMemorySize();
23752386
}
23762387

2377-
size_t remainingCacheSize = totalCacheSize;
23782388
for (TierId tid = 0; tid < numTiers_; tid++) {
23792389
auto tierSizeRatio =
23802390
static_cast<double>(allocator_[tid]->getMemorySize()) / totalCacheSize;
23812391
size_t tierPoolSize = static_cast<size_t>(tierSizeRatio * size);
2382-
tierPoolSizes.push_back(tierPoolSize);
2383-
remainingPoolSize -= tierPoolSizes.back();
2384-
remainingCacheSize -= tierPoolSizes.back();
2385-
}
23862392

2387-
if (remainingPoolSize) {
2388-
if (remainingPoolSize < remainingCacheSize) {
2389-
for (TierId tid = 0; (tid < numTiers_) && remainingPoolSize;
2390-
tid++, remainingPoolSize--) {
2391-
tierPoolSizes[tid]++;
2392-
}
2393-
} else {
2394-
throw std::invalid_argument(folly::sformat(
2395-
"Not enough memory to allocate pool of size {}", size));
2396-
}
2393+
tierPoolSizes.push_back(tierPoolSize);
23972394
}
23982395

23992396
for (TierId tid = 0; tid < numTiers_; tid++) {
2397+
// TODO: what if we manage to add pool only in one tier?
2398+
// we should probably remove that on failure
24002399
auto res = allocator_[tid]->addPool(
24012400
name, tierPoolSizes[tid], allocSizes, ensureProvisionable);
24022401
XDCHECK(tid == 0 || res == pid);

cachelib/allocator/CacheAllocator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,8 @@ class CacheAllocator : public CacheBase {
16021602
// handle to the item. On failure an empty handle.
16031603
ItemHandle tryEvictToNextMemoryTier(Item* item);
16041604

1605+
size_t memoryTierSize(TierId tid) const;
1606+
16051607
// Deserializer CacheAllocatorMetadata and verify the version
16061608
//
16071609
// @param deserializer Deserializer object

cachelib/allocator/CacheAllocatorConfig.h

Lines changed: 45 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "cachelib/allocator/MemoryTierCacheConfig.h"
2929
#include "cachelib/allocator/MM2Q.h"
3030
#include "cachelib/allocator/MemoryMonitor.h"
31+
#include "cachelib/allocator/MemoryTierCacheConfig.h"
3132
#include "cachelib/allocator/NvmAdmissionPolicy.h"
3233
#include "cachelib/allocator/PoolOptimizeStrategy.h"
3334
#include "cachelib/allocator/RebalanceStrategy.h"
@@ -205,15 +206,15 @@ class CacheAllocatorConfig {
205206
// cachePersistence().
206207
CacheAllocatorConfig& usePosixForShm();
207208

208-
// Configures cache memory tiers. Accepts vector of MemoryTierCacheConfig.
209-
// Each vector element describes configuration for a single memory cache tier.
210-
// @throw std::invalid_argument if:
211-
// - the size of configs is 0
212-
// - memory tiers use both size and ratio parameters
209+
// Configures cache memory tiers. Each tier represents a cache region inside
210+
// byte-addressable memory such as DRAM, Pmem, CXLmem.
211+
// Accepts vector of MemoryTierCacheConfig. Each vector element describes
212+
// configuration for a single memory cache tier. Tier sizes are specified as
213+
// ratios, the number of parts of total cache size each tier would occupy.
213214
CacheAllocatorConfig& configureMemoryTiers(const MemoryTierConfigs& configs);
214215

215-
// Return vector of memory tier configs.
216-
MemoryTierConfigs getMemoryTierConfigs() const;
216+
// Return reference to MemoryTierCacheConfigs.
217+
const MemoryTierConfigs& getMemoryTierConfigs() const;
217218

218219
// This turns on a background worker that periodically scans through the
219220
// access container and look for expired items and remove them.
@@ -352,7 +353,7 @@ class CacheAllocatorConfig {
352353

353354
const std::string& getCacheName() const noexcept { return cacheName; }
354355

355-
size_t getCacheSize() const noexcept;
356+
size_t getCacheSize() const noexcept { return size; }
356357

357358
bool isUsingPosixShm() const noexcept { return usePosixShm; }
358359

@@ -367,13 +368,19 @@ class CacheAllocatorConfig {
367368
bool validateStrategy(
368369
const std::shared_ptr<PoolOptimizeStrategy>& strategy) const;
369370

371+
// check that memory tier ratios are set properly
372+
const CacheAllocatorConfig& validateMemoryTiers() const;
373+
370374
// @return a map representation of the configs
371375
std::map<std::string, std::string> serialize() const;
372376

377+
// The max number of memory cache tiers
378+
inline static const size_t kMaxCacheMemoryTiers = 2;
379+
373380
// Cache name for users to indentify their own cache.
374381
std::string cacheName{""};
375382

376-
// Amount of memory for this cache instance
383+
// Amount of memory for this cache instance (sum of all memory tiers' sizes)
377384
size_t size = 1 * 1024 * 1024 * 1024;
378385

379386
// Directory for shared memory related metadata
@@ -581,8 +588,6 @@ class CacheAllocatorConfig {
581588
friend CacheT;
582589

583590
private:
584-
void validateMemoryTiersWithSize(const MemoryTierConfigs&, size_t) const;
585-
586591
// Configuration for memory tiers.
587592
MemoryTierConfigs memoryTierConfigs{
588593
{MemoryTierCacheConfig::fromShm().setRatio(1)}
@@ -606,8 +611,6 @@ CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::setCacheName(
606611

607612
template <typename T>
608613
CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::setCacheSize(size_t _size) {
609-
validateMemoryTiersWithSize(this->memoryTierConfigs, _size);
610-
611614
size = _size;
612615
constexpr size_t maxCacheSizeWithCoredump = 64'424'509'440; // 60GB
613616
if (size <= maxCacheSizeWithCoredump) {
@@ -861,57 +864,24 @@ CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::enableItemReaperInBackground(
861864

862865
template <typename T>
863866
CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::configureMemoryTiers(
864-
const MemoryTierConfigs& config) {
865-
if (!config.size()) {
866-
throw std::invalid_argument("There must be at least one memory tier.");
867+
const MemoryTierConfigs& config) {
868+
if (config.size() > kMaxCacheMemoryTiers) {
869+
throw std::invalid_argument(folly::sformat(
870+
"Too many memory tiers. The number of supported tiers is {}.",
871+
kMaxCacheMemoryTiers));
867872
}
868-
869-
for (auto tier_config: config) {
870-
auto tier_size = tier_config.getSize();
871-
auto tier_ratio = tier_config.getRatio();
872-
if ((!tier_size and !tier_ratio) || (tier_size and tier_ratio)) {
873-
throw std::invalid_argument(
874-
"For each memory tier either size or ratio must be set.");
875-
}
873+
if (!config.size()) {
874+
throw std::invalid_argument(
875+
"There must be at least one memory tier config.");
876876
}
877-
878-
validateMemoryTiersWithSize(config, this->size);
879-
880877
memoryTierConfigs = config;
881-
882878
return *this;
883879
}
884880

885881
template <typename T>
886-
typename CacheAllocatorConfig<T>::MemoryTierConfigs
882+
const typename CacheAllocatorConfig<T>::MemoryTierConfigs&
887883
CacheAllocatorConfig<T>::getMemoryTierConfigs() const {
888-
MemoryTierConfigs config = memoryTierConfigs;
889-
size_t sum_ratios = 0;
890-
891-
for (auto &tier_config: config) {
892-
if (auto *v = std::get_if<PosixSysVSegmentOpts>(&tier_config.shmOpts)) {
893-
v->usePosix = usePosixShm;
894-
}
895-
896-
sum_ratios += tier_config.getRatio();
897-
}
898-
899-
if (sum_ratios == 0)
900-
return config;
901-
902-
// if ratios are used, size must be specified
903-
XDCHECK(size);
904-
905-
// Convert ratios to sizes, size must be non-zero
906-
size_t sum_sizes = 0;
907-
size_t partition_size = size / sum_ratios;
908-
for (auto& tier_config: config) {
909-
tier_config.setSize(partition_size * tier_config.getRatio());
910-
tier_config.setRatio(0);
911-
sum_sizes += tier_config.getSize();
912-
}
913-
914-
return config;
884+
return memoryTierConfigs;
915885
}
916886

917887
template <typename T>
@@ -1037,46 +1007,6 @@ CacheAllocatorConfig<T>::setSkipPromoteChildrenWhenParentFailed() {
10371007
return *this;
10381008
}
10391009

1040-
template <typename T>
1041-
size_t CacheAllocatorConfig<T>::getCacheSize() const noexcept {
1042-
if (size)
1043-
return size;
1044-
1045-
size_t sum_sizes = 0;
1046-
for (const auto &tier_config : getMemoryTierConfigs()) {
1047-
sum_sizes += tier_config.getSize();
1048-
}
1049-
1050-
return sum_sizes;
1051-
}
1052-
1053-
template <typename T>
1054-
void CacheAllocatorConfig<T>::validateMemoryTiersWithSize(
1055-
const MemoryTierConfigs &config, size_t size) const {
1056-
size_t sum_ratios = 0;
1057-
size_t sum_sizes = 0;
1058-
1059-
for (const auto &tier_config: config) {
1060-
sum_ratios += tier_config.getRatio();
1061-
sum_sizes += tier_config.getSize();
1062-
}
1063-
1064-
if (sum_ratios && sum_sizes) {
1065-
throw std::invalid_argument("Cannot mix ratios and sizes.");
1066-
} else if (sum_sizes) {
1067-
if (size && sum_sizes != size) {
1068-
throw std::invalid_argument(
1069-
"Sum of tier sizes doesn't match total cache size. "
1070-
"Setting of cache total size is not required when per-tier "
1071-
"sizes are specified - it is calculated as sum of tier sizes.");
1072-
}
1073-
} else if (!sum_ratios && !sum_sizes) {
1074-
throw std::invalid_argument(
1075-
"Either sum of all memory tiers sizes or sum of all ratios "
1076-
"must be greater than 0.");
1077-
}
1078-
}
1079-
10801010
template <typename T>
10811011
const CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::validate() const {
10821012
// we can track tail hits only if MMType is MM2Q
@@ -1101,23 +1031,7 @@ const CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::validate() const {
11011031
"It's not allowed to enable both RemoveCB and ItemDestructor.");
11021032
}
11031033

1104-
size_t sum_ratios = 0;
1105-
for (auto tier_config: memoryTierConfigs) {
1106-
sum_ratios += tier_config.getRatio();
1107-
}
1108-
1109-
if (sum_ratios) {
1110-
if (!size) {
1111-
throw std::invalid_argument(
1112-
"Total cache size must be specified when size ratios are "
1113-
"used to specify memory tier sizes.");
1114-
} else if (size < sum_ratios) {
1115-
throw std::invalid_argument(
1116-
"Sum of all tier size ratios is greater than total cache size.");
1117-
}
1118-
}
1119-
1120-
return *this;
1034+
return validateMemoryTiers();
11211035
}
11221036

11231037
template <typename T>
@@ -1144,6 +1058,24 @@ bool CacheAllocatorConfig<T>::validateStrategy(
11441058
(type != PoolOptimizeStrategy::MarginalHits || trackTailHits);
11451059
}
11461060

1061+
template <typename T>
1062+
const CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::validateMemoryTiers()
1063+
const {
1064+
size_t parts = 0;
1065+
for (const auto& tierConfig : memoryTierConfigs) {
1066+
if (!tierConfig.getRatio()) {
1067+
throw std::invalid_argument("Tier ratio must be an integer number >=1.");
1068+
}
1069+
parts += tierConfig.getRatio();
1070+
}
1071+
1072+
if (parts > size) {
1073+
throw std::invalid_argument(
1074+
"Sum of tier ratios must be less than total cache size.");
1075+
}
1076+
return *this;
1077+
}
1078+
11471079
template <typename T>
11481080
std::map<std::string, std::string> CacheAllocatorConfig<T>::serialize() const {
11491081
std::map<std::string, std::string> configMap;

0 commit comments

Comments
 (0)