Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r908:f11bf6145d1b
Date: 2014-03-01 17:03 +0100
http://bitbucket.org/pypy/stmgc/changeset/f11bf6145d1b/

Log:    The first test about major gc passes.

diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -130,8 +130,94 @@
     s_mutex_unlock();
 }
 
+
+/************************************************************/
+
+
+static struct list_s *mark_objects_to_trace;
+
+
+static inline struct object_s *mark_first_seg(object_t *obj)
+{
+    return (struct object_s *)REAL_ADDRESS(stm_object_pages, obj);
+}
+
+static inline bool mark_is_visited(object_t *obj)
+{
+    uintptr_t lock_idx = (((uintptr_t)obj) >> 4) - WRITELOCK_START;
+    assert(lock_idx >= 0);
+    assert(lock_idx < sizeof(write_locks));
+    return write_locks[lock_idx] != 0;
+}
+
+static inline void mark_set_visited(object_t *obj)
+{
+    uintptr_t lock_idx = (((uintptr_t)obj) >> 4) - WRITELOCK_START;
+    write_locks[lock_idx] = 0xff;
+}
+
+static inline void mark_record_trace(object_t **pobj)
+{
+    /* takes a normal pointer to a thread-local pointer to an object */
+    object_t *obj = *pobj;
+
+    if (obj == NULL)
+        return;
+    if (mark_is_visited(obj))
+        return;    /* already visited this object */
+
+    mark_set_visited(obj);
+    LIST_APPEND(mark_objects_to_trace, obj);
+}
+
+static void mark_collect_modified_objects(void)
+{
+    //...
+}
+
+static void mark_collect_roots(void)
+{
+    stm_thread_local_t *tl = stm_all_thread_locals;
+    do {
+        object_t **current = tl->shadowstack;
+        object_t **base = tl->shadowstack_base;
+        while (current-- != base) {
+            assert(*current != (object_t *)-1);
+            mark_record_trace(current);
+        }
+        mark_record_trace(&tl->thread_local_obj);
+
+        tl = tl->next;
+    } while (tl != stm_all_thread_locals);
+}
+
+static void mark_visit_all_objects(void)
+{
+    while (!list_is_empty(mark_objects_to_trace)) {
+        object_t *obj = (object_t *)list_pop_item(mark_objects_to_trace);
+
+        stmcb_trace(mark_first_seg(obj), &mark_record_trace);
+
+        if (!is_fully_in_shared_pages(obj)) {
+            abort();//xxx;
+        }
+    }
+}
+
+static inline bool largemalloc_keep_object_at(char *data)
+{
+    /* this is called by largemalloc_sweep() */
+    return mark_is_visited((object_t *)(data - stm_object_pages));
+}
+
+static void sweep_large_objects(void)
+{
+    largemalloc_sweep();
+}
+
 static void major_collection_now_at_safe_point(void)
 {
+    dprintf(("\n"));
     dprintf((" .----- major_collection_now_at_safe_point -----\n"));
     assert(_has_mutex());
 
@@ -141,7 +227,23 @@
     dprintf((" | used before collection: %ld\n",
              (long)pages_ctl.total_allocated));
 
-    fprintf(stderr, "hi, I should be doing a major GC here\n");
+    /* marking */
+    mark_objects_to_trace = list_create();
+    mark_collect_modified_objects();
+    mark_collect_roots();
+    mark_visit_all_objects();
+    list_free(mark_objects_to_trace);
+    mark_objects_to_trace = NULL;
+
+    /* sweeping */
+    mutex_pages_lock();
+    sweep_large_objects();
+    //sweep_uniform_pages();
+    mutex_pages_unlock();
+
+    dprintf((" | used after collection:  %ld\n",
+             (long)pages_ctl.total_allocated));
+    dprintf((" `----------------------------------------------\n"));
 
     reset_major_collection_requested();
 }
diff --git a/c7/stm/gcpage.h b/c7/stm/gcpage.h
--- a/c7/stm/gcpage.h
+++ b/c7/stm/gcpage.h
@@ -35,6 +35,7 @@
 
 static void major_collection_if_requested(void);
 static void major_collection_now_at_safe_point(void);
+static bool largemalloc_keep_object_at(char *data);   /* for largemalloc.c */
 
 
 static char *_allocate_small_slowpath(uint64_t size);
diff --git a/c7/stm/largemalloc.c b/c7/stm/largemalloc.c
--- a/c7/stm/largemalloc.c
+++ b/c7/stm/largemalloc.c
@@ -60,6 +60,10 @@
     assert(!(p->size & FLAG_SORTED));
     return chunk_at_offset(p, CHUNK_HEADER_SIZE + p->size);
 }
+static mchunk_t *next_chunk_a(mchunk_t *p)
+{
+    return chunk_at_offset(p, CHUNK_HEADER_SIZE + (p->size & ~FLAG_SORTED));
+}
 
 
 /* The free chunks are stored in "bins".  Each bin is a doubly-linked
@@ -420,3 +424,48 @@
     }
     return 1;
 }
+
+
+#ifdef STM_TESTS
+bool (*_stm_largemalloc_keep)(char *data) = NULL;
+#endif
+
+static inline bool _largemalloc_sweep_keep(mchunk_t *chunk)
+{
+#ifdef STM_TESTS
+    if (_stm_largemalloc_keep != NULL)
+        return _stm_largemalloc_keep((char *)&chunk->d);
+#endif
+    return largemalloc_keep_object_at((char *)&chunk->d);
+}
+
+static void largemalloc_sweep(void)
+{
+    /* This may be slightly optimized by inlining _stm_large_free() and
+       making cases, e.g. we might know already if the previous block
+       was free or not.  It's probably not really worth it. */
+    mchunk_t *mnext, *chunk = first_chunk;
+
+    if (chunk->prev_size == THIS_CHUNK_FREE)
+        chunk = next_chunk_a(chunk);   /* go to the first non-free chunk */
+
+    while (chunk != last_chunk) {
+
+        /* here, the chunk we're pointing to is not free */
+        assert(chunk->prev_size != THIS_CHUNK_FREE);
+
+        /* first figure out the next non-free chunk */
+        mnext = next_chunk_u(chunk);
+        if (mnext->prev_size == THIS_CHUNK_FREE)
+            mnext = next_chunk_a(mnext);
+
+        /* use the callback to know if 'chunk' contains an object that
+           survives or dies */
+        if (!_largemalloc_sweep_keep(chunk)) {
+            size_t size = chunk->size;
+            _stm_large_free((char *)&chunk->d);     /* dies */
+            increment_total_allocated(-(size + LARGE_MALLOC_OVERHEAD));
+        }
+        chunk = mnext;
+    }
+}
diff --git a/c7/stm/largemalloc.h b/c7/stm/largemalloc.h
--- a/c7/stm/largemalloc.h
+++ b/c7/stm/largemalloc.h
@@ -13,5 +13,7 @@
 
 void _stm_large_dump(void);
 
+static void largemalloc_sweep(void);
+
 
 #define LARGE_MALLOC_OVERHEAD   (2 * sizeof(size_t))   /* estimate */
diff --git a/c7/stm/pages.c b/c7/stm/pages.c
--- a/c7/stm/pages.c
+++ b/c7/stm/pages.c
@@ -197,7 +197,6 @@
     mutex_pages_unlock();
 }
 
-#if 0
 static bool is_fully_in_shared_pages(object_t *obj)
 {
     uintptr_t first_page = ((uintptr_t)obj) / 4096UL;
@@ -217,4 +216,3 @@
 
     return true;
 }
-#endif
diff --git a/c7/stm/pages.h b/c7/stm/pages.h
--- a/c7/stm/pages.h
+++ b/c7/stm/pages.h
@@ -41,4 +41,4 @@
     _pages_privatize(pagenum, count, full);
 }
 
-//static bool is_fully_in_shared_pages(object_t *obj);  -- not needed?
+static bool is_fully_in_shared_pages(object_t *obj);
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -49,7 +49,7 @@
                      PROT_NONE);
 
         struct stm_priv_segment_info_s *pr = get_priv_segment(i);
-        assert(i + 1 < 256);
+        assert(i + 1 < 0xff);   /* 0xff (255) is used by major collections */
         pr->write_lock_num = i + 1;
         pr->pub.segment_num = i;
         pr->pub.segment_base = segment_base;
diff --git a/c7/test/test_gcpage.py b/c7/test/test_gcpage.py
--- a/c7/test/test_gcpage.py
+++ b/c7/test/test_gcpage.py
@@ -100,5 +100,4 @@
         assert 5000 <= lib._stm_total_allocated() <= 8192
 
         stm_major_collect()
-        py.test.skip("in-progress")
         assert lib._stm_total_allocated() == 0
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to