tokio/runtime/metrics/
runtime.rs

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