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