[pypy-commit] stmgc c8-new-page-handling: in-progress: break everything :-) The goal is to use backups that are
arigo
noreply at buildbot.pypy.org
Tue Sep 23 18:41:56 CEST 2014
Author: Armin Rigo <arigo at tunes.org>
Branch: c8-new-page-handling
Changeset: r1410:61d043d6d6f9
Date: 2014-09-23 18:42 +0200
http://bitbucket.org/pypy/stmgc/changeset/61d043d6d6f9/
Log: in-progress: break everything :-) The goal is to use backups that
are longer-lived than one transaction, in order to allow the
segfault handler to cleanly reconstruct any missing page in all
cases.
diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -29,48 +29,6 @@
}
-static void _update_obj_from(int from_seg, object_t *obj, uintptr_t only_page)
-{
- /* updates 'obj' in our accessible pages from another segment's
- page or bk copy. (never touch PROT_NONE memory)
- only_page = -1 means update whole obj, only_page=pagenum means only
- update memory in page 'pagenum'
- */
- /* XXXXXXX: are we sure everything is readable in from_seg??? */
- size_t obj_size;
-
- dprintf(("_update_obj_from(%d, %p)\n", from_seg, obj));
- assert(get_priv_segment(from_seg)->privatization_lock);
-
- /* look the obj up in the other segment's modified_old_objects to
- get its backup copy: */
- acquire_modified_objs_lock(from_seg);
-
- wlog_t *item;
- struct tree_s *tree = get_priv_segment(from_seg)->modified_old_objects;
- TREE_FIND(tree, (uintptr_t)obj, item, goto not_found);
-
- obj_size = stmcb_size_rounded_up((struct object_s*)item->val);
-
- memcpy_to_accessible_pages(STM_SEGMENT->segment_num, obj,
- (char*)item->val, obj_size, only_page);
-
- release_modified_objs_lock(from_seg);
- return;
-
- not_found:
- /* copy from page directly (obj is unmodified) */
- obj_size = stmcb_size_rounded_up(
- (struct object_s*)REAL_ADDRESS(get_segment_base(from_seg), obj));
-
- memcpy_to_accessible_pages(STM_SEGMENT->segment_num, obj,
- REAL_ADDRESS(get_segment_base(from_seg), obj),
- obj_size, only_page);
-
- release_modified_objs_lock(from_seg);
-}
-
-
static void copy_bk_objs_in_page_from(int from_segnum, uintptr_t pagenum)
{
/* looks at all bk copies of objects overlapping page 'pagenum' and
@@ -78,7 +36,8 @@
dprintf(("copy_bk_objs_in_page_from(%d, %lu)\n", from_segnum, pagenum));
acquire_modified_objs_lock(from_segnum);
- struct tree_s *tree = get_priv_segment(from_segnum)->modified_old_objects;
+ abort();
+ struct tree_s *tree = NULL; // get_priv_segment(from_segnum)->modified_old_objects;
wlog_t *item;
TREE_LOOP_FORWARD(tree, item); {
object_t *obj = (object_t*)item->addr;
@@ -111,15 +70,15 @@
return;
while ((cl = cl->next)) {
- if ((uintptr_t)cl == -1)
+ if (cl == (void *)-1)
return;
OPT_ASSERT(cl->segment_num >= 0 && cl->segment_num < NB_SEGMENTS);
object_t *obj;
size_t i = 0;
- while ((obj = cl->written[i])) {
- _update_obj_from(cl->segment_num, obj, pagenum);
+ while ((obj = cl->written[i].object)) {
+ abort(); //_update_obj_from(cl->segment_num, obj, pagenum);
i++;
};
@@ -177,7 +136,7 @@
/* in case page is already newer, validate everything now to have a common
revision for all pages */
- _stm_validate(NULL, true);
+ //_stm_validate(NULL, true);
}
static void _signal_handler(int sig, siginfo_t *siginfo, void *context)
@@ -219,101 +178,111 @@
void _dbg_print_commit_log()
{
- volatile struct stm_commit_log_entry_s *cl;
- cl = (volatile struct stm_commit_log_entry_s *)&commit_log_root;
+ struct stm_commit_log_entry_s *cl = &commit_log_root;
- fprintf(stderr, "root (%p, %d)\n", cl->next, cl->segment_num);
+ fprintf(stderr, "commit log root (%p, %d)\n", cl->next, cl->segment_num);
while ((cl = cl->next)) {
- if ((uintptr_t)cl == -1) {
- fprintf(stderr, "INEVITABLE\n");
+ if (cl == (void *)-1) {
+ fprintf(stderr, " INEVITABLE\n");
return;
}
- size_t i = 0;
fprintf(stderr, " elem (%p, %d)\n", cl->next, cl->segment_num);
- object_t *obj;
- while ((obj = cl->written[i])) {
- fprintf(stderr, "-> %p\n", obj);
- i++;
- };
+ struct stm_undo_s *undo = cl->written;
+ struct stm_undo_s *end = undo + cl->written_count;
+ for (; undo < end; undo++) {
+ fprintf(stderr, " obj %p, size %d, ofs %lu\n", undo->object,
+ SLICE_SIZE(undo->slice), SLICE_OFFSET(undo->slice));
+ }
}
}
+static void reapply_undo_log(struct stm_undo_s *undo)
+{
+ /* read the object (or object slice) described by 'undo', and
+ re-applies it to our current segment.
+ */
+ dprintf(("_update_obj_from_undo(obj=%p, size=%d, ofs=%lu)\n",
+ undo->object, SLICE_SIZE(undo->slice), SLICE_OFFSET(undo->slice)));
-static void _stm_validate(void *free_if_abort, bool locks_acquired)
+ size_t ofs = SLICE_OFFSET(undo->slice);
+ size_t size = SLICE_SIZE(undo->slice);
+ stm_char *slice_start = ((stm_char *)undo->object) + ofs;
+ stm_char *slice_end = slice_start + size;
+
+ uintptr_t page_start = ((uintptr_t)slice_start) / 4096;
+ if ((uintptr_t)slice_end <= (page_start + 1) * 4096) {
+
+ /* the object fits inside a single page: fast path */
+ if (get_page_status_in(STM_SEGMENT->segment_num, page_start)
+ == PAGE_NO_ACCESS) {
+ return; /* ignore the object: it is in a NO_ACCESS page */
+ }
+
+ char *src = undo->backup;
+ char *dst = REAL_ADDRESS(STM_SEGMENT->segment_base, slice_start);
+ memcpy(dst, src, size);
+ }
+ else {
+ abort(); //XXX
+ }
+}
+
+static void reset_modified_from_backup_copies(int segment_num); /* forward */
+
+static void _stm_validate(void *free_if_abort)
{
/* go from last known entry in commit log to the
most current one and apply all changes done
by other transactions. Abort if we read one of
the committed objs. */
- if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) {
- assert((uintptr_t)STM_PSEGMENT->last_commit_log_entry->next == -1);
- if (locks_acquired)
- release_all_privatization_locks();
- return;
- }
-
- if (locks_acquired)
- assert(all_privatization_locks_acquired());
- else
- acquire_all_privatization_locks();
-
- volatile struct stm_commit_log_entry_s *cl, *prev_cl;
- cl = prev_cl = (volatile struct stm_commit_log_entry_s *)
- STM_PSEGMENT->last_commit_log_entry;
+ struct stm_commit_log_entry_s *cl = STM_PSEGMENT->last_commit_log_entry;
+ struct stm_commit_log_entry_s *next_cl;
+ /* Don't check this 'cl'. This entry is already checked */
bool needs_abort = false;
- /* Don't check 'cl'. This entry is already checked */
- while ((cl = cl->next)) {
- if ((uintptr_t)cl == -1) {
+ while ((next_cl = cl->next) != NULL) {
+ if (next_cl == (void *)-1) {
/* there is an inevitable transaction running */
- release_all_privatization_locks();
#if STM_TESTS
- free(free_if_abort);
+ if (free_if_abort != (void *)-1)
+ free(free_if_abort);
stm_abort_transaction();
#endif
- cl = prev_cl;
+ abort(); /* XXX non-busy wait here */
_stm_collectable_safe_point();
acquire_all_privatization_locks();
continue;
}
- prev_cl = cl;
+ cl = next_cl;
- OPT_ASSERT(cl->segment_num >= 0 && cl->segment_num < NB_SEGMENTS);
+ /*int srcsegnum = cl->segment_num;
+ OPT_ASSERT(srcsegnum >= 0 && srcsegnum < NB_SEGMENTS);*/
- object_t *obj;
- size_t i = 0;
- while ((obj = cl->written[i])) {
- _update_obj_from(cl->segment_num, obj, -1);
+ struct stm_undo_s *undo = cl->written;
+ struct stm_undo_s *end = cl->written + cl->written_count;
- if (_stm_was_read(obj)) {
- needs_abort = true;
+ for (; undo < end; undo++) {
- /* if we wrote this obj, we need to free its backup and
- remove it from modified_old_objects because
- we would otherwise overwrite the updated obj on abort */
- acquire_modified_objs_lock(STM_SEGMENT->segment_num);
- wlog_t *item;
- struct tree_s *tree = STM_PSEGMENT->modified_old_objects;
- TREE_FIND(tree, (uintptr_t)obj, item, goto not_found);
-
- free((void*)item->val);
- TREE_FIND_DELETE(tree, item);
-
- not_found:
- /* nothing todo */
- release_modified_objs_lock(STM_SEGMENT->segment_num);
+ if (_stm_was_read(undo->object)) {
+ /* first reset all modified objects from the backup
+ copies as soon as the first conflict is detected;
+ then we will proceed below to update our segment from
+ the old (but unmodified) version to the newer version. */
+ if (!needs_abort) {
+ reset_modified_from_backup_copies(STM_SEGMENT->segment_num);
+ needs_abort = true;
+ }
}
-
- i++;
- };
+ reapply_undo_log(undo);
+ }
/* last fully validated entry */
- STM_PSEGMENT->last_commit_log_entry = (struct stm_commit_log_entry_s *)cl;
+ STM_PSEGMENT->last_commit_log_entry = cl;
}
- release_all_privatization_locks();
if (needs_abort) {
- free(free_if_abort);
+ if (free_if_abort != (void *)-1)
+ free(free_if_abort);
stm_abort_transaction();
}
}
@@ -324,69 +293,61 @@
// we don't need the privatization lock, as we are only
// reading from modified_old_objs and nobody but us can change it
- struct tree_s *tree = STM_PSEGMENT->modified_old_objects;
- size_t count = tree_count(tree);
- size_t byte_len = sizeof(struct stm_commit_log_entry_s) + (count + 1) * sizeof(object_t*);
+ struct list_s *list = STM_PSEGMENT->modified_old_objects;
+ OPT_ASSERT((list_count(list) % 3) == 0);
+ size_t count = list_count(list) / 3;
+ size_t byte_len = sizeof(struct stm_commit_log_entry_s) +
+ count * sizeof(struct stm_undo_s);
struct stm_commit_log_entry_s *result = malloc(byte_len);
result->next = NULL;
result->segment_num = STM_SEGMENT->segment_num;
-
- int i = 0;
- wlog_t *item;
- TREE_LOOP_FORWARD(tree, item); {
- result->written[i] = (object_t*)item->addr;
- i++;
- } TREE_LOOP_END;
-
- OPT_ASSERT(count == i);
- result->written[count] = NULL;
-
+ result->written_count = count;
+ memcpy(result->written, list->items, count * sizeof(struct stm_undo_s));
return result;
}
-static void _validate_and_add_to_commit_log()
+static void _validate_and_attach(struct stm_commit_log_entry_s *new)
{
- struct stm_commit_log_entry_s *new;
- volatile struct stm_commit_log_entry_s **to;
+ struct stm_commit_log_entry_s *old;
+
+ while (1) {
+ _stm_validate(/* free_if_abort =*/ new);
+
+ /* try to attach to commit log: */
+ old = STM_PSEGMENT->last_commit_log_entry;
+ if (old->next == NULL &&
+ __sync_bool_compare_and_swap(&old->next, NULL, new))
+ break; /* success! */
+ }
+}
+
+static void _validate_and_turn_inevitable(void)
+{
+ _validate_and_attach((struct stm_commit_log_entry_s *)-1);
+}
+
+static void _validate_and_add_to_commit_log(void)
+{
+ struct stm_commit_log_entry_s *old, *new;
new = _create_commit_log_entry();
if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) {
- OPT_ASSERT((uintptr_t)STM_PSEGMENT->last_commit_log_entry->next == -1);
+ old = STM_PSEGMENT->last_commit_log_entry;
+ OPT_ASSERT(old->next == (void *)-1);
- to = &(STM_PSEGMENT->last_commit_log_entry->next);
- bool yes = __sync_bool_compare_and_swap(to, (void*)-1, new);
+ bool yes = __sync_bool_compare_and_swap(&old->next, (void*)-1, new);
OPT_ASSERT(yes);
- return;
}
-
- /* regular transaction: */
- do {
- _stm_validate(new, false);
-
- /* try attaching to commit log: */
- to = &(STM_PSEGMENT->last_commit_log_entry->next);
- } while (!__sync_bool_compare_and_swap(to, NULL, new));
-}
-
-static void _validate_and_turn_inevitable()
-{
- struct stm_commit_log_entry_s *new;
- volatile struct stm_commit_log_entry_s **to;
-
- new = (struct stm_commit_log_entry_s*)-1;
- do {
- stm_validate();
-
- /* try attaching to commit log: */
- to = &(STM_PSEGMENT->last_commit_log_entry->next);
- } while (!__sync_bool_compare_and_swap(to, NULL, new));
+ else {
+ _validate_and_attach(new);
+ }
}
/* ############# STM ############# */
void stm_validate()
{
- _stm_validate(NULL, false);
+ _stm_validate(NULL);
}
@@ -441,7 +402,7 @@
choosing to make us PRIVATE is harder because then nobody must ever
update the shared page in stm_validate() except if it is the sole
reader of it. But then we don't actually know which revision the page is at. */
- long i;
+ int i;
for (i = 0; i < NB_SEGMENTS; i++) {
if (i == my_segnum)
continue;
@@ -466,12 +427,13 @@
/* phew, now add the obj to the write-set and register the
backup copy. */
/* XXX: possibly slow check; try overflow objs again? */
- if (!tree_contains(STM_PSEGMENT->modified_old_objects, (uintptr_t)obj)) {
+ abort();
+ /*if (!tree_contains(STM_PSEGMENT->modified_old_objects, (uintptr_t)obj)) {
acquire_modified_objs_lock(my_segnum);
tree_insert(STM_PSEGMENT->modified_old_objects,
(uintptr_t)obj, (uintptr_t)bk_obj);
release_modified_objs_lock(my_segnum);
- }
+ }*/
/* XXX else... what occurs with bk_obj? */
/* done fiddling with protection and privatization */
@@ -529,7 +491,7 @@
reset_transaction_read_version();
}
- assert(tree_is_cleared(STM_PSEGMENT->modified_old_objects));
+ assert(list_is_empty(STM_PSEGMENT->modified_old_objects));
assert(list_is_empty(STM_PSEGMENT->objects_pointing_to_nursery));
assert(tree_is_cleared(STM_PSEGMENT->young_outside_nursery));
assert(tree_is_cleared(STM_PSEGMENT->nursery_objects_shadows));
@@ -601,7 +563,8 @@
and clear the tree: */
acquire_modified_objs_lock(STM_SEGMENT->segment_num);
- struct tree_s *tree = STM_PSEGMENT->modified_old_objects;
+ abort();
+ struct tree_s *tree = NULL; //XXX STM_PSEGMENT->modified_old_objects;
wlog_t *item;
TREE_LOOP_FORWARD(tree, item); {
object_t *obj = (object_t*)item->addr;
@@ -632,7 +595,7 @@
s_mutex_unlock();
}
-void reset_modified_from_backup_copies(int segment_num)
+static void reset_modified_from_backup_copies(int segment_num)
{
#pragma push_macro("STM_PSEGMENT")
#pragma push_macro("STM_SEGMENT")
@@ -641,7 +604,8 @@
acquire_modified_objs_lock(segment_num);
struct stm_priv_segment_info_s *pseg = get_priv_segment(segment_num);
- struct tree_s *tree = pseg->modified_old_objects;
+ abort();
+ struct tree_s *tree = NULL; //XXX pseg->modified_old_objects;
wlog_t *item;
TREE_LOOP_FORWARD(tree, item); {
object_t *obj = (object_t*)item->addr;
diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -51,7 +51,16 @@
struct stm_segment_info_s pub;
uint8_t modified_objs_lock;
- struct tree_s *modified_old_objects;
+
+ /* All the old objects (older than the current transaction) that
+ the current transaction attempts to modify. This is used to
+ track the STM status: these are old objects that where written
+ to and that will need to be recorded in the commit log. The
+ list contains three entries for every such object, in the same
+ format as 'struct stm_undo_s' below.
+ */
+ struct list_s *modified_old_objects;
+
struct list_s *objects_pointing_to_nursery;
struct tree_s *young_outside_nursery;
struct tree_s *nursery_objects_shadows;
@@ -90,12 +99,24 @@
};
/* Commit Log things */
+struct stm_undo_s {
+ object_t *object; /* the object that is modified */
+ char *backup; /* some backup data (a slice of the original obj) */
+ uint64_t slice; /* location and size of this slice (== the whole
+ object, unless card marking is enabled). The
+ size is in the lower 2 bytes, and the offset
+ in the remaining 6 bytes. */
+};
+#define SLICE_OFFSET(slice) ((slice) >> 16)
+#define SLICE_SIZE(slice) ((int)((slice) & 0xFFFF))
+
struct stm_commit_log_entry_s {
- volatile struct stm_commit_log_entry_s *next;
+ struct stm_commit_log_entry_s *volatile next;
int segment_num;
- object_t *written[]; /* terminated with a NULL ptr */
+ size_t written_count;
+ struct stm_undo_s written[];
};
-static struct stm_commit_log_entry_s commit_log_root = {NULL, -1};
+static struct stm_commit_log_entry_s commit_log_root = {NULL, -1, 0};
static char *stm_object_pages;
@@ -137,7 +158,7 @@
static void abort_data_structures_from_segment_num(int segment_num);
static void _signal_handler(int sig, siginfo_t *siginfo, void *context);
-static void _stm_validate(void *free_if_abort, bool locks_acquired);
+static void _stm_validate(void *free_if_abort);
static inline void _duck(void) {
/* put a call to _duck() between two instructions that set 0 into
diff --git a/c8/stm/misc.c b/c8/stm/misc.c
--- a/c8/stm/misc.c
+++ b/c8/stm/misc.c
@@ -46,8 +46,9 @@
long _stm_count_modified_old_objects(void)
{
assert(STM_PSEGMENT->modified_old_objects);
- assert(tree_count(STM_PSEGMENT->modified_old_objects) < 10000);
- return tree_count(STM_PSEGMENT->modified_old_objects);
+ assert(list_count(STM_PSEGMENT->modified_old_objects) < 30000);
+ assert((list_count(STM_PSEGMENT->modified_old_objects) % 3) == 0);
+ return list_count(STM_PSEGMENT->modified_old_objects) / 3;
}
long _stm_count_objects_pointing_to_nursery(void)
@@ -59,8 +60,8 @@
object_t *_stm_enum_modified_old_objects(long index)
{
- wlog_t* entry = tree_item(STM_PSEGMENT->modified_old_objects, index);
- return (object_t*)entry->addr;
+ return (object_t *)list_item(
+ STM_PSEGMENT->modified_old_objects, index * 3);
}
object_t *_stm_enum_objects_pointing_to_nursery(long index)
@@ -86,7 +87,7 @@
object_t *_stm_next_last_cl_entry()
{
if (_last_cl_entry != &commit_log_root)
- return _last_cl_entry->written[_last_cl_entry_index++];
+ return _last_cl_entry->written[_last_cl_entry_index++].object;
return NULL;
}
#endif
diff --git a/c8/stm/setup.c b/c8/stm/setup.c
--- a/c8/stm/setup.c
+++ b/c8/stm/setup.c
@@ -136,7 +136,7 @@
assert(0 <= i && i < 255); /* 255 is WL_VISITED in gcpage.c */
pr->pub.segment_num = i;
pr->pub.segment_base = segment_base;
- pr->modified_old_objects = tree_create();
+ pr->modified_old_objects = list_create();
pr->objects_pointing_to_nursery = list_create();
pr->young_outside_nursery = tree_create();
pr->nursery_objects_shadows = tree_create();
@@ -173,7 +173,7 @@
struct stm_priv_segment_info_s *pr = get_priv_segment(i);
assert(list_is_empty(pr->objects_pointing_to_nursery));
list_free(pr->objects_pointing_to_nursery);
- tree_free(pr->modified_old_objects);
+ list_free(pr->modified_old_objects);
tree_free(pr->young_outside_nursery);
tree_free(pr->nursery_objects_shadows);
tree_free(pr->callbacks_on_commit_and_abort[0]);
More information about the pypy-commit
mailing list