[Dropping libvir-list]
Eric Blake wrote:
> >> If gnulib would give
> >> us posix_memalign on mingw, we could nuke this #if altogether.
> >
> > That's pretty difficult (unless you also add a posix_memalign_free)
> > because at the time posix_memalign returns you have lost the base
> > pointer for free().
>
> Providing a posix_memalign_free defeats the purpose - POSIX requires
> that plain free() will cover the memory returned by posix_memalign. The
> list of platforms missing posix_memalign is a bit daunting:
>
> MacOS X 10.5, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1,
> HP-UX 11,
> IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 1.5.x, mingw, MSVC 9, Interix 3.5,
> BeOS.
>
> but what would be interesting to know is how many of those platforms
> return page-aligned pointers for any malloc() request of a page or more
> of memory.
Tested with the attached program:
MacOS X 10.5 page-aligned for size >= 4 * pagesize
FreeBSD 6.4 page-aligned for size >= pagesize - 16
NetBSD 5.1 page-aligned for size >= pagesize - 16
OpenBSD 4.9 page-aligned for size >= pagesize
Minix 3.1.8 not page-aligned at all
AIX 5.1 not page-aligned at all
HP-UX 11 not page-aligned at all
IRIX 6.5 not page-aligned at all
OSF/1 5.1 not page-aligned at all
Solaris 10 not page-aligned at all
Cygwin 1.5.x not page-aligned at all
mingw not page-aligned at all
MSVC 9 not page-aligned at all
Interix 3.5 -- likely the same as MSVC.
BeOS -- likely the same as glibc: not page-aligned at all
I tried a posix_memalign() implementation that assumes that if
p = malloc(n) and p < q < p + n, free(q) will be equivalent to free(p).
Results:
MacOS X 10.5 many error messages
FreeBSD 6.4 many error messages
NetBSD 5.1 crashes
OpenBSD 4.9 crashes
Minix 3.1.8 crashes
AIX 5.1 crashes
HP-UX 11 crashes
IRIX 6.5 crashes
OSF/1 5.1 runs out of memory, process cannot be killed with "kill -9"
Solaris 10 leaks memory
Cygwin 1.5.x crashes
mingw leaks memory, hangs
MSVC 9 leaks memory
So, there doesn't seem to be an avenue in second-guessing how the malloc()
implementation works internally.
> That is, we may be able to coerce malloc into aligned
> results by over-allocating and over-aligning the user's request, if the
> system malloc() has at least one mode of returning page-aligned memory.
However, over-allocating wastes memory. We have a 'pagealign_alloc' module
that does not waste memory.
> Another alternative is to override free() at the same time as providing
> posix_memalign().
I wouldn't like to slow down free(), which is used in many places, for the
sake of posix_memalign() (as opposed to pagealign_alloc()) which is rarely
used.
Bruno
2011-11-25 Bruno Haible <[email protected]>
pagealign_alloc: Doc and comments.
* doc/posix-functions/posix_memalign.texi: Refer to the pagealign_alloc
module.
* lib/pagealign_alloc.c (pagealign_alloc): Add comment.
--- doc/posix-functions/posix_memalign.texi.orig Fri Nov 25 22:29:43 2011
+++ doc/posix-functions/posix_memalign.texi Fri Nov 25 22:19:11 2011
@@ -17,3 +17,6 @@
MacOS X 10.5, FreeBSD 6.0, NetBSD 3.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1,
HP-UX 11,
IRIX 6.5, OSF/1 5.1, Solaris 10, Cygwin 1.5.x, mingw, MSVC 9, Interix 3.5,
BeOS.
@end itemize
+
+The Gnulib module @code{pagealign_alloc} provides a similar API
+that returns memory aligned on a system page boundary.
--- lib/pagealign_alloc.c.orig Fri Nov 25 22:29:43 2011
+++ lib/pagealign_alloc.c Fri Nov 25 22:29:26 2011
@@ -123,6 +123,9 @@
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
# ifdef HAVE_MAP_ANONYMOUS
const int fd = -1;
--
In memoriam Valentín Elizalde <http://en.wikipedia.org/wiki/Valentín_Elizalde>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main ()
{
static int fib[] =
{ 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578 };
int pagesize = getpagesize();
int block_sizes[16];
int i;
printf ("pagesize = 0x%X\n", pagesize);
block_sizes[0] = pagesize / 4;
block_sizes[1] = pagesize / 2 - 16;
block_sizes[2] = pagesize / 2;
block_sizes[3] = pagesize - 16;
block_sizes[4] = pagesize;
block_sizes[5] = pagesize * 3 / 2;
block_sizes[6] = pagesize * 2;
block_sizes[7] = pagesize * 5 / 2;
block_sizes[8] = pagesize * 3;
block_sizes[9] = pagesize * 4;
block_sizes[10] = pagesize * 5;
block_sizes[11] = pagesize * 8;
block_sizes[12] = pagesize * 9;
block_sizes[13] = pagesize * 16;
block_sizes[14] = pagesize * 17;
block_sizes[15] = pagesize * 32;
for (i = 0; i < sizeof(fib)/sizeof(fib[0]); i++)
{
void *new_block = malloc (fib[i]);
int j;
printf ("After allocating %d bytes:\n", fib[i]);
for (j = 0; j < sizeof(block_sizes)/sizeof(block_sizes[0]); j++)
{
int block_size = block_sizes[j];
void *p = malloc (block_size);
printf (" size=0x%05X -> 0x%08lX\n", block_size, (unsigned long) p);
free (p);
}
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main ()
{
static int fib[] =
{ 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578 };
int pagesize = getpagesize();
int block_sizes[16];
int i;
printf ("pagesize = 0x%X\n", pagesize);
block_sizes[0] = pagesize / 4;
block_sizes[1] = pagesize / 2 - 16;
block_sizes[2] = pagesize / 2;
block_sizes[3] = pagesize - 16;
block_sizes[4] = pagesize;
block_sizes[5] = pagesize * 3 / 2;
block_sizes[6] = pagesize * 2;
block_sizes[7] = pagesize * 5 / 2;
block_sizes[8] = pagesize * 3;
block_sizes[9] = pagesize * 4;
block_sizes[10] = pagesize * 5;
block_sizes[11] = pagesize * 8;
block_sizes[12] = pagesize * 9;
block_sizes[13] = pagesize * 16;
block_sizes[14] = pagesize * 17;
block_sizes[15] = pagesize * 32;
for (i = 0; i < sizeof(fib)/sizeof(fib[0]); i++)
{
void *new_block = malloc (fib[i]);
int j;
printf ("After allocating %d bytes:\n", fib[i]);
for (j = 0; j < sizeof(block_sizes)/sizeof(block_sizes[0]); j++)
{
int block_size = block_sizes[j];
int k;
printf (" size=0x%05X ->", block_size);
for (k = 0; k < 100; k++)
{
void *p = (void *) (((unsigned long) malloc (block_size + pagesize - 1) | (pagesize - 1)) + 1);
if ((k % 25) == 0)
printf (" 0x%08lX", (unsigned long) p);
free (p);
}
printf ("\n");
}
}
return 0;
}