Skip to content

Commit e50a45c

Browse files
igchorvictoria-mcgrath
authored andcommitted
Issue75 rebased (pmem#88)
* pmem#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 b6c5044 commit e50a45c

File tree

10 files changed

+280
-257
lines changed

10 files changed

+280
-257
lines changed

cachelib/allocator/CacheAllocator-inl.h

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,24 @@ ShmSegmentOpts CacheAllocator<CacheTrait>::createShmCacheOpts(TierId tid) {
249249
ShmSegmentOpts opts;
250250
opts.alignment = sizeof(Slab);
251251
opts.typeOpts = memoryTierConfigs[tid].getShmTypeOpts();
252+
if (auto *v = std::get_if<PosixSysVSegmentOpts>(&opts.typeOpts)) {
253+
v->usePosix = config_.usePosixShm;
254+
}
252255

253256
return opts;
254257
}
255258

259+
template <typename CacheTrait>
260+
size_t CacheAllocator<CacheTrait>::memoryTierSize(TierId tid) const
261+
{
262+
auto partitions = std::accumulate(memoryTierConfigs.begin(), memoryTierConfigs.end(), 0UL,
263+
[](const size_t i, const MemoryTierCacheConfig& config){
264+
return i + config.getRatio();
265+
});
266+
267+
return memoryTierConfigs[tid].calculateTierSize(config_.getCacheSize(), partitions);
268+
}
269+
256270
template <typename CacheTrait>
257271
std::unique_ptr<MemoryAllocator>
258272
CacheAllocator<CacheTrait>::createNewMemoryAllocator(TierId tid) {
@@ -263,7 +277,8 @@ CacheAllocator<CacheTrait>::createNewMemoryAllocator(TierId tid) {
263277
config_.getCacheSize(), config_.slabMemoryBaseAddr,
264278
createShmCacheOpts(tid))
265279
.addr,
266-
memoryTierConfigs[tid].getSize());
280+
memoryTierSize(tid)
281+
);
267282
}
268283

269284
template <typename CacheTrait>
@@ -274,7 +289,7 @@ CacheAllocator<CacheTrait>::restoreMemoryAllocator(TierId tid) {
274289
shmManager_
275290
->attachShm(detail::kShmCacheName + std::to_string(tid),
276291
config_.slabMemoryBaseAddr, createShmCacheOpts(tid)).addr,
277-
memoryTierConfigs[tid].getSize(),
292+
memoryTierSize(tid),
278293
config_.disableFullCoredump);
279294
}
280295

@@ -2387,12 +2402,27 @@ PoolId CacheAllocator<CacheTrait>::addPool(
23872402
folly::SharedMutex::WriteHolder w(poolsResizeAndRebalanceLock_);
23882403

23892404
PoolId pid = 0;
2390-
auto tierConfigs = config_.getMemoryTierConfigs();
2405+
std::vector<size_t> tierPoolSizes;
2406+
const auto &tierConfigs = config_.getMemoryTierConfigs();
2407+
size_t totalCacheSize = 0;
2408+
23912409
for (TierId tid = 0; tid < numTiers_; tid++) {
2392-
auto tierSizeRatio = static_cast<double>(
2393-
tierConfigs[tid].getSize()) / config_.getCacheSize();
2394-
auto tierPoolSize = static_cast<size_t>(tierSizeRatio * size);
2395-
auto res = allocator_[tid]->addPool(name, tierPoolSize, allocSizes, ensureProvisionable);
2410+
totalCacheSize += allocator_[tid]->getMemorySize();
2411+
}
2412+
2413+
for (TierId tid = 0; tid < numTiers_; tid++) {
2414+
auto tierSizeRatio =
2415+
static_cast<double>(allocator_[tid]->getMemorySize()) / totalCacheSize;
2416+
size_t tierPoolSize = static_cast<size_t>(tierSizeRatio * size);
2417+
2418+
tierPoolSizes.push_back(tierPoolSize);
2419+
}
2420+
2421+
for (TierId tid = 0; tid < numTiers_; tid++) {
2422+
// TODO: what if we manage to add pool only in one tier?
2423+
// we should probably remove that on failure
2424+
auto res = allocator_[tid]->addPool(
2425+
name, tierPoolSizes[tid], allocSizes, ensureProvisionable);
23962426
XDCHECK(tid == 0 || res == pid);
23972427
pid = res;
23982428
}
@@ -2555,6 +2585,16 @@ const std::string CacheAllocator<CacheTrait>::getCacheName() const {
25552585
return config_.cacheName;
25562586
}
25572587

2588+
template <typename CacheTrait>
2589+
size_t CacheAllocator<CacheTrait>::getPoolSize(PoolId poolId) const {
2590+
size_t poolSize = 0;
2591+
for (auto& allocator: allocator_) {
2592+
const auto& pool = allocator->getPool(poolId);
2593+
poolSize += pool.getPoolSize();
2594+
}
2595+
return poolSize;
2596+
}
2597+
25582598
template <typename CacheTrait>
25592599
PoolStats CacheAllocator<CacheTrait>::getPoolStats(PoolId poolId) const {
25602600
const auto& pool = allocator_[currentTier()]->getPool(poolId);

cachelib/allocator/CacheAllocator.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,8 +1106,8 @@ class CacheAllocator : public CacheBase {
11061106
// get cache name
11071107
const std::string getCacheName() const override final;
11081108

1109-
// whether it is object-cache
1110-
bool isObjectCache() const override final { return false; }
1109+
// combined pool size for all memory tiers
1110+
size_t getPoolSize(PoolId pid) const;
11111111

11121112
// pool stats by pool id
11131113
PoolStats getPoolStats(PoolId pid) const override final;
@@ -1673,6 +1673,8 @@ class CacheAllocator : public CacheBase {
16731673
// handle to the item. On failure an empty handle.
16741674
WriteHandle tryEvictToNextMemoryTier(Item& item);
16751675

1676+
size_t memoryTierSize(TierId tid) const;
1677+
16761678
// Deserializer CacheAllocatorMetadata and verify the version
16771679
//
16781680
// @param deserializer Deserializer object

cachelib/allocator/CacheAllocatorConfig.h

Lines changed: 20 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -207,15 +207,15 @@ class CacheAllocatorConfig {
207207
// cachePersistence().
208208
CacheAllocatorConfig& usePosixForShm();
209209

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

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

220220
// This turns on a background worker that periodically scans through the
221221
// access container and look for expired items and remove them.
@@ -369,7 +369,7 @@ class CacheAllocatorConfig {
369369

370370
const std::string& getCacheName() const noexcept { return cacheName; }
371371

372-
size_t getCacheSize() const noexcept;
372+
size_t getCacheSize() const noexcept { return size; }
373373

374374
bool isUsingPosixShm() const noexcept { return usePosixShm; }
375375

@@ -391,8 +391,7 @@ class CacheAllocatorConfig {
391391
std::map<std::string, std::string> serialize() const;
392392

393393
// The max number of memory cache tiers
394-
// TODO: increase this number when multi-tier configs are enabled
395-
inline static const size_t kMaxCacheMemoryTiers = 1;
394+
inline static const size_t kMaxCacheMemoryTiers = 2;
396395

397396
// Cache name for users to indentify their own cache.
398397
std::string cacheName{""};
@@ -608,8 +607,6 @@ class CacheAllocatorConfig {
608607
friend CacheT;
609608

610609
private:
611-
void validateMemoryTiersWithSize(const MemoryTierConfigs&, size_t) const;
612-
613610
// Configuration for memory tiers.
614611
MemoryTierConfigs memoryTierConfigs{
615612
{MemoryTierCacheConfig::fromShm().setRatio(1)}
@@ -642,8 +639,6 @@ CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::setCacheName(
642639

643640
template <typename T>
644641
CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::setCacheSize(size_t _size) {
645-
validateMemoryTiersWithSize(this->memoryTierConfigs, _size);
646-
647642
size = _size;
648643
constexpr size_t maxCacheSizeWithCoredump = 64'424'509'440; // 60GB
649644
if (size <= maxCacheSizeWithCoredump) {
@@ -897,57 +892,24 @@ CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::enableItemReaperInBackground(
897892

898893
template <typename T>
899894
CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::configureMemoryTiers(
900-
const MemoryTierConfigs& config) {
901-
if (!config.size()) {
902-
throw std::invalid_argument("There must be at least one memory tier.");
895+
const MemoryTierConfigs& config) {
896+
if (config.size() > kMaxCacheMemoryTiers) {
897+
throw std::invalid_argument(folly::sformat(
898+
"Too many memory tiers. The number of supported tiers is {}.",
899+
kMaxCacheMemoryTiers));
903900
}
904-
905-
for (auto tier_config: config) {
906-
auto tier_size = tier_config.getSize();
907-
auto tier_ratio = tier_config.getRatio();
908-
if ((!tier_size and !tier_ratio) || (tier_size and tier_ratio)) {
909-
throw std::invalid_argument(
910-
"For each memory tier either size or ratio must be set.");
911-
}
901+
if (!config.size()) {
902+
throw std::invalid_argument(
903+
"There must be at least one memory tier config.");
912904
}
913-
914-
validateMemoryTiersWithSize(config, this->size);
915-
916905
memoryTierConfigs = config;
917-
918906
return *this;
919907
}
920908

921909
template <typename T>
922-
typename CacheAllocatorConfig<T>::MemoryTierConfigs
910+
const typename CacheAllocatorConfig<T>::MemoryTierConfigs&
923911
CacheAllocatorConfig<T>::getMemoryTierConfigs() const {
924-
MemoryTierConfigs config = memoryTierConfigs;
925-
size_t sum_ratios = 0;
926-
927-
for (auto &tier_config: config) {
928-
if (auto *v = std::get_if<PosixSysVSegmentOpts>(&tier_config.shmOpts)) {
929-
v->usePosix = usePosixShm;
930-
}
931-
932-
sum_ratios += tier_config.getRatio();
933-
}
934-
935-
if (sum_ratios == 0)
936-
return config;
937-
938-
// if ratios are used, size must be specified
939-
XDCHECK(size);
940-
941-
// Convert ratios to sizes, size must be non-zero
942-
size_t sum_sizes = 0;
943-
size_t partition_size = size / sum_ratios;
944-
for (auto& tier_config: config) {
945-
tier_config.setSize(partition_size * tier_config.getRatio());
946-
tier_config.setRatio(0);
947-
sum_sizes += tier_config.getSize();
948-
}
949-
950-
return config;
912+
return memoryTierConfigs;
951913
}
952914

953915
template <typename T>
@@ -1079,46 +1041,6 @@ CacheAllocatorConfig<T>::setSkipPromoteChildrenWhenParentFailed() {
10791041
return *this;
10801042
}
10811043

1082-
template <typename T>
1083-
size_t CacheAllocatorConfig<T>::getCacheSize() const noexcept {
1084-
if (size)
1085-
return size;
1086-
1087-
size_t sum_sizes = 0;
1088-
for (const auto &tier_config : getMemoryTierConfigs()) {
1089-
sum_sizes += tier_config.getSize();
1090-
}
1091-
1092-
return sum_sizes;
1093-
}
1094-
1095-
template <typename T>
1096-
void CacheAllocatorConfig<T>::validateMemoryTiersWithSize(
1097-
const MemoryTierConfigs &config, size_t size) const {
1098-
size_t sum_ratios = 0;
1099-
size_t sum_sizes = 0;
1100-
1101-
for (const auto &tier_config: config) {
1102-
sum_ratios += tier_config.getRatio();
1103-
sum_sizes += tier_config.getSize();
1104-
}
1105-
1106-
if (sum_ratios && sum_sizes) {
1107-
throw std::invalid_argument("Cannot mix ratios and sizes.");
1108-
} else if (sum_sizes) {
1109-
if (size && sum_sizes != size) {
1110-
throw std::invalid_argument(
1111-
"Sum of tier sizes doesn't match total cache size. "
1112-
"Setting of cache total size is not required when per-tier "
1113-
"sizes are specified - it is calculated as sum of tier sizes.");
1114-
}
1115-
} else if (!sum_ratios && !sum_sizes) {
1116-
throw std::invalid_argument(
1117-
"Either sum of all memory tiers sizes or sum of all ratios "
1118-
"must be greater than 0.");
1119-
}
1120-
}
1121-
11221044
template <typename T>
11231045
const CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::validate() const {
11241046
// we can track tail hits only if MMType is MM2Q
@@ -1143,23 +1065,7 @@ const CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::validate() const {
11431065
"It's not allowed to enable both RemoveCB and ItemDestructor.");
11441066
}
11451067

1146-
size_t sum_ratios = 0;
1147-
for (auto tier_config: memoryTierConfigs) {
1148-
sum_ratios += tier_config.getRatio();
1149-
}
1150-
1151-
if (sum_ratios) {
1152-
if (!size) {
1153-
throw std::invalid_argument(
1154-
"Total cache size must be specified when size ratios are "
1155-
"used to specify memory tier sizes.");
1156-
} else if (size < sum_ratios) {
1157-
throw std::invalid_argument(
1158-
"Sum of all tier size ratios is greater than total cache size.");
1159-
}
1160-
}
1161-
1162-
return *this;
1068+
return validateMemoryTiers();
11631069
}
11641070

11651071
template <typename T>

cachelib/allocator/MemoryTierCacheConfig.h

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -40,42 +40,46 @@ class MemoryTierCacheConfig {
4040
return config;
4141
}
4242

43-
// Specifies size of this memory tier. Sizes of tiers must be specified by
44-
// either setting size explicitly or using ratio, mixing of the two is not supported.
45-
MemoryTierCacheConfig& setSize(size_t _size) {
46-
size = _size;
47-
return *this;
48-
}
49-
5043
// Specifies ratio of this memory tier to other tiers. Absolute size
5144
// of each tier can be calculated as:
52-
// cacheSize * tierRatio / Sum of ratios for all tiers; the difference
53-
// between total cache size and sum of all tier sizes resulted from
54-
// round off error is accounted for when calculating the last tier's
55-
// size to make the totals equal.
56-
MemoryTierCacheConfig& setRatio(double _ratio) {
45+
// cacheSize * tierRatio / Sum of ratios for all tiers.
46+
MemoryTierCacheConfig& setRatio(size_t _ratio) {
47+
if (!_ratio) {
48+
throw std::invalid_argument("Tier ratio must be an integer number >=1.");
49+
}
5750
ratio = _ratio;
5851
return *this;
5952
}
6053

6154
size_t getRatio() const noexcept { return ratio; }
6255

63-
size_t getSize() const noexcept { return size; }
64-
6556
const ShmTypeOpts& getShmTypeOpts() const noexcept { return shmOpts; }
6657

67-
// Size of this memory tiers
68-
size_t size{0};
58+
size_t calculateTierSize(size_t totalCacheSize, size_t partitionNum) const {
59+
if (!partitionNum) {
60+
throw std::invalid_argument(
61+
"The total number of tier ratios must be an integer number >=1.");
62+
}
6963

70-
// Ratio is a number of parts of the total cache size to be allocated for this tier.
71-
// E.g. if X is a total cache size, Yi are ratios specified for memory tiers,
72-
// then size of the i-th tier Xi = (X / (Y1 + Y2)) * Yi and X = sum(Xi)
73-
size_t ratio{0};
64+
if (partitionNum > totalCacheSize) {
65+
throw std::invalid_argument(
66+
"Ratio must be less or equal to total cache size.");
67+
}
68+
69+
return static_cast<size_t>(getRatio() * (static_cast<double>(totalCacheSize) / partitionNum));
70+
}
71+
72+
private:
73+
// Ratio is a number of parts of the total cache size to be allocated for this
74+
// tier. E.g. if X is a total cache size, Yi are ratios specified for memory
75+
// tiers, and Y is the sum of all Yi, then size of the i-th tier
76+
// Xi = (X / Y) * Yi. For examle, to configure 2-tier cache where each
77+
// tier is a half of the total cache size, set both tiers' ratios to 1.
78+
size_t ratio{1};
7479

7580
// Options specific to shm type
7681
ShmTypeOpts shmOpts;
7782

78-
private:
7983
MemoryTierCacheConfig() = default;
8084
};
8185
} // namespace cachelib

cachelib/allocator/memory/SlabAllocator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
using namespace facebook::cachelib;
4141

4242
namespace {
43-
size_t roundDownToSlabSize(size_t size) { return size - (size % sizeof(Slab)); }
43+
static inline size_t roundDownToSlabSize(size_t size) { return size - (size % sizeof(Slab)); }
4444
} // namespace
4545

4646
// definitions to avoid ODR violation.

0 commit comments

Comments
 (0)