Skip to content

Commit 48feb62

Browse files
victoria-mcgrathbyrnedj
authored andcommitted
Initial version of config API extension to support multiple memory tiers
* New class MemoryTierCacheConfig allows to configure a memory tier. Setting tier size and location of a file for file-backed memory are supported in this initial implementation; * New member, vector of memory tiers, is added to class CacheAllocatorConfig. * New test suite, chelib/allocator/tests/MemoryTiersTest.cpp, demonstrates the usage of and tests extended config API. Integrate Memory Tier config API with CacheAllocator. Enabled memory tier config API for cachebench. Assumes NUMA bindings support - this commit was done before tiering support enabled. fix memBind call replaces Add MemoryTierCacheConfig::fromShm() (commit 1c7c15d) Move validation code for memory tiers to validate() method and convert ratios to sizes lazily Do not compensate for rounding error when calculating tier sizes (pmem#43) Compensation results in ratios being different than originially specified. Fixed total cache size in CacheMemoryStats (pmem#38) Return a sum of sizes of each tier instead of just 1st tier's size. 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 4ab790e commit 48feb62

13 files changed

+310
-23
lines changed

cachelib/allocator/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ if (BUILD_TESTS)
117117
add_test (tests/ChainedHashTest.cpp)
118118
add_test (tests/AllocatorResizeTypeTest.cpp)
119119
add_test (tests/AllocatorHitStatsTypeTest.cpp)
120+
add_test (tests/AllocatorMemoryTiersTest.cpp)
121+
add_test (tests/MemoryTiersTest.cpp)
120122
add_test (tests/MultiAllocatorTest.cpp)
121123
add_test (tests/NvmAdmissionPolicyTest.cpp)
122124
add_test (tests/CacheAllocatorConfigTest.cpp)

cachelib/allocator/CacheAllocator-inl.h

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,13 @@ CacheAllocator<CacheTrait>::CacheAllocator(
5353
: isOnShm_{type != InitMemType::kNone ? true
5454
: config.memMonitoringEnabled()},
5555
config_(config.validate()),
56+
memoryTierConfigs(config.getMemoryTierConfigs()),
5657
tempShm_(type == InitMemType::kNone && isOnShm_
57-
? std::make_unique<TempShmMapping>(config_.size)
58+
? std::make_unique<TempShmMapping>(config_.getCacheSize())
5859
: nullptr),
5960
shmManager_(type != InitMemType::kNone
6061
? std::make_unique<ShmManager>(config_.cacheDir,
61-
config_.usePosixShm)
62+
config_.isUsingPosixShm())
6263
: nullptr),
6364
deserializer_(type == InitMemType::kMemAttach ? createDeserializer()
6465
: nullptr),
@@ -112,7 +113,9 @@ ShmSegmentOpts CacheAllocator<CacheTrait>::createShmCacheOpts() {
112113
// TODO: we support single tier so far
113114
XDCHECK_EQ(memoryTierConfigs.size(), 1ul);
114115
opts.memBindNumaNodes = memoryTierConfigs[0].getMemBind();
115-
116+
if (memoryTierConfigs.size() > 1) {
117+
throw std::invalid_argument("CacheLib only supports a single memory tier");
118+
}
116119
return opts;
117120
}
118121

@@ -122,10 +125,10 @@ CacheAllocator<CacheTrait>::createNewMemoryAllocator() {
122125
return std::make_unique<MemoryAllocator>(
123126
getAllocatorConfig(config_),
124127
shmManager_
125-
->createShm(detail::kShmCacheName, config_.size,
128+
->createShm(detail::kShmCacheName, config_.getCacheSize(),
126129
config_.slabMemoryBaseAddr, createShmCacheOpts())
127130
.addr,
128-
config_.size);
131+
config_.getCacheSize());
129132
}
130133

131134
template <typename CacheTrait>
@@ -135,9 +138,8 @@ CacheAllocator<CacheTrait>::restoreMemoryAllocator() {
135138
deserializer_->deserialize<MemoryAllocator::SerializationType>(),
136139
shmManager_
137140
->attachShm(detail::kShmCacheName, config_.slabMemoryBaseAddr,
138-
createShmCacheOpts())
139-
.addr,
140-
config_.size,
141+
createShmCacheOpts()).addr,
142+
config_.getCacheSize(),
141143
config_.disableFullCoredump);
142144
}
143145

@@ -243,10 +245,10 @@ std::unique_ptr<MemoryAllocator> CacheAllocator<CacheTrait>::initAllocator(
243245
if (type == InitMemType::kNone) {
244246
if (isOnShm_ == true) {
245247
return std::make_unique<MemoryAllocator>(
246-
getAllocatorConfig(config_), tempShm_->getAddr(), config_.size);
248+
getAllocatorConfig(config_), tempShm_->getAddr(), config_.getCacheSize());
247249
} else {
248250
return std::make_unique<MemoryAllocator>(getAllocatorConfig(config_),
249-
config_.size);
251+
config_.getCacheSize());
250252
}
251253
} else if (type == InitMemType::kMemNew) {
252254
return createNewMemoryAllocator();
@@ -2177,6 +2179,13 @@ const std::string CacheAllocator<CacheTrait>::getCacheName() const {
21772179
return config_.cacheName;
21782180
}
21792181

2182+
template <typename CacheTrait>
2183+
size_t CacheAllocator<CacheTrait>::getPoolSize(PoolId poolId) const {
2184+
const auto& pool = allocator_->getPool(poolId);
2185+
size_t poolSize = pool.getPoolSize();
2186+
return poolSize;
2187+
}
2188+
21802189
template <typename CacheTrait>
21812190
PoolStats CacheAllocator<CacheTrait>::getPoolStats(PoolId poolId) const {
21822191
const auto& pool = allocator_->getPool(poolId);
@@ -2251,7 +2260,7 @@ PoolEvictionAgeStats CacheAllocator<CacheTrait>::getPoolEvictionAgeStats(
22512260
template <typename CacheTrait>
22522261
CacheMetadata CacheAllocator<CacheTrait>::getCacheMetadata() const noexcept {
22532262
return CacheMetadata{kCachelibVersion, kCacheRamFormatVersion,
2254-
kCacheNvmFormatVersion, config_.size};
2263+
kCacheNvmFormatVersion, config_.getCacheSize()};
22552264
}
22562265

22572266
template <typename CacheTrait>

cachelib/allocator/CacheAllocator.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,9 @@ class CacheAllocator : public CacheBase {
11591159
// whether it is object-cache
11601160
bool isObjectCache() const override final { return false; }
11611161

1162+
// combined pool size for all memory tiers
1163+
size_t getPoolSize(PoolId pid) const;
1164+
11621165
// pool stats by pool id
11631166
PoolStats getPoolStats(PoolId pid) const override final;
11641167

@@ -1986,6 +1989,8 @@ class CacheAllocator : public CacheBase {
19861989

19871990
Config config_{};
19881991

1992+
const typename Config::MemoryTierConfigs memoryTierConfigs;
1993+
19891994
// Manages the temporary shared memory segment for memory allocator that
19901995
// is not persisted when cache process exits.
19911996
std::unique_ptr<TempShmMapping> tempShm_;

cachelib/allocator/CacheAllocatorConfig.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,19 +194,24 @@ class CacheAllocatorConfig {
194194
// This allows cache to be persisted across restarts. One example use case is
195195
// to preserve the cache when releasing a new version of your service. Refer
196196
// to our user guide for how to set up cache persistence.
197+
// TODO: get rid of baseAddr or if set make sure all mapping are adjacent?
198+
// We can also make baseAddr a per-tier configuration
197199
CacheAllocatorConfig& enableCachePersistence(std::string directory,
198200
void* baseAddr = nullptr);
199201

200-
// uses posix shm segments instead of the default sys-v shm segments.
201-
// @throw std::invalid_argument if called without enabling
202-
// cachePersistence()
202+
// Uses posix shm segments instead of the default sys-v shm
203+
// segments. @throw std::invalid_argument if called without enabling
204+
// cachePersistence().
203205
CacheAllocatorConfig& usePosixForShm();
204206

205207
// Configures cache memory tiers. Each tier represents a cache region inside
206208
// byte-addressable memory such as DRAM, Pmem, CXLmem.
207209
// Accepts vector of MemoryTierCacheConfig. Each vector element describes
208210
// configuration for a single memory cache tier. Tier sizes are specified as
209211
// ratios, the number of parts of total cache size each tier would occupy.
212+
// @throw std::invalid_argument if:
213+
// - the size of configs is 0
214+
// - the size of configs is greater than kMaxCacheMemoryTiers
210215
CacheAllocatorConfig& configureMemoryTiers(const MemoryTierConfigs& configs);
211216

212217
// Return reference to MemoryTierCacheConfigs.
@@ -374,8 +379,7 @@ class CacheAllocatorConfig {
374379
std::map<std::string, std::string> serialize() const;
375380

376381
// The max number of memory cache tiers
377-
// TODO: increase this number when multi-tier configs are enabled
378-
inline static const size_t kMaxCacheMemoryTiers = 1;
382+
inline static const size_t kMaxCacheMemoryTiers = 2;
379383

380384
// Cache name for users to indentify their own cache.
381385
std::string cacheName{""};
@@ -1085,7 +1089,7 @@ std::map<std::string, std::string> CacheAllocatorConfig<T>::serialize() const {
10851089

10861090
configMap["size"] = std::to_string(size);
10871091
configMap["cacheDir"] = cacheDir;
1088-
configMap["posixShm"] = usePosixShm ? "set" : "empty";
1092+
configMap["posixShm"] = isUsingPosixShm() ? "set" : "empty";
10891093

10901094
configMap["defaultAllocSizes"] = "";
10911095
// Stringify std::set

cachelib/allocator/MemoryTierCacheConfig.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ class MemoryTierCacheConfig {
2424
public:
2525
// Creates instance of MemoryTierCacheConfig for Posix/SysV Shared memory.
2626
static MemoryTierCacheConfig fromShm() {
27-
// TODO: expand this method when adding support for file-mapped memory
2827
return MemoryTierCacheConfig();
2928
}
3029

@@ -51,7 +50,7 @@ class MemoryTierCacheConfig {
5150
return numaNodes;
5251
}
5352

54-
size_t calculateTierSize(size_t totalCacheSize, size_t partitionNum) {
53+
size_t calculateTierSize(size_t totalCacheSize, size_t partitionNum) const {
5554
// TODO: Call this method when tiers are enabled in allocator
5655
// to calculate tier sizes in bytes.
5756
if (!partitionNum) {
@@ -66,7 +65,7 @@ class MemoryTierCacheConfig {
6665

6766
return getRatio() * (totalCacheSize / partitionNum);
6867
}
69-
68+
7069
private:
7170
// Ratio is a number of parts of the total cache size to be allocated for this
7271
// tier. E.g. if X is a total cache size, Yi are ratios specified for memory
@@ -80,6 +79,7 @@ class MemoryTierCacheConfig {
8079

8180
// TODO: introduce a container for tier settings when adding support for
8281
// file-mapped memory
82+
8383
MemoryTierCacheConfig() = default;
8484
};
8585
} // 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.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (c) Intel Corporation.
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+
#include "cachelib/allocator/tests/AllocatorMemoryTiersTest.h"
18+
19+
namespace facebook {
20+
namespace cachelib {
21+
namespace tests {
22+
23+
using LruAllocatorMemoryTiersTest = AllocatorMemoryTiersTest<LruAllocator>;
24+
25+
// TODO(MEMORY_TIER): add more tests with different eviction policies
26+
TEST_F(LruAllocatorMemoryTiersTest, MultiTiersValid1) { this->testMultiTiersValid1(); }
27+
28+
} // end of namespace tests
29+
} // end of namespace cachelib
30+
} // end of namespace facebook
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its 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/CacheAllocatorConfig.h"
20+
#include "cachelib/allocator/MemoryTierCacheConfig.h"
21+
#include "cachelib/allocator/tests/TestBase.h"
22+
23+
namespace facebook {
24+
namespace cachelib {
25+
namespace tests {
26+
27+
template <typename AllocatorT>
28+
class AllocatorMemoryTiersTest : public AllocatorTest<AllocatorT> {
29+
public:
30+
void testMultiTiersValid1() {
31+
typename AllocatorT::Config config;
32+
config.setCacheSize(100 * Slab::kSize);
33+
ASSERT_NO_THROW(config.configureMemoryTiers({
34+
MemoryTierCacheConfig::fromShm()
35+
.setRatio(1).setMemBind(std::string("0")),
36+
MemoryTierCacheConfig::fromShm()
37+
.setRatio(1).setMemBind(std::string("0"))
38+
}));
39+
}
40+
};
41+
} // namespace tests
42+
} // namespace cachelib
43+
} // namespace facebook

cachelib/allocator/tests/AllocatorTypeTest.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "cachelib/allocator/tests/BaseAllocatorTest.h"
1818
#include "cachelib/allocator/tests/TestBase.h"
19+
#include "cachelib/allocator/MemoryTierCacheConfig.h"
1920

2021
namespace facebook {
2122
namespace cachelib {
@@ -226,6 +227,12 @@ TYPED_TEST(BaseAllocatorTest, ReaperSkippingSlabTraversalWhileSlabReleasing) {
226227
}
227228

228229
TYPED_TEST(BaseAllocatorTest, ReaperShutDown) { this->testReaperShutDown(); }
230+
TYPED_TEST(BaseAllocatorTest, ReaperShutDownFile) {
231+
this->testReaperShutDown({
232+
MemoryTierCacheConfig::fromShm()
233+
.setRatio(1).setMemBind(std::string("0"))
234+
});
235+
}
229236

230237
TYPED_TEST(BaseAllocatorTest, ShutDownWithActiveHandles) {
231238
this->testShutDownWithActiveHandles();

cachelib/allocator/tests/BaseAllocatorTest.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1259,7 +1259,7 @@ class BaseAllocatorTest : public AllocatorTest<AllocatorT> {
12591259
this->testLruLength(alloc, poolId, sizes, keyLen, evictedKeys);
12601260
}
12611261

1262-
void testReaperShutDown() {
1262+
void testReaperShutDown(typename AllocatorT::Config::MemoryTierConfigs cfgs = {}) {
12631263
const size_t nSlabs = 20;
12641264
const size_t size = nSlabs * Slab::kSize;
12651265

@@ -1269,6 +1269,8 @@ class BaseAllocatorTest : public AllocatorTest<AllocatorT> {
12691269
config.setAccessConfig({8, 8});
12701270
config.enableCachePersistence(this->cacheDir_);
12711271
config.enableItemReaperInBackground(std::chrono::seconds(1), {});
1272+
if (cfgs.size())
1273+
config.configureMemoryTiers(cfgs);
12721274
std::vector<typename AllocatorT::Key> keys;
12731275
{
12741276
AllocatorT alloc(AllocatorT::SharedMemNew, config);

0 commit comments

Comments
 (0)