Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cachelib/allocator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ if (BUILD_TESTS)
add_test (tests/AllocatorHitStatsTypeTest.cpp)
add_test (tests/MultiAllocatorTest.cpp)
add_test (tests/NvmAdmissionPolicyTest.cpp)
add_test (tests/CacheAllocatorConfigTest.cpp)
add_test (nvmcache/tests/NvmItemTests.cpp)
add_test (nvmcache/tests/InFlightPutsTest.cpp)
add_test (nvmcache/tests/TombStoneTests.cpp)
Expand Down
68 changes: 66 additions & 2 deletions cachelib/allocator/CacheAllocatorConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "cachelib/allocator/Cache.h"
#include "cachelib/allocator/MM2Q.h"
#include "cachelib/allocator/MemoryMonitor.h"
#include "cachelib/allocator/MemoryTierCacheConfig.h"
#include "cachelib/allocator/NvmAdmissionPolicy.h"
#include "cachelib/allocator/PoolOptimizeStrategy.h"
#include "cachelib/allocator/RebalanceStrategy.h"
Expand All @@ -50,6 +51,7 @@ class CacheAllocatorConfig {
using NvmCacheDeviceEncryptor = typename CacheT::NvmCacheT::DeviceEncryptor;
using MoveCb = typename CacheT::MoveCb;
using NvmCacheConfig = typename CacheT::NvmCacheT::Config;
using MemoryTierConfigs = std::vector<MemoryTierCacheConfig>;
using Key = typename CacheT::Key;
using EventTrackerSharedPtr = std::shared_ptr<typename CacheT::EventTracker>;
using Item = typename CacheT::Item;
Expand Down Expand Up @@ -199,6 +201,16 @@ class CacheAllocatorConfig {
// cachePersistence()
CacheAllocatorConfig& usePosixForShm();

// Configures cache memory tiers. Each tier represents a cache region inside
// byte-addressable memory such as DRAM, Pmem, CXLmem.
// Accepts vector of MemoryTierCacheConfig. Each vector element describes
// configuration for a single memory cache tier. Tier sizes are specified as
// ratios, the number of parts of total cache size each tier would occupy.
CacheAllocatorConfig& configureMemoryTiers(const MemoryTierConfigs& configs);

// Return reference to MemoryTierCacheConfigs.
const MemoryTierConfigs& getMemoryTierConfigs();

// This turns on a background worker that periodically scans through the
// access container and look for expired items and remove them.
CacheAllocatorConfig& enableItemReaperInBackground(
Expand Down Expand Up @@ -362,15 +374,22 @@ class CacheAllocatorConfig {
bool validateStrategy(
const std::shared_ptr<PoolOptimizeStrategy>& strategy) const;

// check that memory tier ratios are set properly
const CacheAllocatorConfig& validateMemoryTiers() const;

// @return a map representation of the configs
std::map<std::string, std::string> serialize() const;

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

// Amount of memory for this cache instance
// Amount of memory for this cache instance (sum of all memory tiers' sizes)
size_t size = 1 * 1024 * 1024 * 1024;

// The max number of memory cache tiers
// TODO: increase this number when multi-tier configs are enabled
const size_t maxCacheMemoryTiers = 1;

// Directory for shared memory related metadata
std::string cacheDir;

Expand Down Expand Up @@ -575,6 +594,10 @@ class CacheAllocatorConfig {
friend CacheT;

private:
// Configuration for memory tiers.
MemoryTierConfigs memoryTierConfigs{
{MemoryTierCacheConfig::fromShm().setRatio(1)}};

void mergeWithPrefix(
std::map<std::string, std::string>& configMap,
const std::map<std::string, std::string>& configMapToMerge,
Expand Down Expand Up @@ -844,6 +867,28 @@ CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::enableItemReaperInBackground(
return *this;
}

template <typename T>
CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::configureMemoryTiers(
const MemoryTierConfigs& config) {
if (config.size() > maxCacheMemoryTiers) {
throw std::invalid_argument(folly::sformat(
"Too many memory tiers. The number of supported tiers is {}.",
maxCacheMemoryTiers));
}
if (!config.size()) {
throw std::invalid_argument(
"There must be at least one memory tier config.");
}
memoryTierConfigs = config;
return *this;
}

template <typename T>
const typename CacheAllocatorConfig<T>::MemoryTierConfigs&
CacheAllocatorConfig<T>::getMemoryTierConfigs() {
return memoryTierConfigs;
}

template <typename T>
CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::disableCacheEviction() {
disableEviction = true;
Expand Down Expand Up @@ -1001,7 +1046,8 @@ const CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::validate() const {
throw std::invalid_argument(
"It's not allowed to enable both RemoveCB and ItemDestructor.");
}
return *this;

return validateMemoryTiers();
}

template <typename T>
Expand All @@ -1028,6 +1074,24 @@ bool CacheAllocatorConfig<T>::validateStrategy(
(type != PoolOptimizeStrategy::MarginalHits || trackTailHits);
}

template <typename T>
const CacheAllocatorConfig<T>& CacheAllocatorConfig<T>::validateMemoryTiers()
const {
size_t parts = 0;
for (const auto& tierConfig : memoryTierConfigs) {
if (!tierConfig.getRatio()) {
throw std::invalid_argument("Tier ratio must be an integer number >=1.");
}
parts += tierConfig.getRatio();
}

if (parts > size) {
throw std::invalid_argument(
"Sum of tier ratios must be less than total cache size.");
}
return *this;
}

template <typename T>
std::map<std::string, std::string> CacheAllocatorConfig<T>::serialize() const {
std::map<std::string, std::string> configMap;
Expand Down
76 changes: 76 additions & 0 deletions cachelib/allocator/MemoryTierCacheConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Copyright (c) Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <string>

#include "cachelib/shm/ShmCommon.h"

namespace facebook {
namespace cachelib {
class MemoryTierCacheConfig {
public:
// Creates instance of MemoryTierCacheConfig for Posix/SysV Shared memory.
static MemoryTierCacheConfig fromShm() {
// TODO: expand this method when adding support for file-mapped memory
return MemoryTierCacheConfig();
}

// Specifies ratio of this memory tier to other tiers. Absolute size
// of each tier can be calculated as:
// cacheSize * tierRatio / Sum of ratios for all tiers.
MemoryTierCacheConfig& setRatio(size_t _ratio) {
if (!_ratio) {
throw std::invalid_argument("Tier ratio must be an integer number >=1.");
}
ratio = _ratio;
return *this;
}

size_t getRatio() const noexcept { return ratio; }

size_t calculateTierSize(size_t totalCacheSize, size_t partitionNum) {
// TODO: Call this method when tiers are enabled in allocator
// to calculate tier sizes in bytes.
if (!partitionNum) {
throw std::invalid_argument(
"The total number of tier ratios must be an integer number >=1.");
}

size_t partitionSize = 0;
if (partitionNum > totalCacheSize) {
throw std::invalid_argument(
"Ratio must be less or equal to total cache size.");
}

return getRatio() * (totalCacheSize / partitionNum);
}

// Ratio is a number of parts of the total cache size to be allocated for this
// tier. E.g. if X is a total cache size, Yi are ratios specified for memory
// tiers, and Y is the sum of all Yi, then size of the i-th tier
// Xi = (X / Y) * Yi. For examle, to configure 2-tier cache where each
// tier is a half of the total cache size, set both tiers' ratios to 1.
size_t ratio{1};

private:
// TODO: introduce a container for tier settings when adding support for
// file-mapped memory
MemoryTierCacheConfig() = default;
};
} // namespace cachelib
} // namespace facebook
72 changes: 72 additions & 0 deletions cachelib/allocator/tests/CacheAllocatorConfigTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "cachelib/allocator/CacheAllocatorConfig.h"
#include "cachelib/allocator/MemoryTierCacheConfig.h"
#include "cachelib/allocator/tests/TestBase.h"

namespace facebook {
namespace cachelib {

namespace tests {

using AllocatorT = LruAllocator;
using MemoryTierConfigs = CacheAllocatorConfig<AllocatorT>::MemoryTierConfigs;

size_t defaultTotalSize = 1 * 1024LL * 1024LL * 1024LL;

class CacheAllocatorConfigTest : public testing::Test {};

MemoryTierConfigs generateTierConfigs(size_t numTiers,
MemoryTierCacheConfig& config) {
return MemoryTierConfigs(numTiers, config);
}

TEST_F(CacheAllocatorConfigTest, MultipleTier0Config) {
AllocatorT::Config config;
// Throws if vector of tier configs is emptry
EXPECT_THROW(config.configureMemoryTiers(MemoryTierConfigs()),
std::invalid_argument);
}

TEST_F(CacheAllocatorConfigTest, MultipleTier1Config) {
AllocatorT::Config config;
// Accepts single-tier configuration
config.setCacheSize(defaultTotalSize)
.configureMemoryTiers({MemoryTierCacheConfig::fromShm().setRatio(1)});
config.validateMemoryTiers();
}

TEST_F(CacheAllocatorConfigTest, InvalidTierRatios) {
AllocatorT::Config config;
EXPECT_THROW(config.configureMemoryTiers(generateTierConfigs(
config.maxCacheMemoryTiers + 1,
MemoryTierCacheConfig::fromShm().setRatio(0))),
std::invalid_argument);
}

TEST_F(CacheAllocatorConfigTest, TotalCacheSizeLessThanRatios) {
AllocatorT::Config config;
// Throws if total cache size is set to 0
config.setCacheSize(defaultTotalSize)
.configureMemoryTiers(
{MemoryTierCacheConfig::fromShm().setRatio(defaultTotalSize + 1)});
EXPECT_THROW(config.validate(), std::invalid_argument);
}

} // namespace tests
} // namespace cachelib
} // namespace facebook