[PATCH] malloc: Cleanup tcache_init()

Wilco Dijkstra Wilco.Dijkstra@arm.com
Thu Apr 3 22:16:48 GMT 2025


Cleanup tcache_init() by using the new __libc_malloc2 interface.
Move the tcache initialization check in __libc_malloc by using a
small tailcalled veneer.  Performance on bench-malloc-simple improves
by 0.6%, bench-malloc-thread by ~0.2% for 1 thread and ~0% for 32.

---

diff --git a/malloc/malloc.c b/malloc/malloc.c
index a0bc733482532ce34684d0357cb9076b03ac8a52..a175901db55452e7ced423270e357b5ca48cd6fd 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -588,9 +588,11 @@ tag_at (void *ptr)
   differs across systems, but is in all cases less than the maximum
   representable value of a size_t.
 */
-void*  __libc_malloc(size_t);
+void *__libc_malloc (size_t);
 libc_hidden_proto (__libc_malloc)
 
+static void *__libc_malloc2 (size_t);
+
 /*
   free(void* p)
   Releases the chunk of memory pointed to by p, that had been previously
@@ -3309,36 +3311,26 @@ tcache_thread_shutdown (void)
 static void
 tcache_init(void)
 {
-  mstate ar_ptr;
-  void *victim = NULL;
-  const size_t bytes = sizeof (tcache_perthread_struct);
-
   if (tcache_shutting_down)
     return;
 
-  arena_get (ar_ptr, bytes);
-  victim = _int_malloc (ar_ptr, bytes);
-  if (!victim && ar_ptr != NULL)
-    {
-      ar_ptr = arena_get_retry (ar_ptr, bytes);
-      victim = _int_malloc (ar_ptr, bytes);
-    }
-
-
-  if (ar_ptr != NULL)
-    __libc_lock_unlock (ar_ptr->mutex);
+  size_t bytes = sizeof (tcache_perthread_struct);
+  tcache = (tcache_perthread_struct *) __libc_malloc2 (bytes);
 
   /* In a low memory situation, we may not be able to allocate memory
      - in which case, we just keep trying later.  However, we
      typically do this very early, so either there is sufficient
      memory, or there isn't enough memory to do non-trivial
      allocations anyway.  */
-  if (victim)
-    {
-      tcache = (tcache_perthread_struct *) victim;
-      memset (tcache, 0, sizeof (tcache_perthread_struct));
-    }
+  if (tcache)
+    memset (tcache, 0, sizeof (tcache_perthread_struct));
+}
 
+static void * __attribute_noinline__
+tcache_malloc_init (size_t bytes)
+{
+  tcache_init ();
+  return __libc_malloc2 (bytes);
 }
 
 # define MAYBE_INIT_TCACHE() \
@@ -3393,8 +3385,6 @@ __libc_malloc2 (size_t bytes)
   if (!__malloc_initialized)
     ptmalloc_init ();
 
-  MAYBE_INIT_TCACHE ();
-
   if (SINGLE_THREAD_P)
     {
       victim = tag_new_usable (_int_malloc (&main_arena, bytes));
@@ -3430,9 +3420,14 @@ __libc_malloc (size_t bytes)
 {
 #if USE_TCACHE
   size_t tc_idx = csize2tidx (checked_request2size (bytes));
+  if (__glibc_likely (tc_idx < mp_.tcache_bins))
+    {
+      if (__glibc_unlikely (tcache == NULL))
+	return tcache_malloc_init (bytes);
 
-  if (tcache_available (tc_idx))
-    return tag_new_usable (tcache_get (tc_idx));
+      if (__glibc_likely (tcache->counts[tc_idx] > 0))
+	return tag_new_usable (tcache_get (tc_idx));
+    }
 #endif
 
   return __libc_malloc2 (bytes);



More information about the Libc-alpha mailing list