proxygen
JemallocHugePageAllocatorTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016-present Facebook, Inc.
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 
18 #include <folly/container/F14Map.h>
19 
20 #include <folly/memory/Malloc.h>
22 
23 #include <vector>
24 
26 
27 static constexpr int kb(int kilos) {
28  return kilos * 1024;
29 }
30 
31 static constexpr int mb(int megs) {
32  return kb(megs * 1024);
33 }
34 
35 TEST(JemallocHugePageAllocatorTest, Basic) {
37 
38  // Allocation should work even if uninitialized
39  auto ptr = jha::allocate(kb(1));
40  EXPECT_NE(nullptr, ptr);
42 
43  bool initialized = jha::init(1);
44  if (initialized) {
46  }
47 
48  ptr = jha::allocate(kb(1));
49  EXPECT_NE(nullptr, ptr);
50 
51  if (initialized) {
53  }
54 
55  // Allocate some arrays on huge page
56  auto array_of_arrays = new (ptr) std::array<int, 100>[5];
57 
58  if (initialized) {
59  EXPECT_FALSE(jha::addressInArena(&array_of_arrays));
60  EXPECT_TRUE(jha::addressInArena(&array_of_arrays[0]));
61  EXPECT_TRUE(jha::addressInArena(&array_of_arrays[0][0]));
62  }
63 
65 }
66 
67 TEST(JemallocHugePageAllocatorTest, LargeAllocations) {
68  // Allocate before init - will not use huge pages
69  void* ptr0 = jha::allocate(kb(1));
70 
71  // One 2MB huge page
72  bool initialized = jha::init(1);
73  if (initialized) {
75  }
76 
77  // This fits
78  void* ptr1 = jha::allocate(mb(1) + kb(512));
79  EXPECT_NE(nullptr, ptr1);
80 
81  if (initialized) {
83  }
84 
85  // This is too large to fit
86  void* ptr2 = jha::allocate(mb(1));
87  EXPECT_NE(nullptr, ptr2);
88 
90 
91  // Free and reuse huge page area
92  jha::deallocate(ptr2);
93  jha::deallocate(ptr0);
94  ptr2 = jha::allocate(mb(1));
95 
96  // No memory in the huge page arena was freed - ptr0 was allocated
97  // before init and ptr2 didn't fit
99 
100  jha::deallocate(ptr1);
101  void* ptr3 = jha::allocate(mb(1) + kb(512));
102  EXPECT_NE(nullptr, ptr3);
103 
104  if (initialized) {
105  EXPECT_EQ(ptr1, ptr3);
107  }
108 
109  // Just using free works equally well
110  free(ptr3);
111  ptr3 = jha::allocate(mb(1) + kb(512));
112  EXPECT_NE(nullptr, ptr3);
113 
114  if (initialized) {
116  }
117 
118  jha::deallocate(ptr2);
119  jha::deallocate(ptr3);
120 }
121 
122 TEST(JemallocHugePageAllocatorTest, MemoryUsageTest) {
123  bool initialized = jha::init(80);
124  if (initialized) {
125  EXPECT_GE(jha::freeSpace(), mb(160));
126  }
127 
128  struct c32 {
129  char val[32];
130  };
131  using Vec32 = std::vector<c32, folly::CxxHugePageAllocator<c32>>;
132  Vec32 vec32;
133  for (int i = 0; i < 10; i++) {
134  vec32.push_back({});
135  }
136  void* ptr1 = jha::allocate(32);
137  if (initialized) {
138  EXPECT_GE(jha::freeSpace(), mb(158));
139  }
140  struct c320 {
141  char val[320];
142  };
143  using Vec320 = std::vector<c320, folly::CxxHugePageAllocator<c320>>;
144  Vec320 vec320;
145  for (int i = 0; i < 10; i++) {
146  vec320.push_back({});
147  }
148  void* ptr2 = jha::allocate(320);
149  if (initialized) {
150  EXPECT_GE(jha::freeSpace(), mb(158));
151  }
152 
153  // Helper to ensure all allocations are freed at the end
154  auto deleter = [](void* data) { jha::deallocate(data); };
155  std::vector<std::unique_ptr<void, decltype(deleter)>> ptr_vec;
156  auto alloc = [&ptr_vec, &deleter](size_t size) {
157  ptr_vec.emplace_back(jha::allocate(size), deleter);
158  };
159 
160  for (int i = 0; i < 10; i++) {
161  alloc(kb(1));
162  }
163  void* ptr3 = jha::allocate(kb(1));
164  if (initialized) {
165  EXPECT_GE(jha::freeSpace(), mb(158));
166  }
167  for (int i = 0; i < 10; i++) {
168  alloc(kb(4));
169  }
170  void* ptr4 = jha::allocate(kb(4));
171  if (initialized) {
172  EXPECT_GE(jha::freeSpace(), mb(158));
173  }
174  for (int i = 0; i < 10; i++) {
175  alloc(kb(10));
176  }
177  void* ptr5 = jha::allocate(kb(10));
178  if (initialized) {
179  EXPECT_GE(jha::freeSpace(), mb(158));
180  }
181  alloc(kb(512));
182  alloc(mb(1));
183  void* ptr6 = jha::allocate(mb(1));
184  if (initialized) {
185  EXPECT_GE(jha::freeSpace(), mb(156));
186  }
187  alloc(mb(2));
188  alloc(mb(4));
189  void* ptr7 = jha::allocate(mb(4));
190  if (initialized) {
191  EXPECT_GE(jha::freeSpace(), mb(146));
192  }
193  alloc(kb(512));
194  alloc(kb(512));
195  if (initialized) {
196  EXPECT_GE(jha::freeSpace(), 145);
197  }
198  void* ptr8 = jha::allocate(mb(64));
199  if (initialized) {
200  EXPECT_GE(jha::freeSpace(), mb(80));
201  }
202  alloc(mb(64));
203  if (initialized) {
204  EXPECT_GE(jha::freeSpace(), mb(16));
205  }
206  alloc(mb(256));
207  alloc(mb(256));
208  alloc(mb(256));
209 
210  // Now free a bunch of objects and then reallocate
211  // the same size objects again.
212  // This should not result in usage of free space.
213  size_t free = jha::freeSpace();
214  jha::deallocate(ptr1);
215  jha::deallocate(ptr2);
216  jha::deallocate(ptr3);
217  jha::deallocate(ptr4);
218  jha::deallocate(ptr5);
219  jha::deallocate(ptr6);
220  jha::deallocate(ptr7);
221  jha::deallocate(ptr8);
222  alloc(32);
223  alloc(320);
224  alloc(kb(1));
225  alloc(kb(4));
226  alloc(kb(10));
227  alloc(mb(1));
228  alloc(mb(4));
229  alloc(mb(64));
230 
231  if (initialized) {
232  EXPECT_EQ(free, jha::freeSpace());
233  }
234 }
235 
236 TEST(JemallocHugePageAllocatorTest, STLAllocator) {
237  using MyVecAllocator = folly::CxxHugePageAllocator<int>;
238  using MyVec = std::vector<int, MyVecAllocator>;
239 
240  using MyMapAllocator =
242  using MyMap = folly::F14FastMap<
243  int,
244  MyVec,
247  MyMapAllocator>;
248 
249  MyVec vec;
250  // This should work, just won't get huge pages since
251  // init hasn't been called yet
252  vec.reserve(100);
253  EXPECT_NE(nullptr, &vec[0]);
254 
255  // Reserve & initialize, not on huge pages
256  MyVec vec2(100);
257  EXPECT_NE(nullptr, &vec[0]);
258 
259  // F14 maps need quite a lot of memory by default
260  bool initialized = jha::init(4);
261  if (initialized) {
263  }
264 
265  // Reallocate, this time on huge pages
266  vec.reserve(200);
267  EXPECT_NE(nullptr, &vec[0]);
268 
269  MyMap map1;
270  map1[0] = {1, 2, 3};
271  auto map2_ptr = std::make_unique<MyMap>();
272  MyMap& map2 = *map2_ptr;
273  map2[0] = {1, 2, 3};
274 
275  if (initialized) {
277  EXPECT_TRUE(jha::addressInArena(&map1[0]));
278  EXPECT_TRUE(jha::addressInArena(&map1[0][0]));
279  EXPECT_TRUE(jha::addressInArena(&map2[0]));
280  EXPECT_TRUE(jha::addressInArena(&map2[0][0]));
281  }
282 
283  // This will be on the huge page arena
284  map1[0] = std::move(vec);
285 
286  // But not this, since vec2 content was allocated before init
287  map1[1] = std::move(vec2);
288 
289  if (initialized) {
290  EXPECT_TRUE(jha::addressInArena(&map1[0]));
291  EXPECT_TRUE(jha::addressInArena(&map1[1]));
292  EXPECT_TRUE(jha::addressInArena(&map1[0][0]));
293  EXPECT_FALSE(jha::addressInArena(&map1[1][0]));
294  }
295 
296  // realloc on huge pages
297  map1[1].reserve(200);
298 
299  if (initialized) {
300  EXPECT_TRUE(jha::addressInArena(&map1[1][0]));
301  }
302 }
void * ptr
TEST(JemallocHugePageAllocatorTest, Basic)
static constexpr int kb(int kilos)
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
double val
Definition: String.cpp:273
#define EXPECT_GE(val1, val2)
Definition: gtest.h:1932
static void deallocate(void *p, size_t=0)
constexpr auto size(C const &c) -> decltype(c.size())
Definition: Access.h:45
void free()
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
static constexpr int mb(int megs)
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
vector< string > vec
Definition: StringTest.cpp:35
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
static constexpr uint64_t data[1]
Definition: Fingerprint.cpp:43