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