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}