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