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