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