On Sun, Oct 9, 2011 at 9:55 PM, Andi Kleen <a...@firstfloor.org> wrote: > From: Andi Kleen <a...@linux.intel.com> > > Use the Linux MADV_DONTNEED call to unmap free pages in the garbage > collector.Then keep the unmapped pages in the free list. This avoid > excessive memory fragmentation on large LTO bulds, which can lead > to gcc bumping into the Linux vm_max_map limit per process. > > Based on a idea from Jakub.
Shouldn't we prefer still "mapped" pages when allocating? Thus, keep the freepages list "sorted"? With the new params to call release_pages less, how does this interact with using MADV_DONTNEED? The only reason to delay MADV_DONTNEED is to avoid splitting huge-pages? Which would mean that we should rather be better at controlling where we allocate from from the free-list? Richard. > gcc/: > > 2011-10-08 Andi Kleen <a...@linux.intel.com> > > PR other/50636 > * config.in, configure: Regenerate. > * configure.ac (madvise): Add to AC_CHECK_FUNCS. > * ggc-page.c (USING_MADVISE): Add. > (page_entry): Add unmapped field. > (alloc_page): Check for unmapped pages. > (release_pages): Add USING_MADVISE branch. > --- > gcc/config.in | 6 ++++++ > gcc/configure | 2 +- > gcc/configure.ac | 2 +- > gcc/ggc-page.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- > 4 files changed, 55 insertions(+), 3 deletions(-) > > diff --git a/gcc/config.in b/gcc/config.in > index f2847d8..e8148b6 100644 > --- a/gcc/config.in > +++ b/gcc/config.in > @@ -1276,6 +1276,12 @@ > #endif > > > +/* Define to 1 if you have the `madvise' function. */ > +#ifndef USED_FOR_TARGET > +#undef HAVE_MADVISE > +#endif > + > + > /* Define to 1 if you have the <malloc.h> header file. */ > #ifndef USED_FOR_TARGET > #undef HAVE_MALLOC_H > diff --git a/gcc/configure b/gcc/configure > index cb55dda..4a54adf 100755 > --- a/gcc/configure > +++ b/gcc/configure > @@ -9001,7 +9001,7 @@ fi > for ac_func in times clock kill getrlimit setrlimit atoll atoq \ > sysconf strsignal getrusage nl_langinfo \ > gettimeofday mbstowcs wcswidth mmap setlocale \ > - clearerr_unlocked feof_unlocked ferror_unlocked fflush_unlocked > fgetc_unlocked fgets_unlocked fileno_unlocked fprintf_unlocked > fputc_unlocked fputs_unlocked fread_unlocked fwrite_unlocked > getchar_unlocked getc_unlocked putchar_unlocked putc_unlocked > + clearerr_unlocked feof_unlocked ferror_unlocked fflush_unlocked > fgetc_unlocked fgets_unlocked fileno_unlocked fprintf_unlocked > fputc_unlocked fputs_unlocked fread_unlocked fwrite_unlocked > getchar_unlocked getc_unlocked putchar_unlocked putc_unlocked madvise > do : > as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` > ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" > diff --git a/gcc/configure.ac b/gcc/configure.ac > index a7b94e6..357902e 100644 > --- a/gcc/configure.ac > +++ b/gcc/configure.ac > @@ -1027,7 +1027,7 @@ define(gcc_UNLOCKED_FUNCS, clearerr_unlocked > feof_unlocked dnl > AC_CHECK_FUNCS(times clock kill getrlimit setrlimit atoll atoq \ > sysconf strsignal getrusage nl_langinfo \ > gettimeofday mbstowcs wcswidth mmap setlocale \ > - gcc_UNLOCKED_FUNCS) > + gcc_UNLOCKED_FUNCS madvise) > > if test x$ac_cv_func_mbstowcs = xyes; then > AC_CACHE_CHECK(whether mbstowcs works, gcc_cv_func_mbstowcs_works, > diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c > index 624f029..b0b3b3f 100644 > --- a/gcc/ggc-page.c > +++ b/gcc/ggc-page.c > @@ -50,6 +50,10 @@ along with GCC; see the file COPYING3. If not see > #define USING_MALLOC_PAGE_GROUPS > #endif > > +#if defined(HAVE_MADVISE) && defined(MADV_DONTNEED) > +# define USING_MADVISE > +#endif > + > /* Strategy: > > This garbage-collecting allocator allocates objects on one of a set > @@ -277,6 +281,9 @@ typedef struct page_entry > /* The lg of size of objects allocated from this page. */ > unsigned char order; > > + /* Unmapped page? */ > + bool unmapped; > + > /* A bit vector indicating whether or not objects are in use. The > Nth bit is one if the Nth object on this page is allocated. This > array is dynamically sized. */ > @@ -740,6 +747,10 @@ alloc_page (unsigned order) > > if (p != NULL) > { > + if (p->unmapped) > + G.bytes_mapped += p->bytes; > + p->unmapped = false; > + > /* Recycle the allocated memory from this page ... */ > *pp = p->next; > page = p->page; > @@ -956,7 +967,42 @@ free_page (page_entry *entry) > static void > release_pages (void) > { > -#ifdef USING_MMAP > +#ifdef USING_MADVISE > + page_entry *p, *start_p; > + char *start; > + size_t len; > + > + for (p = G.free_pages; p; ) > + { > + if (p->unmapped) > + { > + p = p->next; > + continue; > + } > + start = p->page; > + len = p->bytes; > + start_p = p; > + p = p->next; > + while (p && p->page == start + len) > + { > + len += p->bytes; > + p = p->next; > + } > + /* Give the page back to the kernel, but don't free the mapping. > + This avoids fragmentation in the virtual memory map of the > + process. Next time we can reuse it by just touching it. */ > + madvise (start, len, MADV_DONTNEED); > + /* Don't count those pages as mapped to not touch the garbage collector > + unnecessarily. */ > + G.bytes_mapped -= len; > + while (start_p != p) > + { > + start_p->unmapped = true; > + start_p = start_p->next; > + } > + } > +#endif > +#if defined(USING_MMAP) && !defined(USING_MADVISE) > page_entry *p, *next; > char *start; > size_t len; > -- > 1.7.5.4 > >