Skip to content

Commit ba089ef

Browse files
victoria-mcgrathigchor
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.
1 parent 14d974e commit ba089ef

File tree

4 files changed

+346
-4
lines changed

4 files changed

+346
-4
lines changed

cachelib/allocator/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ if (BUILD_TESTS)
109109
add_test (tests/ChainedHashTest.cpp)
110110
add_test (tests/AllocatorResizeTypeTest.cpp)
111111
add_test (tests/AllocatorHitStatsTypeTest.cpp)
112+
add_test (tests/MemoryTiersTest.cpp)
112113
add_test (tests/MultiAllocatorTest.cpp)
113114
add_test (tests/NvmAdmissionPolicyTest.cpp)
114115
add_test (nvmcache/tests/NvmItemTests.cpp)

cachelib/allocator/CacheAllocatorConfig.h

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <string>
2626

2727
#include "cachelib/allocator/Cache.h"
28+
#include "cachelib/allocator/MemoryTierCacheConfig.h"
2829
#include "cachelib/allocator/MM2Q.h"
2930
#include "cachelib/allocator/MemoryMonitor.h"
3031
#include "cachelib/allocator/NvmAdmissionPolicy.h"
@@ -49,6 +50,7 @@ class CacheAllocatorConfig {
4950
using NvmCacheDeviceEncryptor = typename CacheT::NvmCacheT::DeviceEncryptor;
5051
using MoveCb = typename CacheT::MoveCb;
5152
using NvmCacheConfig = typename CacheT::NvmCacheT::Config;
53+
using MemoryTierConfigs = std::vector<MemoryTierCacheConfig>;
5254
using Key = typename CacheT::Key;
5355
using EventTrackerSharedPtr = std::shared_ptr<typename CacheT::EventTracker>;
5456
using Item = typename CacheT::Item;
@@ -186,14 +188,23 @@ class CacheAllocatorConfig {
186188
// This allows cache to be persisted across restarts. One example use case is
187189
// to preserve the cache when releasing a new version of your service. Refer
188190
// to our user guide for how to set up cache persistence.
191+
// TODO: get rid of baseAddr or if set make sure all mapping are adjacent?
192+
// We can also make baseAddr a per-tier configuration
189193
CacheAllocatorConfig& enableCachePersistence(std::string directory,
190194
void* baseAddr = nullptr);
191195

192-
// uses posix shm segments instead of the default sys-v shm segments.
193-
// @throw std::invalid_argument if called without enabling
194-
// cachePersistence()
196+
// Uses posix shm segments instead of the default sys-v shm
197+
// segments. @throw std::invalid_argument if called without enabling
198+
// cachePersistence().
195199
CacheAllocatorConfig& usePosixForShm();
196200

201+
// Configures cache memory tiers. Accepts vector of MemoryTierCacheConfig.
202+
// Each vector element describes configuration for a single memory cache tier.
203+
CacheAllocatorConfig& configureMemoryTiers(const MemoryTierConfigs& configs);
204+
205+
// Return reference to MemoryTierCacheConfigs.
206+
const MemoryTierConfigs& getMemoryTierConfigs();
207+
197208
// This turns on a background worker that periodically scans through the
198209
// access container and look for expired items and remove them.
199210
CacheAllocatorConfig& enableItemReaperInBackground(
@@ -541,6 +552,9 @@ class CacheAllocatorConfig {
541552
// cache.
542553
uint64_t nvmAdmissionMinTTL{0};
543554

555+
// Configuration for memory tiers.
556+
MemoryTierConfigs memoryTierConfigs;
557+
544558
friend CacheT;
545559

546560
private:
@@ -801,6 +815,74 @@ CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::enableItemReaperInBackground(
801815
return *this;
802816
}
803817

818+
template <typename T>
819+
CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::configureMemoryTiers(
820+
const MemoryTierConfigs& config) {
821+
memoryTierConfigs = config;
822+
size_t sum_ratios = 0;
823+
size_t sum_sizes = 0;
824+
825+
for (auto tier_config: memoryTierConfigs) {
826+
auto tier_size = tier_config.getSize();
827+
auto tier_ratio = tier_config.getRatio();
828+
if ((!tier_size and !tier_ratio) || (tier_size and tier_ratio)) {
829+
throw std::invalid_argument(
830+
"For each memory tier either size or ratio must be set.");
831+
}
832+
sum_ratios += tier_ratio;
833+
sum_sizes += tier_size;
834+
}
835+
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+
}
872+
873+
if (sum_sizes && !getCacheSize()) {
874+
setCacheSize(sum_sizes);
875+
}
876+
877+
return *this;
878+
}
879+
880+
//const std::vector<MemoryTierCacheConfig>& CacheAllocatorConfig<T>::getMemoryTierConfigs() {
881+
template <typename T>
882+
const typename CacheAllocatorConfig<T>::MemoryTierConfigs& CacheAllocatorConfig<T>::getMemoryTierConfigs() {
883+
return memoryTierConfigs;
884+
}
885+
804886
template <typename T>
805887
CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::disableCacheEviction() {
806888
disableEviction = true;
@@ -970,7 +1052,7 @@ std::map<std::string, std::string> CacheAllocatorConfig<T>::serialize() const {
9701052

9711053
configMap["size"] = std::to_string(size);
9721054
configMap["cacheDir"] = cacheDir;
973-
configMap["posixShm"] = usePosixShm ? "set" : "empty";
1055+
configMap["posixShm"] = isUsingPosixShm() ? "set" : "empty";
9741056

9751057
configMap["defaultAllocSizes"] = "";
9761058
// Stringify std::set
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
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+
#pragma once
18+
19+
#include <string>
20+
21+
namespace facebook {
22+
namespace cachelib {
23+
class MemoryTierCacheConfig {
24+
public:
25+
// Creates instance of MemoryTierCacheConfig for file-backed memory.
26+
// @param path to file which CacheLib will use to map memory from.
27+
// TODO: add fromDirectory, fromAnonymousMemory
28+
static MemoryTierCacheConfig fromFile(const std::string& _file) {
29+
MemoryTierCacheConfig config;
30+
config.path = _file;
31+
return config;
32+
}
33+
34+
// Specifies size of this memory tier. Sizes of tiers must be specified by
35+
// either setting size explicitly or using ratio, mixing of the two is not supported.
36+
MemoryTierCacheConfig& setSize(size_t _size) {
37+
size = _size;
38+
return *this;
39+
}
40+
41+
// Specifies ratio of this memory tier to other tiers. Absolute size
42+
// of each tier can be calculated as:
43+
// cacheSize * tierRatio / Sum of ratios for all tiers; the difference
44+
// between total cache size and sum of all tier sizes resulted from
45+
// round off error is accounted for when calculating the last tier's
46+
// size to make the totals equal.
47+
MemoryTierCacheConfig& setRatio(double _ratio) {
48+
ratio = _ratio;
49+
return *this;
50+
}
51+
52+
size_t getRatio() const noexcept { return ratio; }
53+
54+
size_t getSize() const noexcept { return size; }
55+
56+
const std::string& getPath() const noexcept { return path; }
57+
58+
bool isFileBacked() const {
59+
return !path.empty();
60+
}
61+
62+
// Size of this memory tiers
63+
size_t size{0};
64+
65+
// Ratio is a number of parts of the total cache size to be allocated for this tier.
66+
// E.g. if X is a total cache size, Yi are ratios specified for memory tiers,
67+
// then size of the i-th tier Xi = (X / (Y1 + Y2)) * Yi and X = sum(Xi)
68+
size_t ratio{0};
69+
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;
74+
75+
private:
76+
MemoryTierCacheConfig() = default;
77+
};
78+
} // namespace cachelib
79+
} // namespace facebook

0 commit comments

Comments
 (0)