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(|histogram| histogram.num_buckets())
478                .unwrap_or_default()
479        }
480
481        /// Deprecated. Use [`poll_time_histogram_num_buckets()`] instead.
482        ///
483        /// [`poll_time_histogram_num_buckets()`]: Self::poll_time_histogram_num_buckets
484        #[doc(hidden)]
485        #[deprecated(note = "renamed to `poll_time_histogram_num_buckets`.")]
486        pub fn poll_count_histogram_num_buckets(&self) -> usize {
487            self.poll_time_histogram_num_buckets()
488        }
489
490        /// Returns the range of task poll times tracked by the given bucket.
491        ///
492        /// This value is configured by calling
493        /// [`metrics_poll_time_histogram_configuration()`] when building the runtime.
494        ///
495        /// # Panics
496        ///
497        /// The method panics if `bucket` represents an invalid bucket index, i.e.
498        /// is greater than or equal to `poll_time_histogram_num_buckets()`.
499        ///
500        /// # Examples
501        ///
502        /// ```
503        /// use tokio::runtime::{self, Handle};
504        ///
505        /// fn main() {
506        ///     runtime::Builder::new_current_thread()
507        ///         .enable_metrics_poll_time_histogram()
508        ///         .build()
509        ///         .unwrap()
510        ///         .block_on(async {
511        ///             let metrics = Handle::current().metrics();
512        ///             let buckets = metrics.poll_time_histogram_num_buckets();
513        ///
514        ///             for i in 0..buckets {
515        ///                 let range = metrics.poll_time_histogram_bucket_range(i);
516        ///                 println!("Histogram bucket {} range: {:?}", i, range);
517        ///             }
518        ///         });
519        /// }
520        /// ```
521        ///
522        /// [`metrics_poll_time_histogram_configuration()`]:
523        ///     crate::runtime::Builder::metrics_poll_time_histogram_configuration
524        #[track_caller]
525        pub fn poll_time_histogram_bucket_range(&self, bucket: usize) -> Range<Duration> {
526            self.handle
527                .inner
528                .worker_metrics(0)
529                .poll_count_histogram
530                .as_ref()
531                .map(|histogram| {
532                    let range = histogram.bucket_range(bucket);
533                    std::ops::Range {
534                        start: Duration::from_nanos(range.start),
535                        end: Duration::from_nanos(range.end),
536                    }
537                })
538                .unwrap_or_default()
539        }
540
541        /// Deprecated. Use [`poll_time_histogram_bucket_range()`] instead.
542        ///
543        /// [`poll_time_histogram_bucket_range()`]: Self::poll_time_histogram_bucket_range
544        #[track_caller]
545        #[doc(hidden)]
546        #[deprecated(note = "renamed to `poll_time_histogram_bucket_range`")]
547        pub fn poll_count_histogram_bucket_range(&self, bucket: usize) -> Range<Duration> {
548            self.poll_time_histogram_bucket_range(bucket)
549        }
550
551        /// Returns the number of tasks currently scheduled in the blocking
552        /// thread pool, spawned using `spawn_blocking`.
553        ///
554        /// This metric returns the **current** number of tasks pending in
555        /// blocking thread pool. As such, the returned value may increase
556        /// or decrease as new tasks are scheduled and processed.
557        ///
558        /// # Examples
559        ///
560        /// ```
561        /// use tokio::runtime::Handle;
562        ///
563        /// # #[tokio::main(flavor = "current_thread")]
564        /// # async fn main() {
565        /// let metrics = Handle::current().metrics();
566        ///
567        /// let n = metrics.blocking_queue_depth();
568        /// println!("{} tasks currently pending in the blocking thread pool", n);
569        /// # }
570        /// ```
571        pub fn blocking_queue_depth(&self) -> usize {
572            self.handle.inner.blocking_queue_depth()
573        }
574    }
575
576    feature! {
577        #![all(
578            tokio_unstable,
579            target_has_atomic = "64"
580        )]
581        /// Returns the number of tasks spawned in this runtime since it was created.
582        ///
583        /// This count starts at zero when the runtime is created and increases by one each time a task is spawned.
584        ///
585        /// The counter is monotonically increasing. It is never decremented or
586        /// reset to zero.
587        ///
588        /// # Examples
589        ///
590        /// ```
591        /// use tokio::runtime::Handle;
592        ///
593        /// # #[tokio::main(flavor = "current_thread")]
594        /// # async fn main() {
595        /// let metrics = Handle::current().metrics();
596        ///
597        /// let n = metrics.spawned_tasks_count();
598        /// println!("Runtime has had {} tasks spawned", n);
599        /// # }
600        /// ```
601        pub fn spawned_tasks_count(&self) -> u64 {
602            self.handle.inner.spawned_tasks_count()
603        }
604
605        /// Returns the number of tasks scheduled from **outside** of the runtime.
606        ///
607        /// The remote schedule count starts at zero when the runtime is created and
608        /// increases by one each time a task is woken from **outside** of the
609        /// runtime. This usually means that a task is spawned or notified from a
610        /// non-runtime thread and must be queued using the Runtime's injection
611        /// queue, which tends to be slower.
612        ///
613        /// The counter is monotonically increasing. It is never decremented or
614        /// reset to zero.
615        ///
616        /// # Examples
617        ///
618        /// ```
619        /// use tokio::runtime::Handle;
620        ///
621        /// # #[tokio::main(flavor = "current_thread")]
622        /// # async fn main() {
623        /// let metrics = Handle::current().metrics();
624        ///
625        /// let n = metrics.remote_schedule_count();
626        /// println!("{} tasks were scheduled from outside the runtime", n);
627        /// # }
628        /// ```
629        pub fn remote_schedule_count(&self) -> u64 {
630            self.handle
631                .inner
632                .scheduler_metrics()
633                .remote_schedule_count
634                .load(Relaxed)
635        }
636
637        /// Returns the number of times that tasks have been forced to yield back to the scheduler
638        /// after exhausting their task budgets.
639        ///
640        /// This count starts at zero when the runtime is created and increases by one each time a task yields due to exhausting its budget.
641        ///
642        /// The counter is monotonically increasing. It is never decremented or
643        /// reset to zero.
644        pub fn budget_forced_yield_count(&self) -> u64 {
645            self.handle
646                .inner
647                .scheduler_metrics()
648                .budget_forced_yield_count
649                .load(Relaxed)
650        }
651
652        /// Returns the number of times the given worker thread unparked but
653        /// performed no work before parking again.
654        ///
655        /// The worker no-op count starts at zero when the runtime is created and
656        /// increases by one each time the worker unparks the thread but finds no
657        /// new work and goes back to sleep. This indicates a false-positive wake up.
658        ///
659        /// The counter is monotonically increasing. It is never decremented or
660        /// reset to zero.
661        ///
662        /// # Arguments
663        ///
664        /// `worker` is the index of the worker being queried. The given value must
665        /// be between 0 and `num_workers()`. The index uniquely identifies a single
666        /// worker and will continue to identify the worker throughout the lifetime
667        /// of the runtime instance.
668        ///
669        /// # Panics
670        ///
671        /// The method panics when `worker` represents an invalid worker, i.e. is
672        /// greater than or equal to `num_workers()`.
673        ///
674        /// # Examples
675        ///
676        /// ```
677        /// use tokio::runtime::Handle;
678        ///
679        /// # #[tokio::main(flavor = "current_thread")]
680        /// # async fn main() {
681        /// let metrics = Handle::current().metrics();
682        ///
683        /// let n = metrics.worker_noop_count(0);
684        /// println!("worker 0 had {} no-op unparks", n);
685        /// # }
686        /// ```
687        pub fn worker_noop_count(&self, worker: usize) -> u64 {
688            self.handle
689                .inner
690                .worker_metrics(worker)
691                .noop_count
692                .load(Relaxed)
693        }
694
695        /// Returns the number of tasks the given worker thread stole from
696        /// another worker thread.
697        ///
698        /// This metric only applies to the **multi-threaded** runtime and will
699        /// always return `0` when using the current thread runtime.
700        ///
701        /// The worker steal count starts at zero when the runtime is created and
702        /// increases by `N` each time the worker has processed its scheduled queue
703        /// and successfully steals `N` more pending tasks from another worker.
704        ///
705        /// The counter is monotonically increasing. It is never decremented or
706        /// reset to zero.
707        ///
708        /// # Arguments
709        ///
710        /// `worker` is the index of the worker being queried. The given value must
711        /// be between 0 and `num_workers()`. The index uniquely identifies a single
712        /// worker and will continue to identify the worker throughout the lifetime
713        /// of the runtime instance.
714        ///
715        /// # Panics
716        ///
717        /// The method panics when `worker` represents an invalid worker, i.e. is
718        /// greater than or equal to `num_workers()`.
719        ///
720        /// # Examples
721        ///
722        /// ```
723        /// use tokio::runtime::Handle;
724        ///
725        /// # #[tokio::main(flavor = "current_thread")]
726        /// # async fn main() {
727        /// let metrics = Handle::current().metrics();
728        ///
729        /// let n = metrics.worker_steal_count(0);
730        /// println!("worker 0 has stolen {} tasks", n);
731        /// # }
732        /// ```
733        pub fn worker_steal_count(&self, worker: usize) -> u64 {
734            self.handle
735                .inner
736                .worker_metrics(worker)
737                .steal_count
738                .load(Relaxed)
739        }
740
741        /// Returns the number of times the given worker thread stole tasks from
742        /// another worker thread.
743        ///
744        /// This metric only applies to the **multi-threaded** runtime and will
745        /// always return `0` when using the current thread runtime.
746        ///
747        /// The worker steal count starts at zero when the runtime is created and
748        /// increases by one each time the worker has processed its scheduled queue
749        /// and successfully steals more pending tasks from another worker.
750        ///
751        /// The counter is monotonically increasing. It is never decremented or
752        /// reset to zero.
753        ///
754        /// # Arguments
755        ///
756        /// `worker` is the index of the worker being queried. The given value must
757        /// be between 0 and `num_workers()`. The index uniquely identifies a single
758        /// worker and will continue to identify the worker throughout the lifetime
759        /// of the runtime instance.
760        ///
761        /// # Panics
762        ///
763        /// The method panics when `worker` represents an invalid worker, i.e. is
764        /// greater than or equal to `num_workers()`.
765        ///
766        /// # Examples
767        ///
768        /// ```
769        /// use tokio::runtime::Handle;
770        ///
771        /// # #[tokio::main(flavor = "current_thread")]
772        /// # async fn main() {
773        /// let metrics = Handle::current().metrics();
774        ///
775        /// let n = metrics.worker_steal_operations(0);
776        /// println!("worker 0 has stolen tasks {} times", n);
777        /// # }
778        /// ```
779        pub fn worker_steal_operations(&self, worker: usize) -> u64 {
780            self.handle
781                .inner
782                .worker_metrics(worker)
783                .steal_operations
784                .load(Relaxed)
785        }
786
787        /// Returns the number of tasks the given worker thread has polled.
788        ///
789        /// The worker poll count starts at zero when the runtime is created and
790        /// increases by one each time the worker polls a scheduled task.
791        ///
792        /// The counter is monotonically increasing. It is never decremented or
793        /// reset to zero.
794        ///
795        /// # Arguments
796        ///
797        /// `worker` is the index of the worker being queried. The given value must
798        /// be between 0 and `num_workers()`. The index uniquely identifies a single
799        /// worker and will continue to identify the worker throughout the lifetime
800        /// of the runtime instance.
801        ///
802        /// # Panics
803        ///
804        /// The method panics when `worker` represents an invalid worker, i.e. is
805        /// greater than or equal to `num_workers()`.
806        ///
807        /// # Examples
808        ///
809        /// ```
810        /// use tokio::runtime::Handle;
811        ///
812        /// # #[tokio::main(flavor = "current_thread")]
813        /// # async fn main() {
814        /// let metrics = Handle::current().metrics();
815        ///
816        /// let n = metrics.worker_poll_count(0);
817        /// println!("worker 0 has polled {} tasks", n);
818        /// # }
819        /// ```
820        pub fn worker_poll_count(&self, worker: usize) -> u64 {
821            self.handle
822                .inner
823                .worker_metrics(worker)
824                .poll_count
825                .load(Relaxed)
826        }
827
828        /// Returns the number of tasks scheduled from **within** the runtime on the
829        /// given worker's local queue.
830        ///
831        /// The local schedule count starts at zero when the runtime is created and
832        /// increases by one each time a task is woken from **inside** of the
833        /// runtime on the given worker. This usually means that a task is spawned
834        /// or notified from within a runtime thread and will be queued on the
835        /// worker-local queue.
836        ///
837        /// The counter is monotonically increasing. It is never decremented or
838        /// reset to zero.
839        ///
840        /// # Arguments
841        ///
842        /// `worker` is the index of the worker being queried. The given value must
843        /// be between 0 and `num_workers()`. The index uniquely identifies a single
844        /// worker and will continue to identify the worker throughout the lifetime
845        /// of the runtime instance.
846        ///
847        /// # Panics
848        ///
849        /// The method panics when `worker` represents an invalid worker, i.e. is
850        /// greater than or equal to `num_workers()`.
851        ///
852        /// # Examples
853        ///
854        /// ```
855        /// use tokio::runtime::Handle;
856        ///
857        /// # #[tokio::main(flavor = "current_thread")]
858        /// # async fn main() {
859        /// let metrics = Handle::current().metrics();
860        ///
861        /// let n = metrics.worker_local_schedule_count(0);
862        /// println!("{} tasks were scheduled on the worker's local queue", n);
863        /// # }
864        /// ```
865        pub fn worker_local_schedule_count(&self, worker: usize) -> u64 {
866            self.handle
867                .inner
868                .worker_metrics(worker)
869                .local_schedule_count
870                .load(Relaxed)
871        }
872
873        /// Returns the number of times the given worker thread saturated its local
874        /// queue.
875        ///
876        /// This metric only applies to the **multi-threaded** scheduler.
877        ///
878        /// The worker overflow count starts at zero when the runtime is created and
879        /// increases by one each time the worker attempts to schedule a task
880        /// locally, but its local queue is full. When this happens, half of the
881        /// local queue is moved to the injection queue.
882        ///
883        /// The counter is monotonically increasing. It is never decremented or
884        /// reset to zero.
885        ///
886        /// # Arguments
887        ///
888        /// `worker` is the index of the worker being queried. The given value must
889        /// be between 0 and `num_workers()`. The index uniquely identifies a single
890        /// worker and will continue to identify the worker throughout the lifetime
891        /// of the runtime instance.
892        ///
893        /// # Panics
894        ///
895        /// The method panics when `worker` represents an invalid worker, i.e. is
896        /// greater than or equal to `num_workers()`.
897        ///
898        /// # Examples
899        ///
900        /// ```
901        /// use tokio::runtime::Handle;
902        ///
903        /// # #[tokio::main(flavor = "current_thread")]
904        /// # async fn main() {
905        /// let metrics = Handle::current().metrics();
906        ///
907        /// let n = metrics.worker_overflow_count(0);
908        /// println!("worker 0 has overflowed its queue {} times", n);
909        /// # }
910        /// ```
911        pub fn worker_overflow_count(&self, worker: usize) -> u64 {
912            self.handle
913                .inner
914                .worker_metrics(worker)
915                .overflow_count
916                .load(Relaxed)
917        }
918
919        /// Returns the number of times the given worker polled tasks with a poll
920        /// duration within the given bucket's range.
921        ///
922        /// Each worker maintains its own histogram and the counts for each bucket
923        /// starts at zero when the runtime is created. Each time the worker polls a
924        /// task, it tracks the duration the task poll time took and increments the
925        /// associated bucket by 1.
926        ///
927        /// Each bucket is a monotonically increasing counter. It is never
928        /// decremented or reset to zero.
929        ///
930        /// # Arguments
931        ///
932        /// `worker` is the index of the worker being queried. The given value must
933        /// be between 0 and `num_workers()`. The index uniquely identifies a single
934        /// worker and will continue to identify the worker throughout the lifetime
935        /// of the runtime instance.
936        ///
937        /// `bucket` is the index of the bucket being queried. The bucket is scoped
938        /// to the worker. The range represented by the bucket can be queried by
939        /// calling [`poll_time_histogram_bucket_range()`]. Each worker maintains
940        /// identical bucket ranges.
941        ///
942        /// # Panics
943        ///
944        /// The method panics when `worker` represents an invalid worker, i.e. is
945        /// greater than or equal to `num_workers()` or if `bucket` represents an
946        /// invalid bucket.
947        ///
948        /// # Examples
949        ///
950        /// ```
951        /// use tokio::runtime::{self, Handle};
952        ///
953        /// fn main() {
954        ///     runtime::Builder::new_current_thread()
955        ///         .enable_metrics_poll_time_histogram()
956        ///         .build()
957        ///         .unwrap()
958        ///         .block_on(async {
959        ///             let metrics = Handle::current().metrics();
960        ///             let buckets = metrics.poll_time_histogram_num_buckets();
961        ///
962        ///             for worker in 0..metrics.num_workers() {
963        ///                 for i in 0..buckets {
964        ///                     let count = metrics.poll_time_histogram_bucket_count(worker, i);
965        ///                     println!("Poll count {}", count);
966        ///                 }
967        ///             }
968        ///         });
969        /// }
970        /// ```
971        ///
972        /// [`poll_time_histogram_bucket_range()`]: crate::runtime::RuntimeMetrics::poll_time_histogram_bucket_range
973        #[track_caller]
974        pub fn poll_time_histogram_bucket_count(&self, worker: usize, bucket: usize) -> u64 {
975            self.handle
976                .inner
977                .worker_metrics(worker)
978                .poll_count_histogram
979                .as_ref()
980                .map(|histogram| histogram.get(bucket))
981                .unwrap_or_default()
982        }
983
984        #[doc(hidden)]
985        #[deprecated(note = "use `poll_time_histogram_bucket_count` instead")]
986        pub fn poll_count_histogram_bucket_count(&self, worker: usize, bucket: usize) -> u64 {
987            self.poll_time_histogram_bucket_count(worker, bucket)
988        }
989
990        /// Returns the mean duration of task polls, in nanoseconds.
991        ///
992        /// This is an exponentially weighted moving average. Currently, this metric
993        /// is only provided by the multi-threaded runtime.
994        ///
995        /// # Arguments
996        ///
997        /// `worker` is the index of the worker being queried. The given value must
998        /// be between 0 and `num_workers()`. The index uniquely identifies a single
999        /// worker and will continue to identify the worker throughout the lifetime
1000        /// of the runtime instance.
1001        ///
1002        /// # Panics
1003        ///
1004        /// The method panics when `worker` represents an invalid worker, i.e. is
1005        /// greater than or equal to `num_workers()`.
1006        ///
1007        /// # Examples
1008        ///
1009        /// ```
1010        /// use tokio::runtime::Handle;
1011        ///
1012        /// # #[tokio::main(flavor = "current_thread")]
1013        /// # async fn main() {
1014        /// let metrics = Handle::current().metrics();
1015        ///
1016        /// let n = metrics.worker_mean_poll_time(0);
1017        /// println!("worker 0 has a mean poll time of {:?}", n);
1018        /// # }
1019        /// ```
1020        #[track_caller]
1021        pub fn worker_mean_poll_time(&self, worker: usize) -> Duration {
1022            let nanos = self
1023                .handle
1024                .inner
1025                .worker_metrics(worker)
1026                .mean_poll_time
1027                .load(Relaxed);
1028            Duration::from_nanos(nanos)
1029        }
1030    }
1031
1032    feature! {
1033        #![all(
1034            tokio_unstable,
1035            target_has_atomic = "64",
1036            feature = "net"
1037        )]
1038            /// Returns the number of file descriptors that have been registered with the
1039            /// runtime's I/O driver.
1040            ///
1041            /// # Examples
1042            ///
1043            /// ```
1044            /// use tokio::runtime::Handle;
1045            ///
1046            /// #[tokio::main]
1047            /// async fn main() {
1048            ///     let metrics = Handle::current().metrics();
1049            ///
1050            ///     let registered_fds = metrics.io_driver_fd_registered_count();
1051            ///     println!("{} fds have been registered with the runtime's I/O driver.", registered_fds);
1052            ///
1053            ///     let deregistered_fds = metrics.io_driver_fd_deregistered_count();
1054            ///
1055            ///     let current_fd_count = registered_fds - deregistered_fds;
1056            ///     println!("{} fds are currently registered by the runtime's I/O driver.", current_fd_count);
1057            /// }
1058            /// ```
1059            pub fn io_driver_fd_registered_count(&self) -> u64 {
1060                self.with_io_driver_metrics(|m| {
1061                    m.fd_registered_count.load(Relaxed)
1062                })
1063            }
1064
1065            /// Returns the number of file descriptors that have been deregistered by the
1066            /// runtime's I/O driver.
1067            ///
1068            /// # Examples
1069            ///
1070            /// ```
1071            /// use tokio::runtime::Handle;
1072            ///
1073            /// #[tokio::main]
1074            /// async fn main() {
1075            ///     let metrics = Handle::current().metrics();
1076            ///
1077            ///     let n = metrics.io_driver_fd_deregistered_count();
1078            ///     println!("{} fds have been deregistered by the runtime's I/O driver.", n);
1079            /// }
1080            /// ```
1081            pub fn io_driver_fd_deregistered_count(&self) -> u64 {
1082                self.with_io_driver_metrics(|m| {
1083                    m.fd_deregistered_count.load(Relaxed)
1084                })
1085            }
1086
1087            /// Returns the number of ready events processed by the runtime's
1088            /// I/O driver.
1089            ///
1090            /// # Examples
1091            ///
1092            /// ```
1093            /// use tokio::runtime::Handle;
1094            ///
1095            /// #[tokio::main]
1096            /// async fn main() {
1097            ///     let metrics = Handle::current().metrics();
1098            ///
1099            ///     let n = metrics.io_driver_ready_count();
1100            ///     println!("{} ready events processed by the runtime's I/O driver.", n);
1101            /// }
1102            /// ```
1103            pub fn io_driver_ready_count(&self) -> u64 {
1104                self.with_io_driver_metrics(|m| m.ready_count.load(Relaxed))
1105            }
1106
1107            fn with_io_driver_metrics<F>(&self, f: F) -> u64
1108            where
1109                F: Fn(&super::IoDriverMetrics) -> u64,
1110            {
1111                // TODO: Investigate if this should return 0, most of our metrics always increase
1112                // thus this breaks that guarantee.
1113                self.handle
1114                    .inner
1115                    .driver()
1116                    .io
1117                    .as_ref()
1118                    .map(|h| f(&h.metrics))
1119                    .unwrap_or(0)
1120            }
1121    }
1122}