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
15struct PointerList {
16  PointerList* Next = nullptr;
17};
18
19struct 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
30struct 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
41struct 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
52struct 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
64template <class AllocWrapper>
65static 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
75template <class AllocWrapper>
76static 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
95template <class AllocWrapper>
96static 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
114static 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}
133int Sink = RegisterAllocBenchmarks();
134
135BENCHMARK_MAIN();
136