The following improves release_pages when using the madvise path
to sort the freelist to get more page entries contiguous and possibly
release them.  This populates the unused prev pointer so the reclaim
can then easily unlink from the freelist without re-ordering it.
The paths not having madvise do not keep the memory allocated, so
I left them untouched.

Re-bootstrap and regtest running on x86_64-unknown-linux-gnu.

I've CCed people messing with release_pages;  This doesn't really
address PR114563 but I thought I post this patch anyway - the
actual issue we run into for the PR is the linear search of
G.free_pages when that list becomes large but a requested allocation
cannot be served from it.

        PR middle-end/114563
        * ggc-page.cc (page_sort): New qsort comparator.
        (release_pages): Sort the free_pages list entries after their
        memory block virtual address to improve contiguous memory
        chunk release.
---
 gcc/ggc-page.cc | 68 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 48 insertions(+), 20 deletions(-)

diff --git a/gcc/ggc-page.cc b/gcc/ggc-page.cc
index 4245f843a29..c9d8a8cd8e9 100644
--- a/gcc/ggc-page.cc
+++ b/gcc/ggc-page.cc
@@ -1010,6 +1010,19 @@ free_page (page_entry *entry)
   G.free_pages = entry;
 }
 
+/* Comparison function to sort page_entry after virtual address.  */
+
+static int
+page_sort (const void *pa_, const void *pb_)
+{
+  const page_entry *pa = *(const page_entry * const *)pa_;
+  const page_entry *pb = *(const page_entry * const *)pb_;
+  if ((uintptr_t)pa->page < (uintptr_t)pb->page)
+    return -1;
+  else
+    return 1;
+}
+
 /* Release the free page cache to the system.  */
 
 static void
@@ -1022,7 +1035,7 @@ release_pages (void)
   char *start;
   size_t len;
   size_t mapped_len;
-  page_entry *next, *prev, *newprev;
+  page_entry *prev;
   size_t free_unit = (GGC_QUIRE_SIZE/2) * G.pagesize;
 
   /* First free larger continuous areas to the OS.
@@ -1031,41 +1044,56 @@ release_pages (void)
      This does not always work because the free_pages list is only
      approximately sorted. */
 
-  p = G.free_pages;
+  auto_vec<page_entry *> pages;
   prev = NULL;
+  p = G.free_pages;
   while (p)
     {
+      p->prev = prev;
+      pages.safe_push (p);
+      prev = p;
+      p = p->next;
+    }
+  pages.qsort (page_sort);
+
+  for (unsigned i = 0; i < pages.length ();)
+    {
+      p = pages[i];
       start = p->page;
-      start_p = p;
+      unsigned start_i = i;
       len = 0;
       mapped_len = 0;
-      newprev = prev;
-      while (p && p->page == start + len)
+      while (i < pages.length () && pages[i]->page == start + len)
         {
+         p = pages[i];
           len += p->bytes;
          if (!p->discarded)
-             mapped_len += p->bytes;
-         newprev = p;
-          p = p->next;
+           mapped_len += p->bytes;
+         ++i;
         }
       if (len >= free_unit)
         {
-          while (start_p != p)
-            {
-              next = start_p->next;
-              free (start_p);
-              start_p = next;
-            }
+         for (unsigned j = start_i; j != i; ++j)
+           {
+             p = pages[j];
+             if (!p->prev)
+               {
+                 G.free_pages = p->next;
+                 if (p->next)
+                   p->next->prev = NULL;
+               }
+             else
+               {
+                 p->prev->next = p->next;
+                 if (p->next)
+                   p->next->prev = p->prev;
+               }
+             free (pages[j]);
+           }
           munmap (start, len);
-         if (prev)
-           prev->next = p;
-          else
-            G.free_pages = p;
           G.bytes_mapped -= mapped_len;
          n1 += len;
-         continue;
         }
-      prev = newprev;
    }
 
   /* Now give back the fragmented pages to the OS, but keep the address 
-- 
2.43.0

Reply via email to