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