aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/metrics/runtime.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/metrics/runtime.rs')
-rw-r--r--src/runtime/metrics/runtime.rs268
1 files changed, 267 insertions, 1 deletions
diff --git a/src/runtime/metrics/runtime.rs b/src/runtime/metrics/runtime.rs
index d29cb3d..95b517c 100644
--- a/src/runtime/metrics/runtime.rs
+++ b/src/runtime/metrics/runtime.rs
@@ -1,5 +1,6 @@
use crate::runtime::Handle;
+use std::ops::Range;
use std::sync::atomic::Ordering::Relaxed;
use std::time::Duration;
@@ -68,7 +69,26 @@ impl RuntimeMetrics {
self.handle.inner.num_blocking_threads()
}
- /// Returns the number of idle threads, which hve spawned by the runtime
+ /// Returns the number of active tasks in the runtime.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tokio::runtime::Handle;
+ ///
+ /// #[tokio::main]
+ /// async fn main() {
+ /// let metrics = Handle::current().metrics();
+ ///
+ /// let n = metrics.active_tasks_count();
+ /// println!("Runtime has {} active tasks", n);
+ /// }
+ /// ```
+ pub fn active_tasks_count(&self) -> usize {
+ self.handle.inner.active_tasks_count()
+ }
+
+ /// Returns the number of idle threads, which have spawned by the runtime
/// for `spawn_blocking` calls.
///
/// # Examples
@@ -124,6 +144,21 @@ impl RuntimeMetrics {
.load(Relaxed)
}
+ /// Returns the number of times that tasks have been forced to yield back to the scheduler
+ /// after exhausting their task budgets.
+ ///
+ /// This count starts at zero when the runtime is created and increases by one each time a task yields due to exhausting its budget.
+ ///
+ /// The counter is monotonically increasing. It is never decremented or
+ /// reset to zero.
+ pub fn budget_forced_yield_count(&self) -> u64 {
+ self.handle
+ .inner
+ .scheduler_metrics()
+ .budget_forced_yield_count
+ .load(Relaxed)
+ }
+
/// Returns the total number of times the given worker thread has parked.
///
/// The worker park count starts at zero when the runtime is created and
@@ -544,6 +579,237 @@ impl RuntimeMetrics {
self.handle.inner.worker_local_queue_depth(worker)
}
+ /// Returns `true` if the runtime is tracking the distribution of task poll
+ /// times.
+ ///
+ /// Task poll times are not instrumented by default as doing so requires
+ /// calling [`Instant::now()`] twice per task poll. The feature is enabled
+ /// by calling [`enable_metrics_poll_count_histogram()`] when building the
+ /// runtime.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tokio::runtime::{self, Handle};
+ ///
+ /// fn main() {
+ /// runtime::Builder::new_current_thread()
+ /// .enable_metrics_poll_count_histogram()
+ /// .build()
+ /// .unwrap()
+ /// .block_on(async {
+ /// let metrics = Handle::current().metrics();
+ /// let enabled = metrics.poll_count_histogram_enabled();
+ ///
+ /// println!("Tracking task poll time distribution: {:?}", enabled);
+ /// });
+ /// }
+ /// ```
+ ///
+ /// [`enable_metrics_poll_count_histogram()`]: crate::runtime::Builder::enable_metrics_poll_count_histogram
+ /// [`Instant::now()`]: std::time::Instant::now
+ pub fn poll_count_histogram_enabled(&self) -> bool {
+ self.handle
+ .inner
+ .worker_metrics(0)
+ .poll_count_histogram
+ .is_some()
+ }
+
+ /// Returns the number of histogram buckets tracking the distribution of
+ /// task poll times.
+ ///
+ /// This value is configured by calling
+ /// [`metrics_poll_count_histogram_buckets()`] when building the runtime.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tokio::runtime::{self, Handle};
+ ///
+ /// fn main() {
+ /// runtime::Builder::new_current_thread()
+ /// .enable_metrics_poll_count_histogram()
+ /// .build()
+ /// .unwrap()
+ /// .block_on(async {
+ /// let metrics = Handle::current().metrics();
+ /// let buckets = metrics.poll_count_histogram_num_buckets();
+ ///
+ /// println!("Histogram buckets: {:?}", buckets);
+ /// });
+ /// }
+ /// ```
+ ///
+ /// [`metrics_poll_count_histogram_buckets()`]:
+ /// crate::runtime::Builder::metrics_poll_count_histogram_buckets
+ pub fn poll_count_histogram_num_buckets(&self) -> usize {
+ self.handle
+ .inner
+ .worker_metrics(0)
+ .poll_count_histogram
+ .as_ref()
+ .map(|histogram| histogram.num_buckets())
+ .unwrap_or_default()
+ }
+
+ /// Returns the range of task poll times tracked by the given bucket.
+ ///
+ /// This value is configured by calling
+ /// [`metrics_poll_count_histogram_resolution()`] when building the runtime.
+ ///
+ /// # Panics
+ ///
+ /// The method panics if `bucket` represents an invalid bucket index, i.e.
+ /// is greater than or equal to `poll_count_histogram_num_buckets()`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tokio::runtime::{self, Handle};
+ ///
+ /// fn main() {
+ /// runtime::Builder::new_current_thread()
+ /// .enable_metrics_poll_count_histogram()
+ /// .build()
+ /// .unwrap()
+ /// .block_on(async {
+ /// let metrics = Handle::current().metrics();
+ /// let buckets = metrics.poll_count_histogram_num_buckets();
+ ///
+ /// for i in 0..buckets {
+ /// let range = metrics.poll_count_histogram_bucket_range(i);
+ /// println!("Histogram bucket {} range: {:?}", i, range);
+ /// }
+ /// });
+ /// }
+ /// ```
+ ///
+ /// [`metrics_poll_count_histogram_resolution()`]:
+ /// crate::runtime::Builder::metrics_poll_count_histogram_resolution
+ #[track_caller]
+ pub fn poll_count_histogram_bucket_range(&self, bucket: usize) -> Range<Duration> {
+ self.handle
+ .inner
+ .worker_metrics(0)
+ .poll_count_histogram
+ .as_ref()
+ .map(|histogram| {
+ let range = histogram.bucket_range(bucket);
+ std::ops::Range {
+ start: Duration::from_nanos(range.start),
+ end: Duration::from_nanos(range.end),
+ }
+ })
+ .unwrap_or_default()
+ }
+
+ /// Returns the number of times the given worker polled tasks with a poll
+ /// duration within the given bucket's range.
+ ///
+ /// Each worker maintains its own histogram and the counts for each bucket
+ /// starts at zero when the runtime is created. Each time the worker polls a
+ /// task, it tracks the duration the task poll time took and increments the
+ /// associated bucket by 1.
+ ///
+ /// Each bucket is a monotonically increasing counter. It is never
+ /// decremented or reset to zero.
+ ///
+ /// # Arguments
+ ///
+ /// `worker` is the index of the worker being queried. The given value must
+ /// be between 0 and `num_workers()`. The index uniquely identifies a single
+ /// worker and will continue to identify the worker throughout the lifetime
+ /// of the runtime instance.
+ ///
+ /// `bucket` is the index of the bucket being queried. The bucket is scoped
+ /// to the worker. The range represented by the bucket can be queried by
+ /// calling [`poll_count_histogram_bucket_range()`]. Each worker maintains
+ /// identical bucket ranges.
+ ///
+ /// # Panics
+ ///
+ /// The method panics when `worker` represents an invalid worker, i.e. is
+ /// greater than or equal to `num_workers()` or if `bucket` represents an
+ /// invalid bucket.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tokio::runtime::{self, Handle};
+ ///
+ /// fn main() {
+ /// runtime::Builder::new_current_thread()
+ /// .enable_metrics_poll_count_histogram()
+ /// .build()
+ /// .unwrap()
+ /// .block_on(async {
+ /// let metrics = Handle::current().metrics();
+ /// let buckets = metrics.poll_count_histogram_num_buckets();
+ ///
+ /// for worker in 0..metrics.num_workers() {
+ /// for i in 0..buckets {
+ /// let count = metrics.poll_count_histogram_bucket_count(worker, i);
+ /// println!("Poll count {}", count);
+ /// }
+ /// }
+ /// });
+ /// }
+ /// ```
+ ///
+ /// [`poll_count_histogram_bucket_range()`]: crate::runtime::RuntimeMetrics::poll_count_histogram_bucket_range
+ #[track_caller]
+ pub fn poll_count_histogram_bucket_count(&self, worker: usize, bucket: usize) -> u64 {
+ self.handle
+ .inner
+ .worker_metrics(worker)
+ .poll_count_histogram
+ .as_ref()
+ .map(|histogram| histogram.get(bucket))
+ .unwrap_or_default()
+ }
+
+ /// Returns the mean duration of task polls, in nanoseconds.
+ ///
+ /// This is an exponentially weighted moving average. Currently, this metric
+ /// is only provided by the multi-threaded runtime.
+ ///
+ /// # Arguments
+ ///
+ /// `worker` is the index of the worker being queried. The given value must
+ /// be between 0 and `num_workers()`. The index uniquely identifies a single
+ /// worker and will continue to identify the worker throughout the lifetime
+ /// of the runtime instance.
+ ///
+ /// # Panics
+ ///
+ /// The method panics when `worker` represents an invalid worker, i.e. is
+ /// greater than or equal to `num_workers()`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use tokio::runtime::Handle;
+ ///
+ /// #[tokio::main]
+ /// async fn main() {
+ /// let metrics = Handle::current().metrics();
+ ///
+ /// let n = metrics.worker_mean_poll_time(0);
+ /// println!("worker 0 has a mean poll time of {:?}", n);
+ /// }
+ /// ```
+ #[track_caller]
+ pub fn worker_mean_poll_time(&self, worker: usize) -> Duration {
+ let nanos = self
+ .handle
+ .inner
+ .worker_metrics(worker)
+ .mean_poll_time
+ .load(Relaxed);
+ Duration::from_nanos(nanos)
+ }
+
/// Returns the number of tasks currently scheduled in the blocking
/// thread pool, spawned using `spawn_blocking`.
///