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 #include "benchmark/benchmark.h"
10 
11 #include <new>
12 #include <vector>
13 #include <cassert>
14 
15 struct PointerList {
16   PointerList* Next = nullptr;
17 };
18 
19 struct MallocWrapper {
20   __attribute__((always_inline))
AllocateMallocWrapper21   static void* Allocate(size_t N) {
22     return std::malloc(N);
23   }
24   __attribute__((always_inline))
DeallocateMallocWrapper25   static void Deallocate(void* P, size_t) {
26     std::free(P);
27   }
28 };
29 
30 struct NewWrapper {
31   __attribute__((always_inline))
AllocateNewWrapper32   static void* Allocate(size_t N) {
33     return ::operator new(N);
34   }
35   __attribute__((always_inline))
DeallocateNewWrapper36   static void Deallocate(void* P, size_t) {
37     ::operator delete(P);
38   }
39 };
40 
41 struct BuiltinNewWrapper {
42   __attribute__((always_inline))
AllocateBuiltinNewWrapper43   static void* Allocate(size_t N) {
44     return __builtin_operator_new(N);
45   }
46   __attribute__((always_inline))
DeallocateBuiltinNewWrapper47   static void Deallocate(void* P, size_t) {
48     __builtin_operator_delete(P);
49   }
50 };
51 
52 struct BuiltinSizedNewWrapper {
53   __attribute__((always_inline))
AllocateBuiltinSizedNewWrapper54   static void* Allocate(size_t N) {
55     return __builtin_operator_new(N);
56   }
57   __attribute__((always_inline))
DeallocateBuiltinSizedNewWrapper58   static void Deallocate(void* P, size_t N) {
59     __builtin_operator_delete(P, N);
60   }
61 };
62 
63 
64 template <class AllocWrapper>
BM_AllocateAndDeallocate(benchmark::State & st)65 static void BM_AllocateAndDeallocate(benchmark::State& st) {
66   const size_t alloc_size = st.range(0);
67   while (st.KeepRunning()) {
68     void* p = AllocWrapper::Allocate(alloc_size);
69     benchmark::DoNotOptimize(p);
70     AllocWrapper::Deallocate(p, alloc_size);
71   }
72 }
73 
74 
75 template <class AllocWrapper>
BM_AllocateOnly(benchmark::State & st)76 static void BM_AllocateOnly(benchmark::State& st) {
77   const size_t alloc_size = st.range(0);
78   PointerList *Start = nullptr;
79 
80   while (st.KeepRunning()) {
81     PointerList* p = (PointerList*)AllocWrapper::Allocate(alloc_size);
82     benchmark::DoNotOptimize(p);
83     p->Next = Start;
84     Start = p;
85   }
86 
87   PointerList *Next = Start;
88   while (Next) {
89     PointerList *Tmp = Next;
90     Next = Tmp->Next;
91     AllocWrapper::Deallocate(Tmp, alloc_size);
92   }
93 }
94 
95 template <class AllocWrapper>
BM_DeallocateOnly(benchmark::State & st)96 static void BM_DeallocateOnly(benchmark::State& st) {
97   const size_t alloc_size = st.range(0);
98   const auto NumAllocs = st.max_iterations;
99 
100   using PtrT = void*;
101   std::vector<void*> Pointers(NumAllocs);
102   for (auto& p : Pointers) {
103     p = AllocWrapper::Allocate(alloc_size);
104   }
105 
106   void** Data = Pointers.data();
107   void** const End = Pointers.data() + Pointers.size();
108   while (st.KeepRunning()) {
109     AllocWrapper::Deallocate(*Data, alloc_size);
110     Data += 1;
111   }
112   assert(Data == End);
113 }
114 
RegisterAllocBenchmarks()115 static int RegisterAllocBenchmarks() {
116   using FnType = void(*)(benchmark::State&);
117   struct {
118     const char* name;
119     FnType func;
120   } TestCases[] = {
121       {"BM_Malloc", &BM_AllocateAndDeallocate<MallocWrapper>},
122       {"BM_New", &BM_AllocateAndDeallocate<NewWrapper>},
123       {"BM_BuiltinNewDelete", BM_AllocateAndDeallocate<BuiltinNewWrapper>},
124       {"BM_BuiltinSizedNewDelete", BM_AllocateAndDeallocate<BuiltinSizedNewWrapper>},
125       {"BM_BuiltinNewAllocateOnly", BM_AllocateOnly<BuiltinSizedNewWrapper>},
126       {"BM_BuiltinNewSizedDeallocateOnly", BM_DeallocateOnly<BuiltinSizedNewWrapper>},
127 
128   };
129   for (auto TC : TestCases) {
130     benchmark::RegisterBenchmark(TC.name, TC.func)->Range(16, 4096 * 2);
131   }
132   return 0;
133 }
134 int Sink = RegisterAllocBenchmarks();
135 
136 BENCHMARK_MAIN();
137