diff --git a/benchtests/Makefile b/benchtests/Makefile
index 5b2fa67f35..5470be7f40 100644
--- a/benchtests/Makefile
+++ b/benchtests/Makefile
@@ -332,8 +332,10 @@ CFLAGS-bench-isfinite.c += $(config-cflags-signaling-nans)
ifeq (${BENCHSET},)
bench-malloc := \
calloc-simple \
+ calloc-tcache \
calloc-thread \
malloc-simple \
+ malloc-tcache \
malloc-thread \
# bench-malloc
else
@@ -456,9 +458,11 @@ VALIDBENCHSETNAMES := \
bench-pthread \
bench-string \
calloc-simple \
+ calloc-tcache \
calloc-thread \
hash-benchset \
malloc-simple \
+ malloc-tcache \
malloc-thread \
math-benchset \
stdio-benchset \
@@ -502,6 +506,11 @@ bench-malloc: $(binaries-bench-malloc)
echo "Running $${run} $${thr}"; \
$(run-bench) $${thr} > $${run}-$${thr}.out; \
done;\
+ elif basename $${run} | grep -q "bench-[cm]alloc-tcache"; then \
+ for thr in 64 512 1024; do \
+ echo "Running $${run} $${thr}"; \
+ $(run-bench) $${thr} > $${run}-$${thr}.out; \
+ done;\
else \
for thr in 8 16 32 64 128 256 512 1024 2048 4096; do \
echo "Running $${run} $${thr}"; \
diff --git a/benchtests/bench-calloc-tcache.c b/benchtests/bench-calloc-tcache.c
new file mode 100644
index 0000000000..5303f872b8
--- /dev/null
+++ b/benchtests/bench-calloc-tcache.c
@@ -0,0 +1,22 @@
+/* Benchmark calloc and free functions.
+ Copyright (C) 2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#define TEST_FUNC(size) calloc (1, size)
+#define TEST_NAME "calloc"
+
+#include "bench-malloc-tcache.c"
diff --git a/benchtests/bench-malloc-tcache.c b/benchtests/bench-malloc-tcache.c
new file mode 100644
index 0000000000..4bd9808e80
--- /dev/null
+++ b/benchtests/bench-malloc-tcache.c
@@ -0,0 +1,174 @@
+/* Benchmark tcache hotpath allocations.
+ Copyright (C) 2013-2025 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ . */
+
+#ifndef TEST_FUNC
+# define TEST_FUNC(size) malloc(size)
+# define TEST_NAME "malloc"
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "bench-util.h"
+#include "bench-util.c"
+#include "bench-timing.h"
+#include "json-lib.h"
+
+/* Benchmark duration in seconds. */
+#define BENCHMARK_DURATION 3
+
+static volatile bool timeout;
+size_t alloc_size;
+
+static void
+alarm_handler (int signum)
+{
+ timeout = true;
+}
+
+struct bench_result {
+ size_t iters;
+ timing_t elapsed;
+};
+
+static __always_inline size_t
+malloc_benchmark_loop (void **elems, size_t nr_items)
+{
+ size_t iters = nr_items;
+
+ while (!timeout)
+ {
+ elems[iters % nr_items] = TEST_FUNC (alloc_size);
+ iters++;
+ free (elems[iters % nr_items]);
+ }
+
+ return iters - nr_items;
+}
+
+static void
+do_benchmark (struct bench_result *res)
+{
+ timing_t start, stop;
+ void *elems[10];
+ memset (elems, 0, sizeof(elems));
+
+ alarm (BENCHMARK_DURATION);
+ /* Ramp up cpu before measuring. */
+ bench_start ();
+ TIMING_NOW (start);
+ res[0].iters = malloc_benchmark_loop (elems, 1);
+ TIMING_NOW (stop);
+ TIMING_DIFF (res[0].elapsed, start, stop);
+
+ timeout = false;
+ alarm (BENCHMARK_DURATION);
+ bench_start ();
+ TIMING_NOW (start);
+ res[1].iters = malloc_benchmark_loop (elems, 4);
+ TIMING_NOW (stop);
+ TIMING_DIFF (res[1].elapsed, start, stop);
+}
+
+static void usage (const char *name)
+{
+ fprintf (stderr, "%s: \n", name);
+ exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+ json_ctx_t json_ctx;
+ double d_total_s, d_total_i;
+ struct sigaction act;
+
+ if (argc == 1)
+ alloc_size = 1024;
+ else if (argc == 2)
+ {
+ long ret;
+
+ errno = 0;
+ ret = strtol (argv[1], NULL, 10);
+
+ if (errno || ret == 0)
+ usage (argv[0]);
+
+ alloc_size = ret;
+ }
+ else
+ usage (argv[0]);
+
+ json_init (&json_ctx, 0, stdout);
+
+ json_document_begin (&json_ctx);
+
+ json_attr_string (&json_ctx, "timing_type", TIMING_TYPE);
+
+ json_attr_object_begin (&json_ctx, "functions");
+
+ json_attr_object_begin (&json_ctx, TEST_NAME);
+
+ memset (&act, 0, sizeof (act));
+ act.sa_handler = &alarm_handler;
+
+ sigaction (SIGALRM, &act, NULL);
+
+ struct bench_result res[2];
+ memset (res, 0, sizeof (struct bench_result) * 2);
+
+ do_benchmark (res);
+
+ d_total_s = res[0].elapsed;
+ d_total_i = res[0].iters;
+
+ json_attr_object_begin (&json_ctx, "simple");
+
+ json_attr_double (&json_ctx, "alloc_size", alloc_size);
+ json_attr_double (&json_ctx, "duration", d_total_s);
+ json_attr_double (&json_ctx, "iterations", d_total_i);
+ json_attr_double (&json_ctx, "time_per_iteration", d_total_s / d_total_i);
+
+ json_attr_object_end (&json_ctx);
+
+ d_total_s = res[1].elapsed;
+ d_total_i = res[1].iters;
+
+ json_attr_object_begin (&json_ctx, "optimized");
+
+ json_attr_double (&json_ctx, "alloc_size", alloc_size);
+ json_attr_double (&json_ctx, "duration", d_total_s);
+ json_attr_double (&json_ctx, "iterations", d_total_i);
+ json_attr_double (&json_ctx, "time_per_iteration", d_total_s / d_total_i);
+
+ json_attr_object_end (&json_ctx);
+
+ json_attr_object_end (&json_ctx);
+
+ json_attr_object_end (&json_ctx);
+
+ json_document_end (&json_ctx);
+
+ return 0;
+}