1 /* Benchmark malloc and free functions.
2 Copyright (C) 2013-2025 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
20 # define TEST_FUNC(size) malloc(size)
21 # define TEST_NAME "malloc"
32 #include <sys/resource.h>
35 #include "bench-timing.h"
38 /* Benchmark duration in seconds. */
39 #define BENCHMARK_DURATION 10
43 # define NUM_THREADS 1
46 /* Maximum memory that can be allocated at any one time is:
48 NUM_THREADS * WORKING_SET_SIZE * MAX_ALLOCATION_SIZE
50 However due to the distribution of the random block sizes
51 the typical amount allocated will be much smaller. */
52 #define WORKING_SET_SIZE 1024
54 #define MIN_ALLOCATION_SIZE 4
55 #define MAX_ALLOCATION_SIZE 32768
57 /* Get a random block size with an inverse square distribution. */
59 get_block_size (unsigned int rand_data
)
62 const float exponent
= -2;
63 /* Minimum value of distribution. */
64 const float dist_min
= MIN_ALLOCATION_SIZE
;
65 /* Maximum value of distribution. */
66 const float dist_max
= MAX_ALLOCATION_SIZE
;
68 float min_pow
= powf (dist_min
, exponent
+ 1);
69 float max_pow
= powf (dist_max
, exponent
+ 1);
71 float r
= (float) rand_data
/ RAND_MAX
;
73 return (unsigned int) powf ((max_pow
- min_pow
) * r
+ min_pow
,
77 #define NUM_BLOCK_SIZES 8000
78 #define NUM_OFFSETS ((WORKING_SET_SIZE) * 4)
80 static unsigned int random_block_sizes
[NUM_BLOCK_SIZES
];
81 static unsigned int random_offsets
[NUM_OFFSETS
];
84 init_random_values (void)
86 for (size_t i
= 0; i
< NUM_BLOCK_SIZES
; i
++)
87 random_block_sizes
[i
] = get_block_size (rand ());
89 for (size_t i
= 0; i
< NUM_OFFSETS
; i
++)
90 random_offsets
[i
] = rand () % WORKING_SET_SIZE
;
94 get_random_block_size (unsigned int *state
)
96 unsigned int idx
= *state
;
98 if (idx
>= NUM_BLOCK_SIZES
- 1)
105 return random_block_sizes
[idx
];
109 get_random_offset (unsigned int *state
)
111 unsigned int idx
= *state
;
113 if (idx
>= NUM_OFFSETS
- 1)
120 return random_offsets
[idx
];
123 static volatile bool timeout
;
126 alarm_handler (int signum
)
131 /* Allocate and free blocks in a random order. */
133 malloc_benchmark_loop (void **ptr_arr
)
135 unsigned int offset_state
= 0, block_state
= 0;
140 unsigned int next_idx
= get_random_offset (&offset_state
);
141 unsigned int next_block
= get_random_block_size (&block_state
);
143 free (ptr_arr
[next_idx
]);
145 ptr_arr
[next_idx
] = TEST_FUNC (next_block
);
161 benchmark_thread (void *arg
)
163 struct thread_args
*args
= (struct thread_args
*) arg
;
165 void *thread_set
= args
->working_set
;
166 timing_t start
, stop
;
169 iters
= malloc_benchmark_loop (thread_set
);
172 TIMING_DIFF (args
->elapsed
, start
, stop
);
179 do_benchmark (size_t num_threads
, size_t *iters
)
181 timing_t elapsed
= 0;
183 if (num_threads
== 1)
185 timing_t start
, stop
;
186 void *working_set
[WORKING_SET_SIZE
];
188 memset (working_set
, 0, sizeof (working_set
));
191 *iters
= malloc_benchmark_loop (working_set
);
194 TIMING_DIFF (elapsed
, start
, stop
);
198 struct thread_args args
[num_threads
];
199 void *working_set
[num_threads
][WORKING_SET_SIZE
];
200 pthread_t threads
[num_threads
];
202 memset (working_set
, 0, sizeof (working_set
));
206 for (size_t i
= 0; i
< num_threads
; i
++)
208 args
[i
].working_set
= working_set
[i
];
209 pthread_create(&threads
[i
], NULL
, benchmark_thread
, &args
[i
]);
212 for (size_t i
= 0; i
< num_threads
; i
++)
214 pthread_join(threads
[i
], NULL
);
215 TIMING_ACCUM (elapsed
, args
[i
].elapsed
);
216 *iters
+= args
[i
].iters
;
222 static void usage(const char *name
)
224 fprintf (stderr
, "%s: <num_threads>\n", name
);
229 main (int argc
, char **argv
)
232 size_t iters
= 0, num_threads
= 1;
234 double d_total_s
, d_total_i
;
235 struct sigaction act
;
244 ret
= strtol(argv
[1], NULL
, 10);
246 if (errno
|| ret
== 0)
254 init_random_values ();
256 json_init (&json_ctx
, 0, stdout
);
258 json_document_begin (&json_ctx
);
260 json_attr_string (&json_ctx
, "timing_type", TIMING_TYPE
);
262 json_attr_object_begin (&json_ctx
, "functions");
264 json_attr_object_begin (&json_ctx
, TEST_NAME
);
266 json_attr_object_begin (&json_ctx
, "");
268 memset (&act
, 0, sizeof (act
));
269 act
.sa_handler
= &alarm_handler
;
271 sigaction (SIGALRM
, &act
, NULL
);
273 alarm (BENCHMARK_DURATION
);
275 cur
= do_benchmark (num_threads
, &iters
);
278 getrusage(RUSAGE_SELF
, &usage
);
283 json_attr_double (&json_ctx
, "duration", d_total_s
);
284 json_attr_double (&json_ctx
, "iterations", d_total_i
);
285 json_attr_double (&json_ctx
, "time_per_iteration", d_total_s
/ d_total_i
);
286 json_attr_double (&json_ctx
, "max_rss", usage
.ru_maxrss
);
288 json_attr_double (&json_ctx
, "threads", num_threads
);
289 json_attr_double (&json_ctx
, "min_size", MIN_ALLOCATION_SIZE
);
290 json_attr_double (&json_ctx
, "max_size", MAX_ALLOCATION_SIZE
);
291 json_attr_double (&json_ctx
, "random_seed", RAND_SEED
);
293 json_attr_object_end (&json_ctx
);
295 json_attr_object_end (&json_ctx
);
297 json_attr_object_end (&json_ctx
);
299 json_document_end (&json_ctx
);