[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 <br...@clisp.org> 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; }