summaryrefslogtreecommitdiff
path: root/erts
diff options
context:
space:
mode:
authorSverker Eriksson <sverker@erlang.org>2020-03-26 16:12:47 +0100
committerSverker Eriksson <sverker@erlang.org>2020-03-26 16:49:38 +0100
commitb40c79b7841ae2912378c0a5a17dd8b80a230fc3 (patch)
tree7a6a56c6156faa4011fff101c2702ae4c8197db1 /erts
parent3825199794da28d79b21052a2e69e2335921d55e (diff)
downloaderlang-b40c79b7841ae2912378c0a5a17dd8b80a230fc3.tar.gz
erts: Fix single core performance bug (ERL-716)
Symptom: Seen on Windows in VirtualBox assigned a single core as a very slow (10s) startup using 100% cpu. Problem: Scheduler out of work calls erts_thr_progress_active(_, 0) which calls leader_update(). The wakeup_managed(0) call at the end of leader_update() will poke aux thread to make thread progress. But the poking thread (the scheduler) has not yet set its own 'current' counter to ERTS_THR_PRGR_VAL_WAITING, which will prevent thread progress to advance. Aux thread spins around in aux_thread() trying but failing to make thread progress. Not until the scheduler is again scheduled by the OS and calls erts_thr_progress_prepare_wait() and set its 'current' to ERTS_THR_PRGR_VAL_WAITING can aux thread make thread progress. In short: Don't wake another thread to do something before you have set all prerequisite for it to do it. Solution: The no-leader-no-active conditional call to wakeup_managed(0) at the end of leader_update() is actally not needed as it is done again in erts_thr_progress_prepare_wait() *after* threads 'current' has been set to ERTS_THR_PRGR_VAL_WAITING.
Diffstat (limited to 'erts')
-rw-r--r--erts/emulator/beam/erl_thr_progress.c17
1 files changed, 3 insertions, 14 deletions
diff --git a/erts/emulator/beam/erl_thr_progress.c b/erts/emulator/beam/erl_thr_progress.c
index bac437efe9..1a3eb6e747 100644
--- a/erts/emulator/beam/erl_thr_progress.c
+++ b/erts/emulator/beam/erl_thr_progress.c
@@ -763,7 +763,6 @@ leader_update(ErtsThrPrgrData *tpd)
(void) block_thread(tpd);
}
else {
- int force_wakeup_check = 0;
erts_aint32_t set_flags = ERTS_THR_PRGR_LFLG_NO_LEADER;
tpd->leader = 0;
tpd->leader_state.current = ERTS_THR_PRGR_VAL_WAITING;
@@ -788,21 +787,11 @@ leader_update(ErtsThrPrgrData *tpd)
/* Need to check umrefc again */
ETHR_MEMBAR(ETHR_StoreLoad);
refc = erts_atomic_read_nob(&intrnl->umrefc[umrefc_ix].refc);
- if (refc == 0) {
- /* Need to force wakeup check */
- force_wakeup_check = 1;
+ if (refc == 0 && got_sched_wakeups()) {
+ /* Someone need to make progress */
+ wakeup_managed(tpd->id);
}
}
-
- if ((force_wakeup_check
- || ((lflgs & (ERTS_THR_PRGR_LFLG_NO_LEADER
- | ERTS_THR_PRGR_LFLG_WAITING_UM
- | ERTS_THR_PRGR_LFLG_ACTIVE_MASK))
- == ERTS_THR_PRGR_LFLG_NO_LEADER))
- && got_sched_wakeups()) {
- /* Someone need to make progress */
- wakeup_managed(tpd->id);
- }
}
}