]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Free large chunks in ggc v2
authorAndi Kleen <ak@linux.intel.com>
Sat, 29 Oct 2011 01:01:54 +0000 (01:01 +0000)
committerAndi Kleen <ak@gcc.gnu.org>
Sat, 29 Oct 2011 01:01:54 +0000 (01:01 +0000)
This implements the freeing back of large chunks in the ggc madvise path
Richard Guenther asked for.  This way on systems with limited
address space malloc() and other allocators still have
a chance to get back at some of the memory ggc freed. The
fragmented pages are still just given back, but the address space
stays allocated.

I tried freeing only aligned 2MB areas to optimize for 2MB huge
pages, but the hit rate was quite low, so I switched to 1MB+
unaligned areas.

v2: Hardcode free unit size instead of param

gcc/:
2011-10-18  Andi Kleen  <ak@linux.intel.com>

* ggc-page (release_pages): First free large continuous
chunks in the madvise path.

From-SVN: r180648

gcc/ChangeLog
gcc/ggc-page.c

index 65df15b4005a369241045b5a5f61f080b7429987..3b2473463b54a4018b6f6dc879b032a5a9945df5 100644 (file)
@@ -1,3 +1,8 @@
+2011-10-18  Andi Kleen  <ak@linux.intel.com>
+
+       * ggc-page (release_pages): First free large continuous
+       chunks in the madvise path.
+
 2011-10-18  Andi Kleen  <ak@linux.intel.com>
 
        * ggc-page.c (alloc_pages): Always round up entry_size.
index 077bc8e2beef5d54118ba7dc4d12cab0ca16f39f..7bef4c02d34854a6e55674ac4c51f3553752bd90 100644 (file)
@@ -973,6 +973,54 @@ release_pages (void)
   page_entry *p, *start_p;
   char *start;
   size_t len;
+  size_t mapped_len;
+  page_entry *next, *prev, *newprev;
+  size_t free_unit = (GGC_QUIRE_SIZE/2) * G.pagesize;
+
+  /* First free larger continuous areas to the OS.
+     This allows other allocators to grab these areas if needed.
+     This is only done on larger chunks to avoid fragmentation. 
+     This does not always work because the free_pages list is only
+     approximately sorted. */
+
+  p = G.free_pages;
+  prev = NULL;
+  while (p)
+    {
+      start = p->page;
+      start_p = p;
+      len = 0;
+      mapped_len = 0;
+      newprev = prev;
+      while (p && p->page == start + len)
+        {
+          len += p->bytes;
+         if (!p->discarded)
+             mapped_len += p->bytes;
+         newprev = p;
+          p = p->next;
+        }
+      if (len >= free_unit)
+        {
+          while (start_p != p)
+            {
+              next = start_p->next;
+              free (start_p);
+              start_p = next;
+            }
+          munmap (start, len);
+         if (prev)
+           prev->next = p;
+          else
+            G.free_pages = p;
+          G.bytes_mapped -= mapped_len;
+         continue;
+        }
+      prev = newprev;
+   }
+
+  /* Now give back the fragmented pages to the OS, but keep the address 
+     space to reuse it next time. */
 
   for (p = G.free_pages; p; )
     {