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