proxygen
MemoryTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2013-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 
17 #include <folly/Memory.h>
18 
19 #include <limits>
20 #include <memory>
21 #include <type_traits>
22 #include <utility>
23 
24 #include <glog/logging.h>
25 
26 #include <folly/ConstexprMath.h>
27 #include <folly/String.h>
28 #include <folly/memory/Arena.h>
31 
32 using namespace folly;
33 
34 static constexpr std::size_t kTooBig = folly::constexpr_max(
36  std::size_t{1} << (8 * sizeof(std::size_t) - 14));
37 
39  auto p = allocateBytes(10);
40  EXPECT_TRUE(p != nullptr);
41  deallocateBytes(p, 10);
42 }
43 
44 TEST(aligned_malloc, examples) {
45  auto trial = [](size_t align) {
46  auto const ptr = aligned_malloc(1, align);
47  return (aligned_free(ptr), uintptr_t(ptr));
48  };
49 
50  if (!kIsSanitize) { // asan allocator raises SIGABRT instead
51  EXPECT_EQ(EINVAL, (trial(2), errno)) << "too small";
52  EXPECT_EQ(EINVAL, (trial(513), errno)) << "not power of two";
53  }
54 
55  EXPECT_EQ(0, trial(512) % 512);
56  EXPECT_EQ(0, trial(8192) % 8192);
57 }
58 
59 TEST(make_unique, compatible_with_std_make_unique) {
60  // HACK: To enforce that `folly::` is imported here.
61  to_shared_ptr(std::unique_ptr<std::string>());
62 
63  using namespace std;
64  make_unique<string>("hello, world");
65 }
66 
68  auto s = std::make_shared<int>(17);
69  EXPECT_EQ(1, s.use_count());
70  EXPECT_EQ(2, (to_weak_ptr(s).lock(), s.use_count())) << "lvalue";
71  EXPECT_EQ(3, (to_weak_ptr(decltype(s)(s)).lock(), s.use_count())) << "rvalue";
72 }
73 
75  using Alloc = SysAllocator<float>;
76  Alloc const a, b;
77  EXPECT_TRUE(a == b);
78  EXPECT_FALSE(a != b);
79 }
80 
82  using Alloc = SysAllocator<float>;
83  Alloc const alloc;
84  auto ptr = allocate_unique<float>(alloc, 3.);
85  EXPECT_EQ(3., *ptr);
86 }
87 
88 TEST(SysAllocator, vector) {
89  using Alloc = SysAllocator<float>;
90  Alloc const alloc;
91  std::vector<float, Alloc> nums(alloc);
92  nums.push_back(3.);
93  nums.push_back(5.);
94  EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
95 }
96 
97 TEST(SysAllocator, bad_alloc) {
98  using Alloc = SysAllocator<float>;
99  Alloc const alloc;
100  std::vector<float, Alloc> nums(alloc);
101  if (!kIsSanitize) {
102  EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
103  }
104 }
105 
106 TEST(AlignedSysAllocator, equality_fixed) {
108  Alloc const a, b;
109  EXPECT_TRUE(a == b);
110  EXPECT_FALSE(a != b);
111 }
112 
113 TEST(AlignedSysAllocator, allocate_unique_fixed) {
115  Alloc const alloc;
116  auto ptr = allocate_unique<float>(alloc, 3.);
117  EXPECT_EQ(3., *ptr);
118  EXPECT_EQ(0, std::uintptr_t(ptr.get()) % 1024);
119 }
120 
121 TEST(AlignedSysAllocator, vector_fixed) {
123  Alloc const alloc;
124  std::vector<float, Alloc> nums(alloc);
125  nums.push_back(3.);
126  nums.push_back(5.);
127  EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
128  EXPECT_EQ(0, std::uintptr_t(nums.data()) % 1024);
129 }
130 
131 TEST(AlignedSysAllocator, bad_alloc_fixed) {
133  Alloc const alloc;
134  std::vector<float, Alloc> nums(alloc);
135  if (!kIsSanitize) {
136  EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
137  }
138 }
139 
140 TEST(AlignedSysAllocator, equality_default) {
142  Alloc const a(1024), b(1024), c(512);
143  EXPECT_TRUE(a == b);
144  EXPECT_FALSE(a != b);
145  EXPECT_FALSE(a == c);
146  EXPECT_TRUE(a != c);
147 }
148 
149 TEST(AlignedSysAllocator, allocate_unique_default) {
151  Alloc const alloc(1024);
152  auto ptr = allocate_unique<float>(alloc, 3.);
153  EXPECT_EQ(3., *ptr);
154  EXPECT_EQ(0, std::uintptr_t(ptr.get()) % 1024);
155 }
156 
157 TEST(AlignedSysAllocator, vector_default) {
159  Alloc const alloc(1024);
160  std::vector<float, Alloc> nums(alloc);
161  nums.push_back(3.);
162  nums.push_back(5.);
163  EXPECT_THAT(nums, testing::ElementsAreArray({3., 5.}));
164  EXPECT_EQ(0, std::uintptr_t(nums.data()) % 1024);
165 }
166 
167 TEST(AlignedSysAllocator, bad_alloc_default) {
169  Alloc const alloc(1024);
170  std::vector<float, Alloc> nums(alloc);
171  if (!kIsSanitize) {
172  EXPECT_THROW(nums.reserve(kTooBig), std::bad_alloc);
173  }
174 }
175 
176 TEST(AlignedSysAllocator, converting_constructor) {
177  using Alloc1 = AlignedSysAllocator<float>;
178  using Alloc2 = AlignedSysAllocator<double>;
179  Alloc1 const alloc1(1024);
180  Alloc2 const alloc2(alloc1);
181 }
182 
184  auto buf = allocate_sys_buffer(256);
185  // Freed at the end of the scope.
186 }
187 
189  size_t deallocates = 0;
190 };
191 
192 template <typename T>
193 class CountedAllocator : public std::allocator<T> {
194  private:
196 
197  public:
199  : stats_(&stats) {}
200  void deallocate(T* p, size_t n) {
201  std::allocator<T>::deallocate(p, n);
202  ++stats_->deallocates;
203  }
204 };
205 
206 TEST(allocate_unique, ctor_failure) {
207  struct CtorThrows {
208  explicit CtorThrows(bool cond) {
209  if (cond) {
210  throw std::runtime_error("nope");
211  }
212  }
213  };
216  {
217  CountedAllocatorStats stats;
218  Alloc const alloc(stats);
219  EXPECT_EQ(0, stats.deallocates);
220  std::unique_ptr<CtorThrows, Deleter> ptr{nullptr, Deleter{alloc}};
221  ptr = allocate_unique<CtorThrows>(alloc, false);
222  EXPECT_NE(nullptr, ptr);
223  EXPECT_EQ(0, stats.deallocates);
224  ptr = nullptr;
225  EXPECT_EQ(nullptr, ptr);
226  EXPECT_EQ(1, stats.deallocates);
227  }
228  {
229  CountedAllocatorStats stats;
230  Alloc const alloc(stats);
231  EXPECT_EQ(0, stats.deallocates);
232  std::unique_ptr<CtorThrows, Deleter> ptr{nullptr, Deleter{alloc}};
233  EXPECT_THROW(
234  ptr = allocate_unique<CtorThrows>(alloc, true), std::runtime_error);
235  EXPECT_EQ(nullptr, ptr);
236  EXPECT_EQ(1, stats.deallocates);
237  }
238 }
239 
240 namespace {
241 template <typename T>
242 struct TestAlloc1 : SysAllocator<T> {
243  template <typename U, typename... Args>
244  void construct(U* p, Args&&... args) {
245  ::new (static_cast<void*>(p)) U(std::forward<Args>(args)...);
246  }
247 };
248 
249 template <typename T>
250 struct TestAlloc2 : TestAlloc1<T> {
251  template <typename U>
252  void destroy(U* p) {
253  p->~U();
254  }
255 };
256 
257 template <typename T>
258 struct TestAlloc3 : TestAlloc2<T> {
259  using folly_has_default_object_construct = std::true_type;
260 };
261 
262 template <typename T>
263 struct TestAlloc4 : TestAlloc3<T> {
264  using folly_has_default_object_destroy = std::true_type;
265 };
266 
267 template <typename T>
268 struct TestAlloc5 : SysAllocator<T> {
269  using folly_has_default_object_construct = std::true_type;
270  using folly_has_default_object_destroy = std::false_type;
271 };
272 } // namespace
273 
274 TEST(AllocatorObjectLifecycleTraits, compiles) {
275  using A = std::allocator<int>;
276  using S = std::string;
277 
278  static_assert(
281 
284 
285  static_assert(
288  int,
289  int>::value,
290  "");
291  static_assert(
294  S,
295  S>::value,
296  "");
297 
298  static_assert(
301  int>::value,
302  "");
303  static_assert(
306  S>::value,
307  "");
308 
309  static_assert(
311  "");
312  static_assert(
313  folly::AllocatorHasDefaultObjectDestroy<TestAlloc1<S>, S>::value, "");
314 
315  static_assert(
317  "");
318  static_assert(
319  !folly::AllocatorHasDefaultObjectDestroy<TestAlloc2<S>, S>::value, "");
320 
321  static_assert(
323  "");
324  static_assert(
325  !folly::AllocatorHasDefaultObjectDestroy<TestAlloc3<S>, S>::value, "");
326 
327  static_assert(
329  "");
330  static_assert(
331  folly::AllocatorHasDefaultObjectDestroy<TestAlloc4<S>, S>::value, "");
332 
333  static_assert(
335  "");
336  static_assert(
337  !folly::AllocatorHasDefaultObjectDestroy<TestAlloc5<S>, S>::value, "");
338 }
339 
340 template <typename T>
342  using value_type = T;
343 
344  ExpectingAlloc(std::size_t expectedSize, std::size_t expectedCount)
345  : expectedSize_{expectedSize}, expectedCount_{expectedCount} {}
346 
347  template <class U>
349  : expectedSize_{other.expectedSize_},
350  expectedCount_{other.expectedCount_} {}
351 
352  T* allocate(std::size_t n) {
353  EXPECT_EQ(expectedSize_, sizeof(T));
354  EXPECT_EQ(expectedSize_, alignof(T));
355  EXPECT_EQ(expectedCount_, n);
356  return std::allocator<T>{}.allocate(n);
357  }
358 
359  void deallocate(T* p, std::size_t n) {
360  std::allocator<T>{}.deallocate(p, n);
361  }
362 
363  std::size_t expectedSize_;
364  std::size_t expectedCount_;
365 };
366 
367 struct alignas(64) OverAlignedType {
368  std::array<char, 64> raw_;
369 };
370 
371 TEST(allocateOverAligned, notActuallyOver) {
372  // allocates 6 bytes with alignment 4, should get turned into an
373  // allocation of 2 elements of something of size and alignment 4
374  ExpectingAlloc<char> a(4, 2);
375  auto p = folly::allocateOverAligned<decltype(a), 4>(a, 6);
376  EXPECT_EQ((reinterpret_cast<uintptr_t>(p) % 4), 0);
377  folly::deallocateOverAligned<decltype(a), 4>(a, p, 6);
378  EXPECT_EQ((folly::allocationBytesForOverAligned<decltype(a), 4>(6)), 8);
379 }
380 
381 TEST(allocateOverAligned, manualOverStdAlloc) {
382  // allocates 6 bytes with alignment 64 using std::allocator, which will
383  // result in a call to aligned_malloc underneath. We free one directly
384  // to check that this is not the padding path
385  std::allocator<short> a;
386  auto p = folly::allocateOverAligned<decltype(a), 64>(a, 3);
387  auto p2 = folly::allocateOverAligned<decltype(a), 64>(a, 3);
388  EXPECT_EQ((reinterpret_cast<uintptr_t>(p) % 64), 0);
389  folly::deallocateOverAligned<decltype(a), 64>(a, p, 3);
390  aligned_free(p2);
391  EXPECT_EQ((folly::allocationBytesForOverAligned<decltype(a), 64>(3)), 6);
392 }
393 
394 TEST(allocateOverAligned, manualOverCustomAlloc) {
395  // allocates 6 byte with alignment 64 using non-standard allocator, which
396  // will result in an allocation of 64 + alignof(max_align_t) underneath.
398  alignof(folly::max_align_t), 64 / alignof(folly::max_align_t) + 1);
399  auto p = folly::allocateOverAligned<decltype(a), 64>(a, 3);
400  EXPECT_EQ((reinterpret_cast<uintptr_t>(p) % 64), 0);
401  folly::deallocateOverAligned<decltype(a), 64>(a, p, 3);
402  EXPECT_EQ(
403  (folly::allocationBytesForOverAligned<decltype(a), 64>(3)),
404  64 + alignof(folly::max_align_t));
405 }
406 
407 TEST(allocateOverAligned, defaultOverCustomAlloc) {
409  alignof(folly::max_align_t), 128 / alignof(folly::max_align_t));
410  auto p = folly::allocateOverAligned(a, 1);
411  EXPECT_EQ((reinterpret_cast<uintptr_t>(p) % 64), 0);
413  EXPECT_EQ(folly::allocationBytesForOverAligned<decltype(a)>(1), 128);
414 }
void * ptr
ExpectingAlloc(std::size_t expectedSize, std::size_t expectedCount)
Definition: MemoryTest.cpp:344
std::unique_ptr< int > A
#define EXPECT_THROW(statement, expected_exception)
Definition: gtest.h:1843
static constexpr std::size_t kTooBig
Definition: MemoryTest.cpp:34
char b
LogLevel max
Definition: LogLevel.cpp:31
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
void aligned_free(void *aligned_ptr)
Definition: Memory.h:89
void deallocate(T *p, std::size_t n)
Definition: MemoryTest.cpp:359
STL namespace.
CountedAllocator(CountedAllocatorStats &stats) noexcept
Definition: MemoryTest.cpp:198
static bool simple
std::size_t expectedCount_
Definition: MemoryTest.cpp:364
folly::std T
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
Definition: lib.cpp:18
requires E e noexcept(noexcept(s.error(std::move(e))))
std::unique_ptr< T, allocator_delete< Alloc > > allocate_unique(Alloc const &alloc, Args &&...args)
Definition: Memory.h:609
T * allocate(std::size_t n)
Definition: MemoryTest.cpp:352
bool_constant< true > true_type
Definition: gtest-port.h:2210
CountedAllocatorStats * stats_
Definition: MemoryTest.cpp:195
constexpr T constexpr_max(T a)
Definition: ConstexprMath.h:68
static void destroy()
std::weak_ptr< T > to_weak_ptr(const std::shared_ptr< T > &ptr)
Definition: Memory.h:346
std::size_t expectedSize_
Definition: MemoryTest.cpp:363
internal::ElementsAreArrayMatcher< typename::std::iterator_traits< Iter >::value_type > ElementsAreArray(Iter first, Iter last)
void * aligned_malloc(size_t size, size_t align)
Definition: Memory.h:85
constexpr bool kIsSanitize
Definition: Portability.h:130
std::allocator_traits< Alloc >::pointer allocateOverAligned(Alloc const &alloc, size_t n)
Definition: Memory.h:198
auto lock(Synchronized< D, M > &synchronized, Args &&...args)
char a
std::array< char, 64 > raw_
Definition: MemoryTest.cpp:368
void BENCHFUN() equality(size_t iters, size_t arg)
void * allocateBytes(size_t n)
Definition: Memory.h:43
size_t allocationBytesForOverAligned(size_t n)
Definition: Memory.h:223
std::enable_if<!std::is_array< T >::value, std::unique_ptr< T > >::type make_unique(Args &&...args)
Definition: Memory.h:259
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
#define EXPECT_THAT(value, matcher)
const char * string
Definition: Conv.cpp:212
#define EXPECT_NE(val1, val2)
Definition: gtest.h:1926
static set< string > s
SysBufferUniquePtr allocate_sys_buffer(std::size_t size)
Definition: Memory.h:641
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
bool_constant< false > false_type
Definition: gtest-port.h:2209
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862
void deallocateOverAligned(Alloc const &alloc, typename std::allocator_traits< Alloc >::pointer ptr, size_t n)
Definition: Memory.h:212
void deallocateBytes(void *p, size_t n)
Definition: Memory.h:47
char c
ExpectingAlloc(ExpectingAlloc< U > const &other) noexcept
Definition: MemoryTest.cpp:348
TEST(SequencedExecutor, CPUThreadPoolExecutor)
std::shared_ptr< T > to_shared_ptr(std::unique_ptr< T, D > &&ptr)
Definition: Memory.h:323
void deallocate(T *p, size_t n)
Definition: MemoryTest.cpp:200