Author: Armin Rigo <[email protected]>
Branch: stmgc-c7
Changeset: r70337:720e8ae12d2f
Date: 2014-03-30 21:26 +0200
http://bitbucket.org/pypy/pypy/changeset/720e8ae12d2f/
Log: import stmgc/976a1d42a508
diff --git a/rpython/translator/stm/src_stm/revision
b/rpython/translator/stm/src_stm/revision
--- a/rpython/translator/stm/src_stm/revision
+++ b/rpython/translator/stm/src_stm/revision
@@ -1,1 +1,1 @@
-4d330c8e6b92
+976a1d42a508
diff --git a/rpython/translator/stm/src_stm/stm/contention.c
b/rpython/translator/stm/src_stm/stm/contention.c
--- a/rpython/translator/stm/src_stm/stm/contention.c
+++ b/rpython/translator/stm/src_stm/stm/contention.c
@@ -123,8 +123,8 @@
#endif
/* Fix the choices that are found incorrect due to TS_INEVITABLE
- or NSE_SIGABORT */
- if (contmgr.other_pseg->pub.nursery_end == NSE_SIGABORT) {
+ or is_abort() */
+ if (is_abort(contmgr.other_pseg->pub.nursery_end)) {
contmgr.abort_other = true;
contmgr.try_sleep = false;
}
@@ -137,6 +137,19 @@
contmgr.abort_other = false;
}
+
+ int wait_category =
+ kind == WRITE_READ_CONTENTION ? STM_TIME_WAIT_WRITE_READ :
+ kind == INEVITABLE_CONTENTION ? STM_TIME_WAIT_INEVITABLE :
+ STM_TIME_WAIT_OTHER;
+
+ int abort_category =
+ kind == WRITE_WRITE_CONTENTION ? STM_TIME_RUN_ABORTED_WRITE_WRITE :
+ kind == WRITE_READ_CONTENTION ? STM_TIME_RUN_ABORTED_WRITE_READ :
+ kind == INEVITABLE_CONTENTION ? STM_TIME_RUN_ABORTED_INEVITABLE :
+ STM_TIME_RUN_ABORTED_OTHER;
+
+
if (contmgr.try_sleep && kind != WRITE_WRITE_CONTENTION &&
contmgr.other_pseg->safe_point != SP_WAIT_FOR_C_TRANSACTION_DONE) {
/* Sleep.
@@ -150,6 +163,10 @@
*/
contmgr.other_pseg->signal_when_done = true;
+ change_timing_state(wait_category);
+
+ /* XXX should also tell other_pseg "please commit soon" */
+
dprintf(("pausing...\n"));
cond_signal(C_AT_SAFE_POINT);
STM_PSEGMENT->safe_point = SP_WAIT_FOR_C_TRANSACTION_DONE;
@@ -159,15 +176,20 @@
if (must_abort())
abort_with_mutex();
+
+ change_timing_state(STM_TIME_RUN_CURRENT);
}
+
else if (!contmgr.abort_other) {
dprintf(("abort in contention\n"));
+ STM_SEGMENT->nursery_end = abort_category;
abort_with_mutex();
}
+
else {
/* We have to signal the other thread to abort, and wait until
it does. */
- contmgr.other_pseg->pub.nursery_end = NSE_SIGABORT;
+ contmgr.other_pseg->pub.nursery_end = abort_category;
int sp = contmgr.other_pseg->safe_point;
switch (sp) {
diff --git a/rpython/translator/stm/src_stm/stm/contention.h
b/rpython/translator/stm/src_stm/stm/contention.h
--- a/rpython/translator/stm/src_stm/stm/contention.h
+++ b/rpython/translator/stm/src_stm/stm/contention.h
@@ -4,7 +4,11 @@
static void write_read_contention_management(uint8_t other_segment_num);
static void inevitable_contention_management(uint8_t other_segment_num);
+static inline bool is_abort(uintptr_t nursery_end) {
+ return (nursery_end <= _STM_NSE_SIGNAL_MAX && nursery_end != NSE_SIGPAUSE);
+}
+
static inline bool is_aborting_now(uint8_t other_segment_num) {
- return (get_segment(other_segment_num)->nursery_end == NSE_SIGABORT &&
+ return (is_abort(get_segment(other_segment_num)->nursery_end) &&
get_priv_segment(other_segment_num)->safe_point != SP_RUNNING);
}
diff --git a/rpython/translator/stm/src_stm/stm/core.c
b/rpython/translator/stm/src_stm/stm/core.c
--- a/rpython/translator/stm/src_stm/stm/core.c
+++ b/rpython/translator/stm/src_stm/stm/core.c
@@ -173,7 +173,7 @@
retry:
if (jmpbuf == NULL) {
- wait_for_end_of_inevitable_transaction(false);
+ wait_for_end_of_inevitable_transaction(tl);
}
if (!acquire_thread_segment(tl))
@@ -182,6 +182,8 @@
assert(STM_PSEGMENT->safe_point == SP_NO_TRANSACTION);
assert(STM_PSEGMENT->transaction_state == TS_NONE);
+ change_timing_state(STM_TIME_RUN_CURRENT);
+ STM_PSEGMENT->start_time = tl->_timing_cur_start;
STM_PSEGMENT->safe_point = SP_RUNNING;
STM_PSEGMENT->transaction_state = (jmpbuf != NULL ? TS_REGULAR
: TS_INEVITABLE);
@@ -434,7 +436,7 @@
list_clear(STM_PSEGMENT->modified_old_objects);
}
-static void _finish_transaction(void)
+static void _finish_transaction(int attribute_to)
{
STM_PSEGMENT->safe_point = SP_NO_TRANSACTION;
STM_PSEGMENT->transaction_state = TS_NONE;
@@ -443,6 +445,8 @@
LIST_FREE(STM_PSEGMENT->objects_pointing_to_nursery);
LIST_FREE(STM_PSEGMENT->large_overflow_objects);
+ timing_end_transaction(attribute_to);
+
stm_thread_local_t *tl = STM_SEGMENT->running_thread;
release_thread_segment(tl);
/* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
@@ -456,6 +460,9 @@
minor_collection(/*commit=*/ true);
+ /* the call to minor_collection() above leaves us with
+ STM_TIME_BOOKKEEPING */
+
s_mutex_lock();
restart:
@@ -506,7 +513,7 @@
}
/* done */
- _finish_transaction();
+ _finish_transaction(STM_TIME_RUN_COMMITTED);
/* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
s_mutex_unlock();
@@ -630,13 +637,16 @@
/* invoke the callbacks */
invoke_and_clear_callbacks_on_abort();
- if (STM_SEGMENT->nursery_end == NSE_SIGABORT) {
+ int attribute_to = STM_TIME_RUN_ABORTED_OTHER;
+
+ if (is_abort(STM_SEGMENT->nursery_end)) {
/* done aborting */
+ attribute_to = STM_SEGMENT->nursery_end;
STM_SEGMENT->nursery_end = pause_signalled ? NSE_SIGPAUSE
: NURSERY_END;
}
- _finish_transaction();
+ _finish_transaction(attribute_to);
/* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
/* Broadcast C_ABORTED to wake up contention.c */
@@ -669,7 +679,7 @@
if (STM_PSEGMENT->transaction_state == TS_REGULAR) {
dprintf(("become_inevitable: %s\n", msg));
- wait_for_end_of_inevitable_transaction(true);
+ wait_for_end_of_inevitable_transaction(NULL);
STM_PSEGMENT->transaction_state = TS_INEVITABLE;
STM_SEGMENT->jmpbuf_ptr = NULL;
clear_callbacks_on_abort();
diff --git a/rpython/translator/stm/src_stm/stm/core.h
b/rpython/translator/stm/src_stm/stm/core.h
--- a/rpython/translator/stm/src_stm/stm/core.h
+++ b/rpython/translator/stm/src_stm/stm/core.h
@@ -29,6 +29,8 @@
#define READMARKER_START ((FIRST_OBJECT_PAGE * 4096UL) >> 4)
#define FIRST_READMARKER_PAGE (READMARKER_START / 4096UL)
+#define OLD_RM_START ((END_NURSERY_PAGE * 4096UL) >> 4)
+#define FIRST_OLD_RM_PAGE (OLD_RM_START / 4096UL)
#define NB_READMARKER_PAGES (FIRST_OBJECT_PAGE - FIRST_READMARKER_PAGE)
#define WRITELOCK_START ((END_NURSERY_PAGE * 4096UL) >> 4)
@@ -120,7 +122,7 @@
/* Start time: to know approximately for how long a transaction has
been running, in contention management */
- uint64_t start_time;
+ double start_time;
/* This is the number stored in the overflowed objects (a multiple of
GCFLAG_OVERFLOW_NUMBER_bit0). It is incremented when the
diff --git a/rpython/translator/stm/src_stm/stm/gcpage.c
b/rpython/translator/stm/src_stm/stm/gcpage.c
--- a/rpython/translator/stm/src_stm/stm/gcpage.c
+++ b/rpython/translator/stm/src_stm/stm/gcpage.c
@@ -135,11 +135,15 @@
if (is_major_collection_requested()) { /* if still true */
+ int oldstate = change_timing_state(STM_TIME_MAJOR_GC);
+
synchronize_all_threads(STOP_OTHERS_UNTIL_MUTEX_UNLOCK);
if (is_major_collection_requested()) { /* if *still* true */
major_collection_now_at_safe_point();
}
+
+ change_timing_state(oldstate);
}
s_mutex_unlock();
diff --git a/rpython/translator/stm/src_stm/stm/nursery.c
b/rpython/translator/stm/src_stm/stm/nursery.c
--- a/rpython/translator/stm/src_stm/stm/nursery.c
+++ b/rpython/translator/stm/src_stm/stm/nursery.c
@@ -319,7 +319,11 @@
stm_safe_point();
+ change_timing_state(STM_TIME_MINOR_GC);
+
_do_minor_collection(commit);
+
+ change_timing_state(commit ? STM_TIME_BOOKKEEPING : STM_TIME_RUN_CURRENT);
}
void stm_collect(long level)
diff --git a/rpython/translator/stm/src_stm/stm/nursery.h
b/rpython/translator/stm/src_stm/stm/nursery.h
--- a/rpython/translator/stm/src_stm/stm/nursery.h
+++ b/rpython/translator/stm/src_stm/stm/nursery.h
@@ -1,11 +1,7 @@
/* Imported by rpython/translator/stm/import_stmgc.py */
/* '_stm_nursery_section_end' is either NURSERY_END or NSE_SIGxxx */
-#define NSE_SIGPAUSE 0
-#define NSE_SIGABORT 1
-#if NSE_SIGABORT > _STM_NSE_SIGNAL_MAX
-# error "update _STM_NSE_SIGNAL_MAX"
-#endif
+#define NSE_SIGPAUSE STM_TIME_WAIT_OTHER
static uint32_t highest_overflow_number;
@@ -15,9 +11,7 @@
static size_t throw_away_nursery(struct stm_priv_segment_info_s *pseg);
static void major_do_minor_collections(void);
-static inline bool must_abort(void) {
- return STM_SEGMENT->nursery_end == NSE_SIGABORT;
-}
+#define must_abort() is_abort(STM_SEGMENT->nursery_end)
static void assert_memset_zero(void *s, size_t n);
diff --git a/rpython/translator/stm/src_stm/stm/pages.c
b/rpython/translator/stm/src_stm/stm/pages.c
--- a/rpython/translator/stm/src_stm/stm/pages.c
+++ b/rpython/translator/stm/src_stm/stm/pages.c
@@ -170,25 +170,24 @@
increment_total_allocated(total);
}
+static void pages_setup_readmarkers_for_nursery(void)
+{
+ /* The nursery page's read markers are never read, but must still
+ be writeable. We'd like to map the pages to a general "trash
+ page"; missing one, we remap all the pages over to the same one.
+ We still keep one page *per segment* to avoid cross-CPU cache
+ conflicts.
-#if 0
-static bool is_fully_in_shared_pages(object_t *obj)
-{
- uintptr_t first_page = ((uintptr_t)obj) / 4096UL;
+ (XXX no performance difference measured so far)
+ */
+ long i, j;
+ for (i = 1; i <= NB_SEGMENTS; i++) {
+ char *segment_base = get_segment_base(i);
- if ((obj->stm_flags & GCFLAG_SMALL_UNIFORM) != 0)
- return (flag_page_private[first_page] == SHARED_PAGE);
-
- ssize_t obj_size = stmcb_size_rounded_up(
- (struct object_s *)REAL_ADDRESS(stm_object_pages, obj));
-
- uintptr_t last_page = (((uintptr_t)obj) + obj_size - 1) / 4096UL;
-
- do {
- if (flag_page_private[first_page++] != SHARED_PAGE)
- return false;
- } while (first_page <= last_page);
-
- return true;
+ for (j = FIRST_READMARKER_PAGE + 1; j < FIRST_OLD_RM_PAGE; j++) {
+ remap_file_pages(segment_base + 4096 * j, 4096, 0,
+ i * NB_PAGES + FIRST_READMARKER_PAGE, 0);
+ /* errors here ignored */
+ }
+ }
}
-#endif
diff --git a/rpython/translator/stm/src_stm/stm/pages.h
b/rpython/translator/stm/src_stm/stm/pages.h
--- a/rpython/translator/stm/src_stm/stm/pages.h
+++ b/rpython/translator/stm/src_stm/stm/pages.h
@@ -40,6 +40,7 @@
static void page_privatize(uintptr_t pagenum);
static void page_reshare(uintptr_t pagenum);
static void _page_do_reshare(long segnum, uintptr_t pagenum);
+static void pages_setup_readmarkers_for_nursery(void);
/* Note: don't ever do "mutex_pages_lock(); mutex_lock()" in that order */
static void mutex_pages_lock(void);
diff --git a/rpython/translator/stm/src_stm/stm/setup.c
b/rpython/translator/stm/src_stm/stm/setup.c
--- a/rpython/translator/stm/src_stm/stm/setup.c
+++ b/rpython/translator/stm/src_stm/stm/setup.c
@@ -37,6 +37,7 @@
(FIRST_READMARKER_PAGE - 2) * 4096UL,
PROT_NONE);
}
+ pages_setup_readmarkers_for_nursery();
}
void stm_setup(void)
@@ -169,6 +170,8 @@
num = tl->prev->associated_segment_num;
}
tl->thread_local_obj = NULL;
+ tl->_timing_cur_state = STM_TIME_OUTSIDE_TRANSACTION;
+ tl->_timing_cur_start = get_stm_time();
/* assign numbers consecutively, but that's for tests; we could also
assign the same number to all of them and they would get their own
diff --git a/rpython/translator/stm/src_stm/stm/sync.c
b/rpython/translator/stm/src_stm/stm/sync.c
--- a/rpython/translator/stm/src_stm/stm/sync.c
+++ b/rpython/translator/stm/src_stm/stm/sync.c
@@ -32,7 +32,6 @@
pthread_cond_t cond[_C_TOTAL];
/* some additional pieces of global state follow */
uint8_t in_use1[NB_SEGMENTS]; /* 1 if running a pthread */
- uint64_t global_time;
};
char reserved[192];
} sync_ctl __attribute__((aligned(64)));
@@ -121,13 +120,14 @@
/************************************************************/
-static void wait_for_end_of_inevitable_transaction(bool can_abort)
+static void wait_for_end_of_inevitable_transaction(
+ stm_thread_local_t *tl_or_null_if_can_abort)
{
long i;
restart:
for (i = 1; i <= NB_SEGMENTS; i++) {
if (get_priv_segment(i)->transaction_state == TS_INEVITABLE) {
- if (can_abort) {
+ if (tl_or_null_if_can_abort == NULL) {
/* handle this case like a contention: it will either
abort us (not the other thread, which is inevitable),
or wait for a while. If we go past this call, then we
@@ -138,7 +138,11 @@
else {
/* wait for stm_commit_transaction() to finish this
inevitable transaction */
+ change_timing_state_tl(tl_or_null_if_can_abort,
+ STM_TIME_WAIT_INEVITABLE);
cond_wait(C_INEVITABLE);
+ /* don't bother changing the timing state again: the caller
+ will very soon go to STM_TIME_RUN_CURRENT */
}
goto restart;
}
@@ -179,6 +183,7 @@
}
/* No segment available. Wait until release_thread_segment()
signals that one segment has been freed. */
+ change_timing_state_tl(tl, STM_TIME_WAIT_FREE_SEGMENT);
cond_wait(C_SEGMENT_FREE);
/* Return false to the caller, which will call us again */
@@ -189,7 +194,6 @@
assert(STM_SEGMENT->segment_num == num);
assert(STM_SEGMENT->running_thread == NULL);
STM_SEGMENT->running_thread = tl;
- STM_PSEGMENT->start_time = ++sync_ctl.global_time;
return true;
}
@@ -307,6 +311,10 @@
static void enter_safe_point_if_requested(void)
{
+ if (STM_SEGMENT->nursery_end == NURSERY_END)
+ return; /* fast path: no safe point requested */
+
+ int previous_state = -1;
assert(_seems_to_be_running_transaction());
assert(_has_mutex());
while (1) {
@@ -323,11 +331,18 @@
#ifdef STM_TESTS
abort_with_mutex();
#endif
+ if (previous_state == -1) {
+ previous_state = change_timing_state(STM_TIME_SYNC_PAUSE);
+ }
cond_signal(C_AT_SAFE_POINT);
STM_PSEGMENT->safe_point = SP_WAIT_FOR_C_REQUEST_REMOVED;
cond_wait(C_REQUEST_REMOVED);
STM_PSEGMENT->safe_point = SP_RUNNING;
}
+
+ if (previous_state != -1) {
+ change_timing_state(previous_state);
+ }
}
static void synchronize_all_threads(enum sync_type_e sync_type)
diff --git a/rpython/translator/stm/src_stm/stm/sync.h
b/rpython/translator/stm/src_stm/stm/sync.h
--- a/rpython/translator/stm/src_stm/stm/sync.h
+++ b/rpython/translator/stm/src_stm/stm/sync.h
@@ -29,7 +29,7 @@
static bool acquire_thread_segment(stm_thread_local_t *tl);
static void release_thread_segment(stm_thread_local_t *tl);
-static void wait_for_end_of_inevitable_transaction(bool can_abort);
+static void wait_for_end_of_inevitable_transaction(stm_thread_local_t *);
enum sync_type_e {
STOP_OTHERS_UNTIL_MUTEX_UNLOCK,
diff --git a/rpython/translator/stm/src_stm/stm/timing.c
b/rpython/translator/stm/src_stm/stm/timing.c
new file mode 100644
--- /dev/null
+++ b/rpython/translator/stm/src_stm/stm/timing.c
@@ -0,0 +1,75 @@
+/* Imported by rpython/translator/stm/import_stmgc.py */
+#ifndef _STM_CORE_H_
+# error "must be compiled via stmgc.c"
+#endif
+
+
+static inline void add_timing(stm_thread_local_t *tl, enum stm_time_e category,
+ double elapsed)
+{
+ tl->timing[category] += elapsed;
+}
+
+#define TIMING_CHANGE(tl, newstate) \
+ double curtime = get_stm_time(); \
+ double elasped = curtime - tl->_timing_cur_start; \
+ enum stm_time_e oldstate = tl->_timing_cur_state; \
+ add_timing(tl, oldstate, elasped); \
+ tl->_timing_cur_state = newstate; \
+ tl->_timing_cur_start = curtime
+
+static enum stm_time_e change_timing_state(enum stm_time_e newstate)
+{
+ stm_thread_local_t *tl = STM_SEGMENT->running_thread;
+ TIMING_CHANGE(tl, newstate);
+ return oldstate;
+}
+
+static void change_timing_state_tl(stm_thread_local_t *tl,
+ enum stm_time_e newstate)
+{
+ TIMING_CHANGE(tl, newstate);
+}
+
+static void timing_end_transaction(enum stm_time_e attribute_to)
+{
+ stm_thread_local_t *tl = STM_SEGMENT->running_thread;
+ TIMING_CHANGE(tl, STM_TIME_OUTSIDE_TRANSACTION);
+ add_timing(tl, attribute_to, tl->timing[STM_TIME_RUN_CURRENT]);
+ tl->timing[STM_TIME_RUN_CURRENT] = 0.0f;
+}
+
+static const char *timer_names[] = {
+ "outside transaction",
+ "run current",
+ "run committed",
+ "run aborted write write",
+ "run aborted write read",
+ "run aborted inevitable",
+ "run aborted other",
+ "wait free segment",
+ "wait write read",
+ "wait inevitable",
+ "wait other",
+ "bookkeeping",
+ "minor gc",
+ "major gc",
+ "sync pause",
+};
+
+void stm_flush_timing(stm_thread_local_t *tl, int verbose)
+{
+ TIMING_CHANGE(tl, tl->_timing_cur_state);
+
+ assert((sizeof(timer_names) / sizeof(timer_names[0])) == _STM_TIME_N);
+ if (verbose > 0) {
+ int i;
+ s_mutex_lock();
+ fprintf(stderr, "thread %p:\n", tl);
+ for (i = 0; i < _STM_TIME_N; i++) {
+ fprintf(stderr, " %-24s %.3f s\n",
+ timer_names[i], (double)tl->timing[i]);
+ }
+ s_mutex_unlock();
+ }
+}
diff --git a/rpython/translator/stm/src_stm/stm/timing.h
b/rpython/translator/stm/src_stm/stm/timing.h
new file mode 100644
--- /dev/null
+++ b/rpython/translator/stm/src_stm/stm/timing.h
@@ -0,0 +1,15 @@
+/* Imported by rpython/translator/stm/import_stmgc.py */
+#include <time.h>
+
+static inline double get_stm_time(void)
+{
+ struct timespec tp;
+ clock_gettime(CLOCK_MONOTONIC, &tp);
+ return tp.tv_sec + tp.tv_nsec * 0.000000001;
+}
+
+static enum stm_time_e change_timing_state(enum stm_time_e newstate);
+static void change_timing_state_tl(stm_thread_local_t *tl,
+ enum stm_time_e newstate);
+
+static void timing_end_transaction(enum stm_time_e attribute_to);
diff --git a/rpython/translator/stm/src_stm/stmgc.c
b/rpython/translator/stm/src_stm/stmgc.c
--- a/rpython/translator/stm/src_stm/stmgc.c
+++ b/rpython/translator/stm/src_stm/stmgc.c
@@ -14,6 +14,7 @@
#include "stm/extra.h"
#include "stm/fprintcolor.h"
#include "stm/weakref.h"
+#include "stm/timing.h"
#include "stm/misc.c"
#include "stm/list.c"
@@ -32,3 +33,4 @@
#include "stm/extra.c"
#include "stm/fprintcolor.c"
#include "stm/weakref.c"
+#include "stm/timing.c"
diff --git a/rpython/translator/stm/src_stm/stmgc.h
b/rpython/translator/stm/src_stm/stmgc.h
--- a/rpython/translator/stm/src_stm/stmgc.h
+++ b/rpython/translator/stm/src_stm/stmgc.h
@@ -55,6 +55,25 @@
object_t *ss;
};
+enum stm_time_e {
+ STM_TIME_OUTSIDE_TRANSACTION,
+ STM_TIME_RUN_CURRENT,
+ STM_TIME_RUN_COMMITTED,
+ STM_TIME_RUN_ABORTED_WRITE_WRITE,
+ STM_TIME_RUN_ABORTED_WRITE_READ,
+ STM_TIME_RUN_ABORTED_INEVITABLE,
+ STM_TIME_RUN_ABORTED_OTHER,
+ STM_TIME_WAIT_FREE_SEGMENT,
+ STM_TIME_WAIT_WRITE_READ,
+ STM_TIME_WAIT_INEVITABLE,
+ STM_TIME_WAIT_OTHER,
+ STM_TIME_BOOKKEEPING,
+ STM_TIME_MINOR_GC,
+ STM_TIME_MAJOR_GC,
+ STM_TIME_SYNC_PAUSE,
+ _STM_TIME_N
+};
+
typedef struct stm_thread_local_s {
/* every thread should handle the shadow stack itself */
struct stm_shadowentry_s *shadowstack, *shadowstack_base;
@@ -67,6 +86,10 @@
/* after an abort, some details about the abort are stored there.
(these fields are not modified on a successful commit) */
long last_abort__bytes_in_nursery;
+ /* timing information, accumulated */
+ float timing[_STM_TIME_N];
+ double _timing_cur_start;
+ enum stm_time_e _timing_cur_state;
/* the next fields are handled internally by the library */
int associated_segment_num;
struct stm_thread_local_s *prev, *next;
@@ -114,7 +137,7 @@
#endif
#define _STM_GCFLAG_WRITE_BARRIER 0x01
-#define _STM_NSE_SIGNAL_MAX 1
+#define _STM_NSE_SIGNAL_MAX _STM_TIME_N
#define _STM_FAST_ALLOC (66*1024)
@@ -337,6 +360,10 @@
const char *msg);
+/* Temporary? */
+void stm_flush_timing(stm_thread_local_t *tl, int verbose);
+
+
/* ==================== END ==================== */
#endif
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit