-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rt: add optional throttling to BasicScheduler #2016
Conversation
Failure is due to elapsed duration checks on MacOS. I know elapsed duration checks are not ideal in CI, but I though they were important here. I already relaxed the boundary compared to the limit I tested on my box, but it doesn't seem enough. Unfortunately, I don't have a MacOS to ascertain this is not a bug in my implementation. Will try to figure out a solution. Any suggestion welcome! :) |
Still no luck with CI on macOS. It's the only platform which show inconsistent
Note: not always the same test in error + it seems very suspicious to me Windows & Linux show expected behavior:
These results were extracted from this CI execution which was triggered by |
fc1e764
to
23e4dc2
Compare
I added a commit to account for the dispersion in timing for CI Commit: 23e4dc2, CI run: https://dev.azure.com/tokio-rs/Tokio/_build/results?buildId=4297&view=results
I choose these tests because they were not added by this PR My conclusion is that we can't check timing bounds with CI on |
99c7b5a
to
a05771c
Compare
73852c3
to
e759c81
Compare
Could anybody tell which issue is blocking the PR? is there any chance that it can be merged in upcoming release? |
It needs one of the maintainers to actually review it and first of all consider the idea good and something they'd like to have as part of tokio. |
aad2846
to
3136c44
Compare
4ef1a66
to
5f95c38
Compare
With some tasks, we don't want to take the risk of waiting for the max_throttling time to elapse before being handled. This is the case when a user starts many task in a serialized way waitting for an acknowledgment that each task is indeed spawned. In this case, we want the task to be handled immediately so that we don't risk to wait max_throttling time for each task.
5f95c38
to
37cb931
Compare
Sorry for the radio silence. I have read your description a few times and glanced at the source. I am not disputing that batching/throttling is a useful optimization technique. I am not following why batching/throttling needs to be implemented in the Tokio runtime and not a layer between Tokio and your application. Could you clarify this? |
We used to implement this as a layer, but since the removal of of We currently use a fork and plan on moving to a dedicate runtime. Sorry for accidentally pushing to this branch and reviving this PR. Closing it now. |
It's fine. However, what I am trying to understand is why does this capability require any specific runtime support? Batching / throttling of action can happen purely at the futures level. I could be missing something. I am trying to understand better because and make sure that I am not missing anything. |
For example, you could implement |
It is also possible to implement a fully self-contained executor that implements throttling. For example, |
While throttling can be implemented on the futures level, this has the problem that the reactor is still woken up whenever e.g. a new UDP packet is received. The main goal here is to throttle the reactor to (as a result) throttle the overall rate of wakeups and batch them all together. A self-contained executor/reactor (both combined) might be an option, I guess we missed that enough API for implementing that from the outside is exposed in tokio 0.2. That might be worth trying. However as @fengalin mentioned above, we're currently looking into moving to a custom, minimal runtime instead. This issue (and generally quite custom behaviour) is of course one big reason for that, but overall we need more direct control over the runtime behavior than what tokio can provide and also only really need maybe 10% of the features tokio offers :) It's a very specific use-case and it seems unrealistic that a general purpose runtime would be fully adaptable to that, or to expect that such niche features like this one here could be merged into tokio (and increase the maintenance burden for everyone). |
Motivation
This PR is a continuation of #1887.
gst-plugin-threadshare
is a framework and a collection ofGStreamer
elements which are developped with the Rust programming language and use the
gstreamer-rs
bindings to theGStreamer
C-based libraries.In the regular
GStreamer
model, pipeline elements spawn there own threads todeal with asynchronous processing. Most of the time, these threads wait for
something to happen which causes multiple overheads. The
gst-plugin-threadshare
model allows elements to share threads which reduces context switches and system
calls, thus lowering CPU load.
The framework executor uses
tokio
. Until release0.2.0
,tokio
featuredfunctions that gave control on the iterations of the executor:
turn
would execute one iteration and indicate if tasks were handled bythe executor.
park
&unpark
.Thanks to these features the framework could benefit from the
tokio
executorwhile implementing a throttling strategy. The throttling strategy consists in
grouping tasks, timers and I/O handling by forcing the thread to sleep during a
short duration. For use cases where a large number of events are to be handled
randomly (e.g. 2,000+ live multimedia streams), this induces an even more
efficient use of the CPU and wider bandwidth.
Since the throttling strategy introduces pauses in the execution thread, timers
need a special treatment so that they are fired close enough to their target
instant. In order to avoid timers from being triggered too late,
gst-plugin-threadshare
implemented its own timers management.See this blog post for a more in-depth explanation of the throttling strategy.
Two solutions are considered for
gst-plugin-threadshare
to keep up withtokio
new versions (see this thread):tokio
's executor.tokio
's executor so thatgst-plugin-threadshare
can keep its throttling strategy.
Solution (1) presents the following benefits:
use cases.
in
tokio
, meaninggst-plugin-threadshare
would not implement its owntimers management.
This PR is an implementation of solution (1). Follow this link
for an evaluation of the resulting behavior for the
BasicScheduler
.Solution
This PR introduces a new optional duration parameter
max_throttling
. If theuser provides a non-null duration and selects the basic scheduler, the
throttling strategy is activated.
max_throttling
is the maximum durationof the thread pauses and the minimal duration between two consecutive timers &
I/O polls.
When throttling is activated, the
BasicScheduler
loops on the newtick_throttling
function instead oftick
. Thetick_throttling
functionuses a state machine to control the descent to the state where the thread would
be actually paused if the
max_throttling
hasn't elapsed yet since the instant thetimers & I/O where last polled.
The purpose of the thread pause is to not be awaken before the intended duration
has elapsed, so the actual pause doesn't rely on a driver's park implementation,
but on a call to
std::thread::sleep
.Since timers I/O are never polled more often than
max_throttling
ms, timersneed a special care. The idea is to consider time frames which start at a polling
instant. Consider a time frame starting now. Since current time frame will last
at least
max_throttling
ms, we need to fire timers that will elapse beforethe first half of current timer frame, otherwise they would be fire further to
their intended instant and always too late.
In order to implement this strategy with minimal impact on existing code, it was
decided to add a new mode to the
time::Driver
. When this mode is activated,the
park_timeout
method fires the timers as described above, polls the I/Ovia the inner driver and returns immediately. This way the scheduler can still
trigger tasks that would depend on the timers before going to sleep.
Tests
In order to ensure on par behavior with the regular
tick
algorithm,basic_scheduler_throttling
was added tort_common
. A new testrt_basic_throttling.rs
takes care of checking the time frame strategy.Tests were also conducted as part of this evaluation
which covers a
tokio
only benchmark as well as a comparison of theimplementations used for the
gst-plugin-threadshare
framework.