Allow hugetlbfs_morecore to shrink the heap.

Signed-off-by: Andrew Hastings <[EMAIL PROTECTED]> on behalf of Cray Inc.
---
I've run the test suite with this on x86_64 and PPC64.

 morecore.c         |   83 +++++++++++++++++++++++++++++++++++------------------
 tests/Makefile     |    2 -
 tests/heapshrink.c |   48 ++++++++++++++++++++++++++++++
 tests/run_tests.sh |    2 +
 4 files changed, 107 insertions(+), 28 deletions(-)

diff -ruNp libhugetlbfs-1.2/morecore.c libhugetlbfs-1.2-shrink/morecore.c
--- libhugetlbfs-1.2/morecore.c 2007-09-10 08:27:44.000000000 -0500
+++ libhugetlbfs-1.2-shrink/morecore.c  2007-11-02 17:32:04.753331000 -0500
@@ -70,7 +70,7 @@ static void *hugetlbfs_morecore(ptrdiff_
 {
        int ret;
        void *p;
-       long newsize = 0;
+       long delta;
 
        DEBUG("hugetlbfs_morecore(%ld) = ...\n", (long)increment);
 
@@ -78,23 +78,21 @@ static void *hugetlbfs_morecore(ptrdiff_
         * how much to grow the heap by =
         *      (size of heap) + malloc request - mmap'd space
         */
-       newsize = (heaptop-heapbase) + increment - mapsize;
+       delta = (heaptop-heapbase) + increment - mapsize;
 
-       DEBUG("heapbase = %p, heaptop = %p, mapsize = %lx, newsize=%ld\n",
-             heapbase, heaptop, mapsize, newsize);
+       DEBUG("heapbase = %p, heaptop = %p, mapsize = %lx, delta=%ld\n",
+             heapbase, heaptop, mapsize, delta);
 
-       /* growing the heap */
-       if (newsize > 0) {
-               /*
-                * convert our request to a multiple of hugepages
-                * we will have more space allocated then used, basically
-                */
-               newsize = ALIGN(newsize, blocksize);
+       /* align to multiple of hugepagesize. */
+       delta = ALIGN(delta, blocksize);
 
-               DEBUG("Attempting to map %ld bytes\n", newsize);
+       if (delta > 0) {
+               /* growing the heap */
+
+               DEBUG("Attempting to map %ld bytes\n", delta);
 
                /* map in (extend) more of the file at the end of our last map 
*/
-               p = mmap(heapbase + mapsize, newsize, PROT_READ|PROT_WRITE,
+               p = mmap(heapbase + mapsize, delta, PROT_READ|PROT_WRITE,
                         MAP_PRIVATE, heap_fd, mapsize);
                if (p == MAP_FAILED) {
                        WARNING("Mapping failed in hugetlbfs_morecore()\n");
@@ -110,7 +108,7 @@ static void *hugetlbfs_morecore(ptrdiff_
                        heapbase = heaptop = p;
                } else if (p != (heapbase + mapsize)) {
                        /* Couldn't get the mapping where we wanted */
-                       munmap(p, newsize);
+                       munmap(p, delta);
                        WARNING("Mapped at %p instead of %p in 
hugetlbfs_morecore()\n",
                              p, heapbase + mapsize);
                        return NULL;
@@ -123,17 +121,57 @@ static void *hugetlbfs_morecore(ptrdiff_
                 * appropriate policy for hugepage allocation */
 
                /* Use mlock to guarantee these pages to the process */
-               ret = mlock(p, newsize);
+               ret = mlock(p, delta);
                if (ret) {
                        WARNING("Failed to reserve huge pages in "
                                        "hugetlbfs_morecore(): %s\n",
                                        strerror(errno));
                } else {
-                       munlock(p, newsize);
+                       munlock(p, delta);
                }
 
                /* we now have mmap'd further */
-               mapsize += newsize;
+               mapsize += delta;
+       } else if (delta < 0) {
+               /* shrinking the heap */
+
+               if (!mapsize) {
+                       WARNING("Can't shrink empty heap!");
+                       return NULL;
+               }
+
+               /*
+                * If we are forced to change the heapaddr from the
+                * original brk() value we have violated brk semantics
+                * (which we are not supposed to do).  This shouldn't
+                * pose a problem until glibc tries to trim the heap to an
+                * address lower than what we aligned heapaddr to.  At that
+                * point the alignment "gap" causes heap corruption.
+                * So we don't allow the heap to shrink below heapbase.
+                */
+               if (mapsize + delta < 0) {
+                       WARNING("Unable to shrink heap below %p\n", heapbase);
+                       delta = -mapsize;
+                       increment = heapbase - heaptop;
+               }
+               DEBUG("Attempting to unmap %ld bytes @ %p\n", -delta,
+                       heapbase + mapsize + delta);
+               ret = munmap(heapbase + mapsize + delta, -delta);
+               if (ret) {
+                       WARNING("Unmapping failed in hugetlbfs_morecore()\n");
+               } else {
+
+                       /*
+                        * Now shrink the hugetlbfs file.
+                        */
+                       mapsize += delta;
+                       ret = ftruncate(heap_fd, mapsize);
+                       if (ret) {
+                               WARNING("Couldn't toss pages in "
+                                       "hugetlbfs_morecore()\n");
+                       }
+               }
+
        }
 
        /* heap is continuous */
@@ -191,16 +229,7 @@ static void __attribute__((constructor))
 
        /* Set some allocator options more appropriate for hugepages */
        
-       /* XXX: This morecore implementation does not support trimming!
-        * If we are forced to change the heapaddr from the original brk()
-        * value we have violated brk semantics (which we are not supposed to
-        * do).  This shouldn't pose a problem until glibc tries to trim the
-        * heap to an address lower than what we aligned heapaddr to.  At that
-        * point the alignment "gap" causes heap corruption.
-        *
-        * So, for now, disable heap trimming.
-        */
-       mallopt(M_TRIM_THRESHOLD, -1);
+       mallopt(M_TRIM_THRESHOLD, blocksize / 2);
        mallopt(M_TOP_PAD, blocksize / 2);
        /* we always want to use our morecore, not ordinary mmap().
         * This doesn't appear to prohibit malloc() from falling back
diff -ruNp libhugetlbfs-1.2/tests/Makefile 
libhugetlbfs-1.2-shrink/tests/Makefile
--- libhugetlbfs-1.2/tests/Makefile     2007-09-10 08:27:44.000000000 -0500
+++ libhugetlbfs-1.2-shrink/tests/Makefile      2007-11-01 17:51:18.000000000 
-0500
@@ -9,7 +9,7 @@ LIB_TESTS = gethugepagesize test_root fi
        misaligned_offset brk_near_huge task-size-overrun stack_grow_into_huge
 LIB_TESTS_64 = straddle_4GB huge_at_4GB_normal_below \
        huge_below_4GB_normal_above
-NOLIB_TESTS = malloc malloc_manysmall dummy
+NOLIB_TESTS = malloc malloc_manysmall dummy heapshrink
 LDSCRIPT_TESTS = zero_filesize_segment
 HUGELINK_TESTS = linkhuge linkhuge_nofd linkshare
 STRESS_TESTS = mmap-gettest mmap-cow shm-gettest shm-getraw shm-fork
diff -ruNp libhugetlbfs-1.2/tests/heapshrink.c 
libhugetlbfs-1.2-shrink/tests/heapshrink.c
--- libhugetlbfs-1.2/tests/heapshrink.c 1969-12-31 18:00:00.000000000 -0600
+++ libhugetlbfs-1.2-shrink/tests/heapshrink.c  2007-11-02 14:56:11.386121000 
-0500
@@ -0,0 +1,48 @@
+/*
+ * Test heap shrinking for libhugetlbfs.
+ * Copyright 2007 Cray Inc.  All rights reserved.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "hugetests.h"
+
+#define        SIZE    (32 * 1024 * 1024)
+
+int main(int argc, char **argv)
+{
+       int is_huge, have_env;
+       void *p;
+
+       test_init(argc, argv);
+
+       have_env = getenv("HUGETLB_MORECORE") != NULL;
+
+       p = malloc(SIZE);
+       memset(p, 0, SIZE);
+       is_huge = test_addr_huge(p+SIZE-1) == 1;
+       if (have_env && !is_huge)
+               FAIL("Heap not on hugepages");
+       if (!have_env && is_huge)
+               FAIL("Heap unexpectedly on hugepages");
+
+       free(p);
+       if (test_addr_huge(p+SIZE-1) == 1)
+               FAIL("Heap did not shrink");
+       PASS();
+}
diff -ruNp libhugetlbfs-1.2/tests/run_tests.sh 
libhugetlbfs-1.2-shrink/tests/run_tests.sh
--- libhugetlbfs-1.2/tests/run_tests.sh 2007-09-10 08:27:44.000000000 -0500
+++ libhugetlbfs-1.2-shrink/tests/run_tests.sh  2007-11-01 17:51:18.000000000 
-0500
@@ -167,6 +167,8 @@ functional_tests () {
     preload_test HUGETLB_MORECORE=yes malloc
     run_test malloc_manysmall
     preload_test HUGETLB_MORECORE=yes malloc_manysmall
+    run_test heapshrink
+    preload_test HUGETLB_MORECORE=yes heapshrink
     elflink_test HUGETLB_VERBOSE=0 linkhuge_nofd # Lib error msgs expected
     elflink_test linkhuge
 

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Libhugetlbfs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel

Reply via email to