implement a pipe based sleep strategy using the IO subsystem
Design goals ============ * Wakeup either on external newWork notifications or on local IO completions -> Sleep strategy is sound without the IO completer * Do as less as possible in a system saturated with work * Pass a hint where to find new work to suspended workers Algorithm ========= Data: Global: hint pipe sleepers count Per worker: dispatch hint buffer in flight flag Sleep: if we have no sleep request in flight Atomic increment sleep count Remember that we are sleeping Prepare read cqe from the hint pipe to dispatch hint buffer Prevent the completer from reaping completions on this worker's IoContext Wait until IO completions occurred NotifyEmper(n): if observed sleepers <= 0 return // Determine how many we are responsible to wake do toWakeup = min(observed sleepers, n) while (!CAS(sleepers, toWakeup)) write toWakeup hints to the hint pipe NotifyAnywhere(n): // Ensure all n notifications take effect while (!CAS(sleepers, observed sleepers - n)) if observed sleeping <= -n return toWakeup = min(observed sleeping, n) write toWakeup hints to the hint pipe onNewWorkCompletion: reset in flight flag allow completer to reap completions on this IoContext Notes ===== * We must decrement the sleepers count on the notifier side to prevent multiple notifiers to observe all the same amount of sleepers, trying to wake up the same sleepers by writing to the pipe and jamming it up with unconsumed hints and thus blocking in the notify write resulting in a deadlock. * The CAS loops on the notifier side are needed because decrementing and incrementing the excess is racy: Two notifier can observe the sum of both their excess decrement and increment to much resulting in a broken counter. * Add the dispatch hint code in AbstractWorkStealingScheduler::nextFiber. This allows workers to check the dispatch hint after there where no local work to execute. This is a trade-off where we trade slower wakeup - a just awoken worker will check for local work - against a faster dispatch hot path when we have work to do in our local WSQ. * The completer tread must not reap completions on the IoContexts of sleeping workers because this introduces a race for cqes and a possible lost wakeup if the completer consumes the completions before the worker is actually waiting for them. * When notifying sleeping workers from anywhere we must ensure that all notifications take effect. This is needed for example when terminating the runtime to prevent sleep attempt from worker thread which are about to sleep but have not incremented the sleeper count yet. We achieve this by always decrementing the sleeper count by the notification count. Thanks to Florian Schmaus <flow@cs.fau.de> for spotting bugs and suggesting improvements.
parent
6c1fd077
No related branches found
No related tags found
Showing
- emper/Debug.hpp 4 additions, 0 deletionsemper/Debug.hpp
- emper/Emper.hpp 7 additions, 0 deletionsemper/Emper.hpp
- emper/Runtime.cpp 2 additions, 0 deletionsemper/Runtime.cpp
- emper/Runtime.hpp 5 additions, 1 deletionemper/Runtime.hpp
- emper/Worker.hpp 14 additions, 1 deletionemper/Worker.hpp
- emper/io/IoContext.cpp 34 additions, 10 deletionsemper/io/IoContext.cpp
- emper/io/IoContext.hpp 48 additions, 2 deletionsemper/io/IoContext.hpp
- emper/io/Stats.cpp 1 addition, 1 deletionemper/io/Stats.cpp
- emper/lib/TaggedPtr.hpp 12 additions, 1 deletionemper/lib/TaggedPtr.hpp
- emper/sleep_strategy/AbstractWorkerSleepStrategy.hpp 2 additions, 0 deletionsemper/sleep_strategy/AbstractWorkerSleepStrategy.hpp
- emper/sleep_strategy/PipeSleepStrategy.cpp 90 additions, 0 deletionsemper/sleep_strategy/PipeSleepStrategy.cpp
- emper/sleep_strategy/PipeSleepStrategy.hpp 296 additions, 0 deletionsemper/sleep_strategy/PipeSleepStrategy.hpp
- emper/sleep_strategy/SemaphoreWorkerSleepStrategy.hpp 2 additions, 0 deletionsemper/sleep_strategy/SemaphoreWorkerSleepStrategy.hpp
- emper/sleep_strategy/WorkerSleepStrategy.hpp 9 additions, 2 deletionsemper/sleep_strategy/WorkerSleepStrategy.hpp
- emper/sleep_strategy/meson.build 1 addition, 0 deletionsemper/sleep_strategy/meson.build
- emper/strategies/AbstractWorkStealingScheduler.cpp 59 additions, 11 deletionsemper/strategies/AbstractWorkStealingScheduler.cpp
- emper/strategies/AbstractWorkStealingScheduler.hpp 6 additions, 0 deletionsemper/strategies/AbstractWorkStealingScheduler.hpp
- emper/strategies/AbstractWorkStealingStats.cpp 4 additions, 0 deletionsemper/strategies/AbstractWorkStealingStats.cpp
- emper/strategies/AbstractWorkStealingWorkerStats.hpp 2 additions, 0 deletionsemper/strategies/AbstractWorkStealingWorkerStats.hpp
- emper/strategies/laws/LawsDispatcher.cpp 6 additions, 0 deletionsemper/strategies/laws/LawsDispatcher.cpp
Loading
Please register or sign in to comment