[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