Patch file to add +sfwi tuning to an R15B01 Erlang VM. Should be present without the patch in R16B01+. It's possible that this patch will apply to other releases. Use at your own risk.
From 005be2e442074ea529ae0a188399eda553cb8783 Mon Sep 17 00:00:00 2001 | |
From: evan <evan@basho.com> | |
Date: Tue, 18 Jun 2013 17:52:54 -0400 | |
Subject: [PATCH] backport sfwi to R15B01 | |
--- | |
erts/emulator/beam/erl_init.c | 16 +++++++ | |
erts/emulator/beam/erl_process.c | 89 ++++++++++++++++++++++++++++++++++++-- | |
erts/emulator/beam/erl_process.h | 9 ++++ | |
erts/etc/common/erlexec.c | 1 + | |
4 files changed, 112 insertions(+), 3 deletions(-) | |
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c | |
index ca4385d..4c2aef3 100644 | |
--- a/erts/emulator/beam/erl_init.c | |
+++ b/erts/emulator/beam/erl_init.c | |
@@ -1283,6 +1283,22 @@ erl_start(int argc, char **argv) | |
("suggested scheduler thread stack size %d kilo words\n", | |
erts_sched_thread_suggested_stack_size)); | |
} | |
+ else if (has_prefix("fwi", sub_param)) { | |
+ long val; | |
+ arg = get_arg(sub_param+3, argv[i+1], &i); | |
+ errno = 0; | |
+ val = strtol(arg, NULL, 10); | |
+ if (errno != 0 || val < 0) { | |
+ erts_fprintf(stderr, | |
+ "bad scheduler forced wakeup " | |
+ "interval %s\n", | |
+ arg); | |
+ erts_usage(); | |
+ } | |
+#ifdef ERTS_SMP | |
+ erts_runq_supervision_interval = val; | |
+#endif | |
+ } | |
else { | |
erts_fprintf(stderr, "bad scheduling option %s\n", argv[i]); | |
erts_usage(); | |
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c | |
index 95d408f..fec9160 100644 | |
--- a/erts/emulator/beam/erl_process.c | |
+++ b/erts/emulator/beam/erl_process.c | |
@@ -211,6 +211,10 @@ static erts_smp_atomic32_t function_calls; | |
#ifdef ERTS_SMP | |
static erts_smp_atomic32_t doing_sys_schedule; | |
static erts_smp_atomic32_t no_empty_run_queues; | |
+long erts_runq_supervision_interval = 0; | |
+static ethr_event runq_supervision_event; | |
+static erts_tid_t runq_supervisor_tid; | |
+static erts_atomic_t runq_supervisor_sleeping; | |
#else /* !ERTS_SMP */ | |
ErtsSchedulerData *erts_scheduler_data; | |
#endif | |
@@ -1794,7 +1798,13 @@ empty_runq(ErtsRunQueue *rq) | |
*/ | |
ASSERT(0 <= empty && empty < 2*erts_no_run_queues); | |
#endif | |
- erts_smp_atomic32_inc_relb(&no_empty_run_queues); | |
+ if (!erts_runq_supervision_interval) | |
+ erts_smp_atomic32_inc_relb(&no_empty_run_queues); | |
+ else { | |
+ erts_smp_atomic32_inc_mb(&no_empty_run_queues); | |
+ if (erts_atomic_read_nob(&runq_supervisor_sleeping)) | |
+ ethr_event_set(&runq_supervision_event); | |
+ } | |
} | |
} | |
@@ -1812,7 +1822,14 @@ non_empty_runq(ErtsRunQueue *rq) | |
*/ | |
ASSERT(0 < empty && empty <= 2*erts_no_run_queues); | |
#endif | |
- erts_smp_atomic32_dec_relb(&no_empty_run_queues); | |
+ if (!erts_runq_supervision_interval) | |
+ erts_smp_atomic32_dec_relb(&no_empty_run_queues); | |
+ else { | |
+ erts_aint32_t no; | |
+ no = erts_smp_atomic32_dec_read_mb(&no_empty_run_queues); | |
+ if (no > 0 && erts_atomic_read_nob(&runq_supervisor_sleeping)) | |
+ ethr_event_set(&runq_supervision_event); | |
+ } | |
} | |
} | |
@@ -2412,7 +2429,6 @@ try_inc_no_active_runqs(int active) | |
return 0; | |
} | |
- | |
static ERTS_INLINE int | |
chk_wake_sched(ErtsRunQueue *crq, int ix, int activate) | |
{ | |
@@ -3875,6 +3891,57 @@ erts_get_scheduler_data(void) | |
return (ErtsSchedulerData *) erts_tsd_get(sched_data_key); | |
} | |
+#ifdef ERTS_SMP | |
+ | |
+static int | |
+no_runqs_to_supervise(void) | |
+{ | |
+ int used; | |
+ erts_aint32_t nerq = erts_smp_atomic32_read_acqb(&no_empty_run_queues); | |
+ if (nerq <= 0) | |
+ return 0; | |
+ get_no_runqs(NULL, &used); | |
+ if (nerq >= used) | |
+ return 0; | |
+ return used; | |
+} | |
+ | |
+static void * | |
+runq_supervisor(void *unused) | |
+{ | |
+ while (1) { | |
+ int ix, no_rqs; | |
+ | |
+ erts_milli_sleep(erts_runq_supervision_interval); | |
+ no_rqs = no_runqs_to_supervise(); | |
+ if (!no_rqs) { | |
+ erts_atomic_set_nob(&runq_supervisor_sleeping, 1); | |
+ while (1) { | |
+ ethr_event_reset(&runq_supervision_event); | |
+ no_rqs = no_runqs_to_supervise(); | |
+ if (no_rqs) { | |
+ erts_atomic_set_nob(&runq_supervisor_sleeping, 0); | |
+ break; | |
+ } | |
+ ethr_event_wait(&runq_supervision_event); | |
+ } | |
+ } | |
+ | |
+ for (ix = 0; ix < no_rqs; ix++) { | |
+ ErtsRunQueue *rq = ERTS_RUNQ_IX(ix); | |
+ if (ERTS_RUNQ_IFLGS_GET(rq) & ERTS_RUNQ_IFLG_NONEMPTY) { | |
+ erts_smp_runq_lock(rq); | |
+ if (rq->len != 0) { | |
+ wake_scheduler_on_empty_runq(rq); /* forced wakeup... */ | |
+ } | |
+ erts_smp_runq_unlock(rq); | |
+ } | |
+ } | |
+ } | |
+ return NULL; | |
+} | |
+ | |
+#endif | |
#endif | |
static int remove_proc_from_runq(ErtsRunQueue *rq, Process *p, int to_inactive); | |
@@ -4851,6 +4918,22 @@ erts_start_schedulers(void) | |
ethr_thr_opts opts = ETHR_THR_OPTS_DEFAULT_INITER; | |
opts.detached = 1; | |
+ | |
+#ifdef ERTS_SMP | |
+ if (erts_runq_supervision_interval) { | |
+ opts.suggested_stack_size = 16; | |
+ erts_atomic_init_nob(&runq_supervisor_sleeping, 0); | |
+ if (0 != ethr_event_init(&runq_supervision_event)) | |
+ erl_exit(1, "Failed to create run-queue supervision event\n"); | |
+ if (0 != ethr_thr_create(&runq_supervisor_tid, | |
+ runq_supervisor, | |
+ NULL, | |
+ &opts)) | |
+ erl_exit(1, "Failed to create run-queue supervision thread\n"); | |
+ | |
+ } | |
+#endif | |
+ | |
opts.suggested_stack_size = erts_sched_thread_suggested_stack_size; | |
if (wanted < 1) | |
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h | |
index cff0783..e1f4f1e 100644 | |
--- a/erts/emulator/beam/erl_process.h | |
+++ b/erts/emulator/beam/erl_process.h | |
@@ -148,6 +148,8 @@ extern int erts_sched_thread_suggested_stack_size; | |
(((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 3)) | |
#define ERTS_RUNQ_FLG_INACTIVE \ | |
(((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 4)) | |
+#define ERTS_RUNQ_FLG_NONEMPTY \ | |
+ (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 5)) | |
#define ERTS_RUNQ_FLGS_MIGRATION_QMASKS \ | |
(ERTS_RUNQ_FLGS_EMIGRATE_QMASK \ | |
@@ -186,6 +188,9 @@ extern int erts_sched_thread_suggested_stack_size; | |
#define ERTS_UNSET_RUNQ_FLG_EVACUATE(FLGS, PRIO) \ | |
((FLGS) &= ~ERTS_RUNQ_FLG_EVACUATE((PRIO))) | |
+#define ERTS_RUNQ_IFLGS_GET(RQ) \ | |
+ ((Uint32) erts_smp_atomic32_read_acqb(&(RQ)->info_flags)) | |
+ | |
#define ERTS_RUNQ_IFLG_SUSPENDED (((erts_aint32_t) 1) << 0) | |
#define ERTS_RUNQ_IFLG_NONEMPTY (((erts_aint32_t) 1) << 1) | |
@@ -370,6 +375,10 @@ struct ErtsRunQueue_ { | |
} ports; | |
}; | |
+#ifdef ERTS_SMP | |
+extern long erts_runq_supervision_interval; | |
+#endif | |
+ | |
typedef union { | |
ErtsRunQueue runq; | |
char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsRunQueue))]; | |
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c | |
index 19b3bb8..ac4e509 100644 | |
--- a/erts/etc/common/erlexec.c | |
+++ b/erts/etc/common/erlexec.c | |
@@ -123,6 +123,7 @@ static char *pluss_val_switches[] = { | |
"bt", | |
"cl", | |
"ct", | |
+ "fwi", | |
"wt", | |
"ss", | |
NULL | |
-- | |
1.7.9.5 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment