1
1
use crate :: runtime:: handle:: Handle ;
2
- use crate :: runtime:: { blocking, driver, Callback , Runtime } ;
2
+ use crate :: runtime:: { blocking, driver, Callback , HistogramBuilder , Runtime } ;
3
3
use crate :: util:: rand:: { RngSeed , RngSeedGenerator } ;
4
4
5
5
use std:: fmt;
@@ -95,6 +95,12 @@ pub struct Builder {
95
95
/// Specify a random number generator seed to provide deterministic results
96
96
pub ( super ) seed_generator : RngSeedGenerator ,
97
97
98
+ /// When true, enables task poll count histogram instrumentation.
99
+ pub ( super ) metrics_poll_count_histogram_enable : bool ,
100
+
101
+ /// Configures the task poll count histogram
102
+ pub ( super ) metrics_poll_count_histogram : HistogramBuilder ,
103
+
98
104
#[ cfg( tokio_unstable) ]
99
105
pub ( super ) unhandled_panic : UnhandledPanic ,
100
106
}
@@ -268,6 +274,10 @@ impl Builder {
268
274
#[ cfg( tokio_unstable) ]
269
275
unhandled_panic : UnhandledPanic :: Ignore ,
270
276
277
+ metrics_poll_count_histogram_enable : false ,
278
+
279
+ metrics_poll_count_histogram : Default :: default ( ) ,
280
+
271
281
disable_lifo_slot : false ,
272
282
}
273
283
}
@@ -877,6 +887,133 @@ impl Builder {
877
887
}
878
888
}
879
889
890
+ cfg_metrics ! {
891
+ /// Enables tracking the distribution of task poll times.
892
+ ///
893
+ /// Task poll times are not instrumented by default as doing so requires
894
+ /// calling [`Instant::now()`] twice per task poll, which could add
895
+ /// measurable overhead. Use the [`Handle::metrics()`] to access the
896
+ /// metrics data.
897
+ ///
898
+ /// The histogram uses fixed bucket sizes. In other words, the histogram
899
+ /// buckets are not dynamic based on input values. Use the
900
+ /// `metrics_poll_count_histogram_` builder methods to configure the
901
+ /// histogram details.
902
+ ///
903
+ /// # Examples
904
+ ///
905
+ /// ```
906
+ /// use tokio::runtime;
907
+ ///
908
+ /// let rt = runtime::Builder::new_multi_thread()
909
+ /// .enable_metrics_poll_count_histogram()
910
+ /// .build()
911
+ /// .unwrap();
912
+ /// # // Test default values here
913
+ /// # fn us(n: u64) -> std::time::Duration { std::time::Duration::from_micros(n) }
914
+ /// # let m = rt.handle().metrics();
915
+ /// # assert_eq!(m.poll_count_histogram_num_buckets(), 10);
916
+ /// # assert_eq!(m.poll_count_histogram_bucket_range(0), us(0)..us(100));
917
+ /// # assert_eq!(m.poll_count_histogram_bucket_range(1), us(100)..us(200));
918
+ /// ```
919
+ ///
920
+ /// [`Handle::metrics()`]: crate::runtime::Handle::metrics
921
+ /// [`Instant::now()`]: std::time::Instant::now
922
+ pub fn enable_metrics_poll_count_histogram( & mut self ) -> & mut Self {
923
+ self . metrics_poll_count_histogram_enable = true ;
924
+ self
925
+ }
926
+
927
+ /// Sets the histogram scale for tracking the distribution of task poll
928
+ /// times.
929
+ ///
930
+ /// Tracking the distribution of task poll times can be done using a
931
+ /// linear or log scale. When using linear scale, each histogram bucket
932
+ /// will represent the same range of poll times. When using log scale,
933
+ /// each histogram bucket will cover a range twice as big as the
934
+ /// previous bucket.
935
+ ///
936
+ /// **Default:** linear scale.
937
+ ///
938
+ /// # Examples
939
+ ///
940
+ /// ```
941
+ /// use tokio::runtime::{self, HistogramScale};
942
+ ///
943
+ /// let rt = runtime::Builder::new_multi_thread()
944
+ /// .enable_metrics_poll_count_histogram()
945
+ /// .metrics_poll_count_histogram_scale(HistogramScale::Log)
946
+ /// .build()
947
+ /// .unwrap();
948
+ /// ```
949
+ pub fn metrics_poll_count_histogram_scale( & mut self , histogram_scale: crate :: runtime:: HistogramScale ) -> & mut Self {
950
+ self . metrics_poll_count_histogram. scale = histogram_scale;
951
+ self
952
+ }
953
+
954
+ /// Sets the histogram resolution for tracking the distribution of task
955
+ /// poll times.
956
+ ///
957
+ /// The resolution is the histogram's first bucket's range. When using a
958
+ /// linear histogram scale, each bucket will cover the same range. When
959
+ /// using a log scale, each bucket will cover a range twice as big as
960
+ /// the previous bucket. In the log case, the resolution represents the
961
+ /// smallest bucket range.
962
+ ///
963
+ /// Note that, when using log scale, the resolution is rounded up to the
964
+ /// nearest power of 2 in nanoseconds.
965
+ ///
966
+ /// **Default:** 100 microseconds.
967
+ ///
968
+ /// # Examples
969
+ ///
970
+ /// ```
971
+ /// use tokio::runtime;
972
+ /// use std::time::Duration;
973
+ ///
974
+ /// let rt = runtime::Builder::new_multi_thread()
975
+ /// .enable_metrics_poll_count_histogram()
976
+ /// .metrics_poll_count_histogram_resolution(Duration::from_micros(100))
977
+ /// .build()
978
+ /// .unwrap();
979
+ /// ```
980
+ pub fn metrics_poll_count_histogram_resolution( & mut self , resolution: Duration ) -> & mut Self {
981
+ assert!( resolution > Duration :: from_secs( 0 ) ) ;
982
+ // Sanity check the argument and also make the cast below safe.
983
+ assert!( resolution <= Duration :: from_secs( 1 ) ) ;
984
+
985
+ let resolution = resolution. as_nanos( ) as u64 ;
986
+ self . metrics_poll_count_histogram. resolution = resolution;
987
+ self
988
+ }
989
+
990
+ /// Sets the number of buckets for the histogram tracking the
991
+ /// distribution of task poll times.
992
+ ///
993
+ /// The last bucket tracks all greater values that fall out of other
994
+ /// ranges. So, configuring the histogram using a linear scale,
995
+ /// resolution of 50ms, and 10 buckets, the 10th bucket will track task
996
+ /// polls that take more than 450ms to complete.
997
+ ///
998
+ /// **Default:** 10
999
+ ///
1000
+ /// # Examples
1001
+ ///
1002
+ /// ```
1003
+ /// use tokio::runtime;
1004
+ ///
1005
+ /// let rt = runtime::Builder::new_multi_thread()
1006
+ /// .enable_metrics_poll_count_histogram()
1007
+ /// .metrics_poll_count_histogram_buckets(15)
1008
+ /// .build()
1009
+ /// .unwrap();
1010
+ /// ```
1011
+ pub fn metrics_poll_count_histogram_buckets( & mut self , buckets: usize ) -> & mut Self {
1012
+ self . metrics_poll_count_histogram. num_buckets = buckets;
1013
+ self
1014
+ }
1015
+ }
1016
+
880
1017
fn build_current_thread_runtime ( & mut self ) -> io:: Result < Runtime > {
881
1018
use crate :: runtime:: scheduler:: { self , CurrentThread } ;
882
1019
use crate :: runtime:: { runtime:: Scheduler , Config } ;
@@ -909,6 +1046,7 @@ impl Builder {
909
1046
unhandled_panic : self . unhandled_panic . clone ( ) ,
910
1047
disable_lifo_slot : self . disable_lifo_slot ,
911
1048
seed_generator : seed_generator_1,
1049
+ metrics_poll_count_histogram : self . metrics_poll_count_histogram_builder ( ) ,
912
1050
} ,
913
1051
) ;
914
1052
@@ -922,6 +1060,14 @@ impl Builder {
922
1060
blocking_pool,
923
1061
) )
924
1062
}
1063
+
1064
+ fn metrics_poll_count_histogram_builder ( & self ) -> Option < HistogramBuilder > {
1065
+ if self . metrics_poll_count_histogram_enable {
1066
+ Some ( self . metrics_poll_count_histogram . clone ( ) )
1067
+ } else {
1068
+ None
1069
+ }
1070
+ }
925
1071
}
926
1072
927
1073
cfg_io_driver ! {
@@ -1050,6 +1196,7 @@ cfg_rt_multi_thread! {
1050
1196
unhandled_panic: self . unhandled_panic. clone( ) ,
1051
1197
disable_lifo_slot: self . disable_lifo_slot,
1052
1198
seed_generator: seed_generator_1,
1199
+ metrics_poll_count_histogram: self . metrics_poll_count_histogram_builder( ) ,
1053
1200
} ,
1054
1201
) ;
1055
1202
0 commit comments