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 <cassert> |
12 | #include <new> |
13 | #include <vector> |
14 | |
15 | struct PointerList { |
16 | PointerList* Next = nullptr; |
17 | }; |
18 | |
19 | struct MallocWrapper { |
20 | __attribute__((always_inline)) static void* Allocate(size_t N) { return std::malloc(size: N); } |
21 | __attribute__((always_inline)) static void Deallocate(void* P, size_t) { std::free(ptr: P); } |
22 | }; |
23 | |
24 | struct NewWrapper { |
25 | __attribute__((always_inline)) static void* Allocate(size_t N) { return ::operator new(N); } |
26 | __attribute__((always_inline)) static void Deallocate(void* P, size_t) { ::operator delete(P); } |
27 | }; |
28 | |
29 | struct BuiltinNewWrapper { |
30 | __attribute__((always_inline)) static void* Allocate(size_t N) { return __builtin_operator_new(N); } |
31 | __attribute__((always_inline)) static void Deallocate(void* P, size_t) { __builtin_operator_delete(P); } |
32 | }; |
33 | |
34 | struct BuiltinSizedNewWrapper { |
35 | __attribute__((always_inline)) static void* Allocate(size_t N) { return __builtin_operator_new(N); } |
36 | __attribute__((always_inline)) static void Deallocate(void* P, size_t N) { __builtin_operator_delete(P, N); } |
37 | }; |
38 | |
39 | template <class AllocWrapper> |
40 | static void BM_AllocateAndDeallocate(benchmark::State& st) { |
41 | const size_t alloc_size = st.range(pos: 0); |
42 | while (st.KeepRunning()) { |
43 | void* p = AllocWrapper::Allocate(alloc_size); |
44 | benchmark::DoNotOptimize(value&: p); |
45 | AllocWrapper::Deallocate(p, alloc_size); |
46 | } |
47 | } |
48 | |
49 | template <class AllocWrapper> |
50 | static void BM_AllocateOnly(benchmark::State& st) { |
51 | const size_t alloc_size = st.range(pos: 0); |
52 | PointerList* Start = nullptr; |
53 | |
54 | while (st.KeepRunning()) { |
55 | PointerList* p = (PointerList*)AllocWrapper::Allocate(alloc_size); |
56 | benchmark::DoNotOptimize(value&: p); |
57 | p->Next = Start; |
58 | Start = p; |
59 | } |
60 | |
61 | PointerList* Next = Start; |
62 | while (Next) { |
63 | PointerList* Tmp = Next; |
64 | Next = Tmp->Next; |
65 | AllocWrapper::Deallocate(Tmp, alloc_size); |
66 | } |
67 | } |
68 | |
69 | template <class AllocWrapper> |
70 | static void BM_DeallocateOnly(benchmark::State& st) { |
71 | const size_t alloc_size = st.range(pos: 0); |
72 | const auto NumAllocs = st.max_iterations; |
73 | |
74 | std::vector<void*> Pointers(NumAllocs); |
75 | for (auto& p : Pointers) { |
76 | p = AllocWrapper::Allocate(alloc_size); |
77 | } |
78 | |
79 | void** Data = Pointers.data(); |
80 | [[maybe_unused]] void** const End = Pointers.data() + Pointers.size(); |
81 | while (st.KeepRunning()) { |
82 | AllocWrapper::Deallocate(*Data, alloc_size); |
83 | Data += 1; |
84 | } |
85 | assert(Data == End); |
86 | } |
87 | |
88 | static int RegisterAllocBenchmarks() { |
89 | using FnType = void (*)(benchmark::State&); |
90 | struct { |
91 | const char* name; |
92 | FnType func; |
93 | } TestCases[] = { |
94 | {.name: "BM_Malloc" , .func: &BM_AllocateAndDeallocate<MallocWrapper>}, |
95 | {.name: "BM_New" , .func: &BM_AllocateAndDeallocate<NewWrapper>}, |
96 | {.name: "BM_BuiltinNewDelete" , .func: BM_AllocateAndDeallocate<BuiltinNewWrapper>}, |
97 | {.name: "BM_BuiltinSizedNewDelete" , .func: BM_AllocateAndDeallocate<BuiltinSizedNewWrapper>}, |
98 | {.name: "BM_BuiltinNewAllocateOnly" , .func: BM_AllocateOnly<BuiltinSizedNewWrapper>}, |
99 | {.name: "BM_BuiltinNewSizedDeallocateOnly" , .func: BM_DeallocateOnly<BuiltinSizedNewWrapper>}, |
100 | |
101 | }; |
102 | for (auto TC : TestCases) { |
103 | benchmark::RegisterBenchmark(name: TC.name, fn: TC.func)->Range(start: 16, limit: 4096 * 2); |
104 | } |
105 | return 0; |
106 | } |
107 | int Sink = RegisterAllocBenchmarks(); |
108 | |
109 | BENCHMARK_MAIN(); |
110 | |