From 3b3197ecc60b52bcab92e0775f544e8533bf7d72 Mon Sep 17 00:00:00 2001 From: Kevin Tew Date: Wed, 5 Nov 2008 21:04:54 +0000 Subject: [PATCH] Reorg of gc2/vm_* and alloc_cache svn: r12255 --- src/mzscheme/gc2/alloc_cache.c | 164 +++++++++++++++++++++++++-------- src/mzscheme/gc2/vm_mmap.c | 111 ++++------------------ src/mzscheme/gc2/vm_osk.c | 1 - src/mzscheme/gc2/vm_osx.c | 64 +------------ 4 files changed, 150 insertions(+), 190 deletions(-) diff --git a/src/mzscheme/gc2/alloc_cache.c b/src/mzscheme/gc2/alloc_cache.c index bdd057cd1d..4cc8914155 100644 --- a/src/mzscheme/gc2/alloc_cache.c +++ b/src/mzscheme/gc2/alloc_cache.c @@ -13,10 +13,36 @@ ACTUALLY_FREEING_PAGES(len) */ +/* interface to GC */ +static void *malloc_pages(size_t len, size_t alignment); +static void *malloc_dirty_pages(size_t len, size_t alignment); +static void free_pages(void *p, size_t len); +static void flush_freed_pages(void); +static void protect_pages(void *p, size_t len, int writable); + +/* interface to OS */ +static void os_vm_free_pages(void *p, size_t len); +static void *os_vm_alloc_pages(size_t len); + +/* private utility functions */ +static void *do_malloc_pages(size_t len, size_t alignment, int dirty_ok); + + +static void *malloc_pages(size_t len, size_t alignment) +{ + return do_malloc_pages(len, alignment, 0); +} + +static void *malloc_dirty_pages(size_t len, size_t alignment) +{ + return do_malloc_pages(len, alignment, 1); +} + typedef struct { void *start; long len; - short age, zeroed; + short age; + short zeroed; } Free_Block; #define BLOCKFREE_UNMAP_AGE 1 @@ -44,7 +70,7 @@ static void collapse_adjacent_pages(void) blockfree[i].start = NULL; blockfree[i].len = 0; if (!blockfree[i].zeroed) - blockfree[j].zeroed = 0; + blockfree[j].zeroed = 0; } else j = i; } @@ -60,12 +86,12 @@ inline static void *find_cached_pages(size_t len, size_t alignment, int dirty_ok if (blockfree[i].len == len) { r = blockfree[i].start; if (!alignment || !((unsigned long)r & (alignment - 1))) { - blockfree[i].start = NULL; - blockfree[i].len = 0; - if (!blockfree[i].zeroed && !dirty_ok) - memset(r, 0, len); - LOGICALLY_ALLOCATING_PAGES(len); - return r; + blockfree[i].start = NULL; + blockfree[i].len = 0; + if (!blockfree[i].zeroed && !dirty_ok) + memset(r, 0, len); + LOGICALLY_ALLOCATING_PAGES(len); + return r; } } } @@ -76,26 +102,26 @@ inline static void *find_cached_pages(size_t len, size_t alignment, int dirty_ok /* Align at start? */ r = blockfree[i].start; if (!alignment || !((unsigned long)r & (alignment - 1))) { - blockfree[i].start += len; - blockfree[i].len -= len; - if (!blockfree[i].zeroed && !dirty_ok) - memset(r, 0, len); - LOGICALLY_ALLOCATING_PAGES(len); - return r; + blockfree[i].start += len; + blockfree[i].len -= len; + if (!blockfree[i].zeroed && !dirty_ok) + memset(r, 0, len); + LOGICALLY_ALLOCATING_PAGES(len); + return r; } /* Align at end? */ r = blockfree[i].start + (blockfree[i].len - len); if (!((unsigned long)r & (alignment - 1))) { - blockfree[i].len -= len; - if (!blockfree[i].zeroed && !dirty_ok) - memset(r, 0, len); - LOGICALLY_ALLOCATING_PAGES(len); - return r; + blockfree[i].len -= len; + if (!blockfree[i].zeroed && !dirty_ok) + memset(r, 0, len); + LOGICALLY_ALLOCATING_PAGES(len); + return r; } /* We don't try a middle alignment, because that would - split the block into three. */ + split the block into three. */ } } @@ -103,7 +129,7 @@ inline static void *find_cached_pages(size_t len, size_t alignment, int dirty_ok return NULL; } -static void free_actual_pages(void *p, size_t len, int zeroed) +static void return_mem_to_cache(void *p, size_t len, int zeroed) { int i; @@ -116,17 +142,17 @@ static void free_actual_pages(void *p, size_t len, int zeroed) for (i = 0; i < BLOCKFREE_CACHE_SIZE; i++) if(blockfree[i].start && (blockfree[i].len < (1024 * 1024))) { if (p == blockfree[i].start + blockfree[i].len) { - blockfree[i].len += len; - if (!zeroed) - blockfree[i].zeroed = 0; - return; + blockfree[i].len += len; + if (!zeroed) + blockfree[i].zeroed = 0; + return; } if (p + len == blockfree[i].start) { - blockfree[i].start = p; - blockfree[i].len += len; - if (!zeroed) - blockfree[i].zeroed = 0; - return; + blockfree[i].start = p; + blockfree[i].len += len; + if (!zeroed) + blockfree[i].zeroed = 0; + return; } } @@ -143,7 +169,7 @@ static void free_actual_pages(void *p, size_t len, int zeroed) /* Might help next time around: */ collapse_adjacent_pages(); - system_free_pages(p, len); + os_vm_free_pages(p, len); ACTUALLY_FREEING_PAGES(len); } @@ -151,7 +177,7 @@ static void free_actual_pages(void *p, size_t len, int zeroed) static void free_pages(void *p, size_t len) { LOGICALLY_FREEING_PAGES(len); - free_actual_pages(p, len, 0); + return_mem_to_cache(p, len, 0); } static void flush_freed_pages(void) @@ -163,12 +189,76 @@ static void flush_freed_pages(void) for (i = 0; i < BLOCKFREE_CACHE_SIZE; i++) { if (blockfree[i].start) { if (blockfree[i].age == BLOCKFREE_UNMAP_AGE) { - system_free_pages(blockfree[i].start, blockfree[i].len); - ACTUALLY_FREEING_PAGES(blockfree[i].len); - blockfree[i].start = NULL; - blockfree[i].len = 0; + os_vm_free_pages(blockfree[i].start, blockfree[i].len); + ACTUALLY_FREEING_PAGES(blockfree[i].len); + blockfree[i].start = NULL; + blockfree[i].len = 0; } else - blockfree[i].age++; + blockfree[i].age++; } } } + +/* Instead of immediately freeing pages with munmap---only to mmap + them again---we cache BLOCKFREE_CACHE_SIZE freed pages. A page is + cached unused for at most BLOCKFREE_UNMAP_AGE cycles of the + collector. (A max age of 1 seems useful, anything more seems + dangerous.) + + The cache is small enough that we don't need an elaborate search + mechanism, but we do a bit of work to collapse adjacent pages in + the cache. */ + +static void *do_malloc_pages(size_t len, size_t alignment, int dirty_ok) +{ + void *r; + + if (!page_size) + page_size = getpagesize(); + + CHECK_USED_AGAINST_MAX(len); + + /* Round up to nearest page: */ + if (len & (page_size - 1)) + len += page_size - (len & (page_size - 1)); + + /* Something from the cache, perhaps? */ + r = find_cached_pages(len, alignment, dirty_ok); + if (r) + return r; + + r = os_vm_alloc_pages(len + alignment); + + if (r == (void *)-1) + return NULL; + + if (alignment) { + /* We allocated too large so we can choose the alignment. */ + size_t extra; + void *real_r; + long pre_extra; + extra = alignment; + + real_r = (void *)(((unsigned long)r + (alignment - 1)) & (~(alignment - 1))); + + pre_extra = real_r - r; + /* in front extra */ + if (pre_extra) { os_vm_free_pages(r, pre_extra); } + /* in back extra exists */ + if (pre_extra < extra) { + if (pre_extra == 0) { + /* Instead of actually unmapping, put it in the cache, and there's + a good chance we can use it next time: */ + ACTUALLY_ALLOCATING_PAGES(extra); + return_mem_to_cache(real_r + len, extra, 1); + } + else { os_vm_free_pages(real_r + len, extra - pre_extra); } + } + r = real_r; + } + + ACTUALLY_ALLOCATING_PAGES(len); + LOGICALLY_ALLOCATING_PAGES(len); + + return r; +} diff --git a/src/mzscheme/gc2/vm_mmap.c b/src/mzscheme/gc2/vm_mmap.c index cfddadece5..73dbfee359 100644 --- a/src/mzscheme/gc2/vm_mmap.c +++ b/src/mzscheme/gc2/vm_mmap.c @@ -1,14 +1,9 @@ -/* - Provides: - mmap-based allocator (uses alloc_cache.c) - determine_max_heap_size() - Requires: - my_qsort (for alloc_cache.c) - LOGICALLY_ALLOCATING_PAGES(len) - ACTUALLY_ALLOCATING_PAGES(len) - LOGICALLY_FREEING_PAGES(len) - ACTUALLY_FREEING_PAGES(len) - Optional: +/* Provides: */ +static void os_vm_free_pages(void *p, size_t len); +static void *os_vm_alloc_pages(size_t len); +static void protect_pages(void *p, size_t len, int writeable); +/* Requires: */ +/* Optional: CHECK_USED_AGAINST_MAX(len) GCPRINT GCOUTF @@ -29,32 +24,22 @@ # define CHECK_USED_AGAINST_MAX(x) /* empty */ #endif -static int page_size; /* OS page size */ - +static long page_size; #ifndef MAP_ANON -static int fd, fd_created; +static int fd; +static int fd_created; #endif -inline static void *find_cached_pages(size_t len, size_t alignment, int dirty_ok); -static void free_actual_pages(void *p, size_t len, int zeroed); +static void os_vm_free_pages(void *p, size_t len) +{ + if (munmap(p, len)) { + GCPRINT(GCOUTF, "Unmap warning: %lx, %ld, %d\n", (long)p, (long)len, errno); + } +} -/* Instead of immediately freeing pages with munmap---only to mmap - them again---we cache BLOCKFREE_CACHE_SIZE freed pages. A page is - cached unused for at most BLOCKFREE_UNMAP_AGE cycles of the - collector. (A max age of 1 seems useful, anything more seems - dangerous.) - - The cache is small enough that we don't need an elaborate search - mechanism, but we do a bit of work to collapse adjacent pages in - the cache. */ - -static void *do_malloc_pages(size_t len, size_t alignment, int dirty_ok) +static void *os_vm_alloc_pages(size_t len) { void *r; - size_t extra = 0; - - if (!page_size) - page_size = getpagesize(); #ifndef MAP_ANON if (!fd_created) { @@ -63,75 +48,22 @@ static void *do_malloc_pages(size_t len, size_t alignment, int dirty_ok) } #endif - CHECK_USED_AGAINST_MAX(len); - /* Round up to nearest page: */ if (len & (page_size - 1)) len += page_size - (len & (page_size - 1)); - /* Something from the cache, perhaps? */ - r = find_cached_pages(len, alignment, dirty_ok); - if (r) - return r; - - extra = alignment; - #ifdef MAP_ANON - r = mmap(NULL, len + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + r = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); #else - r = mmap(NULL, len + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + r = mmap(NULL, len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); #endif if (r == (void *)-1) return NULL; - if (extra) { - /* We allocated too large so we can choose the alignment. */ - void *real_r; - long pre_extra; - - real_r = (void *)(((unsigned long)r + (alignment - 1)) & (~(alignment - 1))); - - pre_extra = real_r - r; - if (pre_extra) - if (munmap(r, pre_extra)) - GCPRINT(GCOUTF, "Unmap warning: %lx, %ld, %d\n", (long)r, pre_extra, errno); - if (pre_extra < extra) { - if (!pre_extra) { - /* Instead of actually unmapping, put it in the cache, and there's - a good chance we can use it next time: */ - ACTUALLY_ALLOCATING_PAGES(extra); - free_actual_pages(real_r + len, extra, 1); - } else { - if (munmap(real_r + len, extra - pre_extra)) - GCPRINT(GCOUTF, "Unmap warning: %lx, %ld, %d\n", (long)r, pre_extra, errno); - } - } - r = real_r; - } - - ACTUALLY_ALLOCATING_PAGES(len); - LOGICALLY_ALLOCATING_PAGES(len); - return r; } -static void *malloc_pages(size_t len, size_t alignment) -{ - return do_malloc_pages(len, alignment, 0); -} - -static void *malloc_dirty_pages(size_t len, size_t alignment) -{ - return do_malloc_pages(len, alignment, 1); -} - -static void system_free_pages(void *p, size_t len) -{ - if (munmap(p, len)) { - GCPRINT(GCOUTF, "Unmap warning: %lx, %ld, %d\n", (long)p, (long)len, errno); - } -} static void protect_pages(void *p, size_t len, int writeable) { @@ -142,8 +74,5 @@ static void protect_pages(void *p, size_t len, int writeable) mprotect(p, len, (writeable ? (PROT_READ | PROT_WRITE) : PROT_READ)); } -# include "alloc_cache.c" - -/*************************************************************/ - -# include "rlimit_heapsize.c" +#include "alloc_cache.c" +#include "rlimit_heapsize.c" diff --git a/src/mzscheme/gc2/vm_osk.c b/src/mzscheme/gc2/vm_osk.c index eb81df335e..0ad57424bf 100644 --- a/src/mzscheme/gc2/vm_osk.c +++ b/src/mzscheme/gc2/vm_osk.c @@ -48,7 +48,6 @@ inline static void *malloc_pages(size_t len, size_t alignment) static void free_pages(void *p, size_t len) { - free_used_pages(len); sfree(p, len); LOGICALLY_FREEING_PAGES(len); diff --git a/src/mzscheme/gc2/vm_osx.c b/src/mzscheme/gc2/vm_osx.c index 52813d6b35..aa84ec96f6 100644 --- a/src/mzscheme/gc2/vm_osx.c +++ b/src/mzscheme/gc2/vm_osx.c @@ -9,10 +9,6 @@ GENERATIONS --- zero or non-zero designate_modified --- when GENERATIONS is non-zero my_qsort (for alloc_cache.c) - LOGICALLY_ALLOCATING_PAGES(len) - ACTUALLY_ALLOCATING_PAGES(len) - LOGICALLY_FREEING_PAGES(len) - ACTUALLY_FREEING_PAGES(len) Optional: CHECK_USED_AGAINST_MAX(len) GCPRINT @@ -93,81 +89,27 @@ static mach_port_t task_self = 0; static mach_port_t exc_port = 0; /* the VM subsystem as defined by the GC files */ -static void *do_malloc_pages(size_t len, size_t alignment, int dirty_ok) +static void *os_vm_alloc_pages(size_t len) { kern_return_t retval; - size_t extra = 0; void *r; if(!task_self) task_self = mach_task_self(); - CHECK_USED_AGAINST_MAX(len); - /* round up to the nearest page: */ if(len & (page_size - 1)) len += page_size - (len & (page_size - 1)); - r = find_cached_pages(len, alignment, dirty_ok); - if (r) - return r; - - extra = alignment; - - retval = vm_allocate(task_self, (vm_address_t*)&r, len + extra, TRUE); + retval = vm_allocate(task_self, (vm_address_t*)&r, len, TRUE); if(retval != KERN_SUCCESS) { GCPRINT(GCOUTF, "Couldn't allocate memory: %s\n", mach_error_string(retval)); abort(); } - if(extra) { - /* we allocated too large so we can choose the alignment */ - void *real_r; - long pre_extra; - - real_r = (void*)(((unsigned long)r + (alignment-1)) & (~(alignment-1))); - pre_extra = real_r - r; - if(pre_extra) { - retval = vm_deallocate(task_self, (vm_address_t)r, pre_extra); - if(retval != KERN_SUCCESS) { - GCPRINT(GCOUTF, "WARNING: couldn't deallocate pre-extra: %s\n", - mach_error_string(retval)); - } - } - if(pre_extra < extra) { - if (!pre_extra) { - /* Instead of actually unmapping, put it in the cache, and there's - a good chance we can use it next time: */ - ACTUALLY_ALLOCATING_PAGES(extra); - free_actual_pages(real_r + len, extra, 1); - } else { - retval = vm_deallocate(task_self, (vm_address_t)real_r + len, - extra - pre_extra); - if(retval != KERN_SUCCESS) { - GCPRINT(GCOUTF, "WARNING: couldn't deallocate post-extra: %s\n", - mach_error_string(retval)); - } - } - } - r = real_r; - } - - ACTUALLY_ALLOCATING_PAGES(len); - LOGICALLY_ALLOCATING_PAGES(len); - return r; } -static void *malloc_pages(size_t len, size_t alignment) -{ - return do_malloc_pages(len, alignment, 0); -} - -static void *malloc_dirty_pages(size_t len, size_t alignment) -{ - return do_malloc_pages(len, alignment, 1); -} - -static void system_free_pages(void *p, size_t len) +static void os_vm_free_pages(void *p, size_t len) { kern_return_t retval;