Feature #14955 ยป 0001-gc.c-use-MADV_FREE-to-release-most-the-heap-page-bod.patch
configure.ac | ||
---|---|---|
AC_CHECK_HEADERS(sys/id.h)
|
||
AC_CHECK_HEADERS(sys/ioctl.h)
|
||
AC_CHECK_HEADERS(sys/mkdev.h)
|
||
AC_CHECK_HEADERS(sys/mman.h)
|
||
AC_CHECK_HEADERS(sys/param.h)
|
||
AC_CHECK_HEADERS(sys/prctl.h)
|
||
AC_CHECK_HEADERS(sys/resource.h)
|
||
... | ... | |
AC_CHECK_FUNCS(lutimes)
|
||
AC_CHECK_FUNCS(malloc_usable_size)
|
||
AC_CHECK_FUNCS(malloc_size)
|
||
AC_CHECK_FUNCS(madvise)
|
||
AC_CHECK_FUNCS(mblen)
|
||
AC_CHECK_FUNCS(memalign)
|
||
AC_CHECK_FUNCS(memset_s)
|
gc.c | ||
---|---|---|
#include <malloc.h>
|
||
#endif
|
||
#if defined(HAVE_SYS_MMAN_H)
|
||
# include <sys/mman.h>
|
||
#endif
|
||
#define rb_setjmp(env) RUBY_SETJMP(env)
|
||
#define rb_jmp_buf rb_jmpbuf_t
|
||
... | ... | |
HEAP_PAGE_BITMAP_PLANES = USE_RGENGC ? 4 : 1 /* RGENGC: mark, unprotected, uncollectible, marking */
|
||
};
|
||
/*
|
||
* TODO: add platform-specific SC_PAGESIZE_ASSUMED definitions, here.
|
||
* 4K is the most common, so we assume it by default.
|
||
* Probably not worth the effort to support MADV_FREE on (rare) platforms
|
||
* where HEAP_PAGE_ALIGN <= _SC_PAGESIZE, so define to 0 in that case.
|
||
*/
|
||
#if defined(__linux__) && defined(__alpha__)
|
||
# define SC_PAGESIZE_ASSUMED (1 << 13) /* XXX untested */
|
||
#endif
|
||
/* this is true for x86_64 and x86 on Linux and FreeBSD */
|
||
#ifndef SC_PAGESIZE_ASSUMED
|
||
# define SC_PAGESIZE_ASSUMED (1 << 12)
|
||
#endif
|
||
#if defined(MADV_FREE) && defined(HAVE_MADVISE) && SC_PAGESIZE_ASSUMED
|
||
# define USE_MADV_FREE (1)
|
||
#else
|
||
# define USE_MADV_FREE (0)
|
||
#endif
|
||
struct heap_page_madv_freed {
|
||
char junk[HEAP_PAGE_ALIGN - SC_PAGESIZE_ASSUMED];
|
||
struct list_node fnode;
|
||
};
|
||
STATIC_ASSERT(heap_page_madv_freed_size,
|
||
sizeof(struct heap_page_madv_freed) <= HEAP_PAGE_SIZE);
|
||
#if USE_MADV_FREE
|
||
static long sc_pagesize;
|
||
static LIST_HEAD(madv_free_head);
|
||
#endif
|
||
struct heap_page {
|
||
short total_slots;
|
||
short free_slots;
|
||
... | ... | |
heap->total_slots -= page->total_slots;
|
||
}
|
||
static int
|
||
heap_page_madv_free_put(struct heap_page_body *body)
|
||
{
|
||
#if USE_MADV_FREE
|
||
static int err;
|
||
struct heap_page_madv_freed *hpmf = (struct heap_page_madv_freed *)body;
|
||
if (err) return FALSE;
|
||
if (sc_pagesize != SC_PAGESIZE_ASSUMED) {
|
||
/* can't use rb_warning during VM shutdown */
|
||
if (RTEST(ruby_verbose)) {
|
||
fprintf(stderr,
|
||
"unable to use MADV_FREE, page size unexpected: %ld != %u\n"
|
||
"RUBY_PLATFORM: "RUBY_PLATFORM"\n"
|
||
"Please report to https://bugs.ruby-lang.org/\n",
|
||
sc_pagesize, SC_PAGESIZE_ASSUMED);
|
||
}
|
||
err = -1;
|
||
return FALSE;
|
||
}
|
||
if (madvise(hpmf->junk, sizeof(hpmf->junk), MADV_FREE) == 0) {
|
||
list_add(&madv_free_head, &hpmf->fnode);
|
||
return TRUE;
|
||
}
|
||
err = errno;
|
||
/* can happen if libc headers are newer than kernel version */
|
||
if (RTEST(ruby_verbose)) {
|
||
fprintf(stderr, "MADV_FREE failed: %s", strerror(err));
|
||
}
|
||
#endif
|
||
return FALSE;
|
||
}
|
||
static void *
|
||
heap_page_madv_free_get(void)
|
||
{
|
||
#if USE_MADV_FREE
|
||
return list_pop(&madv_free_head, struct heap_page_madv_freed, fnode);
|
||
#endif
|
||
return 0;
|
||
}
|
||
static void
|
||
heap_page_free(rb_objspace_t *objspace, struct heap_page *page)
|
||
{
|
||
struct heap_page_body *body = GET_PAGE_BODY(page->start);
|
||
heap_allocated_pages--;
|
||
objspace->profile.total_freed_pages++;
|
||
aligned_free(GET_PAGE_BODY(page->start));
|
||
if (!heap_page_madv_free_put(body)) {
|
||
aligned_free(body);
|
||
}
|
||
free(page);
|
||
}
|
||
... | ... | |
int limit = HEAP_PAGE_OBJ_LIMIT;
|
||
/* assign heap_page body (contains heap_page_header and RVALUEs) */
|
||
page_body = (struct heap_page_body *)aligned_malloc(HEAP_PAGE_ALIGN, HEAP_PAGE_SIZE);
|
||
page_body = heap_page_madv_free_get();
|
||
if (!page_body) {
|
||
page_body = aligned_malloc(HEAP_PAGE_ALIGN, HEAP_PAGE_SIZE);
|
||
}
|
||
if (page_body == 0) {
|
||
rb_memerror();
|
||
}
|
||
... | ... | |
/* assign heap_page entry */
|
||
page = (struct heap_page *)calloc(1, sizeof(struct heap_page));
|
||
if (page == 0) {
|
||
aligned_free(page_body);
|
||
rb_memerror();
|
||
if (!heap_page_madv_free_put(page_body)) {
|
||
aligned_free(page_body);
|
||
}
|
||
rb_memerror();
|
||
}
|
||
/* adjust obj_limit (object number available in this page) */
|
||
... | ... | |
{
|
||
rb_objspace_t *objspace = &rb_objspace;
|
||
#if USE_MADV_FREE
|
||
sc_pagesize = sysconf(_SC_PAGESIZE);
|
||
#endif
|
||
gc_stress_set(objspace, ruby_initial_gc_stress);
|
||
#if RGENGC_ESTIMATE_OLDMALLOC
|
||
-
|