Skip to content

Commit 3c34254

Browse files
Issue75 rebased (#88)
* #75: Use actual tier sizes (rounded down to slab size and decreased by header size) when creating new memory pools * Added getPoolSize method to calculate combined pool size for all tiers; added pool size validation to tests * Explicitly specified type for totalCacheSize to avoid overflow * Minor test change * Reworked tests * Minor change * Deleted redundant tests * Deleted unused constant * 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 Co-authored-by: Victoria McGrath <[email protected]>
1 parent 1d16e1a commit 3c34254

12 files changed

+379
-254
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: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,24 @@ ShmSegmentOpts CacheAllocator<CacheTrait>::createShmCacheOpts(TierId tid) {
202202
ShmSegmentOpts opts;
203203
opts.alignment = sizeof(Slab);
204204
opts.typeOpts = memoryTierConfigs[tid].getShmTypeOpts();
205+
if (auto *v = std::get_if<PosixSysVSegmentOpts>(&opts.typeOpts)) {
206+
v->usePosix = config_.usePosixShm;
207+
}
205208

206209
return opts;
207210
}
208211

212+
template <typename CacheTrait>
213+
size_t CacheAllocator<CacheTrait>::memoryTierSize(TierId tid) const
214+
{
215+
auto partitions = std::accumulate(memoryTierConfigs.begin(), memoryTierConfigs.end(), 0UL,
216+
[](const size_t i, const MemoryTierCacheConfig& config){
217+
return i + config.getRatio();
218+
});
219+
220+
return memoryTierConfigs[tid].calculateTierSize(config_.getCacheSize(), partitions);
221+
}
222+
209223
template <typename CacheTrait>
210224
std::unique_ptr<MemoryAllocator>
211225
CacheAllocator<CacheTrait>::createNewMemoryAllocator(TierId tid) {
@@ -216,7 +230,8 @@ CacheAllocator<CacheTrait>::createNewMemoryAllocator(TierId tid) {
216230
config_.getCacheSize(), config_.slabMemoryBaseAddr,
217231
createShmCacheOpts(tid))
218232
.addr,
219-
memoryTierConfigs[tid].getSize());
233+
memoryTierSize(tid)
234+
);
220235
}
221236

222237
template <typename CacheTrait>
@@ -227,7 +242,7 @@ CacheAllocator<CacheTrait>::restoreMemoryAllocator(TierId tid) {
227242
shmManager_
228243
->attachShm(detail::kShmCacheName + std::to_string(tid),
229244
config_.slabMemoryBaseAddr, createShmCacheOpts(tid)).addr,
230-
memoryTierConfigs[tid].getSize(),
245+
memoryTierSize(tid),
231246
config_.disableFullCoredump);
232247
}
233248

@@ -2250,12 +2265,27 @@ PoolId CacheAllocator<CacheTrait>::addPool(
22502265
folly::SharedMutex::WriteHolder w(poolsResizeAndRebalanceLock_);
22512266

22522267
PoolId pid = 0;
2253-
auto tierConfigs = config_.getMemoryTierConfigs();
2268+
std::vector<size_t> tierPoolSizes;
2269+
const auto &tierConfigs = config_.getMemoryTierConfigs();
2270+
size_t totalCacheSize = 0;
2271+
22542272
for (TierId tid = 0; tid < numTiers_; tid++) {
2255-
auto tierSizeRatio = static_cast<double>(
2256-
tierConfigs[tid].getSize()) / config_.getCacheSize();
2257-
auto tierPoolSize = static_cast<size_t>(tierSizeRatio * size);
2258-
auto res = allocator_[tid]->addPool(name, tierPoolSize, allocSizes, ensureProvisionable);
2273+
totalCacheSize += allocator_[tid]->getMemorySize();
2274+
}
2275+
2276+
for (TierId tid = 0; tid < numTiers_; tid++) {
2277+
auto tierSizeRatio =
2278+
static_cast<double>(allocator_[tid]->getMemorySize()) / totalCacheSize;
2279+
size_t tierPoolSize = static_cast<size_t>(tierSizeRatio * size);
2280+
2281+
tierPoolSizes.push_back(tierPoolSize);
2282+
}
2283+
2284+
for (TierId tid = 0; tid < numTiers_; tid++) {
2285+
// TODO: what if we manage to add pool only in one tier?
2286+
// we should probably remove that on failure
2287+
auto res = allocator_[tid]->addPool(
2288+
name, tierPoolSizes[tid], allocSizes, ensureProvisionable);
22592289
XDCHECK(tid == 0 || res == pid);
22602290
pid = res;
22612291
}
@@ -2418,6 +2448,16 @@ const std::string CacheAllocator<CacheTrait>::getCacheName() const {
24182448
return config_.cacheName;
24192449
}
24202450

2451+
template <typename CacheTrait>
2452+
size_t CacheAllocator<CacheTrait>::getPoolSize(PoolId poolId) const {
2453+
size_t poolSize = 0;
2454+
for (auto& allocator: allocator_) {
2455+
const auto& pool = allocator->getPool(poolId);
2456+
poolSize += pool.getPoolSize();
2457+
}
2458+
return poolSize;
2459+
}
2460+
24212461
template <typename CacheTrait>
24222462
PoolStats CacheAllocator<CacheTrait>::getPoolStats(PoolId poolId) const {
24232463
const auto& pool = allocator_[currentTier()]->getPool(poolId);

cachelib/allocator/CacheAllocator.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,9 @@ class CacheAllocator : public CacheBase {
10451045
// get cache name
10461046
const std::string getCacheName() const override final;
10471047

1048+
// combined pool size for all memory tiers
1049+
size_t getPoolSize(PoolId pid) const;
1050+
10481051
// pool stats by pool id
10491052
PoolStats getPoolStats(PoolId pid) const override final;
10501053

@@ -1578,6 +1581,8 @@ class CacheAllocator : public CacheBase {
15781581
// handle to the item. On failure an empty handle.
15791582
WriteHandle tryEvictToNextMemoryTier(Item& item);
15801583

1584+
size_t memoryTierSize(TierId tid) const;
1585+
15811586
// Deserializer CacheAllocatorMetadata and verify the version
15821587
//
15831588
// @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)