[pypy-commit] stmgc default: In-progress: resharing of pages. Doesn't work right now, so is not enabled.
arigo
noreply at buildbot.pypy.org
Sun Mar 2 12:30:27 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r922:2e8187050db2
Date: 2014-03-02 12:30 +0100
http://bitbucket.org/pypy/stmgc/changeset/2e8187050db2/
Log: In-progress: resharing of pages. Doesn't work right now, so is not
enabled.
diff --git a/c7/stm/contention.c b/c7/stm/contention.c
--- a/c7/stm/contention.c
+++ b/c7/stm/contention.c
@@ -50,7 +50,9 @@
uint8_t prev_owner = ((volatile uint8_t *)write_locks)[lock_idx];
if (prev_owner != 0 && prev_owner != STM_PSEGMENT->write_lock_num) {
- uint8_t other_segment_num = prev_owner - 1;
+ uint8_t other_segment_num = prev_owner - _SINGLE_SEGMENT_PAGE;
+ assert(get_priv_segment(other_segment_num)->write_lock_num ==
+ prev_owner);
contention_management(other_segment_num);
/* The rest of this code is for the case where we continue to
diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -189,6 +189,112 @@
}
}
+/************************************************************/
+
+
+static inline void mark_single_flag_private(uintptr_t pagenum, uint8_t flagnum)
+{
+ uint8_t old_flag = flag_page_private[pagenum];
+
+ if (old_flag == SHARED_PAGE) /* nothing to do, page already shared */
+ return;
+
+ if (old_flag == flagnum) /* page already marked for this segment */
+ return;
+
+ if (old_flag == PRIVATE_PAGE) { /* a not-seen-before private page */
+ flag_page_private[pagenum] = flagnum;
+ return;
+ }
+
+ /* else, conflict: the page has been seen from two different segments.
+ Use REMAPPING_PAGE to mean this situation here. */
+ flag_page_private[pagenum] = REMAPPING_PAGE;
+}
+
+static inline void mark_flag_page_private(object_t *obj, uint8_t flag_num,
+ char *segment_base)
+{
+ uintptr_t first_page = ((uintptr_t)obj) / 4096UL;
+
+ if (LIKELY((obj->stm_flags & GCFLAG_SMALL_UNIFORM) != 0)) {
+ mark_single_flag_private(first_page, flag_num);
+ }
+ else {
+ char *realobj;
+ size_t obj_size;
+ uintptr_t end_page;
+
+ /* get the size of the object */
+ realobj = REAL_ADDRESS(segment_base, obj);
+ obj_size = stmcb_size_rounded_up((struct object_s *)realobj);
+
+ /* that's the page *following* the last page with the object */
+ end_page = (((uintptr_t)obj) + obj_size + 4095) / 4096UL;
+
+ while (first_page < end_page)
+ mark_single_flag_private(first_page++, flag_num);
+ }
+}
+
+static void major_reshare_pages_range(uintptr_t first_page, uintptr_t end_page)
+{
+ uintptr_t i;
+ for (i = first_page; i < end_page; i++) {
+
+ uint8_t flag = flag_page_private[i];
+
+ if (flag == REMAPPING_PAGE) {
+ /* this page stays private after major collection */
+ flag_page_private[i] = PRIVATE_PAGE;
+ }
+ else if (flag >= PRIVATE_PAGE) {
+ /* this page becomes shared again */
+
+ /* XXX rather slow version here. improve! */
+
+ abort(); /* doesn't work, actually. we can't keep object data
+ from segment 1 and largemalloc's chunk data from
+ segment 0. mess mess mess */
+
+ char buffer[4096 + 64];
+ char *pbuffer = buffer;
+ pbuffer += ((-(uintptr_t)pbuffer) & 63); /* align */
+
+ char *ppage0 = get_segment_base(0) + i * 4096;
+ char *ppage1 = get_segment_base(1) + i * 4096;
+
+ /* do two copies: out of the page seen now as in the seg 0,
+ and then back into the same location after remapping */
+ pagecopy(pbuffer, ppage0);
+ /* a better approach is possible in which we don't have this */
+ madvise(ppage0, 4096, MADV_DONTNEED);
+ madvise(ppage1, 4096, MADV_DONTNEED);
+ d_remap_file_pages(ppage0, 4096, i);
+ d_remap_file_pages(ppage1, 4096, i);
+ pagecopy(ppage0, pbuffer);
+ flag_page_private[i] = SHARED_PAGE;
+
+ increment_total_allocated(-4096 * (NB_SEGMENTS-1));
+ }
+ }
+}
+
+static void major_reshare_pages(void)
+{
+ /* re-share pages if possible. Each re-sharing decreases
+ total_allocated by 4096. */
+ major_reshare_pages_range(
+ END_NURSERY_PAGE,
+ (uninitialized_page_start - stm_object_pages) / 4096UL);
+ major_reshare_pages_range(
+ (uninitialized_page_stop - stm_object_pages) / 4096UL,
+ NB_PAGES);
+}
+
+/************************************************************/
+
+
static inline void mark_record_trace(object_t **pobj)
{
/* takes a normal pointer to a thread-local pointer to an object */
@@ -198,13 +304,34 @@
return; /* already visited this object */
LIST_APPEND(mark_objects_to_trace, obj);
+
+ /* Note: this obj might be visited already, but from a different
+ segment. We ignore this case and skip re-visiting the object
+ anyway. The idea is that such an object is old (not from the
+ current transaction), otherwise it would not be possible to see
+ it in two segments; and moreover it is not modified, otherwise
+ mark_trace() would have been called on two different segments
+ already. That means that this object is identical in all
+ segments and only needs visiting once. (It may actually be in a
+ shared page, or maybe not.)
+ */
}
static void mark_trace(object_t *obj, char *segment_base)
{
+ uint8_t flag_num =
+ ((struct stm_priv_segment_info_s *)
+ REAL_ADDRESS(segment_base, STM_PSEGMENT))->write_lock_num;
+
assert(list_is_empty(mark_objects_to_trace));
while (1) {
+
+ /* first update the flag in flag_page_private[] to correspond
+ to this segment */
+ if (0) mark_flag_page_private(obj, flag_num, segment_base);
+
+ /* trace into the object (the version from 'segment_base') */
struct object_s *realobj =
(struct object_s *)REAL_ADDRESS(segment_base, obj);
stmcb_trace(realobj, &mark_record_trace);
@@ -373,7 +500,7 @@
static void major_collection_now_at_safe_point(void)
{
dprintf(("\n"));
- dprintf((" .----- major_collection_now_at_safe_point -----\n"));
+ dprintf((" .----- major collection -----------------------\n"));
assert(_has_mutex());
/* first, force a minor collection in each of the other segments */
@@ -396,6 +523,7 @@
/* sweeping */
mutex_pages_lock();
+ if (0) major_reshare_pages();
sweep_large_objects();
//sweep_uniform_pages();
mutex_pages_unlock();
@@ -403,9 +531,6 @@
clean_write_locks();
major_set_write_locks();
- /* XXX should re-share pages if possible; and each re-sharing
- decreases total_allocated by 4096 */
-
dprintf((" | used after collection: %ld\n",
(long)pages_ctl.total_allocated));
dprintf((" `----------------------------------------------\n"));
diff --git a/c7/stm/pages.h b/c7/stm/pages.h
--- a/c7/stm/pages.h
+++ b/c7/stm/pages.h
@@ -13,6 +13,10 @@
/* Page is private for each segment. */
PRIVATE_PAGE,
+
+ /* Higher values are used by gcpage.c to mark pages that are privatized
+ but where so far only one segment was found. */
+ _SINGLE_SEGMENT_PAGE
};
static uint8_t flag_page_private[NB_PAGES];
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -49,8 +49,8 @@
PROT_NONE);
struct stm_priv_segment_info_s *pr = get_priv_segment(i);
- assert(i + 1 <= 255);
- pr->write_lock_num = i + 1;
+ assert(_SINGLE_SEGMENT_PAGE + i <= 255);
+ pr->write_lock_num = _SINGLE_SEGMENT_PAGE + i;
pr->pub.segment_num = i;
pr->pub.segment_base = segment_base;
pr->objects_pointing_to_nursery = NULL;
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
@@ -182,3 +182,28 @@
def test_trace_correct_version_of_overflow_objects_2(self):
self.test_trace_correct_version_of_overflow_objects_1(size=5000)
+
+ def test_reshare_if_no_longer_modified_0(self, invert=0):
+ if invert:
+ self.switch(1)
+ self.start_transaction()
+ x = stm_allocate(5000)
+ self.push_root(x)
+ self.commit_transaction()
+ x = self.pop_root()
+ #
+ self.switch(1 - invert)
+ self.start_transaction()
+ self.push_root(x)
+ stm_set_char(x, 'A')
+ stm_major_collect()
+ assert lib._stm_total_allocated() == 5000 + LMO + 2 * 4096 # 2 pages
+ self.commit_transaction()
+ #
+ self.start_transaction()
+ stm_major_collect()
+ py.test.skip("XXX implement me")
+ assert lib._stm_total_allocated() == 5000 + LMO # shared again
+
+ def test_reshare_if_no_longer_modified_1(self):
+ self.test_reshare_if_no_longer_modified_0(invert=1)
diff --git a/c7/test/test_random.py b/c7/test/test_random.py
--- a/c7/test/test_random.py
+++ b/c7/test/test_random.py
@@ -364,6 +364,7 @@
thread_state.push_roots(ex)
ex.do('%s = stm_allocate(%s)' % (r, size))
+ ex.do('# 0x%x' % (int(ffi.cast("uintptr_t", ex.content[r]))))
thread_state.transaction_state.add_root(r, 0, True)
thread_state.pop_roots(ex)
@@ -375,6 +376,7 @@
r = global_state.get_new_root_name(True, num)
thread_state.push_roots(ex)
ex.do('%s = stm_allocate_refs(%s)' % (r, num))
+ ex.do('# 0x%x' % (int(ffi.cast("uintptr_t", ex.content[r]))))
thread_state.transaction_state.add_root(r, "ffi.NULL", True)
thread_state.pop_roots(ex)
More information about the pypy-commit
mailing list