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