tokio/runtime/metrics/
runtime.rs

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