[PATCH] malloc: Count tcache entries downwards
Cupertino Miranda
cupertino.miranda@oracle.com
Fri Apr 11 07:35:03 GMT 2025
Hi Wilco,
On 10-04-2025 14:43, Wilco Dijkstra wrote:
>
> Currently tcache requires 2 global variable accesses to determine
> whether a block can be added to the tcache. Change the counts array
> to indicate the number of entries that could be added by counting
> downwards. If the count reaches zero, no more blocks can be added.
> If the entries pointer is not NULL, at least one block is available
> for allocation.
>
> Now each tcache bin can support a different maximum number of blocks,
> and they can be individually switched on or off (a zero initialized
> count+entry means the tcache bin is not available for free or malloc).
>
> Performance is neutral on current trunk (+1.4% on malloc-bench-thread 32),
> but after the outstanding improvements to free it gives ~5%.
>
> ---
>
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index a0bc733482532ce34684d0357cb9076b03ac8a52..c3e46518c5335467bb9b6ba0f0e96c4d18ee25e6 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -3169,7 +3169,7 @@ tcache_put (mchunkptr chunk, size_t tc_idx)
>
> e->next = PROTECT_PTR (&e->next, tcache->entries[tc_idx]);
> tcache->entries[tc_idx] = e;
> - ++(tcache->counts[tc_idx]);
> + --(tcache->counts[tc_idx]);
> }
>
> /* Caller must ensure that we know tc_idx is valid and there's
> @@ -3192,7 +3192,7 @@ tcache_get_n (size_t tc_idx, tcache_entry **ep)
> else
> *ep = PROTECT_PTR (ep, REVEAL_PTR (e->next));
>
> - --(tcache->counts[tc_idx]);
> + ++(tcache->counts[tc_idx]);
> e->key = 0;
> return (void *) e;
> }
> @@ -3217,7 +3217,7 @@ tcache_available (size_t tc_idx)
> {
> if (tc_idx < mp_.tcache_bins
> && tcache != NULL
> - && tcache->counts[tc_idx] > 0)
> + && tcache->entries[tc_idx] != NULL)
This will not be Ok for the pointer sizzling, which sizzles the entries.
Why not check for:
tcache->counts[tc_idx] != 0
> return true;
> else
> return false;
> @@ -3265,7 +3265,7 @@ tcache_free (mchunkptr p, INTERNAL_SIZE_T size)
> if (__glibc_unlikely (e->key == tcache_key))
> tcache_double_free_verify (e, tc_idx);
>
> - if (tcache->counts[tc_idx] < mp_.tcache_count)
> + if (tcache->counts[tc_idx] != 0)
You do it here.
> {
> tcache_put (p, tc_idx);
> done = true;
> @@ -3337,6 +3337,8 @@ tcache_init(void)
> {
> tcache = (tcache_perthread_struct *) victim;
> memset (tcache, 0, sizeof (tcache_perthread_struct));
> + for (int i = 0; i < TCACHE_MAX_BINS; i++)
> + tcache->counts[i] = mp_.tcache_count;
> }
>
> }
> @@ -4006,8 +4008,7 @@ _int_malloc (mstate av, size_t bytes)
> mchunkptr tc_victim;
>
> /* While bin not empty and tcache not full, copy chunks. */
> - while (tcache->counts[tc_idx] < mp_.tcache_count
> - && (tc_victim = *fb) != NULL)
> + while (tcache->counts[tc_idx] != 0 && (tc_victim = *fb) != NULL)
> {
> if (__glibc_unlikely (misaligned_chunk (tc_victim)))
> malloc_printerr ("malloc(): unaligned fastbin chunk detected 3");
> @@ -4067,8 +4068,7 @@ _int_malloc (mstate av, size_t bytes)
> mchunkptr tc_victim;
>
> /* While bin not empty and tcache not full, copy chunks over. */
> - while (tcache->counts[tc_idx] < mp_.tcache_count
> - && (tc_victim = last (bin)) != bin)
> + while (tcache->counts[tc_idx] != 0 && (tc_victim = last (bin)) != bin)
> {
> if (tc_victim != NULL)
> {
> @@ -4204,8 +4204,7 @@ _int_malloc (mstate av, size_t bytes)
> #if USE_TCACHE
> /* Fill cache first, return to user only if cache fills.
> We may return one of these chunks later. */
> - if (tcache_nb > 0
> - && tcache->counts[tc_idx] < mp_.tcache_count)
> + if (tcache_nb > 0 && tcache->counts[tc_idx] != 0)
> {
> tcache_put (victim, tc_idx);
> return_cached = 1;
>
>
More information about the Libc-alpha
mailing list