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