[pypy-commit] stmgc c8-marker: in-progress: import some code from c7
arigo
noreply at buildbot.pypy.org
Sat Mar 7 16:33:45 CET 2015
Author: Armin Rigo <arigo at tunes.org>
Branch: c8-marker
Changeset: r1695:a3f57a07666c
Date: 2015-03-07 16:34 +0100
http://bitbucket.org/pypy/stmgc/changeset/a3f57a07666c/
Log: in-progress: import some code from c7
diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -528,6 +528,7 @@
STM_PSEGMENT->safe_point = SP_NO_TRANSACTION;
list_clear(STM_PSEGMENT->modified_old_objects);
+ list_clear(STM_PSEGMENT->modified_old_objects_markers);
STM_PSEGMENT->last_commit_log_entry = new;
release_modification_lock(STM_SEGMENT->segment_num);
}
@@ -557,6 +558,7 @@
STM_PSEGMENT->transaction_state = TS_NONE;
STM_PSEGMENT->safe_point = SP_NO_TRANSACTION;
list_clear(STM_PSEGMENT->modified_old_objects);
+ list_clear(STM_PSEGMENT->modified_old_objects_markers);
STM_PSEGMENT->last_commit_log_entry = new;
/* do it: */
@@ -630,6 +632,7 @@
(uintptr_t)obj, /* obj */
(uintptr_t)bk_slice, /* bk_addr */
NEW_SLICE(slice_off, slice_sz));
+ timing_record_write();
dprintf(("> append slice %p, off=%lu, sz=%lu\n", bk_slice, slice_off, slice_sz));
release_modification_lock(STM_SEGMENT->segment_num);
@@ -1051,6 +1054,7 @@
assert(STM_PSEGMENT->safe_point == SP_NO_TRANSACTION);
assert(STM_PSEGMENT->transaction_state == TS_NONE);
+ timing_event(tl, STM_TRANSACTION_START);
STM_PSEGMENT->transaction_state = TS_REGULAR;
STM_PSEGMENT->safe_point = SP_RUNNING;
#ifndef NDEBUG
@@ -1071,6 +1075,7 @@
}
assert(list_is_empty(STM_PSEGMENT->modified_old_objects));
+ assert(list_is_empty(STM_PSEGMENT->modified_old_objects_markers));
assert(list_is_empty(STM_PSEGMENT->large_overflow_objects));
assert(list_is_empty(STM_PSEGMENT->objects_pointing_to_nursery));
assert(list_is_empty(STM_PSEGMENT->young_weakrefs));
@@ -1080,6 +1085,10 @@
assert(tree_is_cleared(STM_PSEGMENT->callbacks_on_commit_and_abort[1]));
assert(list_is_empty(STM_PSEGMENT->young_objects_with_light_finalizers));
assert(STM_PSEGMENT->finalizers == NULL);
+#ifndef NDEBUG
+ /* this should not be used when objects_pointing_to_nursery == NULL */
+ STM_PSEGMENT->modified_old_objects_markers_num_old = 99999999999999999L;
+#endif
check_nursery_at_transaction_start();
@@ -1125,7 +1134,7 @@
/************************************************************/
-static void _finish_transaction()
+static void _finish_transaction(enum stm_event_e event)
{
stm_thread_local_t *tl = STM_SEGMENT->running_thread;
@@ -1136,6 +1145,7 @@
list_clear(STM_PSEGMENT->objects_pointing_to_nursery);
list_clear(STM_PSEGMENT->old_objects_with_cards_set);
list_clear(STM_PSEGMENT->large_overflow_objects);
+ timing_event(tl, event);
release_thread_segment(tl);
/* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
@@ -1236,7 +1246,7 @@
/* done */
stm_thread_local_t *tl = STM_SEGMENT->running_thread;
- _finish_transaction();
+ _finish_transaction(STM_TRANSACTION_COMMIT);
/* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
s_mutex_unlock();
@@ -1369,7 +1379,7 @@
: NURSERY_END;
}
- _finish_transaction();
+ _finish_transaction(STM_TRANSACTION_ABORT);
/* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
return tl;
diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -93,6 +93,12 @@
struct tree_s *young_outside_nursery;
struct tree_s *nursery_objects_shadows;
+ /* For each entry in 'modified_old_objects', we have two entries
+ in the following list, which give the marker at the time we added
+ the entry to modified_old_objects. */
+ struct list_s *modified_old_objects_markers;
+ uintptr_t modified_old_objects_markers_num_old;
+
/* List of all young weakrefs to check in minor collections. These
are the only weakrefs that may point to young objects and never
contain NULL. */
diff --git a/c8/stm/gcpage.c b/c8/stm/gcpage.c
--- a/c8/stm/gcpage.c
+++ b/c8/stm/gcpage.c
@@ -386,6 +386,20 @@
LIST_FREE(uniques);
}
+static void mark_visit_from_markers(void)
+{
+ long j;
+ for (j = 1; j < NB_SEGMENTS; j++) {
+ struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
+ struct list_s *lst = pseg->modified_old_objects_markers;
+ uintptr_t i;
+ for (i = list_count(lst); i > 0; i -= 2) {
+ mark_visit_possibly_new_object((object_t *)list_item(lst, i - 1),
+ pseg);
+ }
+ }
+}
+
static void mark_visit_from_roots(void)
{
if (testing_prebuilt_objs != NULL) {
@@ -683,6 +697,7 @@
/* marking */
LIST_CREATE(marked_objects_to_trace);
mark_visit_from_modified_objects();
+ mark_visit_from_markers();
mark_visit_from_roots();
mark_visit_from_finalizer_pending();
diff --git a/c7/stm/marker.c b/c8/stm/marker.c
copy from c7/stm/marker.c
copy to c8/stm/marker.c
--- a/c7/stm/marker.c
+++ b/c8/stm/marker.c
@@ -31,15 +31,6 @@
}
}
-static void _timing_fetch_inev(void)
-{
- stm_loc_marker_t marker;
- marker.tl = STM_SEGMENT->running_thread;
- marker_fetch(&marker);
- STM_PSEGMENT->marker_inev.odd_number = marker.odd_number;
- STM_PSEGMENT->marker_inev.object = marker.object;
-}
-
static void marker_fetch_obj_write(object_t *obj, stm_loc_marker_t *out_marker)
{
/* From 'out_marker->tl', fill in 'out_marker->segment_base' and
@@ -48,23 +39,16 @@
*/
assert(_has_mutex());
- /* here, we acquired the other thread's marker_lock, which means that:
-
- (1) it has finished filling 'modified_old_objects' after it sets
- up the write_locks[] value that we're conflicting with
-
- (2) it is not mutating 'modified_old_objects' right now (we have
- the global mutex_lock at this point too).
- */
- long i;
+ long i, num;
int in_segment_num = out_marker->tl->associated_segment_num;
assert(in_segment_num >= 1);
struct stm_priv_segment_info_s *pseg = get_priv_segment(in_segment_num);
struct list_s *mlst = pseg->modified_old_objects;
struct list_s *mlstm = pseg->modified_old_objects_markers;
- assert(list_count(mlstm) <= 2 * list_count(mlst));
- for (i = list_count(mlstm) / 2; --i >= 0; ) {
- if (list_item(mlst, i) == (uintptr_t)obj) {
+ num = list_count(mlstm) / 2;
+ assert(num * 3 <= list_count(mlst));
+ for (i = 0; i < num; i++) {
+ if (list_item(mlst, i * 3) == (uintptr_t)obj) {
out_marker->odd_number = list_item(mlstm, i * 2 + 0);
out_marker->object = (object_t *)list_item(mlstm, i * 2 + 1);
return;
@@ -80,7 +64,7 @@
marker.tl = STM_SEGMENT->running_thread;
marker_fetch(&marker);
- long base_count = list_count(STM_PSEGMENT->modified_old_objects);
+ long base_count = list_count(STM_PSEGMENT->modified_old_objects) / 3;
struct list_s *mlstm = STM_PSEGMENT->modified_old_objects_markers;
while (list_count(mlstm) < 2 * base_count) {
mlstm = list_append2(mlstm, 0, 0);
@@ -89,55 +73,21 @@
STM_PSEGMENT->modified_old_objects_markers = mlstm;
}
-static void _timing_contention(enum stm_event_e kind,
- uint8_t other_segment_num, object_t *obj)
+static void timing_write_read_contention(object_t *obj)
{
- struct stm_priv_segment_info_s *other_pseg;
- other_pseg = get_priv_segment(other_segment_num);
+ if (stmcb_timing_event == NULL)
+ return;
- char *other_segment_base = other_pseg->pub.segment_base;
- acquire_marker_lock(other_segment_base);
+ /* Collect the older location of the write from the current thread. */
+ stm_loc_marker_t marker;
+ marker.tl = STM_SEGMENT->running_thread;
+ marker.segment_base = STM_SEGMENT->segment_base;
+ marker_fetch_obj_write(obj, &marker);
- stm_loc_marker_t markers[2];
-
- /* Collect the location for myself. It's usually the current
- location, except in a write-read abort, in which case it's the
- older location of the write. */
- markers[0].tl = STM_SEGMENT->running_thread;
- markers[0].segment_base = STM_SEGMENT->segment_base;
-
- if (kind == STM_CONTENTION_WRITE_READ)
- marker_fetch_obj_write(obj, &markers[0]);
- else
- marker_fetch(&markers[0]);
-
- /* For some categories, we can also collect the relevant information
- for the other segment. */
- markers[1].tl = other_pseg->pub.running_thread;
- markers[1].segment_base = other_pseg->pub.segment_base;
-
- switch (kind) {
- case STM_CONTENTION_WRITE_WRITE:
- marker_fetch_obj_write(obj, &markers[1]);
- break;
- case STM_CONTENTION_INEVITABLE:
- markers[1].odd_number = other_pseg->marker_inev.odd_number;
- markers[1].object = other_pseg->marker_inev.object;
- break;
- default:
- markers[1].odd_number = 0;
- markers[1].object = NULL;
- break;
- }
-
- stmcb_timing_event(markers[0].tl, kind, markers);
-
- /* only release the lock after stmcb_timing_event(), otherwise it could
- run into race conditions trying to interpret 'markers[1].object' */
- release_marker_lock(other_segment_base);
+ stmcb_timing_event(marker.tl, STM_CONTENTION_WRITE_READ, &marker);
}
void (*stmcb_timing_event)(stm_thread_local_t *tl, /* the local thread */
enum stm_event_e event,
- stm_loc_marker_t *markers);
+ stm_loc_marker_t *marker);
diff --git a/c7/stm/marker.h b/c8/stm/marker.h
copy from c7/stm/marker.h
copy to c8/stm/marker.h
--- a/c7/stm/marker.h
+++ b/c8/stm/marker.h
@@ -1,8 +1,6 @@
static void _timing_record_write(void);
-static void _timing_fetch_inev(void);
-static void _timing_contention(enum stm_event_e kind,
- uint8_t other_segment_num, object_t *obj);
+static void timing_write_read_contention(object_t *obj);
#define timing_event(tl, event) \
@@ -10,10 +8,3 @@
#define timing_record_write() \
(stmcb_timing_event != NULL ? _timing_record_write() : (void)0)
-
-#define timing_fetch_inev() \
- (stmcb_timing_event != NULL ? _timing_fetch_inev() : (void)0)
-
-#define timing_contention(kind, other_segnum, obj) \
- (stmcb_timing_event != NULL ? \
- _timing_contention(kind, other_segnum, obj) : (void)0)
diff --git a/c8/stm/nursery.c b/c8/stm/nursery.c
--- a/c8/stm/nursery.c
+++ b/c8/stm/nursery.c
@@ -410,6 +410,18 @@
}
}
+static void collect_roots_from_markers(uintptr_t num_old)
+{
+ dprintf(("collect_roots_from_markers\n"));
+ /* visit the marker objects */
+ struct list_s *mlst = STM_PSEGMENT->modified_old_objects_markers;
+ STM_PSEGMENT->modified_old_objects_markers_num_old = list_count(mlst);
+ uintptr_t i, total = list_count(mlst);
+ assert((total & 1) == 0);
+ for (i = num_old + 1; i < total; i += 2) {
+ minor_trace_if_young((object_t **)list_ptr_to_item(mlst, i));
+ }
+}
static void collect_objs_still_young_but_with_finalizers(void)
{
@@ -494,6 +506,13 @@
dprintf(("minor_collection commit=%d\n", (int)commit));
STM_PSEGMENT->minor_collect_will_commit_now = commit;
+
+ uintptr_t num_old;
+ if (STM_PSEGMENT->overflow_number_has_been_used)
+ num_old = STM_PSEGMENT->modified_old_objects_markers_num_old;
+ else
+ num_old = 0;
+
if (!commit) {
/* 'STM_PSEGMENT->overflow_number' is used now by this collection,
in the sense that it's copied to the overflow objects */
@@ -502,6 +521,8 @@
collect_cardrefs_to_nursery();
+ collect_roots_from_markers(num_old);
+
collect_roots_in_nursery();
if (STM_PSEGMENT->finalizers != NULL)
diff --git a/c8/stm/setup.c b/c8/stm/setup.c
--- a/c8/stm/setup.c
+++ b/c8/stm/setup.c
@@ -100,6 +100,7 @@
pr->pub.segment_num = i;
pr->pub.segment_base = segment_base;
pr->modified_old_objects = list_create();
+ pr->modified_old_objects_markers = list_create();
pr->large_overflow_objects = list_create();
pr->young_weakrefs = list_create();
pr->old_weakrefs = list_create();
@@ -152,6 +153,7 @@
list_free(pr->objects_pointing_to_nursery);
list_free(pr->old_objects_with_cards_set);
list_free(pr->modified_old_objects);
+ list_free(pr->modified_old_objects_markers);
assert(list_is_empty(pr->large_overflow_objects));
list_free(pr->large_overflow_objects);
list_free(pr->young_weakrefs);
diff --git a/c8/stmgc.c b/c8/stmgc.c
--- a/c8/stmgc.c
+++ b/c8/stmgc.c
@@ -14,6 +14,7 @@
#include "stm/gcpage.h"
#include "stm/extra.h"
#include "stm/fprintcolor.h"
+#include "stm/marker.h"
#include "stm/rewind_setjmp.h"
#include "stm/finalizer.h"
@@ -34,5 +35,6 @@
#include "stm/core.c"
#include "stm/extra.c"
#include "stm/fprintcolor.c"
+#include "stm/marker.c"
#include "stm/rewind_setjmp.c"
#include "stm/finalizer.c"
diff --git a/c8/stmgc.h b/c8/stmgc.h
--- a/c8/stmgc.h
+++ b/c8/stmgc.h
@@ -342,6 +342,69 @@
void stm_resume_all_other_threads(void);
+/* Profiling events. In the comments: content of the markers, if any */
+enum stm_event_e {
+ /* always STM_TRANSACTION_START followed later by one of COMMIT or ABORT */
+ STM_TRANSACTION_START,
+ STM_TRANSACTION_COMMIT,
+ STM_TRANSACTION_ABORT,
+
+ /* write-read contention: a "marker" is included in the PYPYSTM file
+ saying where the write was done. Followed by STM_TRANSACTION_ABORT. */
+ STM_CONTENTION_WRITE_READ,
+
+ /* always one STM_WAIT_xxx followed later by STM_WAIT_DONE */
+ STM_WAIT_FREE_SEGMENT,
+ STM_WAIT_OTHER_INEVITABLE,
+ STM_WAIT_DONE,
+
+ /* start and end of GC cycles */
+ STM_GC_MINOR_START,
+ STM_GC_MINOR_DONE,
+ STM_GC_MAJOR_START,
+ STM_GC_MAJOR_DONE,
+
+ _STM_EVENT_N
+};
+
+#define STM_EVENT_NAMES \
+ "transaction start", \
+ "transaction commit", \
+ "transaction abort", \
+ "contention write read", \
+ "wait free segment", \
+ "wait other inevitable", \
+ "wait done", \
+ "gc minor start", \
+ "gc minor done", \
+ "gc major start", \
+ "gc major done"
+
+/* The markers pushed in the shadowstack are an odd number followed by a
+ regular pointer. */
+typedef struct {
+ stm_thread_local_t *tl;
+ char *segment_base; /* base to interpret the 'object' below */
+ uintptr_t odd_number; /* marker odd number, or 0 if marker is missing */
+ object_t *object; /* marker object, or NULL if marker is missing */
+} stm_loc_marker_t;
+extern void (*stmcb_timing_event)(stm_thread_local_t *tl, /* the local thread */
+ enum stm_event_e event,
+ stm_loc_marker_t *marker);
+
+/* Calling this sets up a stmcb_timing_event callback that will produce
+ a binary file called 'profiling_file_name'. Call it with
+ 'fork_mode == 0' for only the main process, and with
+ 'fork_mode == 1' to also write files called
+ 'profiling_file_name.fork<PID>' after a fork(). Call it with NULL to
+ stop profiling. Returns -1 in case of error (see errno then).
+ The optional 'expand_marker' function pointer is called to expand
+ the marker's odd_number and object into data, starting at the given
+ position and with the given maximum length. */
+int stm_set_timing_log(const char *profiling_file_name, int fork_mode,
+ int expand_marker(stm_loc_marker_t *, char *, int));
+
+
/* Convenience macros to push the markers into the shadowstack */
#define STM_PUSH_MARKER(tl, odd_num, p) do { \
uintptr_t _odd_num = (odd_num); \
diff --git a/c8/test/support.py b/c8/test/support.py
--- a/c8/test/support.py
+++ b/c8/test/support.py
@@ -124,6 +124,46 @@
long stm_call_on_abort(stm_thread_local_t *, void *key, void callback(void *));
long stm_call_on_commit(stm_thread_local_t *, void *key, void callback(void *));
+/* Profiling events. In the comments: content of the markers, if any */
+enum stm_event_e {
+ /* always STM_TRANSACTION_START followed later by one of COMMIT or ABORT */
+ STM_TRANSACTION_START,
+ STM_TRANSACTION_COMMIT,
+ STM_TRANSACTION_ABORT,
+
+ /* write-read contention: a "marker" is included in the PYPYSTM file
+ saying where the write was done. Followed by STM_TRANSACTION_ABORT. */
+ STM_CONTENTION_WRITE_READ,
+
+ /* always one STM_WAIT_xxx followed later by STM_WAIT_DONE */
+ STM_WAIT_FREE_SEGMENT,
+ STM_WAIT_OTHER_INEVITABLE,
+ STM_WAIT_DONE,
+
+ /* start and end of GC cycles */
+ STM_GC_MINOR_START,
+ STM_GC_MINOR_DONE,
+ STM_GC_MAJOR_START,
+ STM_GC_MAJOR_DONE,
+ ...
+};
+
+typedef struct {
+ stm_thread_local_t *tl;
+ /* If segment_base==NULL, the remaining fields are undefined. If non-NULL,
+ the rest is a marker to interpret from this segment_base addr. */
+ char *segment_base;
+ uintptr_t odd_number;
+ object_t *object;
+} stm_loc_marker_t;
+
+typedef void (*stmcb_timing_event_fn)(stm_thread_local_t *tl,
+ enum stm_event_e event,
+ stm_loc_marker_t *markers);
+stmcb_timing_event_fn stmcb_timing_event;
+
+int stm_set_timing_log(const char *profiling_file_name, int prof_mode,
+ int expand_marker(stm_loc_marker_t *, char *, int));
long _stm_count_modified_old_objects(void);
long _stm_count_objects_pointing_to_nursery(void);
diff --git a/c7/test/test_marker.py b/c8/test/test_marker.py
copy from c7/test/test_marker.py
copy to c8/test/test_marker.py
More information about the pypy-commit
mailing list