blob: 371b8c61a1b25bef1ef371e9e607a0dde8d5881b [file] [log] [blame]
Brian Silverman20350ac2021-11-17 18:19:55 -08001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following disclaimer
10// in the documentation and/or other materials provided with the
11// distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived from
14// this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
Austin Schuh745610d2015-09-06 18:19:50 -070028#include <stdlib.h>
29#include <stdio.h>
Brian Silverman20350ac2021-11-17 18:19:55 -080030#include <stdint.h>
31
32#include <algorithm>
33
34#include "run_benchmark.h"
35
36static void bench_fastpath_throughput(long iterations,
37 uintptr_t param)
38{
39 size_t sz = 32;
40 for (; iterations>0; iterations--) {
41 void *p = malloc(sz);
42 if (!p) {
43 abort();
44 }
45 free(p);
46 // this makes next iteration use different free list. So
47 // subsequent iterations may actually overlap in time.
48 sz = ((sz * 8191) & 511) + 16;
49 }
50}
51
52static void bench_fastpath_dependent(long iterations,
53 uintptr_t param)
54{
55 size_t sz = 32;
56 for (; iterations>0; iterations--) {
57 void *p = malloc(sz);
58 if (!p) {
59 abort();
60 }
61 free(p);
62 // this makes next iteration depend on current iteration. But this
63 // iteration's free may still overlap with next iteration's malloc
64 sz = ((sz | reinterpret_cast<size_t>(p)) & 511) + 16;
65 }
66}
67
68static void bench_fastpath_simple(long iterations,
69 uintptr_t param)
70{
71 size_t sz = static_cast<size_t>(param);
72 for (; iterations>0; iterations--) {
73 void *p = malloc(sz);
74 if (!p) {
75 abort();
76 }
77 free(p);
78 // next iteration will use same free list as this iteration. So it
79 // should be prevent next iterations malloc to go too far before
80 // free done. But using same size will make free "too fast" since
81 // we'll hit size class cache.
82 }
83}
84
85#ifdef __GNUC__
86#define HAVE_SIZED_FREE_OPTION
87
88extern "C" void tc_free_sized(void *ptr, size_t size) __attribute__((weak));
89extern "C" void *tc_memalign(size_t align, size_t size) __attribute__((weak));
90
91static bool is_sized_free_available(void)
92{
93 return tc_free_sized != NULL;
94}
95
96static bool is_memalign_available(void)
97{
98 return tc_memalign != NULL;
99}
100
101static void bench_fastpath_simple_sized(long iterations,
102 uintptr_t param)
103{
104 size_t sz = static_cast<size_t>(param);
105 for (; iterations>0; iterations--) {
106 void *p = malloc(sz);
107 if (!p) {
108 abort();
109 }
110 tc_free_sized(p, sz);
111 // next iteration will use same free list as this iteration. So it
112 // should be prevent next iterations malloc to go too far before
113 // free done. But using same size will make free "too fast" since
114 // we'll hit size class cache.
115 }
116}
117
118static void bench_fastpath_memalign(long iterations,
119 uintptr_t param)
120{
121 size_t sz = static_cast<size_t>(param);
122 for (; iterations>0; iterations--) {
123 void *p = tc_memalign(32, sz);
124 if (!p) {
125 abort();
126 }
127 free(p);
128 // next iteration will use same free list as this iteration. So it
129 // should be prevent next iterations malloc to go too far before
130 // free done. But using same size will make free "too fast" since
131 // we'll hit size class cache.
132 }
133}
134
135#endif // __GNUC__
136
137#define STACKSZ (1 << 16)
138
139static void bench_fastpath_stack(long iterations,
140 uintptr_t _param)
141{
142
143 void *stack[STACKSZ];
144 size_t sz = 64;
145 long param = static_cast<long>(_param);
146 param &= STACKSZ - 1;
147 param = param ? param : 1;
148 for (; iterations>0; iterations -= param) {
149 for (long k = param-1; k >= 0; k--) {
150 void *p = malloc(sz);
151 if (!p) {
152 abort();
153 }
154 stack[k] = p;
155 // this makes next iteration depend on result of this iteration
156 sz = ((sz | reinterpret_cast<size_t>(p)) & 511) + 16;
157 }
158 for (long k = 0; k < param; k++) {
159 free(stack[k]);
160 }
161 }
162}
163
164static void bench_fastpath_stack_simple(long iterations,
165 uintptr_t _param)
166{
167
168 void *stack[STACKSZ];
169 size_t sz = 128;
170 long param = static_cast<long>(_param);
171 param &= STACKSZ - 1;
172 param = param ? param : 1;
173 for (; iterations>0; iterations -= param) {
174 for (long k = param-1; k >= 0; k--) {
175 void *p = malloc(sz);
176 if (!p) {
177 abort();
178 }
179 stack[k] = p;
180 }
181 for (long k = 0; k < param; k++) {
182 free(stack[k]);
183 }
184 }
185}
186
187static void bench_fastpath_rnd_dependent(long iterations,
188 uintptr_t _param)
189{
190 static const uintptr_t rnd_c = 1013904223;
191 static const uintptr_t rnd_a = 1664525;
192
193 void *ptrs[STACKSZ];
194 size_t sz = 128;
195 if ((_param & (_param - 1))) {
196 abort();
197 }
198 if (_param > STACKSZ) {
199 abort();
200 }
201 int param = static_cast<int>(_param);
202
203 for (; iterations>0; iterations -= param) {
204 for (int k = param-1; k >= 0; k--) {
205 void *p = malloc(sz);
206 if (!p) {
207 abort();
208 }
209 ptrs[k] = p;
210 sz = ((sz | reinterpret_cast<size_t>(p)) & 511) + 16;
211 }
212
213 // this will iterate through all objects in order that is
214 // unpredictable to processor's prefetchers
215 uint32_t rnd = 0;
216 uint32_t free_idx = 0;
217 do {
218 free(ptrs[free_idx]);
219 rnd = rnd * rnd_a + rnd_c;
220 free_idx = rnd & (param - 1);
221 } while (free_idx != 0);
222 }
223}
224
225static void *randomize_buffer[13<<20];
226
227
228void randomize_one_size_class(size_t size) {
229 int count = (100<<20) / size;
230 if (count * sizeof(randomize_buffer[0]) > sizeof(randomize_buffer)) {
231 abort();
232 }
233 for (int i = 0; i < count; i++) {
234 randomize_buffer[i] = malloc(size);
235 }
236 std::random_shuffle(randomize_buffer, randomize_buffer + count);
237 for (int i = 0; i < count; i++) {
238 free(randomize_buffer[i]);
239 }
240}
241
242void randomize_size_classes() {
243 randomize_one_size_class(8);
244 int i;
245 for (i = 16; i < 256; i += 16) {
246 randomize_one_size_class(i);
247 }
248 for (; i < 512; i += 32) {
249 randomize_one_size_class(i);
250 }
251 for (; i < 1024; i += 64) {
252 randomize_one_size_class(i);
253 }
254 for (; i < (4 << 10); i += 128) {
255 randomize_one_size_class(i);
256 }
257 for (; i < (32 << 10); i += 1024) {
258 randomize_one_size_class(i);
259 }
260}
Austin Schuh745610d2015-09-06 18:19:50 -0700261
262int main(void)
263{
Brian Silverman20350ac2021-11-17 18:19:55 -0800264 randomize_size_classes();
265
266 report_benchmark("bench_fastpath_throughput", bench_fastpath_throughput, 0);
267 report_benchmark("bench_fastpath_dependent", bench_fastpath_dependent, 0);
268 report_benchmark("bench_fastpath_simple", bench_fastpath_simple, 64);
269 report_benchmark("bench_fastpath_simple", bench_fastpath_simple, 2048);
270 report_benchmark("bench_fastpath_simple", bench_fastpath_simple, 16384);
271
272#ifdef HAVE_SIZED_FREE_OPTION
273 if (is_sized_free_available()) {
274 report_benchmark("bench_fastpath_simple_sized", bench_fastpath_simple_sized, 64);
275 report_benchmark("bench_fastpath_simple_sized", bench_fastpath_simple_sized, 2048);
276 }
277
278 if (is_memalign_available()) {
279 report_benchmark("bench_fastpath_memalign", bench_fastpath_memalign, 64);
280 report_benchmark("bench_fastpath_memalign", bench_fastpath_memalign, 2048);
281 }
282
283#endif
284
285 for (int i = 8; i <= 512; i <<= 1) {
286 report_benchmark("bench_fastpath_stack", bench_fastpath_stack, i);
287 }
288 report_benchmark("bench_fastpath_stack_simple", bench_fastpath_stack_simple, 32);
289 report_benchmark("bench_fastpath_stack_simple", bench_fastpath_stack_simple, 8192);
290 report_benchmark("bench_fastpath_rnd_dependent", bench_fastpath_rnd_dependent, 32);
291 report_benchmark("bench_fastpath_rnd_dependent", bench_fastpath_rnd_dependent, 8192);
292 return 0;
Austin Schuh745610d2015-09-06 18:19:50 -0700293}