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
15struct PointerList {
16 PointerList* Next = nullptr;
17};
18
19struct MallocWrapper {
20 __attribute__((always_inline)) static void* Allocate(size_t N) { return std::malloc(N); }
21 __attribute__((always_inline)) static void Deallocate(void* P, size_t) { std::free(P); }
22};
23
24struct NewWrapper {
25 __attribute__((always_inline)) static void* Allocate(size_t N) { return ::operator new(N); }
26 __attribute__((always_inline)) static void Deallocate(void* P, size_t) { ::operator delete(p: P); }
27};
28
29struct BuiltinNewWrapper {
30 __attribute__((always_inline)) static void* Allocate(size_t N) { return __builtin_operator_new(N); }
31 __attribute__((always_inline)) static void Deallocate(void* P, size_t) { __builtin_operator_delete(P); }
32};
33
34struct BuiltinSizedNewWrapper {
35 __attribute__((always_inline)) static void* Allocate(size_t N) { return __builtin_operator_new(N); }
36 __attribute__((always_inline)) static void Deallocate(void* P, size_t N) { __builtin_operator_delete(P, N); }
37};
38
39template <class AllocWrapper>
40static 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
49template <class AllocWrapper>
50static 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
69template <class AllocWrapper>
70static 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
88static int RegisterAllocBenchmarks() {
89 using FnType = void (*)(benchmark::State&);
90 struct {
91 const char* name;
92 FnType func;
93 } TestCases[] = {
94 {.name: "BM_Malloc", &BM_AllocateAndDeallocate<MallocWrapper>},
95 {.name: "BM_New", &BM_AllocateAndDeallocate<NewWrapper>},
96 {.name: "BM_BuiltinNewDelete", BM_AllocateAndDeallocate<BuiltinNewWrapper>},
97 {.name: "BM_BuiltinSizedNewDelete", BM_AllocateAndDeallocate<BuiltinSizedNewWrapper>},
98 {.name: "BM_BuiltinNewAllocateOnly", BM_AllocateOnly<BuiltinSizedNewWrapper>},
99 {.name: "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}
107int Sink = RegisterAllocBenchmarks();
108
109BENCHMARK_MAIN();
110