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