Skip to content

Commit b0e2574

Browse files
committed
Extend cachebench to bind memory tiers to NUMA nodes
1 parent d4ff258 commit b0e2574

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.cpp)
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
@@ -137,8 +137,53 @@ std::shared_ptr<RebalanceStrategy> CacheConfig::getRebalanceStrategy() const {
137137
MemoryTierConfig::MemoryTierConfig(const folly::dynamic& configJson) {
138138
JSONSetVal(configJson, file);
139139
JSONSetVal(configJson, ratio);
140+
JSONSetVal(configJson, memBindNodes);
140141

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

144189
} // 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)