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