[PATCH v2] malloc: Remove unused tcache code from unsorted bin scan

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Fri Feb 6 16:04:55 GMT 2026



On 06/02/26 12:29, Wilco Dijkstra wrote:
> Hi Adhemerval,
> 
>> Now that tcache_unsorted_limit is not used anywhere, I think it should be
>> removed from manual (manual/probes.texi and manual/tunables.texi), along
>> with the tunables definition (elf/dl-tunables.list) and related tests
>> (elf/tst-rtld-list-tunables.exp).
> 
> Good point, I've removed the remaining references in v2:
> 
> Now that fastbins have been removed, there is no need to add chunks
> to tcache during an unsorted scan.  Small blocks can only be added
> to unsorted as a result of a remainder chunk split off a larger block,
> so there is no point in checking for additional chunks to place in
> tcache.  The last remainder is checked first, and will be used if it
> is large enough or an exact fit.  The unsorted bin scan becomes simpler
> as a result.  Remove the tcache_unsorted_limit tunable and manual entries.
> 
> Passes regress, OK for commit?

LGTM, thanks.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> 
> ---
> 
> diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
> index 5bc5f037920d6db99bff4df513ac2ea3ae416b2a..040a544c0e0fe57c2205966412ea8589bb178189 100644
> --- a/elf/dl-tunables.list
> +++ b/elf/dl-tunables.list
> @@ -71,9 +71,6 @@ glibc {
>      tcache_count {
>        type: SIZE_T
>      }
> -    tcache_unsorted_limit {
> -      type: SIZE_T
> -    }
>      mxfast {
>        type: SIZE_T
>        minval: 0
> diff --git a/elf/tst-rtld-list-tunables.exp b/elf/tst-rtld-list-tunables.exp
> index 8df6f5906e6ccc1cc4094947e7084fbb8605dae3..9590021f3ae305a6088eaf81b106d2355b8da57a 100644
> --- a/elf/tst-rtld-list-tunables.exp
> +++ b/elf/tst-rtld-list-tunables.exp
> @@ -8,7 +8,6 @@ glibc.malloc.mxfast: 0x0 (min: 0x0, max: 0x[f]+)
>  glibc.malloc.perturb: 0 (min: 0, max: 255)
>  glibc.malloc.tcache_count: 0x0 (min: 0x0, max: 0x[f]+)
>  glibc.malloc.tcache_max: 0x0 (min: 0x0, max: 0x[f]+)
> -glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0x[f]+)
>  glibc.malloc.top_pad: 0x20000 (min: 0x0, max: 0x[f]+)
>  glibc.malloc.trim_threshold: 0x0 (min: 0x0, max: 0x[f]+)
>  glibc.rtld.dynamic_sort: 2 (min: 1, max: 2)
> diff --git a/malloc/arena.c b/malloc/arena.c
> index 5bfcd7f9723a8a6396ec53ea49bef5472fa28672..cabeb0d8ce1783121af3327ccd3371ab516b8722 100644
> --- a/malloc/arena.c
> +++ b/malloc/arena.c
> @@ -238,7 +238,6 @@ TUNABLE_CALLBACK_FNDECL (set_arena_test, size_t)
>  #if USE_TCACHE
>  TUNABLE_CALLBACK_FNDECL (set_tcache_max, size_t)
>  TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t)
> -TUNABLE_CALLBACK_FNDECL (set_tcache_unsorted_limit, size_t)
>  #endif
>  TUNABLE_CALLBACK_FNDECL (set_hugetlb, size_t)
>  
> @@ -290,8 +289,6 @@ __ptmalloc_init (void)
>  # if USE_TCACHE
>    TUNABLE_GET (tcache_max, size_t, TUNABLE_CALLBACK (set_tcache_max));
>    TUNABLE_GET (tcache_count, size_t, TUNABLE_CALLBACK (set_tcache_count));
> -  TUNABLE_GET (tcache_unsorted_limit, size_t,
> -	       TUNABLE_CALLBACK (set_tcache_unsorted_limit));
>  # endif
>    TUNABLE_GET (hugetlb, size_t, TUNABLE_CALLBACK (set_hugetlb));
>  
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index a49e211925ae6303d064b7e590fd015e85affe38..0ff016e549694f457c3fe090f3265d35f1d60e28 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -1797,9 +1797,6 @@ struct malloc_par
>    size_t tcache_max_bytes;
>    /* Maximum number of chunks in each bucket.  */
>    size_t tcache_count;
> -  /* Maximum number of chunks to remove from the unsorted list, which
> -     aren't used to prefill the cache.  */
> -  size_t tcache_unsorted_limit;
>  #endif
>  };
>  
> @@ -1832,7 +1829,6 @@ static struct malloc_par mp_ =
>    .tcache_count = TCACHE_FILL_COUNT,
>    .tcache_small_bins = TCACHE_SMALL_BINS,
>    .tcache_max_bytes = MAX_TCACHE_SMALL_SIZE + 1,
> -  .tcache_unsorted_limit = 0 /* No limit.  */
>  #endif
>  };
>  
> @@ -3824,10 +3820,6 @@ _int_malloc (mstate av, size_t bytes)
>    mchunkptr fwd;                    /* misc temp for linking */
>    mchunkptr bck;                    /* misc temp for linking */
>  
> -#if USE_TCACHE
> -  size_t tcache_unsorted_count;	    /* count of unsorted chunks processed */
> -#endif
> -
>    /*
>       Convert request size to internal form by adding SIZE_SZ bytes
>       overhead plus possibly more to obtain necessary alignment and/or
> @@ -3925,24 +3917,8 @@ _int_malloc (mstate av, size_t bytes)
>       the most recent non-exact fit.  Place other traversed chunks in
>       bins.  Note that this step is the only place in any routine where
>       chunks are placed in bins.
> -
> -     The outer loop here is needed because we might not realize until
> -     near the end of malloc that we should have consolidated, so must
> -     do so and retry. This happens at most once, and only when we would
> -     otherwise need to expand memory to service a "small" request.
>     */
>  
> -#if USE_TCACHE
> -  INTERNAL_SIZE_T tcache_nb = 0;
> -  size_t tc_idx = csize2tidx (nb);
> -  if (tc_idx < mp_.tcache_small_bins)
> -    tcache_nb = nb;
> -  int return_cached = 0;
> -
> -  tcache_unsorted_count = 0;
> -#endif
> -
> -  for (;; )
>      {
>        int iters = 0;
>        while ((victim = unsorted_chunks (av)->bk) != unsorted_chunks (av))
> @@ -4012,28 +3988,10 @@ _int_malloc (mstate av, size_t bytes)
>                set_inuse_bit_at_offset (victim, size);
>                if (av != &main_arena)
>  		set_non_main_arena (victim);
> -#if USE_TCACHE
> -	      if (__glibc_unlikely (tcache_inactive ()))
> -		tcache_init (av);
> -	      /* Fill cache first, return to user only if cache fills.
> -		 We may return one of these chunks later.  */
> -	      if (tcache_nb > 0
> -		  && tcache->num_slots[tc_idx] != 0)
> -		{
> -		  tcache_put (victim, tc_idx);
> -		  return_cached = 1;
> -		  continue;
> -		}
> -	      else
> -		{
> -#endif
>                check_malloced_chunk (av, victim, nb);
>                void *p = chunk2mem (victim);
>                alloc_perturb (p, bytes);
>                return p;
> -#if USE_TCACHE
> -		}
> -#endif
>              }
>  
>            /* Place chunk in bin.  Only splitting can put
> @@ -4107,31 +4065,11 @@ _int_malloc (mstate av, size_t bytes)
>            fwd->bk = victim;
>            bck->fd = victim;
>  
> -#if USE_TCACHE
> -      /* If we've processed as many chunks as we're allowed while
> -	 filling the cache, return one of the cached ones.  */
> -      ++tcache_unsorted_count;
> -      if (return_cached
> -	  && mp_.tcache_unsorted_limit > 0
> -	  && tcache_unsorted_count > mp_.tcache_unsorted_limit)
> -	{
> -	  return tcache_get (tc_idx);
> -	}
> -#endif
> -
>  #define MAX_ITERS       10000
>            if (++iters >= MAX_ITERS)
>              break;
>          }
>  
> -#if USE_TCACHE
> -      /* If all the small chunks we found ended up cached, return one now.  */
> -      if (return_cached)
> -	{
> -	  return tcache_get (tc_idx);
> -	}
> -#endif
> -
>        /*
>           If a large request, scan through the chunks of current bin in
>           sorted order to find smallest that fits.  Use the skip list for this.
> @@ -5114,13 +5052,6 @@ do_set_tcache_count (size_t value)
>    return 0;
>  }
>  
> -static __always_inline int
> -do_set_tcache_unsorted_limit (size_t value)
> -{
> -  LIBC_PROBE (memory_tunable_tcache_unsorted_limit, 2, value, mp_.tcache_unsorted_limit);
> -  mp_.tcache_unsorted_limit = value;
> -  return 1;
> -}
>  #endif
>  
>  static __always_inline int
> diff --git a/manual/probes.texi b/manual/probes.texi
> index ee019e651706f49253279b332edb7fc343a04183..23340e8e0774ae080bc6cecf0a916902c490f629 100644
> --- a/manual/probes.texi
> +++ b/manual/probes.texi
> @@ -235,13 +235,6 @@ tunable is set.  Argument @var{$arg1} is the requested value, and
>  @var{$arg2} is the previous value of this tunable.
>  @end deftp
>  
> -@deftp Probe memory_tunable_tcache_unsorted_limit (int @var{$arg1}, int @var{$arg2})
> -This probe is triggered when the
> -@code{glibc.malloc.tcache_unsorted_limit} tunable is set.  Argument
> -@var{$arg1} is the requested value, and @var{$arg2} is the previous
> -value of this tunable.
> -@end deftp
> -
>  @deftp Probe memory_tcache_double_free (void *@var{$arg1}, int @var{$arg2})
>  This probe is triggered when @code{free} determines that the memory
>  being freed has probably already been freed, and resides in the
> diff --git a/manual/tunables.texi b/manual/tunables.texi
> index 7956df919beeb0b05b93d942e8dd8938ecc4d018..cacc0ea65262f06eb8c7f8a40520d5d85444a171 100644
> --- a/manual/tunables.texi
> +++ b/manual/tunables.texi
> @@ -53,7 +53,6 @@ glibc.cpu.x86_shstk:
>  glibc.pthread.stack_cache_size: 0x2800000 (min: 0x0, max: 0xffffffffffffffff)
>  glibc.malloc.mmap_max: 0 (min: 0, max: 2147483647)
>  glibc.cpu.plt_rewrite: 0 (min: 0, max: 2)
> -glibc.malloc.tcache_unsorted_limit: 0x0 (min: 0x0, max: 0xffffffffffffffff)
>  glibc.cpu.x86_ibt:
>  glibc.cpu.hwcaps:
>  glibc.malloc.arena_max: 0x0 (min: 0x1, max: 0xffffffffffffffff)
> @@ -243,21 +242,6 @@ per-thread cache is approximately 236 KB on 64-bit systems and 118 KB
>  on 32-bit systems.
>  @end deftp
>  
> -@deftp Tunable glibc.malloc.tcache_unsorted_limit
> -When the user requests memory and the request cannot be met via the
> -per-thread cache, the arenas are used to meet the request.  At this
> -time, additional chunks will be moved from existing arena lists to
> -pre-fill the corresponding cache.  While copies from the fastbins,
> -smallbins, and regular bins are bounded and predictable due to the bin
> -sizes, copies from the unsorted bin are not bounded, and incur
> -additional time penalties as they need to be sorted as they're
> -scanned.  To make scanning the unsorted list more predictable and
> -bounded, the user may set this tunable to limit the number of chunks
> -that are scanned from the unsorted list while searching for chunks to
> -pre-fill the per-thread cache with.  The default, or when set to zero,
> -is no limit.
> -@end deftp
> -
>  @deftp Tunable glibc.malloc.mxfast
>  One of the optimizations @code{malloc} uses is to maintain a series of ``fast
>  bins'' that hold chunks up to a specific size.  The default and
> 



More information about the Libc-alpha mailing list