Author: Armin Rigo <[email protected]>
Branch: c7-more-segments
Changeset: r1051:234b6a0ba9a5
Date: 2014-03-16 17:22 +0100
http://bitbucket.org/pypy/stmgc/changeset/234b6a0ba9a5/
Log: Resharing pages, still buggy, in-progress
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -263,7 +263,62 @@
return false;
}
-static void synchronize_object_now(object_t *obj, bool assume_local_private)
+static void copy_object_to_shared(object_t *obj, int source_segment_num)
+{
+ /* Only used by major GC. XXX There is a lot of code duplication
+ with synchronize_object_now() but I don't completely see how to
+ improve...
+ */
+ assert(_has_mutex_pages());
+ assert(!_is_young(obj));
+
+ uintptr_t start = (uintptr_t)obj;
+ uintptr_t first_page = start / 4096UL;
+ struct object_s *realobj = (struct object_s *)
+ REAL_ADDRESS(get_segment(source_segment_num)->segment_base, obj);
+
+ if (realobj->stm_flags & GCFLAG_SMALL_UNIFORM) {
+ abort();//XXX WRITE THE FAST CASE
+ }
+ else {
+ ssize_t obj_size = stmcb_size_rounded_up(realobj);
+ assert(obj_size >= 16);
+ uintptr_t end = start + obj_size;
+ uintptr_t last_page = (end - 1) / 4096UL;
+
+ for (; first_page <= last_page; first_page++) {
+
+ /* Copy the object into the shared page, if needed */
+ if (is_private_page(source_segment_num, first_page)) {
+
+ uintptr_t copy_size;
+ if (first_page == last_page) {
+ /* this is the final fragment */
+ copy_size = end - start;
+ }
+ else {
+ /* this is a non-final fragment, going up to the
+ page's end */
+ copy_size = 4096 - (start & 4095);
+ }
+ /* double-check that the result fits in one page */
+ assert(copy_size > 0);
+ assert(copy_size + (start & 4095) <= 4096);
+
+ char *src = REAL_ADDRESS(STM_SEGMENT->segment_base, start);
+ char *dst = REAL_ADDRESS(stm_object_pages, start);
+ if (copy_size == 4096)
+ pagecopy(dst, src);
+ else
+ memcpy(dst, src, copy_size);
+ }
+
+ start = (start + 4096) & ~4095;
+ }
+ }
+}
+
+static void synchronize_object_now(object_t *obj)
{
/* Copy around the version of 'obj' that lives in our own segment.
It is first copied into the shared pages, and then into other
@@ -306,12 +361,9 @@
assert(copy_size + (start & 4095) <= 4096);
/* First copy the object into the shared page, if needed */
- assert(IMPLY(assume_local_private,
- is_private_page(myself, first_page)));
-
char *src = REAL_ADDRESS(STM_SEGMENT->segment_base, start);
char *dst = REAL_ADDRESS(stm_object_pages, start);
- if (assume_local_private || is_private_page(myself, first_page)) {
+ if (is_private_page(myself, first_page)) {
if (copy_size == 4096)
pagecopy(dst, src);
else
@@ -352,7 +404,7 @@
return;
LIST_FOREACH_R(STM_PSEGMENT->large_overflow_objects, object_t *,
- synchronize_object_now(item, false));
+ synchronize_object_now(item));
}
static void push_modified_to_other_segments(void)
@@ -374,7 +426,7 @@
/* copy the object to the shared page, and to the other
private pages as needed */
- synchronize_object_now(item, true);
+ synchronize_object_now(item);
}));
list_clear(STM_PSEGMENT->modified_old_objects);
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -224,4 +224,5 @@
asm("/* workaround for llvm bug */");
}
-static void synchronize_object_now(object_t *obj, bool assume_local_private);
+static void copy_object_to_shared(object_t *obj, int source_segment_num);
+static void synchronize_object_now(object_t *obj);
diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -192,130 +192,129 @@
/************************************************************/
+static uintptr_t object_last_page(object_t *obj)
+{
+ uintptr_t lastbyte;
+ struct object_s *realobj =
+ (struct object_s *)REAL_ADDRESS(stm_object_pages, obj);
-#if 0
-static inline void mark_single_flag_private(uintptr_t pagenum)
-{
- if (flag_page_private[pagenum] == PRIVATE_PAGE) {
- assert(pagenum >= END_NURSERY_PAGE);
- assert(pagenum < NB_PAGES);
- flag_page_private[pagenum] = SEGMENT1_PAGE;
+ if (realobj->stm_flags & GCFLAG_SMALL_UNIFORM) {
+ lastbyte = (uintptr_t)obj;
}
else {
- assert(flag_page_private[pagenum] == SHARED_PAGE ||
- flag_page_private[pagenum] == SEGMENT1_PAGE);
+ /* get the size of the object */
+ size_t obj_size = stmcb_size_rounded_up(realobj);
+
+ /* that's the last byte within the object */
+ lastbyte = ((uintptr_t)obj) + obj_size - 1;
}
+ return lastbyte / 4096UL;
}
-static inline void mark_flag_page_private(object_t *obj, char *segment_base)
+/* A macro that expands to: run the 'expression' for every page that
+ touches objects in the 'modified_old_objects' list.
+*/
+#define BITOP(expression) \
+ LIST_FOREACH_R( \
+ get_priv_segment(segment_num)->modified_old_objects, \
+ object_t * /* item */, \
+ ({ \
+ struct page_shared_s *ps; \
+ uintptr_t pagenum = ((uintptr_t)item) / 4096UL; \
+ uintptr_t count = object_last_page(item) - pagenum; \
+ ps = &pages_privatized[pagenum - PAGE_FLAG_START]; \
+ do { \
+ expression; \
+ ps++; \
+ } while (count--); \
+ }));
+
+static void major_hide_private_bits_for_modified_objects(long segment_num)
{
- uintptr_t first_page = ((uintptr_t)obj) / 4096UL;
-
- if (LIKELY((obj->stm_flags & GCFLAG_SMALL_UNIFORM) != 0)) {
- mark_single_flag_private(first_page);
- }
- 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++);
- }
+ uint64_t negativebitmask = ~(1 << (segment_num - 1));
+#ifndef NDEBUG
+ BITOP(assert((ps->by_segment & negativebitmask) != ps->by_segment));
+#endif
+ BITOP(ps->by_segment &= negativebitmask);
}
-static void major_reshare_pages_range(uintptr_t first_page, uintptr_t end_page)
+static void major_restore_private_bits_for_modified_objects(long segment_num)
{
- uintptr_t i;
- for (i = first_page; i < end_page; i++) {
+ uint64_t positivebitmask = 1 << (segment_num - 1);
+ BITOP(ps->by_segment |= positivebitmask);
+}
- switch (flag_page_private[i]) {
-
- case SEGMENT1_PAGE:
- /* this page stays private after major collection */
- flag_page_private[i] = PRIVATE_PAGE;
- break;
-
- case PRIVATE_PAGE:;
- /* this page becomes shared again. No object in it was
- traced belonging to a segment other than 0.
-
- XXX This is maybe a too-strict condition, but the more
- general condition "all traced objects belong to the same
- segment" has problems with large objects in segments > 0.
- More precisely: we'd need to keep in the shared page the
- content of the objects (from segment > 0), but also the
- largemalloc's chunk data (stored in segment 0).
- */
-#if NB_SEGMENTS != 2
-# error "limited to NB_SEGMENTS == 2"
-#endif
- char *ppage0 = get_segment_base(0) + i * 4096;
- char *ppage1 = get_segment_base(1) + i * 4096;
-
- /* two cases for mapping pages to file-pages (fpages):
- - (0->0, 1->1)
- - (0->1, 1->0)
- Distinguish which case it is by hacking a lot */
-
- // 0->0,1->1 or 0->1,1->0
- /* map page 1 to fpage 0: */
- d_remap_file_pages(ppage1, 4096, i);
- // 0->0,1->0 or 0->1,1->0
-
- char oldvalue0 = *ppage0;
- char oldvalue1 = *ppage1;
- asm("":::"memory");
- *ppage0 = 1 + oldvalue1;
- asm("":::"memory");
- char newvalue1 = *ppage1;
- asm("":::"memory");
- *ppage0 = oldvalue0;
- /* if we are in 0->0,1->0, old and new are different:
- In this case we are done. We keep the largemalloc
- data structure and objects of ppage0/fpage0 */
- if (oldvalue1 == newvalue1) {
- // 0->1,1->0
- /* ppage0/fpage1 has the data structure that we want
- in ppage1/fpage0, so we copy it */
- pagecopy(ppage1, ppage0); // copy from page0 to page1,
- // i.e. from the underlying memory seg1 to seg0
- d_remap_file_pages(ppage0, 4096, i);
- // 0->0,1->0
- }
- flag_page_private[i] = SHARED_PAGE;
-
- increment_total_allocated(-4096 * (NB_SEGMENTS-1));
- break;
-
- case SHARED_PAGE:
- break; /* stay shared */
-
- default:
- assert(!"unexpected flag_page_private");
- }
- }
-}
+#undef BITOP
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, /* not the nursery! */
- (uninitialized_page_start - stm_object_pages) / 4096UL);
- major_reshare_pages_range(
- (uninitialized_page_stop - stm_object_pages) / 4096UL,
- NB_PAGES);
+
+ long i;
+ mutex_pages_lock();
+ for (i = 1; i <= NB_SEGMENTS; i++) {
+
+ /* For each segment, push the current overflow objects from
+ private pages to the corresponding shared pages, if necessary.
+ */
+ struct list_s *lst = get_priv_segment(i)->large_overflow_objects;
+ if (lst != NULL) {
+ LIST_FOREACH_R(lst, object_t *, copy_object_to_shared(item, i));
+ }
+
+ /* The 'modified_old_objects' list gives the list of objects
+ whose pages need to remain private. We temporarily remove
+ these bits from 'pages_privatized', so that these pages will
+ be skipped by the loop below.
+ */
+ major_hide_private_bits_for_modified_objects(i);
+ }
+
+ /* Now loop over all pages that are still in 'pages_privatized',
+ and re-share them.
+ */
+ uintptr_t pagenum, endpagenum;
+ struct page_shared_s ps;
+ pagenum = END_NURSERY_PAGE; /* starts after the nursery */
+ endpagenum = (uninitialized_page_start - stm_object_pages) / 4096UL;
+
+ while (1) {
+ if (UNLIKELY(pagenum == endpagenum)) {
+ /* we reach this point usually twice, because there are
+ more pages after 'uninitialized_page_stop' */
+ if (endpagenum == NB_PAGES)
+ break; /* done */
+ pagenum = (uninitialized_page_stop - stm_object_pages) / 4096UL;
+ endpagenum = NB_PAGES;
+ if (pagenum == endpagenum)
+ break; /* no pages in the 2nd section, so done too */
+ }
+
+ ps = pages_privatized[pagenum - PAGE_FLAG_START];
+ if (ps.by_segment != 0) {
+ pages_privatized[pagenum - PAGE_FLAG_START].by_segment = 0;
+
+ long j;
+ for (j = 0; j < NB_SEGMENTS; j++) {
+ if (ps.by_segment & (1 << j)) {
+ /* Page 'pagenum' is private in segment 'j + 1'. Reshare */
+ page_reshare(j + 1, pagenum);
+ }
+ }
+ }
+ pagenum++;
+ }
+
+ /* Done. Now 'pages_privatized' should be entirely zeroes. Restore
+ the previously-hidden bits
+ */
+ for (i = 1; i <= NB_SEGMENTS; i++) {
+ major_restore_private_bits_for_modified_objects(i);
+ }
+ mutex_pages_unlock();
}
-#endif
+
/************************************************************/
@@ -472,7 +471,9 @@
static void sweep_large_objects(void)
{
+ mutex_pages_lock();
_stm_largemalloc_sweep();
+ mutex_pages_unlock();
}
static void clean_write_locks(void)
@@ -488,7 +489,7 @@
memset(write_locks + lock2_idx, 0, sizeof(write_locks) - lock2_idx);
}
-static void major_set_write_locks(void)
+static void major_restore_write_locks(void)
{
/* restore the write locks on the modified objects */
long i;
@@ -518,6 +519,10 @@
dprintf((" | used before collection: %ld\n",
(long)pages_ctl.total_allocated));
+ /* reshare pages */
+ if (RESHARE_PAGES)
+ major_reshare_pages();
+
/* marking */
LIST_CREATE(mark_objects_to_trace);
mark_visit_from_modified_objects();
@@ -531,17 +536,11 @@
clean_up_segment_lists();
/* sweeping */
- mutex_pages_lock();
-#if 0
- if (RESHARE_PAGES)
- major_reshare_pages();
-#endif
sweep_large_objects();
//sweep_uniform_pages();
- mutex_pages_unlock();
clean_write_locks();
- major_set_write_locks();
+ major_restore_write_locks();
dprintf((" | used after collection: %ld\n",
(long)pages_ctl.total_allocated));
diff --git a/c7/stm/gcpage.h b/c7/stm/gcpage.h
--- a/c7/stm/gcpage.h
+++ b/c7/stm/gcpage.h
@@ -15,7 +15,7 @@
#define GC_MAJOR_COLLECT 1.82
/* re-share pages after major collections (1 or 0) */
-#define RESHARE_PAGES 0
+#define RESHARE_PAGES 1
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -200,7 +200,7 @@
*/
if (STM_PSEGMENT->minor_collect_will_commit_now) {
mutex_pages_lock();
- synchronize_object_now(obj, false);
+ synchronize_object_now(obj);
mutex_pages_unlock();
}
else
diff --git a/c7/stm/pages.c b/c7/stm/pages.c
--- a/c7/stm/pages.c
+++ b/c7/stm/pages.c
@@ -140,6 +140,33 @@
mutex_pages_unlock();
}
+static void page_reshare(long segment_num, uintptr_t pagenum)
+{
+ char *segment_base = get_segment(segment_num)->segment_base;
+
+#if 0 /* disabled: the private page that we are removing is
+ typically missing the inter-object information from
+ largemalloc.c */
+ long i, errors=0;
+ uint64_t *p = (uint64_t *)(stm_object_pages + pagenum * 4096UL);
+ uint64_t *q = (uint64_t *)(segment_base + pagenum * 4096UL);
+ for (i = 0; i < 4096 / 8; i++) {
+ if (p[i] != q[i]) {
+ fprintf(stderr, "%p: 0x%lx\t\t%p: 0x%lx\n",
+ &p[i], p[i], &q[i], q[i]);
+ errors++;
+ }
+ }
+ assert(!errors);
+#endif
+
+ madvise(segment_base + pagenum * 4096UL, 4096, MADV_DONTNEED);
+ d_remap_file_pages(segment_base + pagenum * 4096UL,
+ 4096, pagenum);
+ increment_total_allocated(-4096);
+}
+
+
#if 0
static bool is_fully_in_shared_pages(object_t *obj)
{
diff --git a/c7/stm/pages.h b/c7/stm/pages.h
--- a/c7/stm/pages.h
+++ b/c7/stm/pages.h
@@ -35,8 +35,9 @@
static struct page_shared_s pages_privatized[PAGE_FLAG_END - PAGE_FLAG_START];
+static void pages_initialize_shared(uintptr_t pagenum, uintptr_t count);
static void page_privatize(uintptr_t pagenum);
-static void pages_initialize_shared(uintptr_t pagenum, uintptr_t count);
+static void page_reshare(long segment_num, uintptr_t pagenum);
static void mutex_pages_lock(void);
static void mutex_pages_unlock(void);
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
@@ -202,7 +202,6 @@
#
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):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit