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