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