Skip to content

Commit 9a73b21

Browse files
committed
Extend cachebench to bind memory tiers to NUMA nodes
1 parent f94c1e3 commit 9a73b21

File tree

4 files changed

+137
-1
lines changed

4 files changed

+137
-1
lines changed

cachelib/cachebench/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,6 @@ if (BUILD_TESTS)
8989
add_test (consistency/tests/ValueHistoryTest.cpp)
9090
add_test (consistency/tests/ValueTrackerTest.cpp)
9191
add_test (util/tests/NandWritesTest.cpp)
92+
add_test (util/tests/MemoryTierConfigTest)
9293
add_test (cache/tests/TimeStampTickerTest.cpp)
9394
endif()

cachelib/cachebench/util/CacheConfig.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,53 @@ std::shared_ptr<RebalanceStrategy> CacheConfig::getRebalanceStrategy() const {
138138
MemoryTierConfig::MemoryTierConfig(const folly::dynamic& configJson) {
139139
JSONSetVal(configJson, file);
140140
JSONSetVal(configJson, ratio);
141+
JSONSetVal(configJson, memBindNodes);
141142

142-
checkCorrectSize<MemoryTierConfig, 40>();
143+
checkCorrectSize<MemoryTierConfig, 72>();
144+
}
145+
146+
static bool starts_with() {return true;}
147+
148+
std::vector<size_t> MemoryTierConfig::parseNumaNodes() {
149+
std::vector<size_t> numaNodes;
150+
151+
std::vector<folly::StringPiece> tokens;
152+
folly::split(",", memBindNodes, tokens, true /*ignore empty*/);
153+
for(const auto &token : tokens) {
154+
if(token.startsWith("!")) {
155+
throw std::invalid_argument(folly::sformat(
156+
"invalid NUMA nodes binding in memory tier config: {} "
157+
"inverse !N or !N-N is not supported "
158+
"nodes may be specified as N,N,N or N-N or N,N-N or N-N,N-N and so forth.",
159+
token));
160+
}
161+
else if(token.startsWith("+")) {
162+
throw std::invalid_argument(folly::sformat(
163+
"invalid NUMA nodes binding in memory tier config: {} "
164+
"relative nodes are not supported. "
165+
"nodes may be specified as N,N,N or N-N or N,N-N or N-N,N-N and so forth.",
166+
token));
167+
}
168+
else if (token.contains("-")) {
169+
size_t begin, end;
170+
if(folly::split("-", token, begin, end) && begin < end) {
171+
while(begin <=end) {
172+
numaNodes.push_back(begin++);
173+
}
174+
} else {
175+
throw std::invalid_argument(folly::sformat(
176+
"invalid NUMA nodes binding in memory tier config: {} "
177+
"Invalid range format. "
178+
"nodes may be specified as N,N,N or N-N or N,N-N or N-N,N-N and so forth.",
179+
token));
180+
}
181+
}
182+
else {
183+
numaNodes.push_back(folly::to<size_t>(token));
184+
}
185+
}
186+
187+
return numaNodes;
143188
}
144189

145190
} // namespace cachebench

cachelib/cachebench/util/CacheConfig.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ struct MemoryTierConfig : public JSONConfig {
4848
MemoryTierCacheConfig getMemoryTierCacheConfig() {
4949
MemoryTierCacheConfig config = memoryTierCacheConfigFromSource();
5050
config.setRatio(ratio);
51+
config.setMemBind(parseNumaNodes());
5152
return config;
5253
}
5354

5455
std::string file{""};
5556
size_t ratio{0};
57+
std::string memBindNodes{""};
5658

5759
private:
5860
MemoryTierCacheConfig memoryTierCacheConfigFromSource() {
@@ -62,6 +64,8 @@ struct MemoryTierConfig : public JSONConfig {
6264
return MemoryTierCacheConfig::fromFile(file);
6365
}
6466
}
67+
68+
std::vector<size_t> parseNumaNodes();
6569
};
6670

6771
struct CacheConfig : public JSONConfig {
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
// Copyright 2022-present Facebook. All Rights Reserved.
18+
19+
#include <algorithm>
20+
21+
#include <gmock/gmock.h>
22+
#include <gtest/gtest.h>
23+
24+
#include "cachelib/cachebench/util/CacheConfig.h"
25+
26+
namespace facebook {
27+
namespace cachelib {
28+
namespace cachebench {
29+
30+
TEST(MemoryTierConfigTest, MemBind_SingleNumaNode) {
31+
const std::string configString =
32+
"{"
33+
" \"ratio\": 1,"
34+
" \"memBindNodes\": 1"
35+
"}";
36+
37+
const std::vector<size_t> expectedNumaNodes = {1};
38+
39+
auto configJson = folly::parseJson(folly::json::stripComments(configString));
40+
41+
MemoryTierConfig memoryTierConfig(configJson);
42+
MemoryTierCacheConfig tierCacheConfig = memoryTierConfig.getMemoryTierCacheConfig();
43+
44+
auto parsedNumaNodes = tierCacheConfig.getMemBind();
45+
ASSERT_TRUE(std::equal(expectedNumaNodes.begin(), expectedNumaNodes.end(), parsedNumaNodes.begin()));
46+
}
47+
48+
TEST(MemoryTierConfigTest, MemBind_RangeNumaNodes) {
49+
const std::string configString =
50+
"{"
51+
" \"ratio\": 1,"
52+
" \"memBindNodes\": \"0-2\""
53+
"}";
54+
55+
const std::vector<size_t> expectedNumaNodes = {0, 1, 2};
56+
57+
auto configJson = folly::parseJson(folly::json::stripComments(configString));
58+
59+
MemoryTierConfig memoryTierConfig(configJson);
60+
MemoryTierCacheConfig tierCacheConfig = memoryTierConfig.getMemoryTierCacheConfig();
61+
62+
auto parsedNumaNodes = tierCacheConfig.getMemBind();
63+
ASSERT_TRUE(std::equal(expectedNumaNodes.begin(), expectedNumaNodes.end(), parsedNumaNodes.begin()));
64+
}
65+
66+
TEST(MemoryTierConfigTest, MemBind_SingleAndRangeNumaNodes) {
67+
const std::string configString =
68+
"{"
69+
" \"ratio\": 1,"
70+
" \"memBindNodes\": \"0,2-5\""
71+
"}";
72+
73+
const std::vector<size_t> expectedNumaNodes = {0, 2, 3, 4, 5};
74+
75+
auto configJson = folly::parseJson(folly::json::stripComments(configString));
76+
77+
MemoryTierConfig memoryTierConfig(configJson);
78+
MemoryTierCacheConfig tierCacheConfig = memoryTierConfig.getMemoryTierCacheConfig();
79+
80+
auto parsedNumaNodes = tierCacheConfig.getMemBind();
81+
ASSERT_TRUE(std::equal(expectedNumaNodes.begin(), expectedNumaNodes.end(), parsedNumaNodes.begin()));
82+
}
83+
84+
} // namespace facebook
85+
} // namespace cachelib
86+
} // namespace cachebench

0 commit comments

Comments
 (0)