Struct tokio_metrics::TaskMetrics
source · #[non_exhaustive]pub struct TaskMetrics {Show 18 fields
pub instrumented_count: u64,
pub dropped_count: u64,
pub first_poll_count: u64,
pub total_first_poll_delay: Duration,
pub total_idled_count: u64,
pub total_idle_duration: Duration,
pub total_scheduled_count: u64,
pub total_scheduled_duration: Duration,
pub total_poll_count: u64,
pub total_poll_duration: Duration,
pub total_fast_poll_count: u64,
pub total_fast_poll_duration: Duration,
pub total_slow_poll_count: u64,
pub total_slow_poll_duration: Duration,
pub total_short_delay_count: u64,
pub total_long_delay_count: u64,
pub total_short_delay_duration: Duration,
pub total_long_delay_duration: Duration,
}
Expand description
Key metrics of instrumented tasks.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. }
syntax; cannot be matched against without a wildcard ..
; and struct update syntax will not work.instrumented_count: u64
The number of tasks instrumented.
§Examples
#[tokio::main]
async fn main() {
let monitor = tokio_metrics::TaskMonitor::new();
let mut interval = monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// 0 tasks have been instrumented
assert_eq!(next_interval().instrumented_count, 0);
monitor.instrument(async {});
// 1 task has been instrumented
assert_eq!(next_interval().instrumented_count, 1);
monitor.instrument(async {});
monitor.instrument(async {});
// 2 tasks have been instrumented
assert_eq!(next_interval().instrumented_count, 2);
// since the last interval was produced, 0 tasks have been instrumented
assert_eq!(next_interval().instrumented_count, 0);
}
dropped_count: u64
The number of tasks dropped.
§Examples
#[tokio::main]
async fn main() {
let monitor = tokio_metrics::TaskMonitor::new();
let mut interval = monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// 0 tasks have been dropped
assert_eq!(next_interval().dropped_count, 0);
let _task = monitor.instrument(async {});
// 0 tasks have been dropped
assert_eq!(next_interval().dropped_count, 0);
monitor.instrument(async {}).await;
drop(monitor.instrument(async {}));
// 2 tasks have been dropped
assert_eq!(next_interval().dropped_count, 2);
// since the last interval was produced, 0 tasks have been dropped
assert_eq!(next_interval().dropped_count, 0);
}
first_poll_count: u64
The number of tasks polled for the first time.
§Derived metrics
mean_first_poll_delay
The mean duration elapsed between the instant tasks are instrumented, and the instant they are first polled.
§Examples
In the below example, no tasks are instrumented or polled in the first sampling interval; one task is instrumented (but not polled) in the second sampling interval; that task is awaited to completion (and, thus, polled at least once) in the third sampling interval; no additional tasks are polled for the first time within the fourth sampling interval:
#[tokio::main]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
let mut interval = metrics_monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// no tasks have been constructed, instrumented, and polled at least once
assert_eq!(next_interval().first_poll_count, 0);
let task = metrics_monitor.instrument(async {});
// `task` has been constructed and instrumented, but has not yet been polled
assert_eq!(next_interval().first_poll_count, 0);
// poll `task` to completion
task.await;
// `task` has been constructed, instrumented, and polled at least once
assert_eq!(next_interval().first_poll_count, 1);
// since the last interval was produced, 0 tasks have been constructed, instrumented and polled
assert_eq!(next_interval().first_poll_count, 0);
}
total_first_poll_delay: Duration
The total duration elapsed between the instant tasks are instrumented, and the instant they are first polled.
§Derived metrics
mean_first_poll_delay
The mean duration elapsed between the instant tasks are instrumented, and the instant they are first polled.
§Examples
In the below example, 0 tasks have been instrumented or polled within the first sampling interval, a total of 500ms elapse between the instrumentation and polling of tasks within the second sampling interval, and a total of 350ms elapse between the instrumentation and polling of tasks within the third sampling interval:
use tokio::time::Duration;
#[tokio::main(flavor = "current_thread", start_paused = true)]
async fn main() {
let monitor = tokio_metrics::TaskMonitor::new();
let mut interval = monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// no tasks have yet been created, instrumented, or polled
assert_eq!(monitor.cumulative().total_first_poll_delay, Duration::ZERO);
assert_eq!(next_interval().total_first_poll_delay, Duration::ZERO);
// constructs and instruments a task, pauses a given duration, then awaits the task
async fn instrument_pause_await(monitor: &tokio_metrics::TaskMonitor, pause: Duration) {
let task = monitor.instrument(async move {});
tokio::time::sleep(pause).await;
task.await;
}
// construct and await a task that pauses for 500ms between instrumentation and first poll
let task_a_pause_time = Duration::from_millis(500);
instrument_pause_await(&monitor, task_a_pause_time).await;
assert_eq!(next_interval().total_first_poll_delay, task_a_pause_time);
assert_eq!(monitor.cumulative().total_first_poll_delay, task_a_pause_time);
// construct and await a task that pauses for 250ms between instrumentation and first poll
let task_b_pause_time = Duration::from_millis(250);
instrument_pause_await(&monitor, task_b_pause_time).await;
// construct and await a task that pauses for 100ms between instrumentation and first poll
let task_c_pause_time = Duration::from_millis(100);
instrument_pause_await(&monitor, task_c_pause_time).await;
assert_eq!(
next_interval().total_first_poll_delay,
task_b_pause_time + task_c_pause_time
);
assert_eq!(
monitor.cumulative().total_first_poll_delay,
task_a_pause_time + task_b_pause_time + task_c_pause_time
);
}
§When is this metric recorded?
The delay between instrumentation and first poll is not recorded until the first poll actually occurs:
// we construct and instrument a task, but do not `await` it
let task = monitor.instrument(async {});
// let's sleep for 1s before we poll `task`
let one_sec = Duration::from_secs(1);
let _ = tokio::time::sleep(one_sec).await;
// although 1s has now elapsed since the instrumentation of `task`,
// this is not reflected in `total_first_poll_delay`...
assert_eq!(next_interval().total_first_poll_delay, Duration::ZERO);
assert_eq!(monitor.cumulative().total_first_poll_delay, Duration::ZERO);
// ...and won't be until `task` is actually polled
task.await;
// now, the 1s delay is reflected in `total_first_poll_delay`:
assert_eq!(next_interval().total_first_poll_delay, one_sec);
assert_eq!(monitor.cumulative().total_first_poll_delay, one_sec);
§What if first-poll-delay is very large?
The first-poll-delay of individual tasks saturates at u64::MAX
nanoseconds. However, if
the total first-poll-delay across monitored tasks exceeds u64::MAX
nanoseconds, this
metric will wrap around:
use tokio::time::Duration;
#[tokio::main(flavor = "current_thread", start_paused = true)]
async fn main() {
let monitor = tokio_metrics::TaskMonitor::new();
// construct and instrument a task, but do not `await` it
let task = monitor.instrument(async {});
// this is the maximum duration representable by tokio_metrics
let max_duration = Duration::from_nanos(u64::MAX);
// let's advance the clock by double this amount and await `task`
let _ = tokio::time::advance(max_duration * 2).await;
task.await;
// the time-to-first-poll of `task` saturates at `max_duration`
assert_eq!(monitor.cumulative().total_first_poll_delay, max_duration);
// ...but note that the metric *will* wrap around if more tasks are involved
let task = monitor.instrument(async {});
let _ = tokio::time::advance(Duration::from_nanos(1)).await;
task.await;
assert_eq!(monitor.cumulative().total_first_poll_delay, Duration::ZERO);
}
total_idled_count: u64
The total number of times that tasks idled, waiting to be awoken.
An idle is recorded as occurring if a non-zero duration elapses between the instant a task completes a poll, and the instant that it is next awoken.
§Derived metrics
mean_idle_duration
The mean duration of idles.
§Examples
#[tokio::main(flavor = "current_thread", start_paused = true)]
async fn main() {
let monitor = tokio_metrics::TaskMonitor::new();
let mut interval = monitor.intervals();
let mut next_interval = move || interval.next().unwrap();
let one_sec = std::time::Duration::from_secs(1);
monitor.instrument(async {}).await;
assert_eq!(next_interval().total_idled_count, 0);
assert_eq!(monitor.cumulative().total_idled_count, 0);
monitor.instrument(async move {
tokio::time::sleep(one_sec).await;
}).await;
assert_eq!(next_interval().total_idled_count, 1);
assert_eq!(monitor.cumulative().total_idled_count, 1);
monitor.instrument(async {
tokio::time::sleep(one_sec).await;
tokio::time::sleep(one_sec).await;
}).await;
assert_eq!(next_interval().total_idled_count, 2);
assert_eq!(monitor.cumulative().total_idled_count, 3);
}
total_idle_duration: Duration
The total duration that tasks idled.
An idle is recorded as occurring if a non-zero duration elapses between the instant a task completes a poll, and the instant that it is next awoken.
§Derived metrics
mean_idle_duration
The mean duration of idles.
§Examples
#[tokio::main(flavor = "current_thread", start_paused = true)]
async fn main() {
let monitor = tokio_metrics::TaskMonitor::new();
let mut interval = monitor.intervals();
let mut next_interval = move || interval.next().unwrap();
let one_sec = std::time::Duration::from_secs(1);
let two_sec = std::time::Duration::from_secs(2);
assert_eq!(next_interval().total_idle_duration.as_nanos(), 0);
assert_eq!(monitor.cumulative().total_idle_duration.as_nanos(), 0);
monitor.instrument(async move {
tokio::time::sleep(one_sec).await;
}).await;
assert_eq!(next_interval().total_idle_duration, one_sec);
assert_eq!(monitor.cumulative().total_idle_duration, one_sec);
monitor.instrument(async move {
tokio::time::sleep(two_sec).await;
}).await;
assert_eq!(next_interval().total_idle_duration, two_sec);
assert_eq!(monitor.cumulative().total_idle_duration, one_sec + two_sec);
}
total_scheduled_count: u64
The total number of times that tasks were awoken (and then, presumably, scheduled for execution).
§Definition
This metric is equal to total_short_delay_duration
§Derived metrics
mean_scheduled_duration
The mean duration that tasks spent waiting to be executed after awakening.
§Examples
In the below example, a task yields to the scheduler a varying number of times between sampling intervals; this metric is equal to the number of times the task yielded:
#[tokio::main]
async fn main(){
let metrics_monitor = tokio_metrics::TaskMonitor::new();
// [A] no tasks have been created, instrumented, and polled more than once
assert_eq!(metrics_monitor.cumulative().total_scheduled_count, 0);
// [B] a `task` is created and instrumented
let task = {
let monitor = metrics_monitor.clone();
metrics_monitor.instrument(async move {
let mut interval = monitor.intervals();
let mut next_interval = move || interval.next().unwrap();
// [E] `task` has not yet yielded to the scheduler, and
// thus has not yet been scheduled since its first `poll`
assert_eq!(next_interval().total_scheduled_count, 0);
tokio::task::yield_now().await; // yield to the scheduler
// [F] `task` has yielded to the scheduler once (and thus been
// scheduled once) since the last sampling interval
assert_eq!(next_interval().total_scheduled_count, 1);
tokio::task::yield_now().await; // yield to the scheduler
tokio::task::yield_now().await; // yield to the scheduler
tokio::task::yield_now().await; // yield to the scheduler
// [G] `task` has yielded to the scheduler thrice (and thus been
// scheduled thrice) since the last sampling interval
assert_eq!(next_interval().total_scheduled_count, 3);
tokio::task::yield_now().await; // yield to the scheduler
next_interval
})
};
// [C] `task` has not yet been polled at all
assert_eq!(metrics_monitor.cumulative().first_poll_count, 0);
assert_eq!(metrics_monitor.cumulative().total_scheduled_count, 0);
// [D] poll `task` to completion
let mut next_interval = task.await;
// [H] `task` has been polled 1 times since the last sample
assert_eq!(next_interval().total_scheduled_count, 1);
// [I] `task` has been polled 0 times since the last sample
assert_eq!(next_interval().total_scheduled_count, 0);
// [J] `task` has yielded to the scheduler a total of five times
assert_eq!(metrics_monitor.cumulative().total_scheduled_count, 5);
}
total_scheduled_duration: Duration
The total duration that tasks spent waiting to be polled after awakening.
§Definition
This metric is equal to total_short_delay_count
§Derived metrics
mean_scheduled_duration
The mean duration that tasks spent waiting to be executed after awakening.
§Examples
use tokio::time::Duration;
#[tokio::main(flavor = "current_thread")]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
let mut interval = metrics_monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// construct and instrument and spawn a task that yields endlessly
tokio::spawn(metrics_monitor.instrument(async {
loop { tokio::task::yield_now().await }
}));
tokio::task::yield_now().await;
// block the executor for 1 second
std::thread::sleep(Duration::from_millis(1000));
tokio::task::yield_now().await;
// `endless_task` will have spent approximately one second waiting
let total_scheduled_duration = next_interval().total_scheduled_duration;
assert!(total_scheduled_duration >= Duration::from_millis(1000));
assert!(total_scheduled_duration <= Duration::from_millis(1100));
}
total_poll_count: u64
The total number of times that tasks were polled.
§Definition
This metric is equal to total_fast_poll_count
§Derived metrics
mean_poll_duration
The mean duration of polls.
§Examples
In the below example, a task with multiple yield points is await’ed to completion; this
metric reflects the number of await
s within each sampling interval:
#[tokio::main]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
// [A] no tasks have been created, instrumented, and polled more than once
assert_eq!(metrics_monitor.cumulative().first_poll_count, 0);
// [B] a `task` is created and instrumented
let task = {
let monitor = metrics_monitor.clone();
metrics_monitor.instrument(async move {
let mut interval = monitor.intervals();
let mut next_interval = move || interval.next().unwrap();
// [E] task is in the midst of its first poll
assert_eq!(next_interval().total_poll_count, 0);
tokio::task::yield_now().await; // poll 1
// [F] task has been polled 1 time
assert_eq!(next_interval().total_poll_count, 1);
tokio::task::yield_now().await; // poll 2
tokio::task::yield_now().await; // poll 3
tokio::task::yield_now().await; // poll 4
// [G] task has been polled 3 times
assert_eq!(next_interval().total_poll_count, 3);
tokio::task::yield_now().await; // poll 5
next_interval // poll 6
})
};
// [C] `task` has not yet been polled at all
assert_eq!(metrics_monitor.cumulative().total_poll_count, 0);
// [D] poll `task` to completion
let mut next_interval = task.await;
// [H] `task` has been polled 2 times since the last sample
assert_eq!(next_interval().total_poll_count, 2);
// [I] `task` has been polled 0 times since the last sample
assert_eq!(next_interval().total_poll_count, 0);
// [J] `task` has been polled 6 times
assert_eq!(metrics_monitor.cumulative().total_poll_count, 6);
}
total_poll_duration: Duration
The total duration elapsed during polls.
§Definition
This metric is equal to total_fast_poll_duration
§Derived metrics
mean_poll_duration
The mean duration of polls.
§Examples
use tokio::time::Duration;
#[tokio::main(flavor = "current_thread", start_paused = true)]
async fn main() {
let monitor = tokio_metrics::TaskMonitor::new();
let mut interval = monitor.intervals();
let mut next_interval = move || interval.next().unwrap();
assert_eq!(next_interval().total_poll_duration, Duration::ZERO);
monitor.instrument(async {
tokio::time::advance(Duration::from_secs(1)).await; // poll 1 (1s)
tokio::time::advance(Duration::from_secs(1)).await; // poll 2 (1s)
() // poll 3 (0s)
}).await;
assert_eq!(next_interval().total_poll_duration, Duration::from_secs(2));
}
total_fast_poll_count: u64
The total number of times that polling tasks completed swiftly.
Here, ‘swiftly’ is defined as completing in strictly less time than
slow_poll_threshold
.
§Derived metrics
mean_fast_poll_duration
The mean duration of fast polls.
§Examples
In the below example, 0 polls occur within the first sampling interval, 3 fast polls occur within the second sampling interval, and 2 fast polls occur within the third sampling interval:
use std::future::Future;
use std::time::Duration;
#[tokio::main]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
let mut interval = metrics_monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// no tasks have been constructed, instrumented, or polled
assert_eq!(next_interval().total_fast_poll_count, 0);
let fast = Duration::ZERO;
// this task completes in three fast polls
let _ = metrics_monitor.instrument(async {
spin_for(fast).await; // fast poll 1
spin_for(fast).await; // fast poll 2
spin_for(fast) // fast poll 3
}).await;
assert_eq!(next_interval().total_fast_poll_count, 3);
// this task completes in two fast polls
let _ = metrics_monitor.instrument(async {
spin_for(fast).await; // fast poll 1
spin_for(fast) // fast poll 2
}).await;
assert_eq!(next_interval().total_fast_poll_count, 2);
}
/// Block the current thread for a given `duration`, then (optionally) yield to the scheduler.
fn spin_for(duration: Duration) -> impl Future<Output=()> {
let start = tokio::time::Instant::now();
while start.elapsed() <= duration {}
tokio::task::yield_now()
}
total_fast_poll_duration: Duration
The total duration of fast polls.
Here, ‘fast’ is defined as completing in strictly less time than
slow_poll_threshold
.
§Derived metrics
mean_fast_poll_duration
The mean duration of fast polls.
§Examples
In the below example, no tasks are polled in the first sampling interval; three fast polls consume a total of 3μs time in the second sampling interval; and two fast polls consume a total of 2μs time in the third sampling interval:
use std::future::Future;
use std::time::Duration;
#[tokio::main]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
let mut interval = metrics_monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// no tasks have been constructed, instrumented, or polled
let interval = next_interval();
assert_eq!(interval.total_fast_poll_duration, Duration::ZERO);
let fast = Duration::from_micros(1);
// this task completes in three fast polls
let task_a_time = time(metrics_monitor.instrument(async {
spin_for(fast).await; // fast poll 1
spin_for(fast).await; // fast poll 2
spin_for(fast) // fast poll 3
})).await;
let interval = next_interval();
assert!(interval.total_fast_poll_duration >= fast * 3);
assert!(interval.total_fast_poll_duration <= task_a_time);
// this task completes in two fast polls
let task_b_time = time(metrics_monitor.instrument(async {
spin_for(fast).await; // fast poll 1
spin_for(fast) // fast poll 2
})).await;
let interval = next_interval();
assert!(interval.total_fast_poll_duration >= fast * 2);
assert!(interval.total_fast_poll_duration <= task_b_time);
}
/// Produces the amount of time it took to await a given async task.
async fn time(task: impl Future) -> Duration {
let start = tokio::time::Instant::now();
task.await;
start.elapsed()
}
/// Block the current thread for a given `duration`, then (optionally) yield to the scheduler.
fn spin_for(duration: Duration) -> impl Future<Output=()> {
let start = tokio::time::Instant::now();
while start.elapsed() <= duration {}
tokio::task::yield_now()
}
total_slow_poll_count: u64
The total number of times that polling tasks completed slowly.
Here, ‘slowly’ is defined as completing in at least as much time as
slow_poll_threshold
.
§Derived metrics
mean_slow_poll_duration
The mean duration of slow polls.
§Examples
In the below example, 0 polls occur within the first sampling interval, 3 slow polls occur within the second sampling interval, and 2 slow polls occur within the third sampling interval:
use std::future::Future;
use std::time::Duration;
#[tokio::main]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
let mut interval = metrics_monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// no tasks have been constructed, instrumented, or polled
assert_eq!(next_interval().total_slow_poll_count, 0);
let slow = 10 * metrics_monitor.slow_poll_threshold();
// this task completes in three slow polls
let _ = metrics_monitor.instrument(async {
spin_for(slow).await; // slow poll 1
spin_for(slow).await; // slow poll 2
spin_for(slow) // slow poll 3
}).await;
assert_eq!(next_interval().total_slow_poll_count, 3);
// this task completes in two slow polls
let _ = metrics_monitor.instrument(async {
spin_for(slow).await; // slow poll 1
spin_for(slow) // slow poll 2
}).await;
assert_eq!(next_interval().total_slow_poll_count, 2);
}
/// Block the current thread for a given `duration`, then (optionally) yield to the scheduler.
fn spin_for(duration: Duration) -> impl Future<Output=()> {
let start = tokio::time::Instant::now();
while start.elapsed() <= duration {}
tokio::task::yield_now()
}
total_slow_poll_duration: Duration
The total duration of slow polls.
Here, ‘slowly’ is defined as completing in at least as much time as
slow_poll_threshold
.
§Derived metrics
mean_slow_poll_duration
The mean duration of slow polls.
§Examples
In the below example, no tasks are polled in the first sampling interval; three slow polls
consume a total of
30 × DEFAULT_SLOW_POLL_THRESHOLD
time in the second sampling interval; and two slow polls consume a total of
20 × DEFAULT_SLOW_POLL_THRESHOLD
time in the
third sampling interval:
use std::future::Future;
use std::time::Duration;
#[tokio::main]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
let mut interval = metrics_monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// no tasks have been constructed, instrumented, or polled
let interval = next_interval();
assert_eq!(interval.total_slow_poll_duration, Duration::ZERO);
let slow = 10 * metrics_monitor.slow_poll_threshold();
// this task completes in three slow polls
let task_a_time = time(metrics_monitor.instrument(async {
spin_for(slow).await; // slow poll 1
spin_for(slow).await; // slow poll 2
spin_for(slow) // slow poll 3
})).await;
let interval = next_interval();
assert!(interval.total_slow_poll_duration >= slow * 3);
assert!(interval.total_slow_poll_duration <= task_a_time);
// this task completes in two slow polls
let task_b_time = time(metrics_monitor.instrument(async {
spin_for(slow).await; // slow poll 1
spin_for(slow) // slow poll 2
})).await;
let interval = next_interval();
assert!(interval.total_slow_poll_duration >= slow * 2);
assert!(interval.total_slow_poll_duration <= task_b_time);
}
/// Produces the amount of time it took to await a given async task.
async fn time(task: impl Future) -> Duration {
let start = tokio::time::Instant::now();
task.await;
start.elapsed()
}
/// Block the current thread for a given `duration`, then (optionally) yield to the scheduler.
fn spin_for(duration: Duration) -> impl Future<Output=()> {
let start = tokio::time::Instant::now();
while start.elapsed() <= duration {}
tokio::task::yield_now()
}
total_short_delay_count: u64
The total count of tasks with short scheduling delays.
This is defined as tasks taking strictly less than
long_delay_threshold
to be executed after being
scheduled.
§Derived metrics
mean_short_delay_duration
The mean duration of short scheduling delays.
total_long_delay_count: u64
The total count of tasks with long scheduling delays.
This is defined as tasks taking
long_delay_threshold
or longer to be executed
after being scheduled.
§Derived metrics
mean_long_delay_duration
The mean duration of short scheduling delays.
total_short_delay_duration: Duration
The total duration of tasks with short scheduling delays.
This is defined as tasks taking strictly less than
long_delay_threshold
to be executed after being
scheduled.
§Derived metrics
mean_short_delay_duration
The mean duration of short scheduling delays.
total_long_delay_duration: Duration
The total number of times that a task had a long scheduling duration.
Here, a long scheduling duration is defined as taking longer to start execution after
scheduling than long_delay_threshold
.
§Derived metrics
mean_long_delay_duration
The mean duration of short scheduling delays.
Implementations§
source§impl TaskMetrics
impl TaskMetrics
sourcepub fn mean_first_poll_delay(&self) -> Duration
pub fn mean_first_poll_delay(&self) -> Duration
The mean duration elapsed between the instant tasks are instrumented, and the instant they are first polled.
§Definition
This metric is derived from total_first_poll_delay
÷ first_poll_count
.
§Interpretation
If this metric increases, it means that, on average, tasks spent longer waiting to be initially polled.
§See also
mean_scheduled_duration
The mean duration that tasks spent waiting to be executed after awakening.
§Examples
In the below example, no tasks are instrumented or polled within the first sampling interval; in the second sampling interval, 500ms elapse between the instrumentation of a task and its first poll; in the third sampling interval, a mean of 750ms elapse between the instrumentation and first poll of two tasks:
use std::time::Duration;
#[tokio::main]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
let mut interval = metrics_monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// no tasks have yet been created, instrumented, or polled
assert_eq!(next_interval().mean_first_poll_delay(), Duration::ZERO);
// constructs and instruments a task, pauses for `pause_time`, awaits the task, then
// produces the total time it took to do all of the aforementioned
async fn instrument_pause_await(
metrics_monitor: &tokio_metrics::TaskMonitor,
pause_time: Duration
) -> Duration
{
let before_instrumentation = tokio::time::Instant::now();
let task = metrics_monitor.instrument(async move {});
tokio::time::sleep(pause_time).await;
task.await;
before_instrumentation.elapsed()
}
// construct and await a task that pauses for 500ms between instrumentation and first poll
let task_a_pause_time = Duration::from_millis(500);
let task_a_total_time = instrument_pause_await(&metrics_monitor, task_a_pause_time).await;
// the `mean_first_poll_delay` will be some duration greater-than-or-equal-to the
// pause time of 500ms, and less-than-or-equal-to the total runtime of `task_a`
let mean_first_poll_delay = next_interval().mean_first_poll_delay();
assert!(mean_first_poll_delay >= task_a_pause_time);
assert!(mean_first_poll_delay <= task_a_total_time);
// construct and await a task that pauses for 500ms between instrumentation and first poll
let task_b_pause_time = Duration::from_millis(500);
let task_b_total_time = instrument_pause_await(&metrics_monitor, task_b_pause_time).await;
// construct and await a task that pauses for 1000ms between instrumentation and first poll
let task_c_pause_time = Duration::from_millis(1000);
let task_c_total_time = instrument_pause_await(&metrics_monitor, task_c_pause_time).await;
// the `mean_first_poll_delay` will be some duration greater-than-or-equal-to the
// average pause time of 500ms, and less-than-or-equal-to the combined total runtime of
// `task_b` and `task_c`
let mean_first_poll_delay = next_interval().mean_first_poll_delay();
assert!(mean_first_poll_delay >= (task_b_pause_time + task_c_pause_time) / 2);
assert!(mean_first_poll_delay <= (task_b_total_time + task_c_total_time) / 2);
}
sourcepub fn mean_idle_duration(&self) -> Duration
pub fn mean_idle_duration(&self) -> Duration
The mean duration of idles.
§Definition
This metric is derived from total_idle_duration
÷
total_idled_count
.
§Interpretation
The idle state is the duration spanning the instant a task completes a poll, and the instant that it is next awoken. Tasks inhabit this state when they are waiting for task-external events to complete (e.g., an asynchronous sleep, a network request, file I/O, etc.). If this metric increases, it means that tasks, in aggregate, spent more time waiting for task-external events to complete.
§Examples
#[tokio::main]
async fn main() {
let monitor = tokio_metrics::TaskMonitor::new();
let one_sec = std::time::Duration::from_secs(1);
monitor.instrument(async move {
tokio::time::sleep(one_sec).await;
}).await;
assert!(monitor.cumulative().mean_idle_duration() >= one_sec);
}
sourcepub fn mean_scheduled_duration(&self) -> Duration
pub fn mean_scheduled_duration(&self) -> Duration
The mean duration that tasks spent waiting to be executed after awakening.
§Definition
This metric is derived from
total_scheduled_duration
÷
total_scheduled_count
.
§Interpretation
If this metric increases, it means that, on average, tasks spent longer in the runtime’s queues before being polled.
§See also
mean_first_poll_delay
The mean duration elapsed between the instant tasks are instrumented, and the instant they are first polled.
§Examples
use tokio::time::Duration;
#[tokio::main(flavor = "current_thread")]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
let mut interval = metrics_monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// construct and instrument and spawn a task that yields endlessly
tokio::spawn(metrics_monitor.instrument(async {
loop { tokio::task::yield_now().await }
}));
tokio::task::yield_now().await;
// block the executor for 1 second
std::thread::sleep(Duration::from_millis(1000));
// get the task to run twice
// the first will have a 1 sec scheduling delay, the second will have almost none
tokio::task::yield_now().await;
tokio::task::yield_now().await;
// `endless_task` will have spent approximately one second waiting
let mean_scheduled_duration = next_interval().mean_scheduled_duration();
assert!(mean_scheduled_duration >= Duration::from_millis(500), "{}", mean_scheduled_duration.as_secs_f64());
assert!(mean_scheduled_duration <= Duration::from_millis(600), "{}", mean_scheduled_duration.as_secs_f64());
}
sourcepub fn mean_poll_duration(&self) -> Duration
pub fn mean_poll_duration(&self) -> Duration
The mean duration of polls.
§Definition
This metric is derived from total_poll_duration
÷
total_poll_count
.
§Interpretation
If this metric increases, it means that, on average, individual polls are tending to take longer. However, this does not necessarily imply increased task latency: An increase in poll durations could be offset by fewer polls.
§See also
slow_poll_ratio
The ratio between the number polls categorized as slow and fast.mean_slow_poll_duration
The mean duration of slow polls.
§Examples
use std::time::Duration;
#[tokio::main(flavor = "current_thread", start_paused = true)]
async fn main() {
let monitor = tokio_metrics::TaskMonitor::new();
let mut interval = monitor.intervals();
let mut next_interval = move || interval.next().unwrap();
assert_eq!(next_interval().mean_poll_duration(), Duration::ZERO);
monitor.instrument(async {
tokio::time::advance(Duration::from_secs(1)).await; // poll 1 (1s)
tokio::time::advance(Duration::from_secs(1)).await; // poll 2 (1s)
() // poll 3 (0s)
}).await;
assert_eq!(next_interval().mean_poll_duration(), Duration::from_secs(2) / 3);
}
sourcepub fn slow_poll_ratio(&self) -> f64
pub fn slow_poll_ratio(&self) -> f64
The ratio between the number polls categorized as slow and fast.
§Definition
This metric is derived from total_slow_poll_count
÷
total_poll_count
.
§Interpretation
If this metric increases, it means that a greater proportion of polls took excessively long before yielding to the scheduler. This does not necessarily imply increased task latency: An increase in the proportion of slow polls could be offset by fewer or faster polls. However, as a rule, should yield to the scheduler frequently.
§See also
mean_poll_duration
The mean duration of polls.mean_slow_poll_duration
The mean duration of slow polls.
§Examples
Changes in this metric may be observed by varying the ratio of slow and slow fast within sampling intervals; for instance:
use std::future::Future;
use std::time::Duration;
#[tokio::main]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
let mut interval = metrics_monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// no tasks have been constructed, instrumented, or polled
let interval = next_interval();
assert_eq!(interval.total_fast_poll_count, 0);
assert_eq!(interval.total_slow_poll_count, 0);
assert!(interval.slow_poll_ratio().is_nan());
let fast = Duration::ZERO;
let slow = 10 * metrics_monitor.slow_poll_threshold();
// this task completes in three fast polls
metrics_monitor.instrument(async {
spin_for(fast).await; // fast poll 1
spin_for(fast).await; // fast poll 2
spin_for(fast); // fast poll 3
}).await;
// this task completes in two slow polls
metrics_monitor.instrument(async {
spin_for(slow).await; // slow poll 1
spin_for(slow); // slow poll 2
}).await;
let interval = next_interval();
assert_eq!(interval.total_fast_poll_count, 3);
assert_eq!(interval.total_slow_poll_count, 2);
assert_eq!(interval.slow_poll_ratio(), ratio(2., 3.));
// this task completes in three slow polls
metrics_monitor.instrument(async {
spin_for(slow).await; // slow poll 1
spin_for(slow).await; // slow poll 2
spin_for(slow); // slow poll 3
}).await;
// this task completes in two fast polls
metrics_monitor.instrument(async {
spin_for(fast).await; // fast poll 1
spin_for(fast); // fast poll 2
}).await;
let interval = next_interval();
assert_eq!(interval.total_fast_poll_count, 2);
assert_eq!(interval.total_slow_poll_count, 3);
assert_eq!(interval.slow_poll_ratio(), ratio(3., 2.));
}
fn ratio(a: f64, b: f64) -> f64 {
a / (a + b)
}
/// Block the current thread for a given `duration`, then (optionally) yield to the scheduler.
fn spin_for(duration: Duration) -> impl Future<Output=()> {
let start = tokio::time::Instant::now();
while start.elapsed() <= duration {}
tokio::task::yield_now()
}
sourcepub fn long_delay_ratio(&self) -> f64
pub fn long_delay_ratio(&self) -> f64
The ratio of tasks exceeding long_delay_threshold
.
§Definition
This metric is derived from total_long_delay_count
÷
total_scheduled_count
.
sourcepub fn mean_fast_poll_duration(&self) -> Duration
pub fn mean_fast_poll_duration(&self) -> Duration
The mean duration of fast polls.
§Definition
This metric is derived from
total_fast_poll_duration
÷
total_fast_poll_count
.
§Examples
In the below example, no tasks are polled in the first sampling interval; three fast polls
consume a mean of
⅜ × DEFAULT_SLOW_POLL_THRESHOLD
time in the
second sampling interval; and two fast polls consume a total of
½ × DEFAULT_SLOW_POLL_THRESHOLD
time in the
third sampling interval:
use std::future::Future;
use std::time::Duration;
#[tokio::main]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
let mut interval = metrics_monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// no tasks have been constructed, instrumented, or polled
assert_eq!(next_interval().mean_fast_poll_duration(), Duration::ZERO);
let threshold = metrics_monitor.slow_poll_threshold();
let fast_1 = 1 * Duration::from_micros(1);
let fast_2 = 2 * Duration::from_micros(1);
let fast_3 = 3 * Duration::from_micros(1);
// this task completes in two fast polls
let total_time = time(metrics_monitor.instrument(async {
spin_for(fast_1).await; // fast poll 1
spin_for(fast_2) // fast poll 2
})).await;
// `mean_fast_poll_duration` ≈ the mean of `fast_1` and `fast_2`
let mean_fast_poll_duration = next_interval().mean_fast_poll_duration();
assert!(mean_fast_poll_duration >= (fast_1 + fast_2) / 2);
assert!(mean_fast_poll_duration <= total_time / 2);
// this task completes in three fast polls
let total_time = time(metrics_monitor.instrument(async {
spin_for(fast_1).await; // fast poll 1
spin_for(fast_2).await; // fast poll 2
spin_for(fast_3) // fast poll 3
})).await;
// `mean_fast_poll_duration` ≈ the mean of `fast_1`, `fast_2`, `fast_3`
let mean_fast_poll_duration = next_interval().mean_fast_poll_duration();
assert!(mean_fast_poll_duration >= (fast_1 + fast_2 + fast_3) / 3);
assert!(mean_fast_poll_duration <= total_time / 3);
}
/// Produces the amount of time it took to await a given task.
async fn time(task: impl Future) -> Duration {
let start = tokio::time::Instant::now();
task.await;
start.elapsed()
}
/// Block the current thread for a given `duration`, then (optionally) yield to the scheduler.
fn spin_for(duration: Duration) -> impl Future<Output=()> {
let start = tokio::time::Instant::now();
while start.elapsed() <= duration {}
tokio::task::yield_now()
}
sourcepub fn mean_short_delay_duration(&self) -> Duration
pub fn mean_short_delay_duration(&self) -> Duration
The average time taken for a task with a short scheduling delay to be executed after being scheduled.
§Definition
This metric is derived from
total_short_delay_duration
÷
total_short_delay_count
.
sourcepub fn mean_slow_poll_duration(&self) -> Duration
pub fn mean_slow_poll_duration(&self) -> Duration
The mean duration of slow polls.
§Definition
This metric is derived from
total_slow_poll_duration
÷
total_slow_poll_count
.
§Interpretation
If this metric increases, it means that a greater proportion of polls took excessively long before yielding to the scheduler. This does not necessarily imply increased task latency: An increase in the proportion of slow polls could be offset by fewer or faster polls.
§See also
mean_poll_duration
The mean duration of polls.slow_poll_ratio
The ratio between the number polls categorized as slow and fast.
§Interpretation
If this metric increases, it means that, on average, slow polls got even slower. This does necessarily imply increased task latency: An increase in average slow poll duration could be offset by fewer or faster polls. However, as a rule, should yield to the scheduler frequently.
§Examples
In the below example, no tasks are polled in the first sampling interval; three slow polls
consume a mean of
1.5 × DEFAULT_SLOW_POLL_THRESHOLD
time in the
second sampling interval; and two slow polls consume a total of
2 × DEFAULT_SLOW_POLL_THRESHOLD
time in the
third sampling interval:
use std::future::Future;
use std::time::Duration;
#[tokio::main]
async fn main() {
let metrics_monitor = tokio_metrics::TaskMonitor::new();
let mut interval = metrics_monitor.intervals();
let mut next_interval = || interval.next().unwrap();
// no tasks have been constructed, instrumented, or polled
assert_eq!(next_interval().mean_slow_poll_duration(), Duration::ZERO);
let threshold = metrics_monitor.slow_poll_threshold();
let slow_1 = 1 * threshold;
let slow_2 = 2 * threshold;
let slow_3 = 3 * threshold;
// this task completes in two slow polls
let total_time = time(metrics_monitor.instrument(async {
spin_for(slow_1).await; // slow poll 1
spin_for(slow_2) // slow poll 2
})).await;
// `mean_slow_poll_duration` ≈ the mean of `slow_1` and `slow_2`
let mean_slow_poll_duration = next_interval().mean_slow_poll_duration();
assert!(mean_slow_poll_duration >= (slow_1 + slow_2) / 2);
assert!(mean_slow_poll_duration <= total_time / 2);
// this task completes in three slow polls
let total_time = time(metrics_monitor.instrument(async {
spin_for(slow_1).await; // slow poll 1
spin_for(slow_2).await; // slow poll 2
spin_for(slow_3) // slow poll 3
})).await;
// `mean_slow_poll_duration` ≈ the mean of `slow_1`, `slow_2`, `slow_3`
let mean_slow_poll_duration = next_interval().mean_slow_poll_duration();
assert!(mean_slow_poll_duration >= (slow_1 + slow_2 + slow_3) / 3);
assert!(mean_slow_poll_duration <= total_time / 3);
}
/// Produces the amount of time it took to await a given task.
async fn time(task: impl Future) -> Duration {
let start = tokio::time::Instant::now();
task.await;
start.elapsed()
}
/// Block the current thread for a given `duration`, then (optionally) yield to the scheduler.
fn spin_for(duration: Duration) -> impl Future<Output=()> {
let start = tokio::time::Instant::now();
while start.elapsed() <= duration {}
tokio::task::yield_now()
}
sourcepub fn mean_long_delay_duration(&self) -> Duration
pub fn mean_long_delay_duration(&self) -> Duration
The average scheduling delay for a task which takes a long time to start executing after being scheduled.
§Definition
This metric is derived from
total_long_delay_duration
÷
total_long_delay_count
.
Trait Implementations§
source§impl Clone for TaskMetrics
impl Clone for TaskMetrics
source§fn clone(&self) -> TaskMetrics
fn clone(&self) -> TaskMetrics
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl Debug for TaskMetrics
impl Debug for TaskMetrics
source§impl Default for TaskMetrics
impl Default for TaskMetrics
source§fn default() -> TaskMetrics
fn default() -> TaskMetrics
impl Copy for TaskMetrics
Auto Trait Implementations§
impl Freeze for TaskMetrics
impl RefUnwindSafe for TaskMetrics
impl Send for TaskMetrics
impl Sync for TaskMetrics
impl Unpin for TaskMetrics
impl UnwindSafe for TaskMetrics
Blanket Implementations§
source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
source§default unsafe fn clone_to_uninit(&self, dst: *mut T)
default unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)source§impl<T> CloneToUninit for Twhere
T: Copy,
impl<T> CloneToUninit for Twhere
T: Copy,
source§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)