Author: Armin Rigo <ar...@tunes.org> Branch: gc-small-uniform Changeset: r1130:b75f80e3f905 Date: 2014-04-05 19:37 +0200 http://bitbucket.org/pypy/stmgc/changeset/b75f80e3f905/
Log: in-progress diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c --- a/c7/stm/gcpage.c +++ b/c7/stm/gcpage.c @@ -64,7 +64,12 @@ object_t *_stm_allocate_old(ssize_t size_rounded_up) { /* only for tests xxx but stm_setup_prebuilt() uses this now too */ - char *p = allocate_outside_nursery_large(size_rounded_up); + char *p; + if (size_rounded_up > GC_LAST_SMALL_SIZE) + p = allocate_outside_nursery_large(size_rounded_up); + else + p = allocate_outside_nursery_small(size_rounded_up); + memset(p, 0, size_rounded_up); object_t *o = (object_t *)(p - stm_object_pages); diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c --- a/c7/stm/nursery.c +++ b/c7/stm/nursery.c @@ -103,7 +103,7 @@ realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj); size = stmcb_size_rounded_up((struct object_s *)realobj); - if (size >= GC_N_SMALL_REQUESTS) { + if (size > GC_LAST_SMALL_SIZE) { /* case 1: object is not small enough. Ask gcpage.c for an allocation via largemalloc. */ diff --git a/c7/stm/smallmalloc.c b/c7/stm/smallmalloc.c --- a/c7/stm/smallmalloc.c +++ b/c7/stm/smallmalloc.c @@ -3,10 +3,33 @@ #endif +#define PAGE_SMSIZE_START END_NURSERY_PAGE +#define PAGE_SMSIZE_END NB_PAGES + +typedef struct { + uint8_t sz; +} fpsz_t; + +static fpsz_t full_pages_object_size[PAGE_SMSIZE_END - PAGE_SMSIZE_START]; +/* ^^^ This array contains the size (in number of words) of the objects + in the given page, provided it's a "full page of small objects". It + is 0 if it's not such a page, if it's fully free, or if it's in + small_page_lists. It is not 0 as soon as the page enters the + segment's 'small_malloc_data.loc_free' (even if the page is not + technically full yet, it will be very soon in this case). +*/ + +static fpsz_t *get_fp_sz(char *smallpage) +{ + uintptr_t pagenum = (((char *)smallpage) - stm_object_pages) / 4096; + return &full_pages_object_size[pagenum - PAGE_SMSIZE_START]; +} + + static void teardown_smallmalloc(void) { memset(small_page_lists, 0, sizeof(small_page_lists)); - assert(free_uniform_pages == NULL); + assert(free_uniform_pages == NULL); /* done by the previous line */ first_small_uniform_loc = (uintptr_t) -1; } @@ -69,6 +92,7 @@ /* Succeeded: we have a page in 'smallpage' */ *fl = smallpage->header.next; + get_fp_sz((char *)smallpage)->sz = n; return (char *)smallpage; } @@ -101,6 +125,7 @@ /* The first slot is immediately returned */ *fl = following; + get_fp_sz((char *)smallpage)->sz = n; return (char *)smallpage; } @@ -114,7 +139,7 @@ static inline char *allocate_outside_nursery_small(uint64_t size) { OPT_ASSERT((size & 7) == 0); - OPT_ASSERT(16 <= size && size < 8 * GC_N_SMALL_REQUESTS); + OPT_ASSERT(16 <= size && size <= GC_LAST_SMALL_SIZE); struct small_free_loc_s *TLPREFIX *fl = &STM_PSEGMENT->small_malloc_data.loc_free[size / 8]; @@ -127,3 +152,28 @@ *fl = result->next; return (char *)result; } + +void _stm_smallmalloc_sweep(void) +{ + long i; + for (i = 2; i < GC_N_SMALL_REQUESTS; i++) { + struct small_page_list_s *page = small_page_lists[i]; + while (page != NULL) { + /* for every page in small_page_lists: assert that the + corresponding full_pages_object_size[] entry is 0 */ + assert(get_fp_sz((char *)page)->sz == 0); + abort(); // walk + page = page->nextpage; + } + } + + fpsz_t *fpsz_start = get_fp_sz(uninitialized_page_stop); + fpsz_t *fpsz_end = &full_pages_object_size[PAGE_SMSIZE_END - + PAGE_SMSIZE_START]; + fpsz_t *fpsz; + for (fpsz = fpsz_start; fpsz < fpsz_end; fpsz++) { + if (fpsz->sz != 0) { + abort(); // walk + } + } +} diff --git a/c7/stm/smallmalloc.h b/c7/stm/smallmalloc.h --- a/c7/stm/smallmalloc.h +++ b/c7/stm/smallmalloc.h @@ -8,6 +8,7 @@ */ #define GC_N_SMALL_REQUESTS 36 +#define GC_LAST_SMALL_SIZE (8 * (GC_N_SMALL_REQUESTS - 1)) struct small_free_loc_s { @@ -19,8 +20,9 @@ free. */ struct small_free_loc_s header; - /* A chained list of all small pages containing objects of - a given small size, and that have at least one free object. */ + /* A chained list of all small pages containing objects of a given + small size, and that have at least one free object. It points + *inside* the next page, to another struct small_page_list_s. */ struct small_page_list_s *nextpage; /* This structure is only two words, so it always fits inside one @@ -57,7 +59,8 @@ static inline char *allocate_outside_nursery_small(uint64_t size) __attribute__((always_inline)); -static char *_allocate_small_slowpath(uint64_t size); +void _stm_smallmalloc_sweep(void); + static void teardown_smallmalloc(void); static inline bool is_small_uniform(object_t *obj) { diff --git a/c7/stmgc.h b/c7/stmgc.h --- a/c7/stmgc.h +++ b/c7/stmgc.h @@ -125,6 +125,8 @@ void _stm_large_dump(void); bool (*_stm_largemalloc_keep)(char *data); void _stm_largemalloc_sweep(void); +bool (*_stm_smallmalloc_keep)(char *data); +void _stm_smallmalloc_sweep(void); void _stm_start_safe_point(void); void _stm_stop_safe_point(void); void _stm_set_nursery_free_count(uint64_t free_count); diff --git a/c7/test/support.py b/c7/test/support.py --- a/c7/test/support.py +++ b/c7/test/support.py @@ -81,6 +81,7 @@ void *memset(void *s, int c, size_t n); bool (*_stm_largemalloc_keep)(char *data); void _stm_largemalloc_sweep(void); +void _stm_smallmalloc_sweep(void); ssize_t stmcb_size_rounded_up(struct object_s *obj); @@ -290,6 +291,8 @@ assert HDR == 8 GCFLAG_WRITE_BARRIER = lib._STM_GCFLAG_WRITE_BARRIER NB_SEGMENTS = lib.STM_NB_SEGMENTS +GC_N_SMALL_REQUESTS = 36 +GC_LAST_SMALL_SIZE = 8 * (GC_N_SMALL_REQUESTS - 1) class Conflict(Exception): diff --git a/c7/test/test_smallmalloc.py b/c7/test/test_smallmalloc.py new file mode 100644 --- /dev/null +++ b/c7/test/test_smallmalloc.py @@ -0,0 +1,32 @@ +from support import * + + +def pageof(p): + return int(ffi.cast("uintptr_t", p)) >> 12 + + +class TestLargeMalloc(BaseTest): + + def test_simple_uniform(self): + page0 = [stm_allocate_old(16) for i in range(0, 4096, 16)] + assert len(set(map(pageof, page0))) == 1 + # + page1 = [stm_allocate_old(16) for i in range(0, 4096, 16)] + assert len(set(map(pageof, page1))) == 1 + # + assert len(set(map(pageof, page0 + page1))) == 2 + + def test_different_sizes_different_pages(self): + seen = [] + for i in range(2, GC_N_SMALL_REQUESTS): + p = pageof(stm_allocate_old(8 * i)) + assert p not in seen + seen.append(p) + for i in range(2, GC_N_SMALL_REQUESTS): + p = pageof(stm_allocate_old(8 * i)) + assert p == seen[0] + seen.pop(0) + + def test_sweep_freeing(self): + p1 = stm_allocate_old(16) + lib._stm_smallmalloc_sweep() _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit