1 /* Benchmark malloc and free functions.
2 Copyright (C) 2013-2023 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/>. */
27 #include <sys/resource.h>
30 #include "bench-timing.h"
33 /* Benchmark duration in seconds. */
34 #define BENCHMARK_DURATION 10
38 # define NUM_THREADS 1
41 /* Maximum memory that can be allocated at any one time is:
43 NUM_THREADS * WORKING_SET_SIZE * MAX_ALLOCATION_SIZE
45 However due to the distribution of the random block sizes
46 the typical amount allocated will be much smaller. */
47 #define WORKING_SET_SIZE 1024
49 #define MIN_ALLOCATION_SIZE 4
50 #define MAX_ALLOCATION_SIZE 32768
52 /* Get a random block size with an inverse square distribution. */
54 get_block_size (unsigned int rand_data
)
57 const float exponent
= -2;
58 /* Minimum value of distribution. */
59 const float dist_min
= MIN_ALLOCATION_SIZE
;
60 /* Maximum value of distribution. */
61 const float dist_max
= MAX_ALLOCATION_SIZE
;
63 float min_pow
= powf (dist_min
, exponent
+ 1);
64 float max_pow
= powf (dist_max
, exponent
+ 1);
66 float r
= (float) rand_data
/ RAND_MAX
;
68 return (unsigned int) powf ((max_pow
- min_pow
) * r
+ min_pow
,
72 #define NUM_BLOCK_SIZES 8000
73 #define NUM_OFFSETS ((WORKING_SET_SIZE) * 4)
75 static unsigned int random_block_sizes
[NUM_BLOCK_SIZES
];
76 static unsigned int random_offsets
[NUM_OFFSETS
];
79 init_random_values (void)
81 for (size_t i
= 0; i
< NUM_BLOCK_SIZES
; i
++)
82 random_block_sizes
[i
] = get_block_size (rand ());
84 for (size_t i
= 0; i
< NUM_OFFSETS
; i
++)
85 random_offsets
[i
] = rand () % WORKING_SET_SIZE
;
89 get_random_block_size (unsigned int *state
)
91 unsigned int idx
= *state
;
93 if (idx
>= NUM_BLOCK_SIZES
- 1)
100 return random_block_sizes
[idx
];
104 get_random_offset (unsigned int *state
)
106 unsigned int idx
= *state
;
108 if (idx
>= NUM_OFFSETS
- 1)
115 return random_offsets
[idx
];
118 static volatile bool timeout
;
121 alarm_handler (int signum
)
126 /* Allocate and free blocks in a random order. */
128 malloc_benchmark_loop (void **ptr_arr
)
130 unsigned int offset_state
= 0, block_state
= 0;
135 unsigned int next_idx
= get_random_offset (&offset_state
);
136 unsigned int next_block
= get_random_block_size (&block_state
);
138 free (ptr_arr
[next_idx
]);
140 ptr_arr
[next_idx
] = malloc (next_block
);
156 benchmark_thread (void *arg
)
158 struct thread_args
*args
= (struct thread_args
*) arg
;
160 void *thread_set
= args
->working_set
;
161 timing_t start
, stop
;
164 iters
= malloc_benchmark_loop (thread_set
);
167 TIMING_DIFF (args
->elapsed
, start
, stop
);
174 do_benchmark (size_t num_threads
, size_t *iters
)
176 timing_t elapsed
= 0;
178 if (num_threads
== 1)
180 timing_t start
, stop
;
181 void *working_set
[WORKING_SET_SIZE
];
183 memset (working_set
, 0, sizeof (working_set
));
186 *iters
= malloc_benchmark_loop (working_set
);
189 TIMING_DIFF (elapsed
, start
, stop
);
193 struct thread_args args
[num_threads
];
194 void *working_set
[num_threads
][WORKING_SET_SIZE
];
195 pthread_t threads
[num_threads
];
197 memset (working_set
, 0, sizeof (working_set
));
201 for (size_t i
= 0; i
< num_threads
; i
++)
203 args
[i
].working_set
= working_set
[i
];
204 pthread_create(&threads
[i
], NULL
, benchmark_thread
, &args
[i
]);
207 for (size_t i
= 0; i
< num_threads
; i
++)
209 pthread_join(threads
[i
], NULL
);
210 TIMING_ACCUM (elapsed
, args
[i
].elapsed
);
211 *iters
+= args
[i
].iters
;
217 static void usage(const char *name
)
219 fprintf (stderr
, "%s: <num_threads>\n", name
);
224 main (int argc
, char **argv
)
227 size_t iters
= 0, num_threads
= 1;
229 double d_total_s
, d_total_i
;
230 struct sigaction act
;
239 ret
= strtol(argv
[1], NULL
, 10);
241 if (errno
|| ret
== 0)
249 init_random_values ();
251 json_init (&json_ctx
, 0, stdout
);
253 json_document_begin (&json_ctx
);
255 json_attr_string (&json_ctx
, "timing_type", TIMING_TYPE
);
257 json_attr_object_begin (&json_ctx
, "functions");
259 json_attr_object_begin (&json_ctx
, "malloc");
261 json_attr_object_begin (&json_ctx
, "");
263 memset (&act
, 0, sizeof (act
));
264 act
.sa_handler
= &alarm_handler
;
266 sigaction (SIGALRM
, &act
, NULL
);
268 alarm (BENCHMARK_DURATION
);
270 cur
= do_benchmark (num_threads
, &iters
);
273 getrusage(RUSAGE_SELF
, &usage
);
278 json_attr_double (&json_ctx
, "duration", d_total_s
);
279 json_attr_double (&json_ctx
, "iterations", d_total_i
);
280 json_attr_double (&json_ctx
, "time_per_iteration", d_total_s
/ d_total_i
);
281 json_attr_double (&json_ctx
, "max_rss", usage
.ru_maxrss
);
283 json_attr_double (&json_ctx
, "threads", num_threads
);
284 json_attr_double (&json_ctx
, "min_size", MIN_ALLOCATION_SIZE
);
285 json_attr_double (&json_ctx
, "max_size", MAX_ALLOCATION_SIZE
);
286 json_attr_double (&json_ctx
, "random_seed", RAND_SEED
);
288 json_attr_object_end (&json_ctx
);
290 json_attr_object_end (&json_ctx
);
292 json_attr_object_end (&json_ctx
);
294 json_document_end (&json_ctx
);