[pypy-commit] stmgc c8-efficient-serial-execution-master: Merge TCP style optimization
tobweber
pypy.commits at gmail.com
Mon Aug 21 06:58:43 EDT 2017
Author: Tobias Weber <tobias_weber89 at gmx.de>
Branch: c8-efficient-serial-execution-master
Changeset: r2152:d56fd821ed46
Date: 2017-08-21 12:10 +0200
http://bitbucket.org/pypy/stmgc/changeset/d56fd821ed46/
Log: Merge TCP style optimization
diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -1117,11 +1117,9 @@
_do_start_transaction(tl);
STM_PSEGMENT->commit_if_not_atomic = false;
- if (repeat_count == 0) { /* else, 'nursery_mark' was already set
- in abort_data_structures_from_segment_num() */
- STM_SEGMENT->nursery_mark = ((stm_char *)_stm_nursery_start +
- stm_fill_mark_nursery_bytes);
- }
+ STM_SEGMENT->nursery_mark = ((stm_char *)_stm_nursery_start +
+ stm_get_transaction_length(tl));
+
return repeat_count;
}
@@ -1304,6 +1302,8 @@
s_mutex_unlock();
+ stm_transaction_length_handle_validation(thread_local_for_logging, false);
+
/* between transactions, call finalizers. this will execute
a transaction itself */
if (tl != NULL)
@@ -1468,22 +1468,6 @@
if (pseg->active_queues)
queues_deactivate_all(pseg, /*at_commit=*/false);
-
- /* Set the next nursery_mark: first compute the value that
- nursery_mark must have had at the start of the aborted transaction */
- stm_char *old_mark =pseg->pub.nursery_mark + pseg->total_throw_away_nursery;
-
- /* This means that the limit, in term of bytes, was: */
- uintptr_t old_limit = old_mark - (stm_char *)_stm_nursery_start;
-
- /* If 'total_throw_away_nursery' is smaller than old_limit, use that */
- if (pseg->total_throw_away_nursery < old_limit)
- old_limit = pseg->total_throw_away_nursery;
-
- /* Now set the new limit to 90% of the old limit */
- pseg->pub.nursery_mark = ((stm_char *)_stm_nursery_start +
- (uintptr_t)(old_limit * 0.9));
-
#ifdef STM_NO_AUTOMATIC_SETJMP
did_abort = 1;
#endif
@@ -1518,6 +1502,8 @@
tl->self_or_0_if_atomic = (intptr_t)tl; /* clear the 'atomic' flag */
STM_PSEGMENT->atomic_nesting_levels = 0;
+ stm_transaction_length_handle_validation(tl, true);
+
if (tl->mem_clear_on_abort)
memset(tl->mem_clear_on_abort, 0, tl->mem_bytes_to_clear_on_abort);
if (tl->mem_reset_on_abort) {
diff --git a/c8/stm/nursery.c b/c8/stm/nursery.c
--- a/c8/stm/nursery.c
+++ b/c8/stm/nursery.c
@@ -4,6 +4,8 @@
#endif
#include "finalizer.h"
+#include <math.h>
+#include <inttypes.h>
/************************************************************/
@@ -13,14 +15,79 @@
static uintptr_t _stm_nursery_start;
+#define DEFAULT_FILL_MARK_NURSERY_BYTES (NURSERY_SIZE / 4)
-#define DEFAULT_FILL_MARK_NURSERY_BYTES (NURSERY_SIZE / 4)
+// corresponds to ~4 GB
+#define LARGE_FILL_MARK_NURSERY_BYTES 0x100000000L
-uintptr_t stm_fill_mark_nursery_bytes = DEFAULT_FILL_MARK_NURSERY_BYTES;
+// corresponds to ~4 MB nursery fill
+#define STM_DEFAULT_RELATIVE_TRANSACTION_LENGTH (0.001)
+// corresponds to ~400 KB nursery fill
+#define STM_MIN_RELATIVE_TRANSACTION_LENGTH (0.0001)
+
+#define BACKOFF_COUNT (20)
+#define BACKOFF_MULTIPLIER (BACKOFF_COUNT / -log10(STM_MIN_RELATIVE_TRANSACTION_LENGTH))
+
+static inline void set_backoff(stm_thread_local_t *tl, double rel_trx_len) {
+ /* the shorter the trx, the more backoff:
+ think a*x + b = backoff, x := -log(rel-trx-len),
+ backoff is <BACKOFF_COUNT> + b at default trx length,
+ linear decrease to b at max trx length */
+ const int b = 5;
+ int new_backoff = (int)((BACKOFF_MULTIPLIER * -log10(rel_trx_len)) + b);
+ tl->transaction_length_backoff = new_backoff;
+ // printf("thread %d, backoff %d\n", tl->thread_local_counter, tl->transaction_length_backoff);
+ tl->linear_transaction_length_increment = rel_trx_len / new_backoff;
+}
+
+static inline double get_new_transaction_length(stm_thread_local_t *tl, bool aborts) {
+ const int multiplier = 2;
+ double previous = tl->relative_transaction_length;
+ double new;
+ if (aborts) {
+ new = previous / multiplier;
+ if (new < STM_MIN_RELATIVE_TRANSACTION_LENGTH) {
+ new = STM_MIN_RELATIVE_TRANSACTION_LENGTH;
+ }
+ set_backoff(tl, new);
+ } else if (tl->transaction_length_backoff == 0) {
+ // backoff counter is zero, exponential increase up to 1
+ new = previous * multiplier;
+ if (new > 1) {
+ new = 1;
+ }
+ if (tl->linear_transaction_length_increment != 0) {
+ // thread had to abort before: slow start
+ set_backoff(tl, new);
+ }
+ } else { // not abort and backoff != 0
+ // in backoff, linear increase up to 1
+ new = previous + tl->linear_transaction_length_increment;
+ if (new > 1) {
+ new = 1;
+ }
+ tl->transaction_length_backoff -= 1;
+ }
+ return new;
+}
+
+static inline void stm_transaction_length_handle_validation(stm_thread_local_t *tl, bool aborts) {
+ tl->relative_transaction_length = get_new_transaction_length(tl, aborts);
+}
+
+static inline uintptr_t stm_get_transaction_length(stm_thread_local_t *tl) {
+ double relative_additional_length = tl->relative_transaction_length;
+ publish_custom_value_event(
+ relative_additional_length, STM_SINGLE_THREAD_MODE_ADAPTIVE);
+ uintptr_t result =
+ (uintptr_t)(LARGE_FILL_MARK_NURSERY_BYTES * relative_additional_length);
+ // printf("%020" PRIxPTR "\n", result);
+ return result;
+}
+
/************************************************************/
-
static void setup_nursery(void)
{
assert(_STM_FAST_ALLOC <= NURSERY_SIZE);
diff --git a/c8/stm/nursery.h b/c8/stm/nursery.h
--- a/c8/stm/nursery.h
+++ b/c8/stm/nursery.h
@@ -56,4 +56,7 @@
static inline struct object_s *mark_loc(object_t *obj);
static inline bool _is_from_same_transaction(object_t *obj);
+static inline void stm_transaction_length_handle_validation(stm_thread_local_t *tl, bool aborts);
+static inline uintptr_t stm_get_transaction_length(stm_thread_local_t *tl);
+
#endif
diff --git a/c8/stm/setup.c b/c8/stm/setup.c
--- a/c8/stm/setup.c
+++ b/c8/stm/setup.c
@@ -245,6 +245,12 @@
numbers automatically. */
tl->last_associated_segment_num = num + 1;
tl->thread_local_counter = ++thread_local_counters;
+
+ /* init adaptive transaction length mode */
+ tl->relative_transaction_length = STM_DEFAULT_RELATIVE_TRANSACTION_LENGTH;
+ tl->transaction_length_backoff = 0;
+ tl->linear_transaction_length_increment = 0;
+
*_get_cpth(tl) = pthread_self();
_init_shadow_stack(tl);
set_gs_register(get_segment_base(num + 1));
diff --git a/c8/stm/sync.c b/c8/stm/sync.c
--- a/c8/stm/sync.c
+++ b/c8/stm/sync.c
@@ -176,6 +176,16 @@
/************************************************************/
+static uint8_t number_of_segments_in_use(void) {
+ uint8_t result = 0;
+ int num;
+ for (num = 1; num < NB_SEGMENTS; num++) {
+ if (sync_ctl.in_use1[num] > 0) {
+ result++;
+ }
+ }
+ return result;
+}
#if 0
void stm_wait_for_current_inevitable_transaction(void)
@@ -202,7 +212,6 @@
}
#endif
-
static void acquire_thread_segment(stm_thread_local_t *tl)
{
/* This function acquires a segment for the currently running thread,
diff --git a/c8/stm/sync.h b/c8/stm/sync.h
--- a/c8/stm/sync.h
+++ b/c8/stm/sync.h
@@ -22,6 +22,7 @@
static void set_gs_register(char *value);
static void ensure_gs_register(long segnum);
+static uint8_t number_of_segments_in_use(void);
/* acquire and release one of the segments for running the given thread
(must have the mutex acquired!) */
diff --git a/c8/stmgc.h b/c8/stmgc.h
--- a/c8/stmgc.h
+++ b/c8/stmgc.h
@@ -88,6 +88,13 @@
struct stm_thread_local_s *prev, *next;
intptr_t self_or_0_if_atomic;
void *creating_pthread[2];
+ /* == adaptive single thread mode == */
+ /* factor that is multiplied with max transaction length before the start of the next transaction on this thread */
+ double relative_transaction_length;
+ /* when zero, transaction length may increase exponentially, otherwise transaction length may only increase linearly. is (re-)set to some value upon abort and counted down until zero upon successful validation. */
+ int transaction_length_backoff;
+ /* during the backoff, transaction length may increase linearly by this increment on every successful validation */
+ double linear_transaction_length_increment;
} stm_thread_local_t;
More information about the pypy-commit
mailing list