diff options
author | Sverker Eriksson <sverker@erlang.org> | 2020-03-26 16:12:47 +0100 |
---|---|---|
committer | Sverker Eriksson <sverker@erlang.org> | 2020-03-26 16:49:38 +0100 |
commit | b40c79b7841ae2912378c0a5a17dd8b80a230fc3 (patch) | |
tree | 7a6a56c6156faa4011fff101c2702ae4c8197db1 /erts | |
parent | 3825199794da28d79b21052a2e69e2335921d55e (diff) | |
download | erlang-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.c | 17 |
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); - } } } |