Author: Armin Rigo <[email protected]>
Branch:
Changeset: r910:6f5c7ae1e5eb
Date: 2014-03-01 18:57 +0100
http://bitbucket.org/pypy/stmgc/changeset/6f5c7ae1e5eb/
Log: Test that largemalloc_sweep() works as expected; start to work on
recording modified objects
diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -136,24 +136,84 @@
static struct list_s *mark_objects_to_trace;
+#define WL_VISITED 42
-static inline struct object_s *mark_first_seg(object_t *obj)
+
+static inline uintptr_t mark_loc(object_t *obj)
{
- return (struct object_s *)REAL_ADDRESS(stm_object_pages, obj);
+ uintptr_t lock_idx = (((uintptr_t)obj) >> 4) - WRITELOCK_START;
+ assert(lock_idx >= 0);
+ assert(lock_idx < sizeof(write_locks));
+ return lock_idx;
}
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));
+ uintptr_t lock_idx = mark_loc(obj);
+ assert(write_locks[lock_idx] == 0 || write_locks[lock_idx] == WL_VISITED);
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;
+ uintptr_t lock_idx = mark_loc(obj);
+ write_locks[lock_idx] = WL_VISITED;
+}
+
+static void mark_record_modified_objects(void)
+{
+ /* The modified objects are the ones that may exist in two different
+ versions: one in the segment that modified it, and another in
+ all other segments. */
+ long i;
+ for (i = 0; i < NB_SEGMENTS; i++) {
+ struct stm_priv_segment_info_s *pseg = get_priv_segment(i);
+ char *base1 = get_segment_base(i); /* two different segments */
+ char *base2 = get_segment_base(!i);
+
+ LIST_FOREACH_R(
+ pseg->modified_old_objects,
+ object_t * /*item*/,
+ ({
+ assert(item != NULL);
+
+ uintptr_t lock_idx = mark_loc(item);
+ assert(write_locks[lock_idx] == pseg->write_lock_num);
+
+ write_locks[lock_idx] = WL_VISITED;
+ LIST_APPEND(mark_objects_to_trace, REAL_ADDRESS(base1, item));
+ LIST_APPEND(mark_objects_to_trace, REAL_ADDRESS(base2, item));
+ }));
+ }
+}
+
+static void reset_write_locks(void)
+{
+ /* the write_locks array, containing the visit marker during
+ major collection, is cleared now, with two memsets (to avoid
+ clearing the never-used range in the middle corresponding to
+ uninitialized pages) */
+ object_t *loc1 = (object_t *)(uninitialized_page_start - stm_object_pages);
+ object_t *loc2 = (object_t *)(uninitialized_page_stop - stm_object_pages);
+ uintptr_t lock1_idx = mark_loc(loc1);
+ uintptr_t lock2_idx = mark_loc(loc2 - 1) + 1;
+
+ memset(write_locks, 0, lock1_idx);
+ memset(write_locks + lock2_idx, 0, sizeof(write_locks) - lock2_idx);
+
+ /* restore the write locks on the modified objects */
+ long i;
+ for (i = 0; i < NB_SEGMENTS; i++) {
+ struct stm_priv_segment_info_s *pseg = get_priv_segment(i);
+
+ LIST_FOREACH_R(
+ pseg->modified_old_objects,
+ object_t * /*item*/,
+ ({
+ uintptr_t lock_idx = mark_loc(item);
+ write_locks[lock_idx] = pseg->write_lock_num;
+ }));
+ }
}
static inline void mark_record_trace(object_t **pobj)
@@ -167,12 +227,7 @@
return; /* already visited this object */
mark_set_visited(obj);
- LIST_APPEND(mark_objects_to_trace, obj);
-}
-
-static void mark_collect_modified_objects(void)
-{
- //...
+ LIST_APPEND(mark_objects_to_trace, REAL_ADDRESS(stm_object_pages, obj));
}
static void mark_collect_roots(void)
@@ -194,25 +249,21 @@
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;
- }
+ struct object_s *obj =
+ (struct object_s *)list_pop_item(mark_objects_to_trace);
+ stmcb_trace(obj, &mark_record_trace);
}
}
static inline bool largemalloc_keep_object_at(char *data)
{
- /* this is called by largemalloc_sweep() */
+ /* this is called by _stm_largemalloc_sweep() */
return mark_is_visited((object_t *)(data - stm_object_pages));
}
static void sweep_large_objects(void)
{
- largemalloc_sweep();
+ _stm_largemalloc_sweep();
}
static void major_collection_now_at_safe_point(void)
@@ -229,7 +280,7 @@
/* marking */
mark_objects_to_trace = list_create();
- mark_collect_modified_objects();
+ mark_record_modified_objects();
mark_collect_roots();
mark_visit_all_objects();
list_free(mark_objects_to_trace);
@@ -241,6 +292,8 @@
//sweep_uniform_pages();
mutex_pages_unlock();
+ reset_write_locks();
+
dprintf((" | used after collection: %ld\n",
(long)pages_ctl.total_allocated));
dprintf((" `----------------------------------------------\n"));
diff --git a/c7/stm/largemalloc.c b/c7/stm/largemalloc.c
--- a/c7/stm/largemalloc.c
+++ b/c7/stm/largemalloc.c
@@ -348,6 +348,10 @@
return (char *)first_chunk;
}
+#ifdef STM_TESTS
+bool (*_stm_largemalloc_keep)(char *data); /* a hook for tests */
+#endif
+
void _stm_largemalloc_init_arena(char *data_start, size_t data_size)
{
int i;
@@ -367,6 +371,10 @@
assert(last_chunk == next_chunk_u(first_chunk));
insert_unsorted(first_chunk);
+
+#ifdef STM_TESTS
+ _stm_largemalloc_keep = NULL;
+#endif
}
int _stm_largemalloc_resize_arena(size_t new_size)
@@ -426,10 +434,6 @@
}
-#ifdef STM_TESTS
-bool (*_stm_largemalloc_keep)(char *data) = NULL;
-#endif
-
static inline bool _largemalloc_sweep_keep(mchunk_t *chunk)
{
#ifdef STM_TESTS
@@ -439,7 +443,7 @@
return largemalloc_keep_object_at((char *)&chunk->d);
}
-static void largemalloc_sweep(void)
+void _stm_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
diff --git a/c7/stm/largemalloc.h b/c7/stm/largemalloc.h
--- a/c7/stm/largemalloc.h
+++ b/c7/stm/largemalloc.h
@@ -10,10 +10,9 @@
major collections, which have their own synchronization mecanisms. */
char *_stm_large_malloc(size_t request_size);
void _stm_large_free(char *data);
+void _stm_largemalloc_sweep(void);
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
@@ -47,7 +47,6 @@
static uint64_t increment_total_allocated(ssize_t add_or_remove)
{
- assert(_has_mutex_pages());
pages_ctl.total_allocated += add_or_remove;
if (pages_ctl.total_allocated >= pages_ctl.total_allocated_bound)
@@ -197,6 +196,7 @@
mutex_pages_unlock();
}
+#if 0
static bool is_fully_in_shared_pages(object_t *obj)
{
uintptr_t first_page = ((uintptr_t)obj) / 4096UL;
@@ -216,3 +216,4 @@
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);
+/* 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 < 0xff); /* 0xff (255) is used by major collections */
+ assert(i + 1 <= 255);
pr->write_lock_num = i + 1;
pr->pub.segment_num = i;
pr->pub.segment_base = segment_base;
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -85,6 +85,8 @@
char *_stm_large_malloc(size_t request_size);
void _stm_large_free(char *data);
void _stm_large_dump(void);
+bool (*_stm_largemalloc_keep)(char *data);
+void _stm_largemalloc_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
@@ -61,6 +61,8 @@
void _stm_large_free(char *data);
void _stm_large_dump(void);
void *memset(void *s, int c, size_t n);
+bool (*_stm_largemalloc_keep)(char *data);
+void _stm_largemalloc_sweep(void);
ssize_t stmcb_size_rounded_up(struct object_s *obj);
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
@@ -115,7 +115,7 @@
prev = self.pop_root()
stm_set_ref(new, 42, prev)
prev = new
- return new
+ return prev
self.start_transaction()
self.push_root(make_chain(5000))
@@ -123,3 +123,15 @@
stm_minor_collect()
assert lib._stm_total_allocated() == (10 * (5000 + LMO) +
10 * (4312 + LMO))
+ stm_major_collect()
+ assert lib._stm_total_allocated() == (10 * (5000 + LMO) +
+ 10 * (4312 + LMO))
+ stm_major_collect()
+ assert lib._stm_total_allocated() == (10 * (5000 + LMO) +
+ 10 * (4312 + LMO))
+ self.pop_root()
+ stm_major_collect()
+ assert lib._stm_total_allocated() == 10 * (5000 + LMO)
+
+ def test_trace_all_versions(self):
+ pass #xxx in-progress
diff --git a/c7/test/test_largemalloc.py b/c7/test/test_largemalloc.py
--- a/c7/test/test_largemalloc.py
+++ b/c7/test/test_largemalloc.py
@@ -118,3 +118,44 @@
ra(d)[sz - 1] = content2
p.append((d, sz, content1, content2))
lib._stm_large_dump()
+
+ def test_random_largemalloc_sweep(self):
+ @ffi.callback("bool(char *)")
+ def keep(data):
+ try:
+ if data in from_before:
+ return False
+ index = all.index(data)
+ seen_for.add(index)
+ return index in keep_me
+ except Exception, e:
+ errors.append(e)
+ raise
+ lib._stm_largemalloc_keep = keep
+ errors = []
+ from_before = set()
+
+ r = random.Random(1000)
+ for j in range(50):
+ sizes = [random.choice(range(104, 500, 8)) for i in range(20)]
+ all = [lib._stm_large_malloc(size) for size in sizes]
+ print all
+
+ keep_me = set()
+ for i in range(len(all)):
+ if r.random() < 0.5:
+ print 'free:', all[i]
+ lib._stm_large_free(all[i])
+ all[i] = None
+ elif r.random() < 0.5:
+ keep_me.add(i)
+
+ seen_for = set()
+ lib._stm_largemalloc_sweep()
+ assert seen_for == set([i for i in range(len(all))
+ if all[i] is not None])
+ lib._stm_large_dump()
+ from_before = [all[i] for i in keep_me]
+
+ if errors:
+ raise errors[0]
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit