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