On 2025-09-10 17:19, Harry Sintonen wrote:
pagealign code (lib/pagealign_alloc.c) has a mistake whereas USE_MMAP code uses the linked list to maintain the memory allocations. This is unnessary as mmap() always returns memory aligned to the page size. Thus the buffer could be passed as-is, similar to what HAVE_POSIX_MEMALIGN code is doing

But then how would pagealign_free (PTR) know what size to pass when it calls munmap (PTR, SIZE)?

You've hit on a severe scaling problem with pagealign_alloc. Thanks for reporting it. From the symptoms you described, I fixed the performance bug by installing the attached patch, which simply prefers posix_memalign to mmap. Although mmap can outperform posix_memalign, evidently that win is small compared to the loss you mention. Plus, the posix_memalign solution is thread-safe.

Although we could instead (or also) try to optimize the mmap (or even the malloc) cases I wonder whether it's worth the hassle nowadays. More likely there are platforms where using C11-style aligned_alloc would be a performance win. That would be easy to add, if there's a need.
From 7c96b402be00117225a6943ab53bb9e5e6e2c02b Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email protected]>
Date: Wed, 10 Sep 2025 18:23:58 -0700
Subject: [PATCH] pagealign_alloc: prefer posix_memalign

Problem reported by Harry Sintonen in:
https://lists.gnu.org/r/bug-gnulib/2025-09/msg00108.html
* lib/pagealign_alloc.c (info_t, memnode_t, struct memnode_s)
(memnode_table, new_memnode, get_memnode):
Omit if HAVE_POSIX_MEMALIGN, even if HAVE_MMAP.
(pagealign_alloc, pagealign_free): Prefer posix_memalign to mmap.
---
 ChangeLog             | 10 ++++++++++
 lib/pagealign_alloc.c | 31 ++++++++++++++++---------------
 2 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index b85b67cf98..2fb14e6f2a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2025-09-10  Paul Eggert  <[email protected]>
+
+	pagealign_alloc: prefer posix_memalign
+	Problem reported by Harry Sintonen in:
+	https://lists.gnu.org/r/bug-gnulib/2025-09/msg00108.html
+	* lib/pagealign_alloc.c (info_t, memnode_t, struct memnode_s)
+	(memnode_table, new_memnode, get_memnode):
+	Omit if HAVE_POSIX_MEMALIGN, even if HAVE_MMAP.
+	(pagealign_alloc, pagealign_free): Prefer posix_memalign to mmap.
+
 2025-09-10  Bruno Haible  <[email protected]>
 
 	Remove support for IRIX.
diff --git a/lib/pagealign_alloc.c b/lib/pagealign_alloc.c
index 06aad1ee52..fdfffb4514 100644
--- a/lib/pagealign_alloc.c
+++ b/lib/pagealign_alloc.c
@@ -46,7 +46,7 @@
 #endif
 
 
-#if HAVE_MMAP || ! HAVE_POSIX_MEMALIGN
+#if ! HAVE_POSIX_MEMALIGN
 
 # if HAVE_MMAP
 /* For each memory region, we store its size.  */
@@ -108,29 +108,30 @@ get_memnode (void *aligned_ptr)
   return ret;
 }
 
-#endif /* HAVE_MMAP || !HAVE_POSIX_MEMALIGN */
+#endif /* !HAVE_POSIX_MEMALIGN */
 
 
 void *
 pagealign_alloc (size_t size)
 {
   void *ret;
-  /* We prefer the mmap() approach over the posix_memalign() or malloc()
-     based approaches, since the latter often waste an entire memory page
-     per call.  */
-#if HAVE_MMAP
-  ret = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE,
-              -1, 0);
-  if (ret == MAP_FAILED)
-    return NULL;
-  new_memnode (ret, size);
-#elif HAVE_POSIX_MEMALIGN
+#if HAVE_POSIX_MEMALIGN
+  /* Prefer posix_memalign to malloc and mmap,
+     as it typically scales better when there are many allocations.  */
   int status = posix_memalign (&ret, getpagesize (), size);
   if (status)
     {
       errno = status;
       return NULL;
     }
+#elif HAVE_MMAP
+  /* Prefer mmap to malloc, since the latter often wastes an entire
+     memory page per call.  */
+  ret = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE,
+              -1, 0);
+  if (ret == MAP_FAILED)
+    return NULL;
+  new_memnode (ret, size);
 #else /* !HAVE_MMAP && !HAVE_POSIX_MEMALIGN */
   size_t pagesize = getpagesize ();
   void *unaligned_ptr = malloc (size + pagesize - 1);
@@ -164,11 +165,11 @@ pagealign_xalloc (size_t size)
 void
 pagealign_free (void *aligned_ptr)
 {
-#if HAVE_MMAP
+#if HAVE_POSIX_MEMALIGN
+  free (aligned_ptr);
+#elif HAVE_MMAP
   if (munmap (aligned_ptr, get_memnode (aligned_ptr)) < 0)
     error (EXIT_FAILURE, errno, "Failed to unmap memory");
-#elif HAVE_POSIX_MEMALIGN
-  free (aligned_ptr);
 #else
   free (get_memnode (aligned_ptr));
 #endif
-- 
2.48.1

Reply via email to