1 | use crate::runtime::Handle; |
2 | |
3 | cfg_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)] |
19 | pub struct RuntimeMetrics { |
20 | handle: Handle, |
21 | } |
22 | |
23 | impl 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 | } |
1106 | |