Skip to content

Commit 2bb164f

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 2bb164f

10 files changed

+275
-9
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: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@ namespace cachelib {
2323
class MemoryTierCacheConfig {
2424
public:
2525
// Creates instance of MemoryTierCacheConfig for Posix/SysV Shared memory.
26-
static MemoryTierCacheConfig fromShm() {
27-
// TODO: expand this method when adding support for file-mapped memory
28-
return MemoryTierCacheConfig();
29-
}
26+
static MemoryTierCacheConfig fromShm() { return MemoryTierCacheConfig(); }
3027

3128
// Specifies ratio of this memory tier to other tiers. Absolute size
3229
// of each tier can be calculated as:
@@ -49,7 +46,7 @@ class MemoryTierCacheConfig {
4946

5047
const NumaBitMask& getMemBind() const noexcept { return numaNodes; }
5148

52-
size_t calculateTierSize(size_t totalCacheSize, size_t partitionNum) {
49+
size_t calculateTierSize(size_t totalCacheSize, size_t partitionNum) const {
5350
// TODO: Call this method when tiers are enabled in allocator
5451
// to calculate tier sizes in bytes.
5552
if (!partitionNum) {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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) {
27+
this->testMultiTiersValid1();
28+
}
29+
30+
} // end of namespace tests
31+
} // end of namespace cachelib
32+
} // end of namespace facebook
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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().setRatio(1).setMemBind(
35+
std::string("0")),
36+
MemoryTierCacheConfig::fromShm().setRatio(1).setMemBind(
37+
std::string("0"))}));
38+
}
39+
};
40+
} // namespace tests
41+
} // namespace cachelib
42+
} // namespace facebook

cachelib/allocator/tests/AllocatorTypeTest.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
#include "cachelib/allocator/MemoryTierCacheConfig.h"
1718
#include "cachelib/allocator/tests/BaseAllocatorTest.h"
1819
#include "cachelib/allocator/tests/TestBase.h"
1920

@@ -226,6 +227,11 @@ TYPED_TEST(BaseAllocatorTest, ReaperSkippingSlabTraversalWhileSlabReleasing) {
226227
}
227228

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

230236
TYPED_TEST(BaseAllocatorTest, ShutDownWithActiveHandles) {
231237
this->testShutDownWithActiveHandles();

cachelib/allocator/tests/BaseAllocatorTest.h

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

1262-
void testReaperShutDown() {
1262+
void testReaperShutDown(
1263+
typename AllocatorT::Config::MemoryTierConfigs cfgs = {}) {
12631264
const size_t nSlabs = 20;
12641265
const size_t size = nSlabs * Slab::kSize;
12651266

@@ -1269,6 +1270,8 @@ class BaseAllocatorTest : public AllocatorTest<AllocatorT> {
12691270
config.setAccessConfig({8, 8});
12701271
config.enableCachePersistence(this->cacheDir_);
12711272
config.enableItemReaperInBackground(std::chrono::seconds(1), {});
1273+
if (cfgs.size())
1274+
config.configureMemoryTiers(cfgs);
12721275
std::vector<typename AllocatorT::Key> keys;
12731276
{
12741277
AllocatorT alloc(AllocatorT::SharedMemNew, config);
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
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(LruAllocatorConfig& actualConfig,
43+
size_t expectedTotalCacheSize = defaultTotalCacheSize,
44+
const std::string& expectedCacheDir = defaultCacheDir) {
45+
EXPECT_EQ(actualConfig.getCacheSize(), expectedTotalCacheSize);
46+
auto configs = actualConfig.getMemoryTierConfigs();
47+
48+
size_t sum_ratios = std::accumulate(
49+
configs.begin(), configs.end(), 0UL,
50+
[](const size_t i, const MemoryTierCacheConfig& config) {
51+
return i + config.getRatio();
52+
});
53+
size_t sum_sizes = std::accumulate(
54+
configs.begin(), configs.end(), 0UL,
55+
[&](const size_t i, const MemoryTierCacheConfig& config) {
56+
return i + config.calculateTierSize(actualConfig.getCacheSize(),
57+
sum_ratios);
58+
});
59+
60+
EXPECT_GE(expectedTotalCacheSize, sum_ratios * Slab::kSize);
61+
EXPECT_LE(sum_sizes, expectedTotalCacheSize);
62+
EXPECT_GE(sum_sizes, expectedTotalCacheSize - configs.size() * Slab::kSize);
63+
}
64+
65+
LruAllocatorConfig createTestCacheConfig(
66+
const Ratios& tierRatios = {1},
67+
bool setPosixForShm = true,
68+
size_t cacheSize = defaultTotalCacheSize,
69+
const std::string& cacheDir = defaultCacheDir) {
70+
LruAllocatorConfig cfg;
71+
cfg.setCacheSize(cacheSize).enableCachePersistence(cacheDir);
72+
73+
if (setPosixForShm)
74+
cfg.usePosixForShm();
75+
LruMemoryTierConfigs tierConfigs;
76+
tierConfigs.reserve(tierRatios.size());
77+
for (auto i = 0; i < tierRatios.size(); ++i) {
78+
tierConfigs.push_back(MemoryTierCacheConfig::fromShm()
79+
.setRatio(tierRatios[i])
80+
.setMemBind(std::string("0")));
81+
}
82+
83+
cfg.configureMemoryTiers(tierConfigs);
84+
return cfg;
85+
}
86+
87+
LruAllocatorConfig createTieredCacheConfig(size_t totalCacheSize,
88+
size_t numTiers = 2) {
89+
LruAllocatorConfig tieredCacheConfig{};
90+
std::vector<MemoryTierCacheConfig> configs;
91+
for (auto i = 1; i <= numTiers; ++i) {
92+
configs.push_back(MemoryTierCacheConfig::fromShm().setRatio(1).setMemBind(
93+
std::string("0")));
94+
}
95+
tieredCacheConfig.setCacheSize(totalCacheSize)
96+
.enableCachePersistence(
97+
folly::sformat("/tmp/multi-tier-test/{}", ::getpid()))
98+
.usePosixForShm()
99+
.configureMemoryTiers(configs);
100+
return tieredCacheConfig;
101+
}
102+
103+
LruAllocatorConfig createDramCacheConfig(size_t totalCacheSize) {
104+
LruAllocatorConfig dramConfig{};
105+
dramConfig.setCacheSize(totalCacheSize);
106+
return dramConfig;
107+
}
108+
109+
void validatePoolSize(PoolId poolId,
110+
std::unique_ptr<LruAllocator>& allocator,
111+
size_t expectedSize) {
112+
size_t actualSize = allocator->getPool(poolId).getPoolSize();
113+
EXPECT_EQ(actualSize, expectedSize);
114+
}
115+
116+
void testAddPool(std::unique_ptr<LruAllocator>& alloc,
117+
size_t poolSize,
118+
bool isSizeValid = true,
119+
size_t numTiers = 2) {
120+
if (isSizeValid) {
121+
auto pool = alloc->addPool("validPoolSize", poolSize);
122+
EXPECT_LE(alloc->getPool(pool).getPoolSize(), poolSize);
123+
if (poolSize >= numTiers * Slab::kSize)
124+
EXPECT_GE(alloc->getPool(pool).getPoolSize(),
125+
poolSize - numTiers * Slab::kSize);
126+
} else {
127+
EXPECT_THROW(alloc->addPool("invalidPoolSize", poolSize),
128+
std::invalid_argument);
129+
// TODO: test this for all tiers
130+
EXPECT_EQ(alloc->getPoolIds().size(), 0);
131+
}
132+
}
133+
};
134+
135+
using LruMemoryTiersTest = MemoryTiersTest<LruAllocator>;
136+
137+
TEST_F(LruMemoryTiersTest, TestValid1TierConfig) {
138+
LruAllocatorConfig cfg = createTestCacheConfig().validate();
139+
basicCheck(cfg);
140+
}
141+
142+
TEST_F(LruMemoryTiersTest, TestValid2TierConfig) {
143+
LruAllocatorConfig cfg = createTestCacheConfig({1, 1});
144+
basicCheck(cfg);
145+
}
146+
147+
TEST_F(LruMemoryTiersTest, TestValid2TierRatioConfig) {
148+
LruAllocatorConfig cfg = createTestCacheConfig({5, 2});
149+
basicCheck(cfg);
150+
}
151+
152+
TEST_F(LruMemoryTiersTest, TestInvalid2TierConfigNumberOfPartitionsTooLarge) {
153+
EXPECT_THROW(createTestCacheConfig({defaultTotalCacheSize, 1}).validate(),
154+
std::invalid_argument);
155+
}
156+
157+
TEST_F(LruMemoryTiersTest, TestInvalid2TierConfigSizesAndRatioNotSet) {
158+
EXPECT_THROW(createTestCacheConfig({1, 0}), std::invalid_argument);
159+
}
160+
161+
TEST_F(LruMemoryTiersTest, TestInvalid2TierConfigRatiosCacheSizeNotSet) {
162+
EXPECT_THROW(createTestCacheConfig({1, 1}, true,
163+
/* cacheSize */ 0)
164+
.validate(),
165+
std::invalid_argument);
166+
}
167+
168+
TEST_F(LruMemoryTiersTest, TestInvalid2TierConfigRatioNotSet) {
169+
EXPECT_THROW(createTestCacheConfig({1, 0}), std::invalid_argument);
170+
}
171+
172+
TEST_F(LruMemoryTiersTest, TestInvalid2TierConfigSizesNeCacheSize) {
173+
EXPECT_THROW(createTestCacheConfig({0, 0}), std::invalid_argument);
174+
}
175+
} // namespace tests
176+
} // namespace cachelib
177+
} // namespace facebook

0 commit comments

Comments
 (0)