Skip to content

Commit 6b4f46b

Browse files
committed
Add MemoryTierCacheConfig::fromShm()
to allow using new configureMemoryTiers() API with legacy behavior. Move validation code for memory tiers to validate() method and convert ratios to sizes lazily (on get)..
1 parent ee63ef3 commit 6b4f46b

7 files changed

+159
-95
lines changed

cachelib/allocator/CacheAllocator-inl.h

+12-18
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,16 @@ CacheAllocator<CacheTrait>::CacheAllocator(Config config)
2727
: memoryTierConfigs(config.getMemoryTierConfigs()),
2828
isOnShm_{config.memMonitoringEnabled()},
2929
config_(config.validate()),
30-
tempShm_(isOnShm_ ? std::make_unique<TempShmMapping>(config_.size)
30+
tempShm_(isOnShm_ ? std::make_unique<TempShmMapping>(
31+
config_.getCacheSize())
3132
: nullptr),
3233
allocator_(isOnShm_ ? std::make_unique<MemoryAllocator>(
3334
getAllocatorConfig(config_),
3435
tempShm_->getAddr(),
35-
config_.size)
36+
config_.getCacheSize())
3637
: std::make_unique<MemoryAllocator>(
37-
getAllocatorConfig(config_), config_.size)),
38+
getAllocatorConfig(config_),
39+
config_.getCacheSize())),
3840
compactCacheManager_(std::make_unique<CCacheManager>(*allocator_)),
3941
compressor_(createPtrCompressor()),
4042
accessContainer_(std::make_unique<AccessContainer>(
@@ -51,7 +53,8 @@ CacheAllocator<CacheTrait>::CacheAllocator(Config config)
5153
nvmCacheState_{config_.cacheDir, config_.isNvmCacheEncryptionEnabled(),
5254
config_.isNvmCacheTruncateAllocSizeEnabled()} {
5355
// TODO(MEMORY_TIER)
54-
if (memoryTierConfigs.size()) {
56+
if (std::holds_alternative<FileShmSegmentOpts>(
57+
memoryTierConfigs[0].getShmTypeOpts())) {
5558
throw std::runtime_error(
5659
"Using custom memory tier is only supported for Shared Memory.");
5760
}
@@ -165,16 +168,7 @@ ShmSegmentOpts CacheAllocator<CacheTrait>::createShmCacheOpts() {
165168

166169
ShmSegmentOpts opts;
167170
opts.alignment = sizeof(Slab);
168-
169-
// If memoryTierConfigs is empty, Fallback to Posix/SysV segment
170-
// to keep legacy bahavior
171-
// TODO(MEMORY_TIER) - guarantee there is always at least one mem
172-
// layer inside Config
173-
if (memoryTierConfigs.size()) {
174-
opts.typeOpts = FileShmSegmentOpts(memoryTierConfigs[0].path);
175-
} else {
176-
opts.typeOpts = PosixSysVSegmentOpts(config_.isUsingPosixShm());
177-
}
171+
opts.typeOpts = memoryTierConfigs[0].getShmTypeOpts();
178172

179173
return opts;
180174
}
@@ -185,10 +179,10 @@ CacheAllocator<CacheTrait>::createNewMemoryAllocator() {
185179
return std::make_unique<MemoryAllocator>(
186180
getAllocatorConfig(config_),
187181
shmManager_
188-
->createShm(detail::kShmCacheName, config_.size,
182+
->createShm(detail::kShmCacheName, config_.getCacheSize(),
189183
config_.slabMemoryBaseAddr, createShmCacheOpts())
190184
.addr,
191-
config_.size);
185+
config_.getCacheSize());
192186
}
193187

194188
template <typename CacheTrait>
@@ -199,7 +193,7 @@ CacheAllocator<CacheTrait>::restoreMemoryAllocator() {
199193
shmManager_
200194
->attachShm(detail::kShmCacheName, config_.slabMemoryBaseAddr,
201195
createShmCacheOpts()).addr,
202-
config_.size,
196+
config_.getCacheSize(),
203197
config_.disableFullCoredump);
204198
}
205199

@@ -2216,7 +2210,7 @@ PoolEvictionAgeStats CacheAllocator<CacheTrait>::getPoolEvictionAgeStats(
22162210
template <typename CacheTrait>
22172211
CacheMetadata CacheAllocator<CacheTrait>::getCacheMetadata() const noexcept {
22182212
return CacheMetadata{kCachelibVersion, kCacheRamFormatVersion,
2219-
kCacheNvmFormatVersion, config_.size};
2213+
kCacheNvmFormatVersion, config_.getCacheSize()};
22202214
}
22212215

22222216
template <typename CacheTrait>

cachelib/allocator/CacheAllocatorConfig.h

+113-53
Original file line numberDiff line numberDiff line change
@@ -200,10 +200,13 @@ class CacheAllocatorConfig {
200200

201201
// Configures cache memory tiers. Accepts vector of MemoryTierCacheConfig.
202202
// Each vector element describes configuration for a single memory cache tier.
203+
// @throw std::invalid_argument if:
204+
// - the size of configs is 0
205+
// - memory tiers use both size and ratio parameters
203206
CacheAllocatorConfig& configureMemoryTiers(const MemoryTierConfigs& configs);
204207

205-
// Return reference to MemoryTierCacheConfigs.
206-
const MemoryTierConfigs& getMemoryTierConfigs();
208+
// Return vector of memory tier configs.
209+
MemoryTierConfigs getMemoryTierConfigs() const;
207210

208211
// This turns on a background worker that periodically scans through the
209212
// access container and look for expired items and remove them.
@@ -334,7 +337,7 @@ class CacheAllocatorConfig {
334337

335338
const std::string& getCacheName() const noexcept { return cacheName; }
336339

337-
size_t getCacheSize() const noexcept { return size; }
340+
size_t getCacheSize() const noexcept;
338341

339342
bool isUsingPosixShm() const noexcept { return usePosixShm; }
340343

@@ -552,12 +555,16 @@ class CacheAllocatorConfig {
552555
// cache.
553556
uint64_t nvmAdmissionMinTTL{0};
554557

555-
// Configuration for memory tiers.
556-
MemoryTierConfigs memoryTierConfigs;
557-
558558
friend CacheT;
559559

560560
private:
561+
void validateMemoryTiersWithSize(const MemoryTierConfigs&, size_t) const;
562+
563+
// Configuration for memory tiers.
564+
MemoryTierConfigs memoryTierConfigs{
565+
{MemoryTierCacheConfig::fromShm().setRatio(1)}
566+
};
567+
561568
void mergeWithPrefix(
562569
std::map<std::string, std::string>& configMap,
563570
const std::map<std::string, std::string>& configMapToMerge,
@@ -576,6 +583,8 @@ CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::setCacheName(
576583

577584
template <typename T>
578585
CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::setCacheSize(size_t _size) {
586+
validateMemoryTiersWithSize(this->memoryTierConfigs, _size);
587+
579588
size = _size;
580589
constexpr size_t maxCacheSizeWithCoredump = 64'424'509'440; // 60GB
581590
if (size <= maxCacheSizeWithCoredump) {
@@ -818,68 +827,62 @@ CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::enableItemReaperInBackground(
818827
template <typename T>
819828
CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::configureMemoryTiers(
820829
const MemoryTierConfigs& config) {
821-
memoryTierConfigs = config;
822-
size_t sum_ratios = 0;
823-
size_t sum_sizes = 0;
830+
if (!config.size()) {
831+
throw std::invalid_argument("There must be at least one memory tier.");
832+
}
824833

825-
for (auto tier_config: memoryTierConfigs) {
834+
for (auto tier_config: config) {
826835
auto tier_size = tier_config.getSize();
827836
auto tier_ratio = tier_config.getRatio();
828837
if ((!tier_size and !tier_ratio) || (tier_size and tier_ratio)) {
829838
throw std::invalid_argument(
830839
"For each memory tier either size or ratio must be set.");
831840
}
832-
sum_ratios += tier_ratio;
833-
sum_sizes += tier_size;
834841
}
835842

836-
if (sum_ratios) {
837-
if (!getCacheSize()) {
838-
throw std::invalid_argument(
839-
"Total cache size must be specified when size ratios are \
840-
used to specify memory tier sizes.");
841-
} else {
842-
if (getCacheSize() < sum_ratios) {
843-
throw std::invalid_argument(
844-
"Sum of all tier size ratios is greater than total cache size.");
845-
}
846-
// Convert ratios to sizes
847-
sum_sizes = 0;
848-
size_t partition_size = getCacheSize() / sum_ratios;
849-
for (auto& tier_config: memoryTierConfigs) {
850-
tier_config.setSize(partition_size * tier_config.getRatio());
851-
sum_sizes += tier_config.getSize();
852-
}
853-
if (getCacheSize() != sum_sizes) {
854-
// Adjust capacity of the last tier to account for rounding error
855-
memoryTierConfigs.back().setSize(memoryTierConfigs.back().getSize() + \
856-
(getCacheSize() - sum_sizes));
857-
sum_sizes = getCacheSize();
858-
}
859-
}
860-
} else if (sum_sizes) {
861-
if (getCacheSize() && sum_sizes != getCacheSize()) {
862-
throw std::invalid_argument(
863-
"Sum of tier sizes doesn't match total cache size. \
864-
Setting of cache total size is not required when per-tier \
865-
sizes are specified - it is calculated as sum of tier sizes.");
866-
}
867-
} else {
868-
throw std::invalid_argument(
869-
"Either sum of all memory tiers sizes or sum of all ratios \
870-
must be greater than 0.");
871-
}
843+
validateMemoryTiersWithSize(config, this->size);
872844

873-
if (sum_sizes && !getCacheSize()) {
874-
setCacheSize(sum_sizes);
875-
}
845+
memoryTierConfigs = config;
876846

877847
return *this;
878848
}
879849

880850
template <typename T>
881-
const typename CacheAllocatorConfig<T>::MemoryTierConfigs& CacheAllocatorConfig<T>::getMemoryTierConfigs() {
882-
return memoryTierConfigs;
851+
typename CacheAllocatorConfig<T>::MemoryTierConfigs
852+
CacheAllocatorConfig<T>::getMemoryTierConfigs() const {
853+
MemoryTierConfigs config = memoryTierConfigs;
854+
size_t sum_ratios = 0;
855+
856+
for (auto &tier_config: config) {
857+
if (auto *v = std::get_if<PosixSysVSegmentOpts>(&tier_config.shmOpts)) {
858+
v->usePosix = usePosixShm;
859+
}
860+
861+
sum_ratios += tier_config.getRatio();
862+
}
863+
864+
if (sum_ratios == 0)
865+
return config;
866+
867+
// if ratios are used, size must be specified
868+
XDCHECK(size);
869+
870+
// Convert ratios to sizes, size must be non-zero
871+
size_t sum_sizes = 0;
872+
size_t partition_size = size / sum_ratios;
873+
for (auto& tier_config: config) {
874+
tier_config.setSize(partition_size * tier_config.getRatio());
875+
tier_config.setRatio(0);
876+
sum_sizes += tier_config.getSize();
877+
}
878+
879+
if (size != sum_sizes) {
880+
// Adjust capacity of the last tier to account for rounding error
881+
config.back().setSize(
882+
config.back().getSize() + (getCacheSize() - sum_sizes));
883+
}
884+
885+
return config;
883886
}
884887

885888
template <typename T>
@@ -997,6 +1000,46 @@ CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::setNvmAdmissionMinTTL(
9971000
return *this;
9981001
}
9991002

1003+
template <typename T>
1004+
size_t CacheAllocatorConfig<T>::getCacheSize() const noexcept {
1005+
if (size)
1006+
return size;
1007+
1008+
size_t sum_sizes = 0;
1009+
for (const auto &tier_config : getMemoryTierConfigs()) {
1010+
sum_sizes += tier_config.getSize();
1011+
}
1012+
1013+
return sum_sizes;
1014+
}
1015+
1016+
template <typename T>
1017+
void CacheAllocatorConfig<T>::validateMemoryTiersWithSize(
1018+
const MemoryTierConfigs &config, size_t size) const {
1019+
size_t sum_ratios = 0;
1020+
size_t sum_sizes = 0;
1021+
1022+
for (const auto &tier_config: config) {
1023+
sum_ratios += tier_config.getRatio();
1024+
sum_sizes += tier_config.getSize();
1025+
}
1026+
1027+
if (sum_ratios && sum_sizes) {
1028+
throw std::invalid_argument("Cannot mix ratios and sizes.");
1029+
} else if (sum_sizes) {
1030+
if (size && sum_sizes != size) {
1031+
throw std::invalid_argument(
1032+
"Sum of tier sizes doesn't match total cache size. "
1033+
"Setting of cache total size is not required when per-tier "
1034+
"sizes are specified - it is calculated as sum of tier sizes.");
1035+
}
1036+
} else if (!sum_ratios && !sum_sizes) {
1037+
throw std::invalid_argument(
1038+
"Either sum of all memory tiers sizes or sum of all ratios "
1039+
"must be greater than 0.");
1040+
}
1041+
}
1042+
10001043
template <typename T>
10011044
const CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::validate() const {
10021045
// we can track tail hits only if MMType is MM2Q
@@ -1018,6 +1061,23 @@ const CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::validate() const {
10181061
size,
10191062
maxCacheSize));
10201063
}
1064+
1065+
size_t sum_ratios = 0;
1066+
for (auto tier_config: memoryTierConfigs) {
1067+
sum_ratios += tier_config.getRatio();
1068+
}
1069+
1070+
if (sum_ratios) {
1071+
if (!size) {
1072+
throw std::invalid_argument(
1073+
"Total cache size must be specified when size ratios are "
1074+
"used to specify memory tier sizes.");
1075+
} else if (size < sum_ratios) {
1076+
throw std::invalid_argument(
1077+
"Sum of all tier size ratios is greater than total cache size.");
1078+
}
1079+
}
1080+
10211081
return *this;
10221082
}
10231083

cachelib/allocator/MemoryTierCacheConfig.h

+13-10
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#include <string>
2020

21+
#include "cachelib/shm/ShmCommon.h"
22+
2123
namespace facebook {
2224
namespace cachelib {
2325
class MemoryTierCacheConfig {
@@ -27,7 +29,14 @@ class MemoryTierCacheConfig {
2729
// TODO: add fromDirectory, fromAnonymousMemory
2830
static MemoryTierCacheConfig fromFile(const std::string& _file) {
2931
MemoryTierCacheConfig config;
30-
config.path = _file;
32+
config.shmOpts = FileShmSegmentOpts(_file);
33+
return config;
34+
}
35+
36+
// Creates instance of MemoryTierCacheConfig for Posix/SysV Shared memory.
37+
static MemoryTierCacheConfig fromShm() {
38+
MemoryTierCacheConfig config;
39+
config.shmOpts = PosixSysVSegmentOpts();
3140
return config;
3241
}
3342

@@ -53,11 +62,7 @@ class MemoryTierCacheConfig {
5362

5463
size_t getSize() const noexcept { return size; }
5564

56-
const std::string& getPath() const noexcept { return path; }
57-
58-
bool isFileBacked() const {
59-
return !path.empty();
60-
}
65+
const ShmTypeOpts& getShmTypeOpts() const noexcept { return shmOpts; }
6166

6267
// Size of this memory tiers
6368
size_t size{0};
@@ -67,10 +72,8 @@ class MemoryTierCacheConfig {
6772
// then size of the i-th tier Xi = (X / (Y1 + Y2)) * Yi and X = sum(Xi)
6873
size_t ratio{0};
6974

70-
// Path to file for file system-backed memory tier
71-
// TODO: consider using variant<file, directory, NUMA> to support different
72-
// memory sources
73-
std::string path;
75+
// Options specific to shm type
76+
ShmTypeOpts shmOpts;
7477

7578
private:
7679
MemoryTierCacheConfig() = default;

cachelib/allocator/tests/AllocatorMemoryTiersTest.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace tests {
2222

2323
using LruAllocatorMemoryTiersTest = AllocatorMemoryTiersTest<LruAllocator>;
2424

25+
// TODO(MEMORY_TIER): add more tests with different eviction policies
2526
TEST_F(LruAllocatorMemoryTiersTest, MultiTiers) { this->testMultiTiers(); }
2627

2728
} // end of namespace tests

cachelib/allocator/tests/BaseAllocatorTest.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -1140,7 +1140,8 @@ class BaseAllocatorTest : public AllocatorTest<AllocatorT> {
11401140
this->testLruLength(alloc, poolId, sizes, keyLen, evictedKeys);
11411141
}
11421142

1143-
void testReaperShutDown(typename AllocatorT::Config::MemoryTierConfigs cfgs = {}) {
1143+
void testReaperShutDown(typename AllocatorT::Config::MemoryTierConfigs cfgs =
1144+
{MemoryTierCacheConfig::fromShm().setRatio(1)}) {
11441145
const size_t nSlabs = 20;
11451146
const size_t size = nSlabs * Slab::kSize;
11461147

@@ -1150,8 +1151,7 @@ class BaseAllocatorTest : public AllocatorTest<AllocatorT> {
11501151
config.setAccessConfig({8, 8});
11511152
config.enableCachePersistence(this->cacheDir_);
11521153
config.enableItemReaperInBackground(std::chrono::seconds(1), {});
1153-
if (cfgs.size())
1154-
config.configureMemoryTiers(cfgs);
1154+
config.configureMemoryTiers(cfgs);
11551155
std::vector<typename AllocatorT::Key> keys;
11561156
{
11571157
AllocatorT alloc(AllocatorT::SharedMemNew, config);

0 commit comments

Comments
 (0)