Repository navigation
metrics: add task schedule latency metric - #7986
Conversation
This new metric tracks the amount of time between when a task is scheduled and when it is polled, also known as queue delay. This duration is recorded in a histogram, just like the poll time metric. This metric is useful for implementing queue management algorithms in systems using tokio. For example, it could be used to implement a generic http load shedder using the CoDel algorithm.
|
|
||
| // Check for a task in the LIFO slot | ||
| let task = match core.lifo_slot.take() { | ||
| Some(task) => task, |
There was a problem hiding this comment.
Should core.stats.start_poll(task.get_scheduled_at()); be called here too ?
There was a problem hiding this comment.
I considered this, but it would also change the behavior of the poll time metric. I do think that would be more correct, but wanted to avoid changing too many things in one PR. I'm happy to make the change though if you think that's fine!
| /// The last time this task was scheduled. Used to measure schedule latency. | ||
| #[cfg(tokio_unstable)] | ||
| /// | ||
| /// Only enabled when the target supports 64-bit atomics because the metric | ||
| /// that uses this field also requires 64-bit atomics. | ||
| #[cfg(all(tokio_unstable, target_has_atomic = "64"))] | ||
| pub(super) scheduled_at: UnsafeCell<Option<Instant>>, |
There was a problem hiding this comment.
This field adds 16 bytes to the header, bringing it up to 48 bytes in total (56 if tracing is enabled too).
This is causing the header_lte_cache_line test (at the bottom of this file) to fail on 32-bit targets. Restricting the field to targets that support 64-bit atomics did not work because some 32-bit targets do support 64-bit atomics.
Maybe sticking this behind a feature (like tracing) would be best?
There was a problem hiding this comment.
I'm okay with changing that test to be <= 64 to accomodate 32-bit targets, they are not that important anyway.
Regardless, the Instant struct is pretty large and space is at a premium in the task header. I don't think we want to dedicate 16 bytes just so we can have nanosecond precision even if it takes a billion years for it to get scheduled. Could we store a u32 of milliseconds since the runtime was created, or something like that? I'm pretty sure we already store a sort of "epoch" instant in the tokio::runtime::time part of the driver.
There was a problem hiding this comment.
That's a good idea, I updated the PR to use this "epoch" approach. I used a u64 though because the struct is already 8-byte aligned on all targets because of the 64-bit owner_id field, so a u32 just wastes 4 bytes. Using a u64 also means we can keep the nanosecond precision, since u64::MAX in nanoseconds is equal to ~584 years.
That brings the size of the struct up to 40 bytes now.
And you're right, the time driver does track the startup time of the time driver. I opted not to use it however because the time driver is not enabled by default, so using it would mean the time driver must be enabled by users in order to use this schedule latency tracking.
| @@ -247,6 +249,16 @@ impl<S> Notified<S> { | |||
| pub(crate) fn task_meta<'meta>(&self) -> crate::runtime::TaskMeta<'meta> { | |||
| self.0.task_meta() | |||
There was a problem hiding this comment.
can we please expose this field in the task meta? That would really help for observability tools because it means that during on_poll_start we can unconditionally know what the scheduling delay was
There was a problem hiding this comment.
I think it would be best to do that in a follow-up PR. I agree it would be very useful, but it'll require some refactoring of the way TaskMeta is constructed.
| /// Startup time of this scheduler. | ||
| /// | ||
| /// This instant is used as the basis of task `scheduled_at` measurements. | ||
| #[cfg(all(tokio_unstable, target_pointer_width = "64"))] | ||
| started_at: Instant, |
There was a problem hiding this comment.
This PR is using these cfgs all over the place. Can we please reduce them a bit? You can define a module that contains a ScheduleLatencyInstant which is either empty or contains an Instant depending on the configuration, and then code actually using it can stop having cfgs. Similarly for the u64 in the task header.
There was a problem hiding this comment.
Makes sense, the cfgs did get a bit out of control after the 64-bit restriction.
I've updated the PR to remove almost all of the cfgs and centralized the logic into a new schedule_latency module. The size of the task Header remains the same as the previous version on both 64-bit and 32-bit targets.
| #[cfg(tokio_unstable)] | ||
| schedule_latencies: Option<HistogramBatch>, |
There was a problem hiding this comment.
I think I would prefer the following approach:
- Everywhere in the code it's just protected by
#[cfg(feature = "schedule-latency")]only. - In
lib.rsyou emit acompile_error!if you enableschedule-latencywithout--cfg tokio_unstable.
Right now the cfgs are pretty inconsistent. Sometimes you only require tokio_unstable. Sometimes you require target_pointer_width = "64". Sometimes you require target_has_atomic = "64". Please make these cfgs consistent.
There was a problem hiding this comment.
With the original cfgs I was trying to align each part with the surrounding metrics code, but I do see your point that it was messy.
I've updated the code to only use #[cfg(feature = "schedule-latency")], and had to add a few additional guards to MetricsBatch to account for the state where unstable metrics are enabled but schedule-latency isn't.
|
@Darksonn I think I've addressed your comments, could you take another look? |
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [tokio](https://tokio.rs) ([source](https://github.com/tokio-rs/tokio)) | dependencies | minor | `1.52.3` β `1.53.1` | --- ### Release Notes <details> <summary>tokio-rs/tokio (tokio)</summary> ### [`v1.53.1`](https://github.com/tokio-rs/tokio/releases/tag/tokio-1.53.1): Tokio v1.53.1 [Compare Source](tokio-rs/tokio@tokio-1.53.0...tokio-1.53.1) ### 1.53.1 (July 20th, 2026) ##### Fixed - signal: restore MSRV by removing `OnceLock::wait` from the Windows handler ([#​8300]) ##### Fixed (unstable) - time: fix alt timer cancellation and insertion race ([#​8252]) ##### Documented - runtime: remove dead link definition in Runtime::block\_on ([#​8301]) [#​8252]: tokio-rs/tokio#8252 [#​8300]: tokio-rs/tokio#8300 [#​8301]: tokio-rs/tokio#8301 ### [`v1.53.0`](https://github.com/tokio-rs/tokio/releases/tag/tokio-1.53.0): Tokio v1.53.0 [Compare Source](tokio-rs/tokio@tokio-1.52.4...tokio-1.53.0) ### 1.53.0 (July 17th, 2026) ##### Added - fs: implement `From<OwnedFd>` and `From<OwnedHandle>` for `File` ([#​8266]) - metrics: add task schedule latency metric ([#​7986]) - net: add `SocketAddr` methods to Unix sockets ([#​8144]) ##### Changed - io: add `#[inline]` to IO trait impls for in-memory types ([#​8242]) - net: implement UCred::pid on FreeBSD ([#​8086]) - net: support Nuttx target os ([#​8259]) - signal: refactor global variables on Windows ([#​8231]) - sync: `mpsc::{Receiver,UnboundedReceiver}` now drops waker on drop, even if there are still senders ([#​8095]) - taskdump: support taskdumps on s390x ([#​8192]) - time: add `#[track_caller]` to `timeout_at()` ([#​8077]) - time: consolidate mutex locks on spurious poll ([#​8124]) - time: defer waker clone on spurious poll ([#​8107]) - time: move lazy-registration state into `Sleep` ([#​8132]) - tracing: remove unnecessary span clone ([#​8126]) ##### Fixed - io: do not treat zero-length reads as EOF in `Chain` ([#​8251]) - net: use getpeereid for QNX peer credentials ([#​8270]) - runtime: avoid illegal state in `FastRand` ([#​8078]) - sync: wake mpsc receiver when a queued `reserve[_many]` returns permits ([#​8260]) - taskdump: skip double wake on `Trace::capture`/`Trace::trace_with` ([#​8043]) - time: avoid stack overflow in runtime constructor ([#​8093]) - time (alt timer): ensure timers stay in the same runtime after `.reset()` ([#​8169]) ##### IO uring (unstable) - fs: use io-uring for `fs::try_exists` ([#​8080]) - fs: use io-uring for renaming files ([#​7800]) - rt: flush io-uring CQE in case of CQE overflow ([#​8277]) ##### Documented - docs: clarify cancel safety wording ([#​8181]) - fs: clarify `create_dir_all` succeeds if path exists ([#​8149]) - io: add warning about stdout reordering with multiple handles ([#​8276]) - net: document pipe `try_read*`/`try_write*` readiness behavior ([#​8032]) - runtime: document interaction with fork() ([#​8202]) - sync: clarify broadcast lagging semantics ([#​8239]) - sync: document memory ordering guarantees for Semaphore ([#​8119]) - task: explain why `yield_now` defers its waker ([#​8254]) - time: add panic docs to `timeout_at()` ([#​8077]) - time: fix reversed poll order in timeout doc ([#​8214]) [#​7800]: tokio-rs/tokio#7800 [#​7986]: tokio-rs/tokio#7986 [#​8032]: tokio-rs/tokio#8032 [#​8043]: tokio-rs/tokio#8043 [#​8077]: tokio-rs/tokio#8077 [#​8078]: tokio-rs/tokio#8078 [#​8080]: tokio-rs/tokio#8080 [#​8086]: tokio-rs/tokio#8086 [#​8093]: tokio-rs/tokio#8093 [#​8095]: tokio-rs/tokio#8095 [#​8107]: tokio-rs/tokio#8107 [#​8119]: tokio-rs/tokio#8119 [#​8124]: tokio-rs/tokio#8124 [#​8126]: tokio-rs/tokio#8126 [#​8132]: tokio-rs/tokio#8132 [#​8144]: tokio-rs/tokio#8144 [#​8149]: tokio-rs/tokio#8149 [#​8169]: tokio-rs/tokio#8169 [#​8181]: tokio-rs/tokio#8181 [#​8192]: tokio-rs/tokio#8192 [#​8193]: tokio-rs/tokio#8193 [#​8202]: tokio-rs/tokio#8202 [#​8214]: tokio-rs/tokio#8214 [#​8231]: tokio-rs/tokio#8231 [#​8239]: tokio-rs/tokio#8239 [#​8242]: tokio-rs/tokio#8242 [#​8251]: tokio-rs/tokio#8251 [#​8254]: tokio-rs/tokio#8254 [#​8259]: tokio-rs/tokio#8259 [#​8260]: tokio-rs/tokio#8260 [#​8266]: tokio-rs/tokio#8266 [#​8270]: tokio-rs/tokio#8270 [#​8276]: tokio-rs/tokio#8276 [#​8277]: tokio-rs/tokio#8277 ### [`v1.52.4`](https://github.com/tokio-rs/tokio/releases/tag/tokio-1.52.4): Tokio v1.52.4 [Compare Source](tokio-rs/tokio@tokio-1.52.3...tokio-1.52.4) ### 1.52.4 (July 16th, 2026) ##### Fixed - runtime: don't skip the driver when `before_park` schedules work ([#​8222]) ##### Fixed (unstable) - taskdump: remove crate disambiguators from output ([#​8264]) [#​8264]: tokio-rs/tokio#8264 [#​8222]: tokio-rs/tokio#8222 </details> --- ### Configuration π **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) π¦ **Automerge**: Enabled. β» **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. π **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNzEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjE3MS4xIiwidGFyZ2V0QnJhbmNoIjoibWFzdGVyIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate <renovate@impure.systems> Co-authored-by: Luca Di Carlo <luca@noreply.git.impure.systems> Reviewed-on: https://git.impure.systems/luca/legifrss/pulls/20
[cb skip] Changes in 1.53.1 ----------------- 1.53.1 (July 20th, 2026) ------------------------ Fixed ----- - signal: restore MSRV by removing `OnceLock::wait` from the Windows handler ([#8300]) Fixed (unstable) ---------------- - time: fix alt timer cancellation and insertion race ([#8252]) Documented ---------- - runtime: remove dead link definition in Runtime::block_on ([#8301]) [#8252]: tokio-rs/tokio#8252 [#8300]: tokio-rs/tokio#8300 [#8301]: tokio-rs/tokio#8301 Changes in 1.53.0 ----------------- 1.53.0 (July 17th, 2026) ------------------------ Added ----- - fs: implement `From<OwnedFd>` and `From<OwnedHandle>` for `File` ([#8266]) - metrics: add task schedule latency metric ([#7986]) - net: add `SocketAddr` methods to Unix sockets ([#8144]) Changed ------- - io: add `#[inline]` to IO trait impls for in-memory types ([#8242]) - net: implement UCred::pid on FreeBSD ([#8086]) - net: support Nuttx target os ([#8259]) - signal: refactor global variables on Windows ([#8231]) - sync: `mpsc::{Receiver,UnboundedReceiver}` now drops waker on drop, even if there are still senders ([#8095]) - taskdump: support taskdumps on s390x ([#8192]) - time: add `#[track_caller]` to `timeout_at()` ([#8077]) - time: consolidate mutex locks on spurious poll ([#8124]) - time: defer waker clone on spurious poll ([#8107]) - time: move lazy-registration state into `Sleep` ([#8132]) - tracing: remove unnecessary span clone ([#8126]) Fixed ----- - io: do not treat zero-length reads as EOF in `Chain` ([#8251]) - net: use getpeereid for QNX peer credentials ([#8270]) - runtime: avoid illegal state in `FastRand` ([#8078]) - sync: wake mpsc receiver when a queued `reserve[_many]` returns permits ([#8260]) - taskdump: skip double wake on `Trace::capture`/`Trace::trace_with` ([#8043]) - time: avoid stack overflow in runtime constructor ([#8093]) - time (alt timer): ensure timers stay in the same runtime after `.reset()` ([#8169]) IO uring (unstable) ------------------- - fs: use io-uring for `fs::try_exists` ([#8080]) - fs: use io-uring for renaming files ([#7800]) - rt: flush io-uring CQE in case of CQE overflow ([#8277]) Documented ---------- - docs: clarify cancel safety wording ([#8181]) - fs: clarify `create_dir_all` succeeds if path exists ([#8149]) - io: add warning about stdout reordering with multiple handles ([#8276]) - net: document pipe `try_read*`/`try_write*` readiness behavior ([#8032]) - runtime: document interaction with fork() ([#8202]) - sync: clarify broadcast lagging semantics ([#8239]) - sync: document memory ordering guarantees for Semaphore ([#8119]) - task: explain why `yield_now` defers its waker ([#8254]) - time: add panic docs to `timeout_at()` ([#8077]) - time: fix reversed poll order in timeout doc ([#8214]) [#7800]: tokio-rs/tokio#7800 [#7986]: tokio-rs/tokio#7986 [#8032]: tokio-rs/tokio#8032 [#8043]: tokio-rs/tokio#8043 [#8077]: tokio-rs/tokio#8077 [#8078]: tokio-rs/tokio#8078 [#8080]: tokio-rs/tokio#8080 [#8086]: tokio-rs/tokio#8086 [#8093]: tokio-rs/tokio#8093 [#8095]: tokio-rs/tokio#8095 [#8107]: tokio-rs/tokio#8107 [#8119]: tokio-rs/tokio#8119 [#8124]: tokio-rs/tokio#8124 [#8126]: tokio-rs/tokio#8126 [#8132]: tokio-rs/tokio#8132 [#8144]: tokio-rs/tokio#8144 [#8149]: tokio-rs/tokio#8149 [#8169]: tokio-rs/tokio#8169 [#8181]: tokio-rs/tokio#8181 [#8192]: tokio-rs/tokio#8192 [#8193]: tokio-rs/tokio#8193 [#8202]: tokio-rs/tokio#8202 [#8214]: tokio-rs/tokio#8214 [#8231]: tokio-rs/tokio#8231 [#8239]: tokio-rs/tokio#8239 [#8242]: tokio-rs/tokio#8242 [#8251]: tokio-rs/tokio#8251 [#8254]: tokio-rs/tokio#8254 [#8259]: tokio-rs/tokio#8259 [#8260]: tokio-rs/tokio#8260 [#8266]: tokio-rs/tokio#8266 [#8270]: tokio-rs/tokio#8270 [#8276]: tokio-rs/tokio#8276 [#8277]: tokio-rs/tokio#8277 Changes in 1.52.4 ----------------- 1.52.4 (July 16th, 2026) ------------------------ Fixed ----- - runtime: don't skip the driver when `before_park` schedules work ([#8222]) Fixed (unstable) ---------------- - taskdump: remove crate disambiguators from output ([#8264]) [#8264]: tokio-rs/tokio#8264 [#8222]: tokio-rs/tokio#8222 Changes in 1.52.3 ----------------- 1.52.3 (May 8th, 2026) ---------------------- Fixed ----- * sync: fix underflow in mpsc channel `len()` ([#8062]) * sync: notify receivers in mpsc `OwnedPermit::release()` method ([#8075]) * sync: require that an `RwLock` has `max_readers != 0` ([#8076]) * sync: return `Empty` from `try_recv()` when mpsc is closed with outstanding permits ([#8074]) [#8062]: tokio-rs/tokio#8062 [#8074]: tokio-rs/tokio#8074 [#8075]: tokio-rs/tokio#8075 [#8076]: tokio-rs/tokio#8076 Changes in 1.52.2 ----------------- 1.52.2 (May 4th, 2026) ---------------------- This release reverts the LIFO slot stealing change introduced in 1.51.0 ([#7431]), due to [its performance impact][#8065]. ([#8100]) [#7431]: tokio-rs/tokio#7431 [#8065]: tokio-rs/tokio#8065 [#8100]: tokio-rs/tokio#8100 Changes in 1.52.1 ----------------- 1.52.1 (April 16th, 2026) ------------------------- Fixed ----- - runtime: revert [#7757] to fix [a regression][#8056] that causes `spawn_blocking` to hang ([#8057]) [#7757]: tokio-rs/tokio#7757 [#8056]: tokio-rs/tokio#8056 [#8057]: tokio-rs/tokio#8057 Changes in 1.52.0 ----------------- 1.52.0 (April 14th, 2026) ------------------------- Added ----- - io: `AioSource::register_borrowed` for I/O safety support ([#7992]) - net: add `try_io` function to `unix::pipe` sender and receiver types ([#8030]) Added (unstable) ---------------- - runtime: `Builder::enable_eager_driver_handoff` setting enable eager hand off of the I/O and time drivers before polling tasks ([#8010]) - taskdump: add `trace_with()` for customized task dumps ([#8025]) - taskdump: allow `impl FnMut()` in `trace_with` instead of just `fn()` ([#8040]) - fs: support `io_uring` in `AsyncRead` for `File` ([#7907]) Changed ------- - runtime: improve `spawn_blocking` scalability with sharded queue ([#7757]) - runtime: use `compare_exchange_weak()` in worker queue ([#8028]) Fixed ----- - runtime: overflow second half of tasks when local queue is filled instead of first half ([#8029]) Documented ---------- - docs: fix typo in `oneshot::Sender::send` docs ([#8026]) - docs: hide #[tokio::main] attribute in the docs of `sync::watch` ([#8035]) - net: add docs on `ConnectionRefused` errors with UDP sockets ([#7870]) [#7757]: tokio-rs/tokio#7757 [#7870]: tokio-rs/tokio#7870 [#7907]: tokio-rs/tokio#7907 [#7992]: tokio-rs/tokio#7992 [#8010]: tokio-rs/tokio#8010 [#8025]: tokio-rs/tokio#8025 [#8026]: tokio-rs/tokio#8026 [#8028]: tokio-rs/tokio#8028 [#8029]: tokio-rs/tokio#8029 [#8030]: tokio-rs/tokio#8030 [#8035]: tokio-rs/tokio#8035 [#8040]: tokio-rs/tokio#8040 Changes in 1.51.4 ----------------- 1.51.4 (July 16th, 2026) ------------------------ Fixed ----- - runtime: don't skip the driver when `before_park` schedules work ([#8222]) [#8222]: tokio-rs/tokio#8222 Changes in 1.51.3 ----------------- 1.51.3 (May 8th, 2026) ---------------------- Fixed ----- * sync: fix underflow in mpsc channel `len()` ([#8062]) * sync: notify receivers in mpsc `OwnedPermit::release()` method ([#8075]) * sync: require that an `RwLock` has `max_readers != 0` ([#8076]) * sync: return `Empty` from `try_recv()` when mpsc is closed with outstanding permits ([#8074]) [#8062]: tokio-rs/tokio#8062 [#8074]: tokio-rs/tokio#8074 [#8075]: tokio-rs/tokio#8075 [#8076]: tokio-rs/tokio#8076 Changes in 1.51.2 ----------------- 1.51.2 (May 4th, 2026) ---------------------- This release reverts the LIFO slot stealing change introduced in 1.51.0 ([#7431]), due to [its performance impact][#8065]. ([#8100]) [#7431]: tokio-rs/tokio#7431 [#8065]: tokio-rs/tokio#8065 [#8100]: tokio-rs/tokio#8100 Changes in 1.51.1 ----------------- 1.51.1 (April 8th, 2026) ------------------------ Fixed ----- - sync: fix semaphore reopens after forget ([#8021]) - net: surface errors from `SO_ERROR` on `recv` for UDP sockets on Linux ([#8001]) Fixed (unstable) ---------------- - metrics: fix `worker_local_schedule_count` test ([#8008]) - rt: do not leak fd when cancelling io\_uring open operation ([#7983]) [#7983]: tokio-rs/tokio#7983 [#8001]: tokio-rs/tokio#8001 [#8008]: tokio-rs/tokio#8008 [#8021]: tokio-rs/tokio#8021 Changes in 1.51.0 ----------------- 1.51.0 (April 3rd, 2026) ------------------------ Added ----- - net: implement `get_peer_cred` on Hurd ([#7989]) - runtime: add `tokio::runtime::worker_index()` ([#7921]) - runtime: add runtime name ([#7924]) - runtime: stabilize `LocalRuntime` ([#7557]) - wasm: add wasm32-wasip2 networking support ([#7933]) Changed ------- - runtime: steal tasks from the LIFO slot ([#7431]) Fixed ----- - docs: do not show "Available on non-loom only." doc label ([#7977]) - macros: improve overall macro hygiene ([#7997]) - sync: fix `notify_waiters` priority in `Notify` ([#7996]) - sync: fix panic in `Chan::recv_many` when called with non-empty vector on closed channel ([#7991]) [#7431]: tokio-rs/tokio#7431 [#7557]: tokio-rs/tokio#7557 [#7921]: tokio-rs/tokio#7921 [#7924]: tokio-rs/tokio#7924 [#7933]: tokio-rs/tokio#7933 [#7977]: tokio-rs/tokio#7977 [#7989]: tokio-rs/tokio#7989 [#7991]: tokio-rs/tokio#7991 [#7996]: tokio-rs/tokio#7996 [#7997]: tokio-rs/tokio#7997 Changes in 1.50.0 ----------------- 1.50.0 (Mar 3rd, 2026) ---------------------- Added ----- - net: add `TcpStream::set_zero_linger` ([#7837]) - rt: add `is_rt_shutdown_err` ([#7771]) Changed ------- - io: add optimizer hint that `memchr` returns in-bounds pointer ([#7792]) - io: implement vectored writes for `write_buf` ([#7871]) - runtime: panic when `event_interval` is set to 0 ([#7838]) - runtime: shorten default thread name to fit in Linux limit ([#7880]) - signal: remember the result of `SetConsoleCtrlHandler` ([#7833]) - signal: specialize windows `Registry` ([#7885]) Fixed ----- - io: always cleanup `AsyncFd` registration list on deregister ([#7773]) - macros: remove (most) local `use` declarations in `tokio::select!` ([#7929]) - net: fix `GET_BUF_SIZE` constant for `target_os = "android"` ([#7889]) - runtime: avoid redundant unpark in current_thread scheduler ([#7834]) - runtime: don't park in `current_thread` if `before_park` defers waker ([#7835]) - io: fix write readiness on ESP32 on short writes ([#7872]) - runtime: wake deferred tasks before entering `block_in_place` ([#7879]) - sync: drop rx waker when oneshot receiver is dropped ([#7886]) - runtime: fix double increment of `num_idle_threads` on shutdown ([#7910], [#7918], [#7922]) Unstable -------- - fs: check for io-uring opcode support ([#7815]) - runtime: avoid lock acquisition after uring init ([#7850]) Documented ---------- - docs: update outdated unstable features section ([#7839]) - io: clarify the behavior of `AsyncWriteExt::shutdown()` ([#7908]) - io: explain how to flush stdout/stderr ([#7904]) - io: fix incorrect and confusing `AsyncWrite` documentation ([#7875]) - rt: clarify the documentation of `Runtime::spawn` ([#7803]) - rt: fix missing quotation in docs ([#7925]) - runtime: correct the default thread name in docs ([#7896]) - runtime: fix `event_interval` doc ([#7932]) - sync: clarify RwLock fairness documentation ([#7919]) - sync: clarify that `recv` returns `None` once closed and no more messages ([#7920]) - task: clarify when to use `spawn_blocking` vs dedicated threads ([#7923]) - task: doc that task drops before `JoinHandle` completion ([#7825]) - signal: guarantee that listeners never return `None` ([#7869]) - task: fix task module feature flags in docs ([#7891]) - task: fix two typos ([#7913]) - task: improve the docs of `Builder::spawn_local` ([#7828]) - time: add docs about auto-advance and when to use sleep ([#7858]) - util: fix typo in docs ([#7926]) [#7771]: tokio-rs/tokio#7771 [#7773]: tokio-rs/tokio#7773 [#7792]: tokio-rs/tokio#7792 [#7803]: tokio-rs/tokio#7803 [#7815]: tokio-rs/tokio#7815 [#7825]: tokio-rs/tokio#7825 [#7828]: tokio-rs/tokio#7828 [#7833]: tokio-rs/tokio#7833 [#7834]: tokio-rs/tokio#7834 [#7835]: tokio-rs/tokio#7835 [#7837]: tokio-rs/tokio#7837 [#7838]: tokio-rs/tokio#7838 [#7839]: tokio-rs/tokio#7839 [#7850]: tokio-rs/tokio#7850 [#7858]: tokio-rs/tokio#7858 [#7869]: tokio-rs/tokio#7869 [#7871]: tokio-rs/tokio#7871 [#7872]: tokio-rs/tokio#7872 [#7875]: tokio-rs/tokio#7875 [#7879]: tokio-rs/tokio#7879 [#7880]: tokio-rs/tokio#7880 [#7885]: tokio-rs/tokio#7885 [#7886]: tokio-rs/tokio#7886 [#7889]: tokio-rs/tokio#7889 [#7891]: tokio-rs/tokio#7891 [#7896]: tokio-rs/tokio#7896 [#7904]: tokio-rs/tokio#7904 [#7908]: tokio-rs/tokio#7908 [#7910]: tokio-rs/tokio#7910 [#7913]: tokio-rs/tokio#7913 [#7918]: tokio-rs/tokio#7918 [#7919]: tokio-rs/tokio#7919 [#7920]: tokio-rs/tokio#7920 [#7922]: tokio-rs/tokio#7922 [#7923]: tokio-rs/tokio#7923 [#7925]: tokio-rs/tokio#7925 [#7926]: tokio-rs/tokio#7926 [#7929]: tokio-rs/tokio#7929 [#7932]: tokio-rs/tokio#7932 Release notes: - 1.53.1: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.53.1 - 1.53.0: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.53.0 - 1.52.4: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.52.4 - 1.52.3: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.52.3 - 1.52.2: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.52.2 - 1.52.1: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.52.1 - 1.52.0: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.52.0 - 1.51.4: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.51.4 - 1.51.3: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.51.3 - 1.51.2: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.51.2 - 1.51.1: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.51.1 - 1.51.0: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.51.0 - 1.50.0: https://github.com/tokio-rs/tokio/releases/tag/tokio-1.50.0 --- Transitive Dependencies ----------------------- - libc (0.2.180 -> 0.2.189) - mio (1.1.1 -> 1.2.3) - socket2 (0.6.2 -> 0.6.5) - syn 3.0.6 (added) - tokio-macros (2.6.0 -> 2.7.2) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This new metric tracks the amount of time between when a task is scheduled and when it is polled, also known as queue delay. This duration is recorded in a histogram, just like the poll time metric.
Motivation
Measuring the amount of time a unit of work spends waiting in a queue, also known as "queue delay" or "sojourn time", is an essential component of the CoDel active queue management algorithm (and any algorithm based on it). CoDel is particularly popular because it requires no configuration or tuning to specific workloads, it maintains low latency and high throughput, and relies on a single parameter (queue delay) so it is relatively simple to implement.
For example, an HTTP server built on tokio could use this metric to power an overload protection layer that uses the CoDel algorithm to reject requests and prevent a latency spiral while still serving close to the maximum possible request volume, without the need for specific workload tuning.
There is some precedent for a task scheduler to expose this metric. The Go runtime exposes this metric as
/sched/latencies:seconds, and the Linux kernel'sschedstattracks process scheduling latency per-cpu and per-process.Solution
Measuring this requires keeping track of the time each task enters the queue in order to calculate the elapsed duration when the task is finally polled. I stored this time in the task header because it's hot data that's updated each time the task is scheduled. This does add some overhead, so I put the metric behind
tokio_unstable, just like the poll time histogram metric.