1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // REQUIRES: -fsized-deallocation
10 // ADDITIONAL_COMPILE_FLAGS: -fsized-deallocation
11
12 #include "benchmark/benchmark.h"
13
14 #include <cassert>
15 #include <cstdlib>
16 #include <new>
17 #include <vector>
18
19 #include "test_macros.h"
20
21 struct PointerList {
22 PointerList* Next = nullptr;
23 };
24
25 struct MallocWrapper {
AllocateMallocWrapper26 __attribute__((always_inline)) static void* Allocate(size_t N) { return std::malloc(N); }
DeallocateMallocWrapper27 __attribute__((always_inline)) static void Deallocate(void* P, size_t) { std::free(P); }
28 };
29
30 struct NewWrapper {
AllocateNewWrapper31 __attribute__((always_inline)) static void* Allocate(size_t N) { return ::operator new(N); }
DeallocateNewWrapper32 __attribute__((always_inline)) static void Deallocate(void* P, size_t) { ::operator delete(P); }
33 };
34
35 #ifdef TEST_COMPILER_CLANG
36 struct BuiltinNewWrapper {
AllocateBuiltinNewWrapper37 __attribute__((always_inline)) static void* Allocate(size_t N) { return __builtin_operator_new(N); }
DeallocateBuiltinNewWrapper38 __attribute__((always_inline)) static void Deallocate(void* P, size_t) { __builtin_operator_delete(P); }
39 };
40
41 struct BuiltinSizedNewWrapper {
AllocateBuiltinSizedNewWrapper42 __attribute__((always_inline)) static void* Allocate(size_t N) { return __builtin_operator_new(N); }
DeallocateBuiltinSizedNewWrapper43 __attribute__((always_inline)) static void Deallocate(void* P, size_t N) { __builtin_operator_delete(P, N); }
44 };
45 #endif
46
47 template <class AllocWrapper>
BM_AllocateAndDeallocate(benchmark::State & st)48 static void BM_AllocateAndDeallocate(benchmark::State& st) {
49 const size_t alloc_size = st.range(0);
50 while (st.KeepRunning()) {
51 void* p = AllocWrapper::Allocate(alloc_size);
52 benchmark::DoNotOptimize(p);
53 AllocWrapper::Deallocate(p, alloc_size);
54 }
55 }
56
57 template <class AllocWrapper>
BM_AllocateOnly(benchmark::State & st)58 static void BM_AllocateOnly(benchmark::State& st) {
59 const size_t alloc_size = st.range(0);
60 PointerList* Start = nullptr;
61
62 while (st.KeepRunning()) {
63 PointerList* p = (PointerList*)AllocWrapper::Allocate(alloc_size);
64 benchmark::DoNotOptimize(p);
65 p->Next = Start;
66 Start = p;
67 }
68
69 PointerList* Next = Start;
70 while (Next) {
71 PointerList* Tmp = Next;
72 Next = Tmp->Next;
73 AllocWrapper::Deallocate(Tmp, alloc_size);
74 }
75 }
76
77 template <class AllocWrapper>
BM_DeallocateOnly(benchmark::State & st)78 static void BM_DeallocateOnly(benchmark::State& st) {
79 const size_t alloc_size = st.range(0);
80 const auto NumAllocs = st.max_iterations;
81
82 std::vector<void*> Pointers(NumAllocs);
83 for (auto& p : Pointers) {
84 p = AllocWrapper::Allocate(alloc_size);
85 }
86
87 void** Data = Pointers.data();
88 [[maybe_unused]] void** const End = Pointers.data() + Pointers.size();
89 while (st.KeepRunning()) {
90 AllocWrapper::Deallocate(*Data, alloc_size);
91 Data += 1;
92 }
93 assert(Data == End);
94 }
95
RegisterAllocBenchmarks()96 static int RegisterAllocBenchmarks() {
97 using FnType = void (*)(benchmark::State&);
98 struct {
99 const char* name;
100 FnType func;
101 } TestCases[] = {
102 {"BM_Malloc", &BM_AllocateAndDeallocate<MallocWrapper>},
103 {"BM_New", &BM_AllocateAndDeallocate<NewWrapper>},
104 #ifdef TEST_COMPILER_CLANG
105 {"BM_BuiltinNewDelete", BM_AllocateAndDeallocate<BuiltinNewWrapper>},
106 {"BM_BuiltinSizedNewDelete", BM_AllocateAndDeallocate<BuiltinSizedNewWrapper>},
107 {"BM_BuiltinNewAllocateOnly", BM_AllocateOnly<BuiltinSizedNewWrapper>},
108 {"BM_BuiltinNewSizedDeallocateOnly", BM_DeallocateOnly<BuiltinSizedNewWrapper>},
109 #endif
110 };
111 for (auto TC : TestCases) {
112 benchmark::RegisterBenchmark(TC.name, TC.func)->Range(16, 4096 * 2);
113 }
114 return 0;
115 }
116 int Sink = RegisterAllocBenchmarks();
117
118 BENCHMARK_MAIN();
119