Skip to content

Commit dc3832d

Browse files
committed
- Add memory tier configs to cache allocator based on NUMA bindings
- Add in MemoryTier tests - Increase max number of tiers to 2 for tiers tests
1 parent 08051fa commit dc3832d

11 files changed

+274
-7
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: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ 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_
5758
? std::make_unique<TempShmMapping>(config_.size)
5859
: nullptr),
@@ -112,7 +113,6 @@ 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-
116116
return opts;
117117
}
118118

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: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ class CacheAllocatorConfig {
207207
// Accepts vector of MemoryTierCacheConfig. Each vector element describes
208208
// configuration for a single memory cache tier. Tier sizes are specified as
209209
// ratios, the number of parts of total cache size each tier would occupy.
210+
// @throw std::invalid_argument if:
211+
// - the size of configs is 0
212+
// - the size of configs is greater than kMaxCacheMemoryTiers
210213
CacheAllocatorConfig& configureMemoryTiers(const MemoryTierConfigs& configs);
211214

212215
// Return reference to MemoryTierCacheConfigs.
@@ -374,8 +377,7 @@ class CacheAllocatorConfig {
374377
std::map<std::string, std::string> serialize() const;
375378

376379
// 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;
380+
inline static const size_t kMaxCacheMemoryTiers = 2;
379381

380382
// Cache name for users to indentify their own cache.
381383
std::string cacheName{""};

cachelib/allocator/MemoryTierCacheConfig.h

Lines changed: 1 addition & 2 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

@@ -49,7 +48,7 @@ class MemoryTierCacheConfig {
4948

5049
const NumaBitMask& getMemBind() const noexcept { return numaNodes; }
5150

52-
size_t calculateTierSize(size_t totalCacheSize, size_t partitionNum) {
51+
size_t calculateTierSize(size_t totalCacheSize, size_t partitionNum) const {
5352
// TODO: Call this method when tiers are enabled in allocator
5453
// to calculate tier sizes in bytes.
5554
if (!partitionNum) {
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);
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
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 <folly/Random.h>
18+
19+
#include <numeric>
20+
21+
#include "cachelib/allocator/CacheAllocator.h"
22+
#include "cachelib/allocator/tests/TestBase.h"
23+
24+
namespace facebook {
25+
namespace cachelib {
26+
namespace tests {
27+
28+
using LruAllocatorConfig = CacheAllocatorConfig<LruAllocator>;
29+
using LruMemoryTierConfigs = LruAllocatorConfig::MemoryTierConfigs;
30+
using Strings = std::vector<std::string>;
31+
using Ratios = std::vector<size_t>;
32+
33+
constexpr size_t MB = 1024ULL * 1024ULL;
34+
constexpr size_t GB = MB * 1024ULL;
35+
36+
const size_t defaultTotalCacheSize{1 * GB};
37+
const std::string defaultCacheDir{"/var/metadataDir"};
38+
39+
template <typename Allocator>
40+
class MemoryTiersTest: public AllocatorTest<Allocator> {
41+
public:
42+
void basicCheck(
43+
LruAllocatorConfig& actualConfig,
44+
size_t expectedTotalCacheSize = defaultTotalCacheSize,
45+
const std::string& expectedCacheDir = defaultCacheDir) {
46+
EXPECT_EQ(actualConfig.getCacheSize(), expectedTotalCacheSize);
47+
auto configs = actualConfig.getMemoryTierConfigs();
48+
49+
size_t sum_ratios = std::accumulate(configs.begin(), configs.end(), 0UL,
50+
[](const size_t i, const MemoryTierCacheConfig& config) { return i + config.getRatio();});
51+
size_t sum_sizes = std::accumulate(configs.begin(), configs.end(), 0UL,
52+
[&](const size_t i, const MemoryTierCacheConfig& config) {
53+
return i + config.calculateTierSize(actualConfig.getCacheSize(), sum_ratios);
54+
});
55+
56+
EXPECT_GE(expectedTotalCacheSize, sum_ratios * Slab::kSize);
57+
EXPECT_LE(sum_sizes, expectedTotalCacheSize);
58+
EXPECT_GE(sum_sizes, expectedTotalCacheSize - configs.size() * Slab::kSize);
59+
}
60+
61+
62+
LruAllocatorConfig createTestCacheConfig(
63+
const Ratios& tierRatios = {1},
64+
bool setPosixForShm = true,
65+
size_t cacheSize = defaultTotalCacheSize,
66+
const std::string& cacheDir = defaultCacheDir) {
67+
LruAllocatorConfig cfg;
68+
cfg.setCacheSize(cacheSize)
69+
.enableCachePersistence(cacheDir);
70+
71+
if (setPosixForShm)
72+
cfg.usePosixForShm();
73+
LruMemoryTierConfigs tierConfigs;
74+
tierConfigs.reserve(tierRatios.size());
75+
for(auto i = 0; i < tierRatios.size(); ++i) {
76+
tierConfigs.push_back(MemoryTierCacheConfig::fromShm()
77+
.setRatio(tierRatios[i])
78+
.setMemBind(std::string("0")));
79+
}
80+
81+
cfg.configureMemoryTiers(tierConfigs);
82+
return cfg;
83+
}
84+
85+
LruAllocatorConfig createTieredCacheConfig(size_t totalCacheSize,
86+
size_t numTiers = 2) {
87+
LruAllocatorConfig tieredCacheConfig{};
88+
std::vector<MemoryTierCacheConfig> configs;
89+
for (auto i = 1; i <= numTiers; ++i) {
90+
configs.push_back(MemoryTierCacheConfig::fromShm()
91+
.setRatio(1)
92+
.setMemBind(std::string("0")));
93+
}
94+
tieredCacheConfig.setCacheSize(totalCacheSize)
95+
.enableCachePersistence(
96+
folly::sformat("/tmp/multi-tier-test/{}", ::getpid()))
97+
.usePosixForShm()
98+
.configureMemoryTiers(configs);
99+
return tieredCacheConfig;
100+
}
101+
102+
LruAllocatorConfig createDramCacheConfig(size_t totalCacheSize) {
103+
LruAllocatorConfig dramConfig{};
104+
dramConfig.setCacheSize(totalCacheSize);
105+
return dramConfig;
106+
}
107+
108+
void validatePoolSize(PoolId poolId,
109+
std::unique_ptr<LruAllocator>& allocator,
110+
size_t expectedSize) {
111+
size_t actualSize = allocator->getPool(poolId).getPoolSize();
112+
EXPECT_EQ(actualSize, expectedSize);
113+
}
114+
115+
void testAddPool(std::unique_ptr<LruAllocator>& alloc,
116+
size_t poolSize,
117+
bool isSizeValid = true,
118+
size_t numTiers = 2) {
119+
if (isSizeValid) {
120+
auto pool = alloc->addPool("validPoolSize", poolSize);
121+
EXPECT_LE(alloc->getPool(pool).getPoolSize(), poolSize);
122+
if (poolSize >= numTiers * Slab::kSize)
123+
EXPECT_GE(alloc->getPool(pool).getPoolSize(), poolSize - numTiers * Slab::kSize);
124+
} else {
125+
EXPECT_THROW(alloc->addPool("invalidPoolSize", poolSize),
126+
std::invalid_argument);
127+
// TODO: test this for all tiers
128+
EXPECT_EQ(alloc->getPoolIds().size(), 0);
129+
}
130+
}
131+
};
132+
133+
using LruMemoryTiersTest = MemoryTiersTest<LruAllocator>;
134+
135+
TEST_F(LruMemoryTiersTest, TestValid1TierConfig) {
136+
LruAllocatorConfig cfg = createTestCacheConfig().validate();
137+
basicCheck(cfg);
138+
}
139+
140+
TEST_F(LruMemoryTiersTest, TestValid2TierConfig) {
141+
LruAllocatorConfig cfg = createTestCacheConfig({1, 1});
142+
basicCheck(cfg);
143+
}
144+
145+
TEST_F(LruMemoryTiersTest, TestValid2TierRatioConfig) {
146+
LruAllocatorConfig cfg = createTestCacheConfig({5, 2});
147+
basicCheck(cfg);
148+
}
149+
150+
TEST_F(LruMemoryTiersTest, TestInvalid2TierConfigNumberOfPartitionsTooLarge) {
151+
EXPECT_THROW(createTestCacheConfig({defaultTotalCacheSize, 1}).validate(),
152+
std::invalid_argument);
153+
}
154+
155+
TEST_F(LruMemoryTiersTest, TestInvalid2TierConfigSizesAndRatioNotSet) {
156+
EXPECT_THROW(createTestCacheConfig({1, 0}),
157+
std::invalid_argument);
158+
}
159+
160+
TEST_F(LruMemoryTiersTest, TestInvalid2TierConfigRatiosCacheSizeNotSet) {
161+
EXPECT_THROW(createTestCacheConfig({1, 1}, true,
162+
/* cacheSize */ 0).validate(),
163+
std::invalid_argument);
164+
}
165+
166+
TEST_F(LruMemoryTiersTest, TestInvalid2TierConfigRatioNotSet) {
167+
EXPECT_THROW(
168+
createTestCacheConfig({1, 0}),
169+
std::invalid_argument);
170+
}
171+
172+
TEST_F(LruMemoryTiersTest, TestInvalid2TierConfigSizesNeCacheSize) {
173+
EXPECT_THROW(createTestCacheConfig({0, 0}),
174+
std::invalid_argument);
175+
}
176+
} // namespace tests
177+
} // namespace cachelib
178+
} // namespace facebook

cachelib/cachebench/util/CacheConfig.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ CacheConfig::CacheConfig(const folly::dynamic& configJson) {
9999
JSONSetVal(configJson, enableItemDestructor);
100100
JSONSetVal(configJson, nvmAdmissionRetentionTimeThreshold);
101101

102-
JSONSetVal(configJson, customConfigJson);
103102
// if you added new fields to the configuration, update the JSONSetVal
104103
// to make them available for the json configs and increment the size
105104
// below

0 commit comments

Comments
 (0)