Project

General

Profile

Feature #14955 ยป 0001-gc.c-use-MADV_FREE-to-release-most-the-heap-page-bod.patch

normalperson (Eric Wong), 08/01/2018 12:44 AM

View differences:

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
-
    (1-1/1)