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))
21   static void* Allocate(size_t N) {
22     return std::malloc(N);
23   }
24   __attribute__((always_inline))
25   static void Deallocate(void* P, size_t) {
26     std::free(P);
27   }
28 };
29 
30 struct NewWrapper {
31   __attribute__((always_inline))
32   static void* Allocate(size_t N) {
33     return ::operator new(N);
34   }
35   __attribute__((always_inline))
36   static void Deallocate(void* P, size_t) {
37     ::operator delete(P);
38   }
39 };
40 
41 struct BuiltinNewWrapper {
42   __attribute__((always_inline))
43   static void* Allocate(size_t N) {
44     return __builtin_operator_new(N);
45   }
46   __attribute__((always_inline))
47   static void Deallocate(void* P, size_t) {
48     __builtin_operator_delete(P);
49   }
50 };
51 
52 struct BuiltinSizedNewWrapper {
53   __attribute__((always_inline))
54   static void* Allocate(size_t N) {
55     return __builtin_operator_new(N);
56   }
57   __attribute__((always_inline))
58   static void Deallocate(void* P, size_t N) {
59     __builtin_operator_delete(P, N);
60   }
61 };
62 
63 
64 template <class AllocWrapper>
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>
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>
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   std::vector<void*> Pointers(NumAllocs);
101   for (auto& p : Pointers) {
102     p = AllocWrapper::Allocate(alloc_size);
103   }
104 
105   void** Data = Pointers.data();
106   void** const End = Pointers.data() + Pointers.size();
107   while (st.KeepRunning()) {
108     AllocWrapper::Deallocate(*Data, alloc_size);
109     Data += 1;
110   }
111   assert(Data == End);
112 }
113 
114 static int RegisterAllocBenchmarks() {
115   using FnType = void(*)(benchmark::State&);
116   struct {
117     const char* name;
118     FnType func;
119   } TestCases[] = {
120       {"BM_Malloc", &BM_AllocateAndDeallocate<MallocWrapper>},
121       {"BM_New", &BM_AllocateAndDeallocate<NewWrapper>},
122       {"BM_BuiltinNewDelete", BM_AllocateAndDeallocate<BuiltinNewWrapper>},
123       {"BM_BuiltinSizedNewDelete", BM_AllocateAndDeallocate<BuiltinSizedNewWrapper>},
124       {"BM_BuiltinNewAllocateOnly", BM_AllocateOnly<BuiltinSizedNewWrapper>},
125       {"BM_BuiltinNewSizedDeallocateOnly", BM_DeallocateOnly<BuiltinSizedNewWrapper>},
126 
127   };
128   for (auto TC : TestCases) {
129     benchmark::RegisterBenchmark(TC.name, TC.func)->Range(16, 4096 * 2);
130   }
131   return 0;
132 }
133 int Sink = RegisterAllocBenchmarks();
134 
135 BENCHMARK_MAIN();
136