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