[pypy-commit] stmgc c7-more-segments: Refactor after discussion with Remi: don't use a tree to record page
arigo
noreply at buildbot.pypy.org
Sun Mar 16 14:34:18 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch: c7-more-segments
Changeset: r1049:9eed4e26972b
Date: 2014-03-16 14:34 +0100
http://bitbucket.org/pypy/stmgc/changeset/9eed4e26972b/
Log: Refactor after discussion with Remi: don't use a tree to record page
remappings, and only do trivial remappings (page N is mapped to
either to segment 0's page N, or to itself). Use a simple array of
bits.
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -8,6 +8,28 @@
memset(write_locks, 0, sizeof(write_locks));
}
+static void check_flag_write_barrier(object_t *obj)
+{
+ /* check that all copies of the object, apart from mine, have the
+ GCFLAG_WRITE_BARRIER. (a bit messy because it's possible that we
+ read a page in the middle of privatization by another thread)
+ */
+#ifndef NDEBUG
+ long i;
+ struct object_s *o1;
+ for (i = 0; i <= NB_SEGMENTS; i++) {
+ if (i == STM_SEGMENT->segment_num)
+ continue;
+ o1 = (struct object_s *)REAL_ADDRESS(get_segment_base(i), obj);
+ if (!(o1->stm_flags & GCFLAG_WRITE_BARRIER)) {
+ mutex_pages_lock(); /* try again... */
+ if (!(o1->stm_flags & GCFLAG_WRITE_BARRIER))
+ stm_fatalerror("missing GCFLAG_WRITE_BARRIER");
+ mutex_pages_unlock();
+ }
+ }
+#endif
+}
void _stm_write_slowpath(object_t *obj)
{
@@ -106,37 +128,20 @@
}
/* check that we really have a private page */
- assert(tree_contains(STM_PSEGMENT->private_page_mapping,
- ((uintptr_t)obj) / 4096));
+ assert(is_private_page(STM_SEGMENT->segment_num,
+ ((uintptr_t)obj) / 4096));
- /* check that so far all copies of the object have the flag
- (a bit messy because it's possible that we read a page in
- the middle of privatization by another thread) */
- long i;
-#ifndef NDEBUG
- long busy_loop = 1000000000;
- for (i = 0; i <= NB_SEGMENTS; i++) {
- while (!(((struct object_s *)REAL_ADDRESS(get_segment_base(i), obj))
- ->stm_flags & GCFLAG_WRITE_BARRIER)) {
- spin_loop();
- if (!--busy_loop)
- stm_fatalerror("missing GCFLAG_WRITE_BARRIER");
- }
- }
-#endif
+ /* check that so far all copies of the object have the flag */
+ check_flag_write_barrier(obj);
/* remove GCFLAG_WRITE_BARRIER, but only if we succeeded in
getting the write-lock */
assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
obj->stm_flags &= ~GCFLAG_WRITE_BARRIER;
- /* for sanity, check that all other segment copies of this object
- still have the flag (including the shared copy) */
- for (i = 0; i <= NB_SEGMENTS; i++) {
- if (i != STM_SEGMENT->segment_num)
- assert(((struct object_s *)REAL_ADDRESS(get_segment_base(i), obj))
- ->stm_flags & GCFLAG_WRITE_BARRIER);
- }
+ /* for sanity, check again that all other segment copies of this
+ object still have the flag (so privatization worked) */
+ check_flag_write_barrier(obj);
}
static void reset_transaction_read_version(void)
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -75,13 +75,6 @@
struct stm_priv_segment_info_s {
struct stm_segment_info_s pub;
- /* Dict whose keys are shared page numbers, and whose values are
- the corresponding private page number. */
- struct tree_s *private_page_mapping;
-
- /* Head of a free list of private pages. */
- uintptr_t private_free_page_num;
-
/* List of old objects (older than the current transaction) that the
current transaction attempts to modify. This is used to track
the STM status: they are old objects that where written to and
diff --git a/c7/stm/misc.c b/c7/stm/misc.c
--- a/c7/stm/misc.c
+++ b/c7/stm/misc.c
@@ -43,9 +43,8 @@
#ifdef STM_TESTS
uintptr_t _stm_get_private_page(uintptr_t pagenum)
{
- wlog_t *item;
- TREE_FIND(*STM_PSEGMENT->private_page_mapping, pagenum, item, return 0);
- return item->val;
+ /* xxx returns 0 or 1 now */
+ return is_private_page(STM_SEGMENT->segment_num, pagenum);
}
long _stm_count_modified_old_objects(void)
diff --git a/c7/stm/pages.c b/c7/stm/pages.c
--- a/c7/stm/pages.c
+++ b/c7/stm/pages.c
@@ -25,6 +25,7 @@
static void teardown_pages(void)
{
memset(&pages_ctl, 0, sizeof(pages_ctl));
+ memset(pages_privatized, 0, sizeof(pages_privatized));
}
static void mutex_pages_lock(void)
@@ -111,41 +112,30 @@
static void page_privatize(uintptr_t pagenum)
{
- wlog_t *item;
- TREE_FIND(*STM_PSEGMENT->private_page_mapping, pagenum, item,
- goto not_found);
+ if (is_private_page(STM_SEGMENT->segment_num, pagenum)) {
+ /* the page is already privatized */
+ return;
+ }
- /* the page is already privatized */
- return;
-
- not_found:;
- /* lock, to prevent concurrent threads from looking up my own
- 'private_page_mapping' in parallel */
+ /* lock, to prevent concurrent threads from looking up this thread's
+ 'pages_privatized' bits in parallel */
mutex_pages_lock();
- /* look up the next free page */
- uintptr_t free_page_num = STM_PSEGMENT->private_free_page_num;
-
- /* "mount" it in the segment
- (XXX later we should again attempt to group together many calls to
- d_remap_file_pages() in succession) */
- char *new_page = STM_SEGMENT->segment_base + pagenum * 4096UL;
- d_remap_file_pages(new_page, 4096,
- NB_PAGES * STM_SEGMENT->segment_num + free_page_num);
+ /* "unmaps" the page to make the address space location correspond
+ again to its underlying file offset (XXX later we should again
+ attempt to group together many calls to d_remap_file_pages() in
+ succession) */
+ uintptr_t pagenum_in_file = NB_PAGES * STM_SEGMENT->segment_num + pagenum;
+ char *new_page = stm_object_pages + pagenum_in_file * 4096UL;
+ d_remap_file_pages(new_page, 4096, pagenum_in_file);
increment_total_allocated(4096);
- /* update private_free_page_num */
- uintptr_t future_page = *(uintptr_t *)new_page;
- if (future_page == 0) {
- future_page = free_page_num + 1;
- }
- STM_PSEGMENT->private_free_page_num = future_page;
-
/* copy the content from the shared (segment 0) source */
pagecopy(new_page, stm_object_pages + pagenum * 4096UL);
- /* update private_page_mapping */
- tree_insert(STM_PSEGMENT->private_page_mapping, pagenum, free_page_num);
+ /* add this thread's 'pages_privatized' bit */
+ uint64_t bitmask = 1UL << (STM_SEGMENT->segment_num - 1);
+ pages_privatized[pagenum - PAGE_FLAG_START].by_segment |= bitmask;
mutex_pages_unlock();
}
diff --git a/c7/stm/pages.h b/c7/stm/pages.h
--- a/c7/stm/pages.h
+++ b/c7/stm/pages.h
@@ -3,17 +3,11 @@
has a "shared copy" and zero or more "private copies".
The shared copy of a page is stored in the mmap at the file offset
- corresponding to the segment 0 offset (with all other segments
- remapping to the segment 0 offset). Private copies for segment N are
- made in the offset from segment N (for 1 <= N <= NB_SEGMENTS),
- picking file offsets that are simply the next free ones. Each
- segment maintains a tree 'private_page_mapping', which maps shared
- pages to private copies.
-
- A major collection looks for pages that are no-longer-used private
- copies, and discard them, remapping the address to the shared page.
- The pages thus freed are recorded into a free list, and can be reused
- as the private copies of the following (unrelated) pages.
+ corresponding to the segment 0 offset. Initially, accessing a page
+ from segment N remaps to segment 0. If the page is turned private,
+ then we "un-remap" it to its initial location. The 'pages_privatized'
+ global array records if a page is currently mapped to segment 0
+ (shared page) or to its natural location (private page).
Note that this page manipulation logic uses remap_file_pages() to
fully hide its execution cost behind the CPU's memory management unit.
@@ -22,6 +16,25 @@
(which works at the object granularity, not the page granularity).
*/
+#define PAGE_FLAG_START END_NURSERY_PAGE
+#define PAGE_FLAG_END NB_PAGES
+
+struct page_shared_s {
+#if NB_SEGMENTS <= 8
+ uint8_t by_segment;
+#elif NB_SEGMENTS <= 16
+ uint16_t by_segment;
+#elif NB_SEGMENTS <= 32
+ uint32_t by_segment;
+#elif NB_SEGMENTS <= 64
+ uint64_t by_segment;
+#else
+# error "NB_SEGMENTS > 64 not supported right now"
+#endif
+};
+
+static struct page_shared_s pages_privatized[PAGE_FLAG_END - PAGE_FLAG_START];
+
static void page_privatize(uintptr_t pagenum);
static void pages_initialize_shared(uintptr_t pagenum, uintptr_t count);
@@ -35,6 +48,7 @@
static inline bool is_private_page(long segnum, uintptr_t pagenum)
{
- return tree_contains(get_priv_segment(segnum)->private_page_mapping,
- pagenum);
+ assert(pagenum >= PAGE_FLAG_START);
+ uint64_t bitmask = 1UL << (segnum - 1);
+ return (pages_privatized[pagenum - PAGE_FLAG_START].by_segment & bitmask);
}
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -58,8 +58,6 @@
pr->write_lock_num = i;
pr->pub.segment_num = i;
pr->pub.segment_base = segment_base;
- pr->private_page_mapping = tree_create();
- pr->private_free_page_num = END_NURSERY_PAGE;
pr->objects_pointing_to_nursery = NULL;
pr->large_overflow_objects = NULL;
pr->modified_old_objects = list_create();
More information about the pypy-commit
mailing list