1 //===-- malloc_benchmark.cpp ------------------------------------*- C++ -*-===//
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 "allocator_config.h"
10 #include "combined.h"
11 #include "common.h"
12 
13 #include "benchmark/benchmark.h"
14 
15 #include <memory>
16 #include <vector>
17 
18 void *CurrentAllocator;
19 template <typename Config> void PostInitCallback() {
20   reinterpret_cast<scudo::Allocator<Config> *>(CurrentAllocator)->initGwpAsan();
21 }
22 
23 template <typename Config> static void BM_malloc_free(benchmark::State &State) {
24   using AllocatorT = scudo::Allocator<Config, PostInitCallback<Config>>;
25   auto Deleter = [](AllocatorT *A) {
26     A->unmapTestOnly();
27     delete A;
28   };
29   std::unique_ptr<AllocatorT, decltype(Deleter)> Allocator(new AllocatorT,
30                                                            Deleter);
31   CurrentAllocator = Allocator.get();
32   Allocator->reset();
33 
34   const size_t NBytes = State.range(0);
35   size_t PageSize = scudo::getPageSizeCached();
36 
37   for (auto _ : State) {
38     void *Ptr = Allocator->allocate(NBytes, scudo::Chunk::Origin::Malloc);
39     auto *Data = reinterpret_cast<uint8_t *>(Ptr);
40     for (size_t I = 0; I < NBytes; I += PageSize)
41       Data[I] = 1;
42     benchmark::DoNotOptimize(Ptr);
43     Allocator->deallocate(Ptr, scudo::Chunk::Origin::Malloc);
44   }
45 
46   State.SetBytesProcessed(uint64_t(State.iterations()) * uint64_t(NBytes));
47 }
48 
49 static const size_t MinSize = 8;
50 static const size_t MaxSize = 128 * 1024;
51 
52 // FIXME: Add DefaultConfig here once we can tear down the exclusive TSD
53 // cleanly.
54 BENCHMARK_TEMPLATE(BM_malloc_free, scudo::AndroidConfig)
55     ->Range(MinSize, MaxSize);
56 BENCHMARK_TEMPLATE(BM_malloc_free, scudo::AndroidSvelteConfig)
57     ->Range(MinSize, MaxSize);
58 #if SCUDO_CAN_USE_PRIMARY64
59 BENCHMARK_TEMPLATE(BM_malloc_free, scudo::FuchsiaConfig)
60     ->Range(MinSize, MaxSize);
61 #endif
62 
63 template <typename Config>
64 static void BM_malloc_free_loop(benchmark::State &State) {
65   using AllocatorT = scudo::Allocator<Config, PostInitCallback<Config>>;
66   auto Deleter = [](AllocatorT *A) {
67     A->unmapTestOnly();
68     delete A;
69   };
70   std::unique_ptr<AllocatorT, decltype(Deleter)> Allocator(new AllocatorT,
71                                                            Deleter);
72   CurrentAllocator = Allocator.get();
73   Allocator->reset();
74 
75   const size_t NumIters = State.range(0);
76   size_t PageSize = scudo::getPageSizeCached();
77   std::vector<void *> Ptrs(NumIters);
78 
79   for (auto _ : State) {
80     size_t SizeLog2 = 0;
81     for (void *&Ptr : Ptrs) {
82       Ptr = Allocator->allocate(1 << SizeLog2, scudo::Chunk::Origin::Malloc);
83       auto *Data = reinterpret_cast<uint8_t *>(Ptr);
84       for (size_t I = 0; I < 1 << SizeLog2; I += PageSize)
85         Data[I] = 1;
86       benchmark::DoNotOptimize(Ptr);
87       SizeLog2 = (SizeLog2 + 1) % 16;
88     }
89     for (void *&Ptr : Ptrs)
90       Allocator->deallocate(Ptr, scudo::Chunk::Origin::Malloc);
91   }
92 
93   State.SetBytesProcessed(uint64_t(State.iterations()) * uint64_t(NumIters) *
94                           8192);
95 }
96 
97 static const size_t MinIters = 8;
98 static const size_t MaxIters = 32 * 1024;
99 
100 // FIXME: Add DefaultConfig here once we can tear down the exclusive TSD
101 // cleanly.
102 BENCHMARK_TEMPLATE(BM_malloc_free_loop, scudo::AndroidConfig)
103     ->Range(MinIters, MaxIters);
104 BENCHMARK_TEMPLATE(BM_malloc_free_loop, scudo::AndroidSvelteConfig)
105     ->Range(MinIters, MaxIters);
106 #if SCUDO_CAN_USE_PRIMARY64
107 BENCHMARK_TEMPLATE(BM_malloc_free_loop, scudo::FuchsiaConfig)
108     ->Range(MinIters, MaxIters);
109 #endif
110 
111 BENCHMARK_MAIN();
112