Skip to main content

tokio/runtime/metrics/
runtime.rs

1use crate::runtime::Handle;
2use std::time::Duration;
3
4cfg_64bit_metrics! {
5    use std::sync::atomic::Ordering::Relaxed;
6}
7
8cfg_unstable_metrics! {
9    use std::ops::Range;
10    use std::thread::ThreadId;
11}
12
13/// Handle to the runtime's metrics.
14///
15/// This handle is internally reference-counted and can be freely cloned. A
16/// `RuntimeMetrics` handle is obtained using the [`Runtime::metrics`] method.
17///
18/// [`Runtime::metrics`]: crate::runtime::Runtime::metrics()
19#[derive(Clone, Debug)]
20pub struct RuntimeMetrics {
21    handle: Handle,
22}
23
24impl RuntimeMetrics {
25    pub(crate) fn new(handle: Handle) -> RuntimeMetrics {
26        RuntimeMetrics { handle }
27    }
28
29    /// Returns the number of worker threads used by the runtime.
30    ///
31    /// The number of workers is set by configuring `worker_threads` on
32    /// `runtime::Builder`. When using the `current_thread` runtime, the return
33    /// value is always `1`.
34    ///
35    /// # Examples
36    ///
37    /// ```
38    /// use tokio::runtime::Handle;
39    ///
40    /// # #[tokio::main(flavor = "current_thread")]
41    /// # async fn main() {
42    /// let metrics = Handle::current().metrics();
43    ///
44    /// let n = metrics.num_workers();
45    /// println!("Runtime is using {} workers", n);
46    /// # }
47    /// ```
48    pub fn num_workers(&self) -> usize {
49        self.handle.inner.num_workers()
50    }
51
52    /// Returns the current number of alive tasks in the runtime.
53    ///
54    /// This counter increases when a task is spawned and decreases when a
55    /// task exits.
56    ///
57    /// Note: When using the multi-threaded runtime this number may not
58    /// not have strong consistency i.e. no tasks may be running but the metric
59    /// reports otherwise.
60    ///
61    /// # Examples
62    ///
63    /// ```
64    /// use tokio::runtime::Handle;
65    ///
66    /// # #[tokio::main(flavor = "current_thread")]
67    /// # async fn main() {
68    /// let metrics = Handle::current().metrics();
69    ///
70    /// let n = metrics.num_alive_tasks();
71    /// println!("Runtime has {} alive tasks", n);
72    /// # }
73    /// ```
74    pub fn num_alive_tasks(&self) -> usize {
75        self.handle.inner.num_alive_tasks()
76    }
77
78    /// Returns the number of tasks currently scheduled in the runtime's
79    /// global queue.
80    ///
81    /// Tasks that are spawned or notified from a non-runtime thread are
82    /// scheduled using the runtime's global queue. This metric returns the
83    /// **current** number of tasks pending in the global queue. As such, the
84    /// returned value may increase or decrease as new tasks are scheduled and
85    /// processed.
86    ///
87    /// # Examples
88    ///
89    /// ```
90    /// use tokio::runtime::Handle;
91    ///
92    /// # #[tokio::main(flavor = "current_thread")]
93    /// # async fn main() {
94    /// let metrics = Handle::current().metrics();
95    ///
96    /// let n = metrics.global_queue_depth();
97    /// println!("{} tasks currently pending in the runtime's global queue", n);
98    /// # }
99    /// ```
100    pub fn global_queue_depth(&self) -> usize {
101        self.handle.inner.injection_queue_depth()
102    }
103
104    cfg_64bit_metrics! {
105        /// Returns the amount of time the given worker thread has been busy.
106        ///
107        /// The worker busy duration starts at zero when the runtime is created and
108        /// increases whenever the worker is spending time processing work. Using
109        /// this value can indicate the load of the given worker. If a lot of time
110        /// is spent busy, then the worker is under load and will check for inbound
111        /// events less often.
112        ///
113        /// The timer is monotonically increasing. It is never decremented or reset
114        /// to zero.
115        ///
116        /// # Arguments
117        ///
118        /// `worker` is the index of the worker being queried. The given value must
119        /// be between 0 and `num_workers()`. The index uniquely identifies a single
120        /// worker and will continue to identify the worker throughout the lifetime
121        /// of the runtime instance.
122        ///
123        /// # Panics
124        ///
125        /// The method panics when `worker` represents an invalid worker, i.e. is
126        /// greater than or equal to `num_workers()`.
127        ///
128        /// # Examples
129        ///
130        /// ```
131        /// use tokio::runtime::Handle;
132        ///
133        /// # #[tokio::main(flavor = "current_thread")]
134        /// # async fn main() {
135        /// let metrics = Handle::current().metrics();
136        ///
137        /// let n = metrics.worker_total_busy_duration(0);
138        /// println!("worker 0 was busy for a total of {:?}", n);
139        /// # }
140        /// ```
141        pub fn worker_total_busy_duration(&self, worker: usize) -> Duration {
142            let nanos = self
143                .handle
144                .inner
145                .worker_metrics(worker)
146                .busy_duration_total
147                .load(Relaxed);
148            Duration::from_nanos(nanos)
149        }
150
151        /// Returns the total number of times the given worker thread has parked.
152        ///
153        /// The worker park count starts at zero when the runtime is created and
154        /// increases by one each time the worker parks the thread waiting for new
155        /// inbound events to process. This usually means the worker has processed
156        /// all pending work and is currently idle.
157        ///
158        /// The counter is monotonically increasing. It is never decremented or
159        /// reset to zero.
160        ///
161        /// # Arguments
162        ///
163        /// `worker` is the index of the worker being queried. The given value must
164        /// be between 0 and `num_workers()`. The index uniquely identifies a single
165        /// worker and will continue to identify the worker throughout the lifetime
166        /// of the runtime instance.
167        ///
168        /// # Panics
169        ///
170        /// The method panics when `worker` represents an invalid worker, i.e. is
171        /// greater than or equal to `num_workers()`.
172        ///
173        /// # Examples
174        ///
175        /// ```
176        /// use tokio::runtime::Handle;
177        ///
178        /// # #[tokio::main(flavor = "current_thread")]
179        /// # async fn main() {
180        /// let metrics = Handle::current().metrics();
181        ///
182        /// let n = metrics.worker_park_count(0);
183        /// println!("worker 0 parked {} times", n);
184        /// # }
185        /// ```
186        pub fn worker_park_count(&self, worker: usize) -> u64 {
187            self.handle
188                .inner
189                .worker_metrics(worker)
190                .park_count
191                .load(Relaxed)
192        }
193
194        /// Returns the total number of times the given worker thread has parked
195        /// and unparked.
196        ///
197        /// The worker park/unpark count starts at zero when the runtime is created
198        /// and increases by one each time the worker parks the thread waiting for
199        /// new inbound events to process. This usually means the worker has processed
200        /// all pending work and is currently idle. When new work becomes available,
201        /// the worker is unparked and the park/unpark count is again increased by one.
202        ///
203        /// An odd count means that the worker is currently parked.
204        /// An even count means that the worker is currently active.
205        ///
206        /// The counter is monotonically increasing. It is never decremented or
207        /// reset to zero.
208        ///
209        /// # Arguments
210        ///
211        /// `worker` is the index of the worker being queried. The given value must
212        /// be between 0 and `num_workers()`. The index uniquely identifies a single
213        /// worker and will continue to identify the worker throughout the lifetime
214        /// of the runtime instance.
215        ///
216        /// # Panics
217        ///
218        /// The method panics when `worker` represents an invalid worker, i.e. is
219        /// greater than or equal to `num_workers()`.
220        ///
221        /// # Examples
222        ///
223        /// ```
224        /// use tokio::runtime::Handle;
225        ///
226        /// # #[tokio::main(flavor = "current_thread")]
227        /// # async fn main() {
228        /// let metrics = Handle::current().metrics();
229        /// let n = metrics.worker_park_unpark_count(0);
230        ///
231        /// println!("worker 0 parked and unparked {} times", n);
232        ///
233        /// if n % 2 == 0 {
234        ///     println!("worker 0 is active");
235        /// } else {
236        ///     println!("worker 0 is parked");
237        /// }
238        /// # }
239        /// ```
240        pub fn worker_park_unpark_count(&self, worker: usize) -> u64 {
241            self.handle
242                .inner
243                .worker_metrics(worker)
244                .park_unpark_count
245                .load(Relaxed)
246        }
247    }
248
249    cfg_unstable_metrics! {
250
251        /// Returns the number of additional threads spawned by the runtime.
252        ///
253        /// The number of workers is set by configuring `max_blocking_threads` on
254        /// `runtime::Builder`.
255        ///
256        /// # Examples
257        ///
258        /// ```
259        /// # #[cfg(not(target_family = "wasm"))]
260        /// # {
261        /// use tokio::runtime::Handle;
262        ///
263        /// # #[tokio::main(flavor = "current_thread")]
264        /// # async fn main() {
265        /// let _ = tokio::task::spawn_blocking(move || {
266        ///     // Stand-in for compute-heavy work or using synchronous APIs
267        ///     1 + 1
268        /// }).await;
269        /// let metrics = Handle::current().metrics();
270        ///
271        /// let n = metrics.num_blocking_threads();
272        /// println!("Runtime has created {} threads", n);
273        /// # }
274        /// # }
275        /// ```
276        pub fn num_blocking_threads(&self) -> usize {
277            self.handle.inner.num_blocking_threads()
278        }
279
280        #[deprecated = "Renamed to num_alive_tasks"]
281        /// Renamed to [`RuntimeMetrics::num_alive_tasks`]
282        pub fn active_tasks_count(&self) -> usize {
283            self.num_alive_tasks()
284        }
285
286        /// Returns the number of idle threads, which have spawned by the runtime
287        /// for `spawn_blocking` calls.
288        ///
289        /// # Examples
290        ///
291        /// ```
292        /// # #[cfg(not(target_family = "wasm"))]
293        /// # {
294        /// use tokio::runtime::Handle;
295        ///
296        /// #[tokio::main]
297        /// async fn main() {
298        ///     let _ = tokio::task::spawn_blocking(move || {
299        ///         // Stand-in for compute-heavy work or using synchronous APIs
300        ///         1 + 1
301        ///     }).await;
302        ///     let metrics = Handle::current().metrics();
303        ///
304        ///     let n = metrics.num_idle_blocking_threads();
305        ///     println!("Runtime has {} idle blocking thread pool threads", n);
306        /// }
307        /// # }
308        /// ```
309        pub fn num_idle_blocking_threads(&self) -> usize {
310            self.handle.inner.num_idle_blocking_threads()
311        }
312
313        /// Returns the thread id of the given worker thread.
314        ///
315        /// The returned value is `None` if the worker thread has not yet finished
316        /// starting up.
317        ///
318        /// If additional information about the thread, such as its native id, are
319        /// required, those can be collected in [`on_thread_start`] and correlated
320        /// using the thread id.
321        ///
322        /// [`on_thread_start`]: crate::runtime::Builder::on_thread_start
323        ///
324        /// # Arguments
325        ///
326        /// `worker` is the index of the worker being queried. The given value must
327        /// be between 0 and `num_workers()`. The index uniquely identifies a single
328        /// worker and will continue to identify the worker throughout the lifetime
329        /// of the runtime instance.
330        ///
331        /// # Panics
332        ///
333        /// The method panics when `worker` represents an invalid worker, i.e. is
334        /// greater than or equal to `num_workers()`.
335        ///
336        /// # Examples
337        ///
338        /// ```
339        /// use tokio::runtime::Handle;
340        ///
341        /// # #[tokio::main(flavor = "current_thread")]
342        /// # async fn main() {
343        /// let metrics = Handle::current().metrics();
344        ///
345        /// let id = metrics.worker_thread_id(0);
346        /// println!("worker 0 has id {:?}", id);
347        /// # }
348        /// ```
349        pub fn worker_thread_id(&self, worker: usize) -> Option<ThreadId> {
350            self.handle
351                .inner
352                .worker_metrics(worker)
353                .thread_id()
354        }
355
356        /// Renamed to [`RuntimeMetrics::global_queue_depth`]
357        #[deprecated = "Renamed to global_queue_depth"]
358        #[doc(hidden)]
359        pub fn injection_queue_depth(&self) -> usize {
360            self.handle.inner.injection_queue_depth()
361        }
362
363        /// Returns the number of tasks currently scheduled in the given worker's
364        /// local queue.
365        ///
366        /// Tasks that are spawned or notified from within a runtime thread are
367        /// scheduled using that worker's local queue. This metric returns the
368        /// **current** number of tasks pending in the worker's local queue. As
369        /// such, the returned value may increase or decrease as new tasks are
370        /// scheduled and processed.
371        ///
372        /// # Arguments
373        ///
374        /// `worker` is the index of the worker being queried. The given value must
375        /// be between 0 and `num_workers()`. The index uniquely identifies a single
376        /// worker and will continue to identify the worker throughout the lifetime
377        /// of the runtime instance.
378        ///
379        /// # Panics
380        ///
381        /// The method panics when `worker` represents an invalid worker, i.e. is
382        /// greater than or equal to `num_workers()`.
383        ///
384        /// # Examples
385        ///
386        /// ```
387        /// use tokio::runtime::Handle;
388        ///
389        /// # #[tokio::main(flavor = "current_thread")]
390        /// # async fn main() {
391        /// let metrics = Handle::current().metrics();
392        ///
393        /// let n = metrics.worker_local_queue_depth(0);
394        /// println!("{} tasks currently pending in worker 0's local queue", n);
395        /// # }
396        /// ```
397        pub fn worker_local_queue_depth(&self, worker: usize) -> usize {
398            self.handle.inner.worker_local_queue_depth(worker)
399        }
400
401        /// Returns `true` if the runtime is tracking the distribution of task poll
402        /// times.
403        ///
404        /// Task poll times are not instrumented by default as doing so requires
405        /// calling [`Instant::now()`] twice per task poll. The feature is enabled
406        /// by calling [`enable_metrics_poll_time_histogram()`] when building the
407        /// runtime.
408        ///
409        /// # Examples
410        ///
411        /// ```
412        /// use tokio::runtime::{self, Handle};
413        ///
414        /// fn main() {
415        ///     runtime::Builder::new_current_thread()
416        ///         .enable_metrics_poll_time_histogram()
417        ///         .build()
418        ///         .unwrap()
419        ///         .block_on(async {
420        ///             let metrics = Handle::current().metrics();
421        ///             let enabled = metrics.poll_time_histogram_enabled();
422        ///
423        ///             println!("Tracking task poll time distribution: {:?}", enabled);
424        ///         });
425        /// }
426        /// ```
427        ///
428        /// [`enable_metrics_poll_time_histogram()`]: crate::runtime::Builder::enable_metrics_poll_time_histogram
429        /// [`Instant::now()`]: std::time::Instant::now
430        pub fn poll_time_histogram_enabled(&self) -> bool {
431            self.handle
432                .inner
433                .worker_metrics(0)
434                .poll_count_histogram
435                .is_some()
436        }
437
438        #[deprecated(note = "Renamed to `poll_time_histogram_enabled`")]
439        #[doc(hidden)]
440        pub fn poll_count_histogram_enabled(&self) -> bool {
441            self.poll_time_histogram_enabled()
442        }
443
444        /// Returns the number of histogram buckets tracking the distribution of
445        /// task poll times.
446        ///
447        /// This value is configured by calling
448        /// [`metrics_poll_time_histogram_configuration()`] when building the runtime.
449        ///
450        /// # Examples
451        ///
452        /// ```
453        /// use tokio::runtime::{self, Handle};
454        ///
455        /// fn main() {
456        ///     runtime::Builder::new_current_thread()
457        ///         .enable_metrics_poll_time_histogram()
458        ///         .build()
459        ///         .unwrap()
460        ///         .block_on(async {
461        ///             let metrics = Handle::current().metrics();
462        ///             let buckets = metrics.poll_time_histogram_num_buckets();
463        ///
464        ///             println!("Histogram buckets: {:?}", buckets);
465        ///         });
466        /// }
467        /// ```
468        ///
469        /// [`metrics_poll_time_histogram_configuration()`]:
470        ///     crate::runtime::Builder::metrics_poll_time_histogram_configuration
471        pub fn poll_time_histogram_num_buckets(&self) -> usize {
472            self.handle
473                .inner
474                .worker_metrics(0)
475                .poll_count_histogram
476                .as_ref()
477                .map_or(0, |histogram| histogram.num_buckets())
478        }
479
480        /// Deprecated. Use [`poll_time_histogram_num_buckets()`] instead.
481        ///
482        /// [`poll_time_histogram_num_buckets()`]: Self::poll_time_histogram_num_buckets
483        #[doc(hidden)]
484        #[deprecated(note = "renamed to `poll_time_histogram_num_buckets`.")]
485        pub fn poll_count_histogram_num_buckets(&self) -> usize {
486            self.poll_time_histogram_num_buckets()
487        }
488
489        /// Returns the range of task poll times tracked by the given bucket.
490        ///
491        /// This value is configured by calling
492        /// [`metrics_poll_time_histogram_configuration()`] when building the runtime.
493        ///
494        /// # Panics
495        ///
496        /// The method panics if `bucket` represents an invalid bucket index, i.e.
497        /// is greater than or equal to `poll_time_histogram_num_buckets()`.
498        ///
499        /// # Examples
500        ///
501        /// ```
502        /// use tokio::runtime::{self, Handle};
503        ///
504        /// fn main() {
505        ///     runtime::Builder::new_current_thread()
506        ///         .enable_metrics_poll_time_histogram()
507        ///         .build()
508        ///         .unwrap()
509        ///         .block_on(async {
510        ///             let metrics = Handle::current().metrics();
511        ///             let buckets = metrics.poll_time_histogram_num_buckets();
512        ///
513        ///             for i in 0..buckets {
514        ///                 let range = metrics.poll_time_histogram_bucket_range(i);
515        ///                 println!("Histogram bucket {} range: {:?}", i, range);
516        ///             }
517        ///         });
518        /// }
519        /// ```
520        ///
521        /// [`metrics_poll_time_histogram_configuration()`]:
522        ///     crate::runtime::Builder::metrics_poll_time_histogram_configuration
523        #[track_caller]
524        pub fn poll_time_histogram_bucket_range(&self, bucket: usize) -> Range<Duration> {
525            self.handle
526                .inner
527                .worker_metrics(0)
528                .poll_count_histogram
529                .as_ref()
530                .map_or_else(Range::default, |histogram| {
531                    let range = histogram.bucket_range(bucket);
532                    std::ops::Range {
533                        start: Duration::from_nanos(range.start),
534                        end: Duration::from_nanos(range.end),
535                    }
536                })
537        }
538
539        /// Deprecated. Use [`poll_time_histogram_bucket_range()`] instead.
540        ///
541        /// [`poll_time_histogram_bucket_range()`]: Self::poll_time_histogram_bucket_range
542        #[track_caller]
543        #[doc(hidden)]
544        #[deprecated(note = "renamed to `poll_time_histogram_bucket_range`")]
545        pub fn poll_count_histogram_bucket_range(&self, bucket: usize) -> Range<Duration> {
546            self.poll_time_histogram_bucket_range(bucket)
547        }
548
549        /// Returns the number of tasks currently scheduled in the blocking
550        /// thread pool, spawned using `spawn_blocking`.
551        ///
552        /// This metric returns the **current** number of tasks pending in
553        /// blocking thread pool. As such, the returned value may increase
554        /// or decrease as new tasks are scheduled and processed.
555        ///
556        /// # Examples
557        ///
558        /// ```
559        /// use tokio::runtime::Handle;
560        ///
561        /// # #[tokio::main(flavor = "current_thread")]
562        /// # async fn main() {
563        /// let metrics = Handle::current().metrics();
564        ///
565        /// let n = metrics.blocking_queue_depth();
566        /// println!("{} tasks currently pending in the blocking thread pool", n);
567        /// # }
568        /// ```
569        pub fn blocking_queue_depth(&self) -> usize {
570            self.handle.inner.blocking_queue_depth()
571        }
572    }
573
574    feature! {
575        #![all(
576            tokio_unstable,
577            target_has_atomic = "64"
578        )]
579        /// Returns the number of tasks spawned in this runtime since it was created.
580        ///
581        /// This count starts at zero when the runtime is created and increases by one each time a task is spawned.
582        ///
583        /// The counter is monotonically increasing. It is never decremented or
584        /// reset to zero.
585        ///
586        /// # Examples
587        ///
588        /// ```
589        /// use tokio::runtime::Handle;
590        ///
591        /// # #[tokio::main(flavor = "current_thread")]
592        /// # async fn main() {
593        /// let metrics = Handle::current().metrics();
594        ///
595        /// let n = metrics.spawned_tasks_count();
596        /// println!("Runtime has had {} tasks spawned", n);
597        /// # }
598        /// ```
599        pub fn spawned_tasks_count(&self) -> u64 {
600            self.handle.inner.spawned_tasks_count()
601        }
602
603        /// Returns the number of tasks scheduled from **outside** of the runtime.
604        ///
605        /// The remote schedule count starts at zero when the runtime is created and
606        /// increases by one each time a task is woken from **outside** of the
607        /// runtime. This usually means that a task is spawned or notified from a
608        /// non-runtime thread and must be queued using the Runtime's injection
609        /// queue, which tends to be slower.
610        ///
611        /// The counter is monotonically increasing. It is never decremented or
612        /// reset to zero.
613        ///
614        /// # Examples
615        ///
616        /// ```
617        /// use tokio::runtime::Handle;
618        ///
619        /// # #[tokio::main(flavor = "current_thread")]
620        /// # async fn main() {
621        /// let metrics = Handle::current().metrics();
622        ///
623        /// let n = metrics.remote_schedule_count();
624        /// println!("{} tasks were scheduled from outside the runtime", n);
625        /// # }
626        /// ```
627        pub fn remote_schedule_count(&self) -> u64 {
628            self.handle
629                .inner
630                .scheduler_metrics()
631                .remote_schedule_count
632                .load(Relaxed)
633        }
634
635        /// Returns the number of times that tasks have been forced to yield back to the scheduler
636        /// after exhausting their task budgets.
637        ///
638        /// This count starts at zero when the runtime is created and increases by one each time a task yields due to exhausting its budget.
639        ///
640        /// The counter is monotonically increasing. It is never decremented or
641        /// reset to zero.
642        pub fn budget_forced_yield_count(&self) -> u64 {
643            self.handle
644                .inner
645                .scheduler_metrics()
646                .budget_forced_yield_count
647                .load(Relaxed)
648        }
649
650        /// Returns the number of times the given worker thread unparked but
651        /// performed no work before parking again.
652        ///
653        /// The worker no-op count starts at zero when the runtime is created and
654        /// increases by one each time the worker unparks the thread but finds no
655        /// new work and goes back to sleep. This indicates a false-positive wake up.
656        ///
657        /// The counter is monotonically increasing. It is never decremented or
658        /// reset to zero.
659        ///
660        /// # Arguments
661        ///
662        /// `worker` is the index of the worker being queried. The given value must
663        /// be between 0 and `num_workers()`. The index uniquely identifies a single
664        /// worker and will continue to identify the worker throughout the lifetime
665        /// of the runtime instance.
666        ///
667        /// # Panics
668        ///
669        /// The method panics when `worker` represents an invalid worker, i.e. is
670        /// greater than or equal to `num_workers()`.
671        ///
672        /// # Examples
673        ///
674        /// ```
675        /// use tokio::runtime::Handle;
676        ///
677        /// # #[tokio::main(flavor = "current_thread")]
678        /// # async fn main() {
679        /// let metrics = Handle::current().metrics();
680        ///
681        /// let n = metrics.worker_noop_count(0);
682        /// println!("worker 0 had {} no-op unparks", n);
683        /// # }
684        /// ```
685        pub fn worker_noop_count(&self, worker: usize) -> u64 {
686            self.handle
687                .inner
688                .worker_metrics(worker)
689                .noop_count
690                .load(Relaxed)
691        }
692
693        /// Returns the number of tasks the given worker thread stole from
694        /// another worker thread.
695        ///
696        /// This metric only applies to the **multi-threaded** runtime and will
697        /// always return `0` when using the current thread runtime.
698        ///
699        /// The worker steal count starts at zero when the runtime is created and
700        /// increases by `N` each time the worker has processed its scheduled queue
701        /// and successfully steals `N` more pending tasks from another worker.
702        ///
703        /// The counter is monotonically increasing. It is never decremented or
704        /// reset to zero.
705        ///
706        /// # Arguments
707        ///
708        /// `worker` is the index of the worker being queried. The given value must
709        /// be between 0 and `num_workers()`. The index uniquely identifies a single
710        /// worker and will continue to identify the worker throughout the lifetime
711        /// of the runtime instance.
712        ///
713        /// # Panics
714        ///
715        /// The method panics when `worker` represents an invalid worker, i.e. is
716        /// greater than or equal to `num_workers()`.
717        ///
718        /// # Examples
719        ///
720        /// ```
721        /// use tokio::runtime::Handle;
722        ///
723        /// # #[tokio::main(flavor = "current_thread")]
724        /// # async fn main() {
725        /// let metrics = Handle::current().metrics();
726        ///
727        /// let n = metrics.worker_steal_count(0);
728        /// println!("worker 0 has stolen {} tasks", n);
729        /// # }
730        /// ```
731        pub fn worker_steal_count(&self, worker: usize) -> u64 {
732            self.handle
733                .inner
734                .worker_metrics(worker)
735                .steal_count
736                .load(Relaxed)
737        }
738
739        /// Returns the number of times the given worker thread stole tasks from
740        /// another worker thread.
741        ///
742        /// This metric only applies to the **multi-threaded** runtime and will
743        /// always return `0` when using the current thread runtime.
744        ///
745        /// The worker steal count starts at zero when the runtime is created and
746        /// increases by one each time the worker has processed its scheduled queue
747        /// and successfully steals more pending tasks from another worker.
748        ///
749        /// The counter is monotonically increasing. It is never decremented or
750        /// reset to zero.
751        ///
752        /// # Arguments
753        ///
754        /// `worker` is the index of the worker being queried. The given value must
755        /// be between 0 and `num_workers()`. The index uniquely identifies a single
756        /// worker and will continue to identify the worker throughout the lifetime
757        /// of the runtime instance.
758        ///
759        /// # Panics
760        ///
761        /// The method panics when `worker` represents an invalid worker, i.e. is
762        /// greater than or equal to `num_workers()`.
763        ///
764        /// # Examples
765        ///
766        /// ```
767        /// use tokio::runtime::Handle;
768        ///
769        /// # #[tokio::main(flavor = "current_thread")]
770        /// # async fn main() {
771        /// let metrics = Handle::current().metrics();
772        ///
773        /// let n = metrics.worker_steal_operations(0);
774        /// println!("worker 0 has stolen tasks {} times", n);
775        /// # }
776        /// ```
777        pub fn worker_steal_operations(&self, worker: usize) -> u64 {
778            self.handle
779                .inner
780                .worker_metrics(worker)
781                .steal_operations
782                .load(Relaxed)
783        }
784
785        /// Returns the number of tasks the given worker thread has polled.
786        ///
787        /// The worker poll count starts at zero when the runtime is created and
788        /// increases by one each time the worker polls a scheduled task.
789        ///
790        /// The counter is monotonically increasing. It is never decremented or
791        /// reset to zero.
792        ///
793        /// # Arguments
794        ///
795        /// `worker` is the index of the worker being queried. The given value must
796        /// be between 0 and `num_workers()`. The index uniquely identifies a single
797        /// worker and will continue to identify the worker throughout the lifetime
798        /// of the runtime instance.
799        ///
800        /// # Panics
801        ///
802        /// The method panics when `worker` represents an invalid worker, i.e. is
803        /// greater than or equal to `num_workers()`.
804        ///
805        /// # Examples
806        ///
807        /// ```
808        /// use tokio::runtime::Handle;
809        ///
810        /// # #[tokio::main(flavor = "current_thread")]
811        /// # async fn main() {
812        /// let metrics = Handle::current().metrics();
813        ///
814        /// let n = metrics.worker_poll_count(0);
815        /// println!("worker 0 has polled {} tasks", n);
816        /// # }
817        /// ```
818        pub fn worker_poll_count(&self, worker: usize) -> u64 {
819            self.handle
820                .inner
821                .worker_metrics(worker)
822                .poll_count
823                .load(Relaxed)
824        }
825
826        /// Returns the number of tasks scheduled from **within** the runtime on the
827        /// given worker's local queue.
828        ///
829        /// The local schedule count starts at zero when the runtime is created and
830        /// increases by one each time a task is woken from **inside** of the
831        /// runtime on the given worker. This usually means that a task is spawned
832        /// or notified from within a runtime thread and will be queued on the
833        /// worker-local queue.
834        ///
835        /// The counter is monotonically increasing. It is never decremented or
836        /// reset to zero.
837        ///
838        /// # Arguments
839        ///
840        /// `worker` is the index of the worker being queried. The given value must
841        /// be between 0 and `num_workers()`. The index uniquely identifies a single
842        /// worker and will continue to identify the worker throughout the lifetime
843        /// of the runtime instance.
844        ///
845        /// # Panics
846        ///
847        /// The method panics when `worker` represents an invalid worker, i.e. is
848        /// greater than or equal to `num_workers()`.
849        ///
850        /// # Examples
851        ///
852        /// ```
853        /// use tokio::runtime::Handle;
854        ///
855        /// # #[tokio::main(flavor = "current_thread")]
856        /// # async fn main() {
857        /// let metrics = Handle::current().metrics();
858        ///
859        /// let n = metrics.worker_local_schedule_count(0);
860        /// println!("{} tasks were scheduled on the worker's local queue", n);
861        /// # }
862        /// ```
863        pub fn worker_local_schedule_count(&self, worker: usize) -> u64 {
864            self.handle
865                .inner
866                .worker_metrics(worker)
867                .local_schedule_count
868                .load(Relaxed)
869        }
870
871        /// Returns the number of times the given worker thread saturated its local
872        /// queue.
873        ///
874        /// This metric only applies to the **multi-threaded** scheduler.
875        ///
876        /// The worker overflow count starts at zero when the runtime is created and
877        /// increases by one each time the worker attempts to schedule a task
878        /// locally, but its local queue is full. When this happens, half of the
879        /// local queue is moved to the injection queue.
880        ///
881        /// The counter is monotonically increasing. It is never decremented or
882        /// reset to zero.
883        ///
884        /// # Arguments
885        ///
886        /// `worker` is the index of the worker being queried. The given value must
887        /// be between 0 and `num_workers()`. The index uniquely identifies a single
888        /// worker and will continue to identify the worker throughout the lifetime
889        /// of the runtime instance.
890        ///
891        /// # Panics
892        ///
893        /// The method panics when `worker` represents an invalid worker, i.e. is
894        /// greater than or equal to `num_workers()`.
895        ///
896        /// # Examples
897        ///
898        /// ```
899        /// use tokio::runtime::Handle;
900        ///
901        /// # #[tokio::main(flavor = "current_thread")]
902        /// # async fn main() {
903        /// let metrics = Handle::current().metrics();
904        ///
905        /// let n = metrics.worker_overflow_count(0);
906        /// println!("worker 0 has overflowed its queue {} times", n);
907        /// # }
908        /// ```
909        pub fn worker_overflow_count(&self, worker: usize) -> u64 {
910            self.handle
911                .inner
912                .worker_metrics(worker)
913                .overflow_count
914                .load(Relaxed)
915        }
916
917        /// Returns the number of times the given worker polled tasks with a poll
918        /// duration within the given bucket's range.
919        ///
920        /// Each worker maintains its own histogram and the counts for each bucket
921        /// starts at zero when the runtime is created. Each time the worker polls a
922        /// task, it tracks the duration the task poll time took and increments the
923        /// associated bucket by 1.
924        ///
925        /// Each bucket is a monotonically increasing counter. It is never
926        /// decremented or reset to zero.
927        ///
928        /// # Arguments
929        ///
930        /// `worker` is the index of the worker being queried. The given value must
931        /// be between 0 and `num_workers()`. The index uniquely identifies a single
932        /// worker and will continue to identify the worker throughout the lifetime
933        /// of the runtime instance.
934        ///
935        /// `bucket` is the index of the bucket being queried. The bucket is scoped
936        /// to the worker. The range represented by the bucket can be queried by
937        /// calling [`poll_time_histogram_bucket_range()`]. Each worker maintains
938        /// identical bucket ranges.
939        ///
940        /// # Panics
941        ///
942        /// The method panics when `worker` represents an invalid worker, i.e. is
943        /// greater than or equal to `num_workers()` or if `bucket` represents an
944        /// invalid bucket.
945        ///
946        /// # Examples
947        ///
948        /// ```
949        /// use tokio::runtime::{self, Handle};
950        ///
951        /// fn main() {
952        ///     runtime::Builder::new_current_thread()
953        ///         .enable_metrics_poll_time_histogram()
954        ///         .build()
955        ///         .unwrap()
956        ///         .block_on(async {
957        ///             let metrics = Handle::current().metrics();
958        ///             let buckets = metrics.poll_time_histogram_num_buckets();
959        ///
960        ///             for worker in 0..metrics.num_workers() {
961        ///                 for i in 0..buckets {
962        ///                     let count = metrics.poll_time_histogram_bucket_count(worker, i);
963        ///                     println!("Poll count {}", count);
964        ///                 }
965        ///             }
966        ///         });
967        /// }
968        /// ```
969        ///
970        /// [`poll_time_histogram_bucket_range()`]: crate::runtime::RuntimeMetrics::poll_time_histogram_bucket_range
971        #[track_caller]
972        pub fn poll_time_histogram_bucket_count(&self, worker: usize, bucket: usize) -> u64 {
973            self.handle
974                .inner
975                .worker_metrics(worker)
976                .poll_count_histogram
977                .as_ref()
978                .map_or(0, |histogram| histogram.get(bucket))
979        }
980
981        #[doc(hidden)]
982        #[deprecated(note = "use `poll_time_histogram_bucket_count` instead")]
983        pub fn poll_count_histogram_bucket_count(&self, worker: usize, bucket: usize) -> u64 {
984            self.poll_time_histogram_bucket_count(worker, bucket)
985        }
986
987        /// Returns the mean duration of task polls, in nanoseconds.
988        ///
989        /// This is an exponentially weighted moving average. Currently, this metric
990        /// is only provided by the multi-threaded runtime.
991        ///
992        /// # Arguments
993        ///
994        /// `worker` is the index of the worker being queried. The given value must
995        /// be between 0 and `num_workers()`. The index uniquely identifies a single
996        /// worker and will continue to identify the worker throughout the lifetime
997        /// of the runtime instance.
998        ///
999        /// # Panics
1000        ///
1001        /// The method panics when `worker` represents an invalid worker, i.e. is
1002        /// greater than or equal to `num_workers()`.
1003        ///
1004        /// # Examples
1005        ///
1006        /// ```
1007        /// use tokio::runtime::Handle;
1008        ///
1009        /// # #[tokio::main(flavor = "current_thread")]
1010        /// # async fn main() {
1011        /// let metrics = Handle::current().metrics();
1012        ///
1013        /// let n = metrics.worker_mean_poll_time(0);
1014        /// println!("worker 0 has a mean poll time of {:?}", n);
1015        /// # }
1016        /// ```
1017        #[track_caller]
1018        pub fn worker_mean_poll_time(&self, worker: usize) -> Duration {
1019            let nanos = self
1020                .handle
1021                .inner
1022                .worker_metrics(worker)
1023                .mean_poll_time
1024                .load(Relaxed);
1025            Duration::from_nanos(nanos)
1026        }
1027    }
1028
1029    feature! {
1030        #![all(tokio_unstable, feature = "schedule-latency")]
1031        /// Returns `true` if the runtime is tracking the distribution of task
1032        /// schedule latencies.
1033        ///
1034        /// Task schedule latencies are not instrumented by default as doing so
1035        /// requires calling [`Instant::now()`] when a task is scheduled and when
1036        /// it is polled. The feature is enabled by calling
1037        /// [`enable_metrics_schedule_latency_histogram()`] when building the runtime.
1038        ///
1039        /// # Examples
1040        ///
1041        /// ```
1042        /// use tokio::runtime::{self, Handle};
1043        ///
1044        /// fn main() {
1045        ///     runtime::Builder::new_current_thread()
1046        ///         .enable_metrics_schedule_latency_histogram()
1047        ///         .build()
1048        ///         .unwrap()
1049        ///         .block_on(async {
1050        ///             let metrics = Handle::current().metrics();
1051        ///             let enabled = metrics.schedule_latency_histogram_enabled();
1052        ///
1053        ///             println!("Tracking task schedule latency distribution: {:?}", enabled);
1054        ///         });
1055        /// }
1056        /// ```
1057        ///
1058        /// [`enable_metrics_schedule_latency_histogram()`]: crate::runtime::Builder::enable_metrics_schedule_latency_histogram
1059        /// [`Instant::now()`]: std::time::Instant::now
1060        pub fn schedule_latency_histogram_enabled(&self) -> bool {
1061            self.handle.inner.worker_metrics(0).schedule_latency_histogram.is_some()
1062        }
1063
1064        /// Returns the number of histogram buckets tracking the distribution of
1065        /// task schedule latencies.
1066        ///
1067        /// This value is configured by calling
1068        /// [`metrics_schedule_latency_histogram_configuration()`] when building the runtime.
1069        ///
1070        /// # Examples
1071        ///
1072        /// ```
1073        /// use tokio::runtime::{self, Handle};
1074        ///
1075        /// fn main() {
1076        ///     runtime::Builder::new_current_thread()
1077        ///         .enable_metrics_schedule_latency_histogram()
1078        ///         .build()
1079        ///         .unwrap()
1080        ///         .block_on(async {
1081        ///             let metrics = Handle::current().metrics();
1082        ///             let buckets = metrics.schedule_latency_histogram_num_buckets();
1083        ///
1084        ///             println!("Histogram buckets: {:?}", buckets);
1085        ///         });
1086        /// }
1087        /// ```
1088        ///
1089        /// [`metrics_schedule_latency_histogram_configuration()`]: crate::runtime::Builder::metrics_schedule_latency_histogram_configuration
1090        pub fn schedule_latency_histogram_num_buckets(&self) -> usize {
1091            self.handle
1092                .inner
1093                .worker_metrics(0)
1094                .schedule_latency_histogram
1095                .as_ref()
1096                .map_or(0, |histogram| histogram.num_buckets())
1097        }
1098
1099        /// Returns the range of task schedule latencies tracked by the given bucket.
1100        ///
1101        /// This value is configured by calling
1102        /// [`metrics_schedule_latency_histogram_configuration()`] when building the runtime.
1103        ///
1104        /// # Panics
1105        ///
1106        /// The method panics if `bucket` represents an invalid bucket index, i.e.
1107        /// is greater than or equal to `schedule_latency_histogram_num_buckets()`.
1108        ///
1109        /// # Examples
1110        ///
1111        /// ```
1112        /// use tokio::runtime::{self, Handle};
1113        ///
1114        /// fn main() {
1115        ///     runtime::Builder::new_current_thread()
1116        ///         .enable_metrics_schedule_latency_histogram()
1117        ///         .build()
1118        ///         .unwrap()
1119        ///         .block_on(async {
1120        ///             let metrics = Handle::current().metrics();
1121        ///             let buckets = metrics.schedule_latency_histogram_num_buckets();
1122        ///
1123        ///             for i in 0..buckets {
1124        ///                 let range = metrics.schedule_latency_histogram_bucket_range(i);
1125        ///                 println!("Histogram bucket {} range: {:?}", i, range);
1126        ///             }
1127        ///         });
1128        /// }
1129        /// ```
1130        ///
1131        /// [`metrics_schedule_latency_histogram_configuration()`]: crate::runtime::Builder::metrics_schedule_latency_histogram_configuration
1132        #[track_caller]
1133        pub fn schedule_latency_histogram_bucket_range(&self, bucket: usize) -> Range<Duration> {
1134            self.handle
1135                .inner
1136                .worker_metrics(0)
1137                .schedule_latency_histogram
1138                .as_ref()
1139                .map_or_else(Range::default, |histogram| {
1140                    let range = histogram.bucket_range(bucket);
1141                    std::ops::Range {
1142                        start: Duration::from_nanos(range.start),
1143                        end: Duration::from_nanos(range.end),
1144                    }
1145                })
1146        }
1147
1148        /// Returns the number of times the given worker polled tasks with a schedule
1149        /// latency within the given bucket's range.
1150        ///
1151        /// Each worker maintains its own histogram and the counts for each bucket
1152        /// starts at zero when the runtime is created. Each time the worker polls a
1153        /// task, it tracks the time elapsed between when the task was scheduled and
1154        /// when it was polled and increments the associated bucket by 1.
1155        ///
1156        /// Each bucket is a monotonically increasing counter. It is never
1157        /// decremented or reset to zero.
1158        ///
1159        /// # Arguments
1160        ///
1161        /// `worker` is the index of the worker being queried. The given value must
1162        /// be between 0 and `num_workers()`. The index uniquely identifies a single
1163        /// worker and will continue to identify the worker throughout the lifetime
1164        /// of the runtime instance.
1165        ///
1166        /// `bucket` is the index of the bucket being queried. The bucket is scoped
1167        /// to the worker. The range represented by the bucket can be queried by
1168        /// calling [`schedule_latency_histogram_bucket_range()`]. Each worker maintains
1169        /// identical bucket ranges.
1170        ///
1171        /// # Panics
1172        ///
1173        /// The method panics when `worker` represents an invalid worker, i.e. is
1174        /// greater than or equal to `num_workers()` or if `bucket` represents an
1175        /// invalid bucket.
1176        ///
1177        /// # Examples
1178        ///
1179        /// ```
1180        /// use tokio::runtime::{self, Handle};
1181        ///
1182        /// fn main() {
1183        ///     runtime::Builder::new_current_thread()
1184        ///         .enable_metrics_schedule_latency_histogram()
1185        ///         .build()
1186        ///         .unwrap()
1187        ///         .block_on(async {
1188        ///             let metrics = Handle::current().metrics();
1189        ///             let buckets = metrics.schedule_latency_histogram_num_buckets();
1190        ///
1191        ///             for worker in 0..metrics.num_workers() {
1192        ///                 for i in 0..buckets {
1193        ///                     let range = metrics.schedule_latency_histogram_bucket_range(i);
1194        ///                     let count = metrics.schedule_latency_histogram_bucket_count(worker, i);
1195        ///                     println!("{} tasks encountered a scheduling latency between {}us and {}us", count, range.start.as_micros(), range.end.as_micros());
1196        ///                 }
1197        ///             }
1198        ///         });
1199        /// }
1200        /// ```
1201        ///
1202        /// [`schedule_latency_histogram_bucket_range()`]: crate::runtime::RuntimeMetrics::schedule_latency_histogram_bucket_range
1203        #[track_caller]
1204        pub fn schedule_latency_histogram_bucket_count(&self, worker: usize, bucket: usize) -> u64 {
1205            self.handle
1206                .inner
1207                .worker_metrics(worker)
1208                .schedule_latency_histogram
1209                .as_ref()
1210                .map_or(0, |histogram| histogram.get(bucket))
1211        }
1212    }
1213
1214    feature! {
1215        #![all(
1216            tokio_unstable,
1217            target_has_atomic = "64",
1218            feature = "net"
1219        )]
1220            /// Returns the number of file descriptors that have been registered with the
1221            /// runtime's I/O driver.
1222            ///
1223            /// # Examples
1224            ///
1225            /// ```
1226            /// use tokio::runtime::Handle;
1227            ///
1228            /// #[tokio::main]
1229            /// async fn main() {
1230            ///     let metrics = Handle::current().metrics();
1231            ///
1232            ///     let registered_fds = metrics.io_driver_fd_registered_count();
1233            ///     println!("{} fds have been registered with the runtime's I/O driver.", registered_fds);
1234            ///
1235            ///     let deregistered_fds = metrics.io_driver_fd_deregistered_count();
1236            ///
1237            ///     let current_fd_count = registered_fds - deregistered_fds;
1238            ///     println!("{} fds are currently registered by the runtime's I/O driver.", current_fd_count);
1239            /// }
1240            /// ```
1241            pub fn io_driver_fd_registered_count(&self) -> u64 {
1242                self.with_io_driver_metrics(|m| {
1243                    m.fd_registered_count.load(Relaxed)
1244                })
1245            }
1246
1247            /// Returns the number of file descriptors that have been deregistered by the
1248            /// runtime's I/O driver.
1249            ///
1250            /// # Examples
1251            ///
1252            /// ```
1253            /// use tokio::runtime::Handle;
1254            ///
1255            /// #[tokio::main]
1256            /// async fn main() {
1257            ///     let metrics = Handle::current().metrics();
1258            ///
1259            ///     let n = metrics.io_driver_fd_deregistered_count();
1260            ///     println!("{} fds have been deregistered by the runtime's I/O driver.", n);
1261            /// }
1262            /// ```
1263            pub fn io_driver_fd_deregistered_count(&self) -> u64 {
1264                self.with_io_driver_metrics(|m| {
1265                    m.fd_deregistered_count.load(Relaxed)
1266                })
1267            }
1268
1269            /// Returns the number of ready events processed by the runtime's
1270            /// I/O driver.
1271            ///
1272            /// # Examples
1273            ///
1274            /// ```
1275            /// use tokio::runtime::Handle;
1276            ///
1277            /// #[tokio::main]
1278            /// async fn main() {
1279            ///     let metrics = Handle::current().metrics();
1280            ///
1281            ///     let n = metrics.io_driver_ready_count();
1282            ///     println!("{} ready events processed by the runtime's I/O driver.", n);
1283            /// }
1284            /// ```
1285            pub fn io_driver_ready_count(&self) -> u64 {
1286                self.with_io_driver_metrics(|m| m.ready_count.load(Relaxed))
1287            }
1288
1289            fn with_io_driver_metrics<F>(&self, f: F) -> u64
1290            where
1291                F: Fn(&super::IoDriverMetrics) -> u64,
1292            {
1293                // TODO: Investigate if this should return 0, most of our metrics always increase
1294                // thus this breaks that guarantee.
1295                self.handle
1296                    .inner
1297                    .driver()
1298                    .io
1299                    .as_ref()
1300                    .map_or(0, |h| f(&h.metrics))
1301            }
1302    }
1303}