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