[PATCH] malloc: Count tcache entries downwards

DJ Delorie dj@redhat.com
Fri May 16 00:04:57 GMT 2025


tl;dr: needs to be rebased to head, and ->counts renamed, but logic is
OK.  LGTM with those changes.

Reviewed-by: DJ Delorie <dj@redhat.com>

Wilco Dijkstra <Wilco.Dijkstra@arm.com> writes:
> 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).

FYI this patch no longer applies to master (malloc.c is busy!  yay!) but
I'll review the code as-is.  I'll also ignore the request to rename
tcache->counts to something that reflects its new purpose, as we could
bikeshed that forever.

> @@ -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]);
>  }

tcache->counts is how many more chunks we can put on the list, so adding
something to the list (tcache_put) should reduce this number.  Ok.

> @@ -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;

This is the opposite (tcache_get) so should increment, since we're
"freeing" a slot.  Ok.

> @@ -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)
>      return true;
>    else
>      return false;

In this version, we protect pointers that are inside the chunks
(e->next) but not pointers outside of chunks (tcache->entries).
So the check here goes from "at least one chunk" to "list is not
empty".  Ok.

> @@ -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)
>  	{

This is testing for "can we put a chunk in tcache".  The new logic is
"has slots".  tcache->counts is a UINT16 so !=0 and >0 are semantically
the same here, so ok.

> @@ -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;
>      }

This is the size of tcache->counts; we initialize each to the tunable
value so we start with "count slots free."  Tunables are set by
ptmalloc_init, which is called from libc_early_init.c, so they'll be set
by this point.  Ok.

> @@ -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)
>  		    {

Ok.

> @@ -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)
>  		{

Ok.

> @@ -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)
>  		{

Ok.



More information about the Libc-alpha mailing list