[pypy-commit] stmgc gc-small-uniform: in-progress

arigo noreply at buildbot.pypy.org
Sat Apr 5 19:38:04 CEST 2014


Author: Armin Rigo <arigo at 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()


More information about the pypy-commit mailing list