From 748b785f19ee6666b4a02511dc8a2c6a708508e4 Mon Sep 17 00:00:00 2001 From: Lucio Franco Date: Thu, 24 Feb 2022 19:53:08 +0000 Subject: [PATCH] tokio: Add initial time driver metrics --- tokio/src/runtime/metrics/mod.rs | 5 +++++ tokio/src/runtime/metrics/runtime.rs | 24 ++++++++++++++++++++++++ tokio/src/runtime/metrics/time.rs | 20 ++++++++++++++++++++ tokio/src/runtime/mod.rs | 4 ++++ tokio/src/time/driver/handle.rs | 6 +++++- tokio/src/time/driver/metrics.rs | 15 +++++++++++++++ tokio/src/time/driver/mod.rs | 10 ++++++++++ tokio/tests/rt_metrics.rs | 23 +++++++++++++++++++++++ 8 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 tokio/src/runtime/metrics/time.rs create mode 100644 tokio/src/time/driver/metrics.rs diff --git a/tokio/src/runtime/metrics/mod.rs b/tokio/src/runtime/metrics/mod.rs index 4b96f1b71..f0c394758 100644 --- a/tokio/src/runtime/metrics/mod.rs +++ b/tokio/src/runtime/metrics/mod.rs @@ -26,6 +26,11 @@ cfg_metrics! { mod io; pub(crate) use io::IoDriverMetrics; } + + cfg_time! { + mod time; + pub(crate) use time::TimerDriverMetrics; + } } cfg_not_metrics! { diff --git a/tokio/src/runtime/metrics/runtime.rs b/tokio/src/runtime/metrics/runtime.rs index 397271ee3..ee930dd01 100644 --- a/tokio/src/runtime/metrics/runtime.rs +++ b/tokio/src/runtime/metrics/runtime.rs @@ -534,3 +534,27 @@ cfg_net! { } } } + +cfg_time! { + impl RuntimeMetrics { + /// Returns the number of timer entries currently tracked by the + /// runtime's timer driver. + /// + /// # Examples + /// + /// ``` + /// use tokio::runtime::Handle; + /// + /// #[tokio::main] + /// async fn main() { + /// let metrics = Handle::current().metrics(); + /// + /// let n = metrics.time_driver_entry_count(); + /// println!("{} timer entries currently tracked by the runtime's time driver.", n); + /// } + /// ``` + pub fn time_driver_entry_count(&self) -> u64 { + self.handle.time_handle.as_ref().map(|h| h.metrics().entry_count.load(Relaxed)).unwrap_or(0) + } + } +} diff --git a/tokio/src/runtime/metrics/time.rs b/tokio/src/runtime/metrics/time.rs new file mode 100644 index 000000000..728ac87d1 --- /dev/null +++ b/tokio/src/runtime/metrics/time.rs @@ -0,0 +1,20 @@ +use std::sync::atomic::{AtomicU64, Ordering::Relaxed}; + +#[derive(Default)] +pub(crate) struct TimerDriverMetrics { + pub(super) entry_count: AtomicU64, +} + +impl TimerDriverMetrics { + pub(crate) fn incr_entry_count(&self) { + let prev = self.entry_count.load(Relaxed); + let new = prev.wrapping_add(1); + self.entry_count.store(new, Relaxed); + } + + pub(crate) fn dec_entry_count(&self) { + let prev = self.entry_count.load(Relaxed); + let new = prev.wrapping_sub(1); + self.entry_count.store(new, Relaxed); + } +} diff --git a/tokio/src/runtime/mod.rs b/tokio/src/runtime/mod.rs index 66856df66..6f04927b4 100644 --- a/tokio/src/runtime/mod.rs +++ b/tokio/src/runtime/mod.rs @@ -191,6 +191,10 @@ cfg_metrics! { cfg_net! { pub(crate) use metrics::IoDriverMetrics; } + + cfg_time! { + pub(crate) use metrics::TimerDriverMetrics; + } } cfg_not_metrics! { diff --git a/tokio/src/time/driver/handle.rs b/tokio/src/time/driver/handle.rs index b61c0476e..0a78a35dd 100644 --- a/tokio/src/time/driver/handle.rs +++ b/tokio/src/time/driver/handle.rs @@ -1,5 +1,5 @@ use crate::loom::sync::Arc; -use crate::time::driver::ClockTime; +use crate::time::driver::{ClockTime, TimerDriverMetrics}; use std::fmt; /// Handle to time driver instance. @@ -30,6 +30,10 @@ impl Handle { pub(super) fn is_shutdown(&self) -> bool { self.inner.is_shutdown() } + + pub(crate) fn metrics(&self) -> &TimerDriverMetrics { + &self.inner.metrics + } } cfg_rt! { diff --git a/tokio/src/time/driver/metrics.rs b/tokio/src/time/driver/metrics.rs new file mode 100644 index 000000000..abd9ab7f3 --- /dev/null +++ b/tokio/src/time/driver/metrics.rs @@ -0,0 +1,15 @@ +cfg_not_rt_and_metrics! { + #[derive(Default)] + pub(crate) struct TimerDriverMetrics {} + + impl TimerDriverMetrics { + pub(crate) fn incr_entry_count(&self) {} + pub(crate) fn dec_entry_count(&self) {} + } +} + +cfg_rt! { + cfg_metrics! { + pub(crate) use crate::runtime::TimerDriverMetrics; + } +} diff --git a/tokio/src/time/driver/mod.rs b/tokio/src/time/driver/mod.rs index 997187747..0832f1673 100644 --- a/tokio/src/time/driver/mod.rs +++ b/tokio/src/time/driver/mod.rs @@ -14,6 +14,9 @@ pub(crate) use self::handle::Handle; mod wheel; +mod metrics; +pub(self) use metrics::TimerDriverMetrics; + pub(super) mod sleep; use crate::loom::sync::atomic::{AtomicBool, Ordering}; @@ -148,6 +151,8 @@ struct Inner { /// True if the driver is being shutdown. pub(super) is_shutdown: AtomicBool, + + metrics: TimerDriverMetrics, } /// Time state shared which must be protected by a `Mutex` @@ -357,6 +362,7 @@ impl Handle { let mut lock = self.get().lock(); if entry.as_ref().might_be_registered() { + self.metrics().dec_entry_count(); lock.wheel.remove(entry); } @@ -377,6 +383,7 @@ impl Handle { // We may have raced with a firing/deregistration, so check before // deregistering. if unsafe { entry.as_ref().might_be_registered() } { + self.metrics().dec_entry_count(); lock.wheel.remove(entry); } @@ -393,6 +400,8 @@ impl Handle { // the timer entry. match unsafe { lock.wheel.insert(entry) } { Ok(when) => { + self.metrics().incr_entry_count(); + if lock .next_wake .map(|next_wake| when < next_wake.get()) @@ -504,6 +513,7 @@ impl Inner { wheel: wheel::Wheel::new(), }), is_shutdown: AtomicBool::new(false), + metrics: TimerDriverMetrics::default(), } } diff --git a/tokio/tests/rt_metrics.rs b/tokio/tests/rt_metrics.rs index 1521cd260..751190e45 100644 --- a/tokio/tests/rt_metrics.rs +++ b/tokio/tests/rt_metrics.rs @@ -403,6 +403,29 @@ fn io_driver_ready_count() { assert_eq!(metrics.io_driver_ready_count(), 2); } +#[test] +fn time_driver_entry_count() { + use tokio::time::sleep; + use tokio_test::task; + + let rt = basic(); + let metrics = rt.metrics(); + + let _guard = rt.handle().enter(); + + assert_eq!(metrics.time_driver_entry_count(), 0); + + let mut fut = task::spawn(sleep(Duration::from_secs(1_000))); + + assert!(fut.poll().is_pending()); + + assert_eq!(metrics.time_driver_entry_count(), 1); + + drop(fut); + + assert_eq!(metrics.time_driver_entry_count(), 0); +} + fn basic() -> Runtime { tokio::runtime::Builder::new_current_thread() .enable_all()