[PATCH v9 1/2] malloc: add tcache support for large chunk caching
Wilco Dijkstra
Wilco.Dijkstra@arm.com
Wed Jun 4 11:48:03 GMT 2025
Hi Cupertino,
-static void * __attribute_noinline__
-tcache_calloc_init (size_t bytes)
-{
- tcache_init ();
- return __libc_calloc2 (bytes);
-}
Why remove this?
@@ -3392,10 +3466,28 @@ void *
__libc_malloc (size_t bytes)
{
#if USE_TCACHE
- size_t tc_idx = usize2tidx (bytes);
+ size_t nb = checked_request2size (bytes);
+
+ if (nb < mp_.tcache_max_bytes)
+ {
+ size_t tc_idx = csize2tidx (nb);
+ if(__glibc_unlikely (tcache == NULL))
+ {
+ tcache_init ();
+ return __libc_malloc2 (bytes);
+ }
This should be a tailcall to a function like tcache_calloc_init
above - otherwise it actually makes things worse than the
MAYBE_TCACHE_INIT.
- if (tcache_available (tc_idx))
- return tag_new_usable (tcache_get (tc_idx));
+ if (tc_idx < TCACHE_SMALL_BINS
+ && tcache->entries[tc_idx] != NULL)
This won't work with the else below.
+ return tag_new_usable (tcache_get (tc_idx));
+ else
+ if ((tc_idx = large_csize2tidx (nb)) < TCACHE_MAX_BINS)
This if is redundant, and the initialization should not be in it.
But worse, this is actually incorrect - the small tcache code can
get here and access random bins...
@@ -3439,8 +3529,19 @@ __libc_free (void *mem)
if (__glibc_unlikely (e->key == tcache_key))
return tcache_double_free_verify (e);
- if (__glibc_likely (tcache->counts[tc_idx] < mp_.tcache_count))
- return tcache_put (p, tc_idx);
+ size_t tc_idx = csize2tidx (size);
+ if (tc_idx < TCACHE_SMALL_BINS)
+ {
+ if (__glibc_likely (tcache->counts[tc_idx] < mp_.tcache_count))
+ return tcache_put (p, tc_idx);
+ }
+ else
+ {
+ if ((tc_idx = large_csize2tidx (size)) < TCACHE_MAX_BINS
This check is redundant, the tc_idx initialization should be before it.
+ && !chunk_is_mmapped (p)
+ && __glibc_likely (tcache->counts[tc_idx] < mp_.tcache_count))
+ return tcache_put_large (p, tc_idx);
+ }
}
#endif
@@ -3825,21 +3908,39 @@ __libc_calloc (size_t n, size_t elem_size)
}
#if USE_TCACHE
- size_t tc_idx = usize2tidx (bytes);
- if (__glibc_likely (tc_idx < mp_.tcache_bins))
+ size_t nb = checked_request2size (bytes);
+ if (nb < mp_.tcache_max_bytes)
{
if (__glibc_unlikely (tcache == NULL))
- return tcache_calloc_init (bytes);
-
- if (__glibc_likely (tcache->entries[tc_idx] != NULL))
{
- void *mem = tcache_get (tc_idx);
+ tcache_init ();
+ return __libc_calloc2 (bytes);
+ }
Same here, why remove the optimization and make things slower?
+ size_t tc_idx = csize2tidx (nb);
+
+ if (tc_idx < TCACHE_SMALL_BINS
+ && tcache->entries[tc_idx] != NULL)
+ {
+ void *mem = tcache_get (tc_idx);
if (__glibc_unlikely (mtag_enabled))
- return tag_new_zero_region (mem, memsize (mem2chunk (mem)));
+ return tag_new_zero_region (mem, memsize (mem2chunk (mem)));
- return clear_memory ((INTERNAL_SIZE_T *) mem, tidx2usize (tc_idx));
+ return clear_memory ((INTERNAL_SIZE_T *) mem, memsize (mem2chunk (mem)));
Why remove the tidx2usize here?
}
+ else
+ if ((tc_idx = large_csize2tidx (nb)) < TCACHE_MAX_BINS
+ && tcache->entries[tc_idx] != NULL)
This if is redundant (you don't need the entries check here either
in principle) and incorrect due to the earlier if.
- LIBC_PROBE (memory_tunable_tcache_max_bytes, 2, value, mp_.tcache_max_bytes);
- mp_.tcache_max_bytes = value;
- mp_.tcache_bins = csize2tidx (request2size(value)) + 1;
+ if (tc_idx + 1 < TCACHE_SMALL_BINS)
+ mp_.tcache_small_bins = tc_idx + 1;
tcache_small_bins can be equal to TCACHE_SMALL_BINS, so use <= in the if.
Cheers,
Wilco
More information about the Libc-alpha
mailing list