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