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 <cassert>
12 #include <new>
13 #include <vector>
14
15 struct PointerList {
16 PointerList* Next = nullptr;
17 };
18
19 struct MallocWrapper {
AllocateMallocWrapper20 __attribute__((always_inline)) static void* Allocate(size_t N) { return std::malloc(N); }
DeallocateMallocWrapper21 __attribute__((always_inline)) static void Deallocate(void* P, size_t) { std::free(P); }
22 };
23
24 struct NewWrapper {
AllocateNewWrapper25 __attribute__((always_inline)) static void* Allocate(size_t N) { return ::operator new(N); }
DeallocateNewWrapper26 __attribute__((always_inline)) static void Deallocate(void* P, size_t) { ::operator delete(P); }
27 };
28
29 struct BuiltinNewWrapper {
AllocateBuiltinNewWrapper30 __attribute__((always_inline)) static void* Allocate(size_t N) { return __builtin_operator_new(N); }
DeallocateBuiltinNewWrapper31 __attribute__((always_inline)) static void Deallocate(void* P, size_t) { __builtin_operator_delete(P); }
32 };
33
34 struct BuiltinSizedNewWrapper {
AllocateBuiltinSizedNewWrapper35 __attribute__((always_inline)) static void* Allocate(size_t N) { return __builtin_operator_new(N); }
DeallocateBuiltinSizedNewWrapper36 __attribute__((always_inline)) static void Deallocate(void* P, size_t N) { __builtin_operator_delete(P, N); }
37 };
38
39 template <class AllocWrapper>
BM_AllocateAndDeallocate(benchmark::State & st)40 static void BM_AllocateAndDeallocate(benchmark::State& st) {
41 const size_t alloc_size = st.range(0);
42 while (st.KeepRunning()) {
43 void* p = AllocWrapper::Allocate(alloc_size);
44 benchmark::DoNotOptimize(p);
45 AllocWrapper::Deallocate(p, alloc_size);
46 }
47 }
48
49 template <class AllocWrapper>
BM_AllocateOnly(benchmark::State & st)50 static void BM_AllocateOnly(benchmark::State& st) {
51 const size_t alloc_size = st.range(0);
52 PointerList* Start = nullptr;
53
54 while (st.KeepRunning()) {
55 PointerList* p = (PointerList*)AllocWrapper::Allocate(alloc_size);
56 benchmark::DoNotOptimize(p);
57 p->Next = Start;
58 Start = p;
59 }
60
61 PointerList* Next = Start;
62 while (Next) {
63 PointerList* Tmp = Next;
64 Next = Tmp->Next;
65 AllocWrapper::Deallocate(Tmp, alloc_size);
66 }
67 }
68
69 template <class AllocWrapper>
BM_DeallocateOnly(benchmark::State & st)70 static void BM_DeallocateOnly(benchmark::State& st) {
71 const size_t alloc_size = st.range(0);
72 const auto NumAllocs = st.max_iterations;
73
74 std::vector<void*> Pointers(NumAllocs);
75 for (auto& p : Pointers) {
76 p = AllocWrapper::Allocate(alloc_size);
77 }
78
79 void** Data = Pointers.data();
80 [[maybe_unused]] void** const End = Pointers.data() + Pointers.size();
81 while (st.KeepRunning()) {
82 AllocWrapper::Deallocate(*Data, alloc_size);
83 Data += 1;
84 }
85 assert(Data == End);
86 }
87
RegisterAllocBenchmarks()88 static int RegisterAllocBenchmarks() {
89 using FnType = void (*)(benchmark::State&);
90 struct {
91 const char* name;
92 FnType func;
93 } TestCases[] = {
94 {"BM_Malloc", &BM_AllocateAndDeallocate<MallocWrapper>},
95 {"BM_New", &BM_AllocateAndDeallocate<NewWrapper>},
96 {"BM_BuiltinNewDelete", BM_AllocateAndDeallocate<BuiltinNewWrapper>},
97 {"BM_BuiltinSizedNewDelete", BM_AllocateAndDeallocate<BuiltinSizedNewWrapper>},
98 {"BM_BuiltinNewAllocateOnly", BM_AllocateOnly<BuiltinSizedNewWrapper>},
99 {"BM_BuiltinNewSizedDeallocateOnly", BM_DeallocateOnly<BuiltinSizedNewWrapper>},
100
101 };
102 for (auto TC : TestCases) {
103 benchmark::RegisterBenchmark(TC.name, TC.func)->Range(16, 4096 * 2);
104 }
105 return 0;
106 }
107 int Sink = RegisterAllocBenchmarks();
108
109 BENCHMARK_MAIN();
110