Struct RuntimeMetrics

Source
#[non_exhaustive]
pub struct RuntimeMetrics { pub workers_count: usize, pub total_park_count: u64, pub max_park_count: u64, pub min_park_count: u64, pub total_busy_duration: Duration, pub max_busy_duration: Duration, pub min_busy_duration: Duration, pub global_queue_depth: usize, pub elapsed: Duration, }
Expand description

Key runtime metrics.

Fields (Non-exhaustive)§

This struct is marked as non-exhaustive
Non-exhaustive structs could have additional fields added in future. Therefore, non-exhaustive structs cannot be constructed in external crates using the traditional Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.
§workers_count: usize

The number of worker threads used by the runtime.

This metric is static for a runtime.

This metric is always equal to tokio::runtime::RuntimeMetrics::num_workers. When using the current_thread runtime, the return value is always 1.

The number of workers is set by configuring worker_threads with tokio::runtime::Builder, or by parameterizing tokio::main.

§Examples

In the below example, the number of workers is set by parameterizing tokio::main:

use tokio::runtime::Handle;

#[tokio::main(flavor = "multi_thread", worker_threads = 10)]
async fn main() {
    let handle = tokio::runtime::Handle::current();
    let monitor = tokio_metrics::RuntimeMonitor::new(&handle);
    let mut intervals = monitor.intervals();
    let mut next_interval = || intervals.next().unwrap();

    assert_eq!(next_interval().workers_count, 10);
}

When using the current_thread runtime, the return value is always 1; e.g.:

use tokio::runtime::Handle;

#[tokio::main(flavor = "current_thread")]
async fn main() {
    let handle = tokio::runtime::Handle::current();
    let monitor = tokio_metrics::RuntimeMonitor::new(&handle);
    let mut intervals = monitor.intervals();
    let mut next_interval = || intervals.next().unwrap();

    assert_eq!(next_interval().workers_count, 1);
}

This metric is always equal to tokio::runtime::RuntimeMetrics::num_workers; e.g.:

use tokio::runtime::Handle;

#[tokio::main]
async fn main() {
    let handle = Handle::current();
    let monitor = tokio_metrics::RuntimeMonitor::new(&handle);
    let mut intervals = monitor.intervals();
    let mut next_interval = || intervals.next().unwrap();

    assert_eq!(next_interval().workers_count, handle.metrics().num_workers());
}
§total_park_count: u64

The number of times worker threads parked.

The worker park count increases by one each time the worker parks the thread waiting for new inbound events to process. This usually means the worker has processed all pending work and is currently idle.

§Definition

This metric is derived from the sum of tokio::runtime::RuntimeMetrics::worker_park_count across all worker threads.

§See also
§Examples
#[tokio::main(flavor = "multi_thread", worker_threads = 2)]
async fn main() {
    let handle = tokio::runtime::Handle::current();
    let monitor = tokio_metrics::RuntimeMonitor::new(&handle);
    let mut intervals = monitor.intervals();
    let mut next_interval = || intervals.next().unwrap();

    let interval = next_interval(); // end of interval 1
    assert_eq!(interval.total_park_count, 0);

    induce_parks().await;

    let interval = next_interval(); // end of interval 2
    assert!(interval.total_park_count >= 1); // usually 1 or 2 parks
}

async fn induce_parks() {
    let _ = tokio::time::timeout(std::time::Duration::ZERO, async {
        loop { tokio::task::yield_now().await; }
    }).await;
}
§max_park_count: u64

The maximum number of times any worker thread parked.

§Definition

This metric is derived from the maximum of tokio::runtime::RuntimeMetrics::worker_park_count across all worker threads.

§See also
§min_park_count: u64

The minimum number of times any worker thread parked.

§Definition

This metric is derived from the maximum of tokio::runtime::RuntimeMetrics::worker_park_count across all worker threads.

§See also
§total_busy_duration: Duration

The amount of time worker threads were busy.

The worker busy duration increases whenever the worker is spending time processing work. Using this value can indicate the total load of workers.

§Definition

This metric is derived from the sum of tokio::runtime::RuntimeMetrics::worker_total_busy_duration across all worker threads.

§See also
§Examples

In the below example, tasks spend a total of 3s busy:

use tokio::time::Duration;

fn main() {
    let start = tokio::time::Instant::now();

    let rt = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap();

    let handle = rt.handle();
    let monitor = tokio_metrics::RuntimeMonitor::new(&handle);
    let mut intervals = monitor.intervals();
    let mut next_interval = || intervals.next().unwrap();

    let delay_1s = Duration::from_secs(1);
    let delay_3s = Duration::from_secs(3);

    rt.block_on(async {
        // keep the main task busy for 1s
        spin_for(delay_1s);

        // spawn a task and keep it busy for 2s
        let _ = tokio::spawn(async move {
            spin_for(delay_3s);
        }).await;
    });

    // flush metrics
    drop(rt);

    let elapsed = start.elapsed();

    let interval =  next_interval(); // end of interval 2
    assert!(interval.total_busy_duration >= delay_1s + delay_3s);
    assert!(interval.total_busy_duration <= elapsed);
}

fn time<F>(task: F) -> Duration
where
    F: Fn() -> ()
{
    let start = tokio::time::Instant::now();
    task();
    start.elapsed()
}

/// Block the current thread for a given `duration`.
fn spin_for(duration: Duration) {
    let start = tokio::time::Instant::now();
    while start.elapsed() <= duration {}
}

Busy times may not accumulate as the above example suggests (FIXME: Why?); e.g., if we remove the three second delay, the time spent busy falls to mere microseconds:

use tokio::time::Duration;

fn main() {
    let rt = tokio::runtime::Builder::new_current_thread()
        .enable_all()
        .build()
        .unwrap();

    let handle = rt.handle();
    let monitor = tokio_metrics::RuntimeMonitor::new(&handle);
    let mut intervals = monitor.intervals();
    let mut next_interval = || intervals.next().unwrap();

    let delay_1s = Duration::from_secs(1);

    let elapsed = time(|| rt.block_on(async {
        // keep the main task busy for 1s
        spin_for(delay_1s);
    }));

    // flush metrics
    drop(rt);

    let interval =  next_interval(); // end of interval 2
    assert!(interval.total_busy_duration >= delay_1s); // FAIL
    assert!(interval.total_busy_duration <= elapsed);
}

fn time<F>(task: F) -> Duration
where
    F: Fn() -> ()
{
    let start = tokio::time::Instant::now();
    task();
    start.elapsed()
}

/// Block the current thread for a given `duration`.
fn spin_for(duration: Duration) {
    let start = tokio::time::Instant::now();
    while start.elapsed() <= duration {}
}
§max_busy_duration: Duration

The maximum amount of time a worker thread was busy.

§Definition

This metric is derived from the maximum of tokio::runtime::RuntimeMetrics::worker_total_busy_duration across all worker threads.

§See also
§min_busy_duration: Duration

The minimum amount of time a worker thread was busy.

§Definition

This metric is derived from the minimum of tokio::runtime::RuntimeMetrics::worker_total_busy_duration across all worker threads.

§See also
§global_queue_depth: usize

The number of tasks currently scheduled in the runtime’s global queue.

Tasks that are spawned or notified from a non-runtime thread are scheduled using the runtime’s global queue. This metric returns the current number of tasks pending in the global queue. As such, the returned value may increase or decrease as new tasks are scheduled and processed.

§Definition

This metric is derived from tokio::runtime::RuntimeMetrics::global_queue_depth.

§Example
let handle = runtime.handle().clone();
let monitor = tokio_metrics::RuntimeMonitor::new(&handle);
let mut intervals = monitor.intervals();
let mut next_interval = || intervals.next().unwrap();

let interval = next_interval(); // end of interval 1
assert_eq!(interval.num_remote_schedules, 0);

// spawn a system thread outside of the runtime
std::thread::spawn(move || {
    // spawn two tasks from this non-runtime thread
    handle.spawn(async {});
    handle.spawn(async {});
}).join().unwrap();

// flush metrics
drop(runtime);

let interval = next_interval(); // end of interval 2
assert_eq!(interval.num_remote_schedules, 2);
§elapsed: Duration

Total amount of time elapsed since observing runtime metrics.

Implementations§

Trait Implementations§

Source§

impl Clone for RuntimeMetrics

Source§

fn clone(&self) -> RuntimeMetrics

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RuntimeMetrics

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for RuntimeMetrics

Source§

fn default() -> RuntimeMetrics

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more