19
19
20
20
use std:: collections:: HashMap ;
21
21
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
22
+ use std:: time:: Duration ;
22
23
23
24
use once_cell:: sync:: OnceCell ;
25
+ use prometheus:: { Gauge , IntCounter , IntGauge } ;
24
26
use tokio:: runtime:: Runtime ;
27
+ use tokio_metrics:: { RuntimeMetrics , RuntimeMonitor } ;
28
+
29
+ use crate :: metrics:: { new_counter, new_float_gauge, new_gauge} ;
25
30
26
31
static RUNTIMES : OnceCell < HashMap < RuntimeType , tokio:: runtime:: Runtime > > = OnceCell :: new ( ) ;
27
32
@@ -63,7 +68,7 @@ impl RuntimesConfig {
63
68
}
64
69
65
70
pub fn with_num_cpus ( num_cpus : usize ) -> Self {
66
- // Non blocking task are supposed to be io intensive, and not require many threads...
71
+ // Non blocking task are supposed to be io intensive, and not require many threads...
67
72
let num_threads_non_blocking = if num_cpus > 6 { 2 } else { 1 } ;
68
73
// On the other hand the blocking actors are cpu intensive. We allocate
69
74
// almost all of the threads to them.
@@ -83,7 +88,8 @@ impl Default for RuntimesConfig {
83
88
}
84
89
85
90
fn start_runtimes ( config : RuntimesConfig ) -> HashMap < RuntimeType , Runtime > {
86
- let mut runtimes = HashMap :: default ( ) ;
91
+ let mut runtimes = HashMap :: with_capacity ( 2 ) ;
92
+
87
93
let blocking_runtime = tokio:: runtime:: Builder :: new_multi_thread ( )
88
94
. worker_threads ( config. num_threads_blocking )
89
95
. thread_name_fn ( || {
@@ -94,7 +100,10 @@ fn start_runtimes(config: RuntimesConfig) -> HashMap<RuntimeType, Runtime> {
94
100
. enable_all ( )
95
101
. build ( )
96
102
. unwrap ( ) ;
103
+
104
+ scrape_tokio_runtime_metrics ( blocking_runtime. handle ( ) , "blocking" ) ;
97
105
runtimes. insert ( RuntimeType :: Blocking , blocking_runtime) ;
106
+
98
107
let non_blocking_runtime = tokio:: runtime:: Builder :: new_multi_thread ( )
99
108
. worker_threads ( config. num_threads_non_blocking )
100
109
. thread_name_fn ( || {
@@ -105,7 +114,10 @@ fn start_runtimes(config: RuntimesConfig) -> HashMap<RuntimeType, Runtime> {
105
114
. enable_all ( )
106
115
. build ( )
107
116
. unwrap ( ) ;
117
+
118
+ scrape_tokio_runtime_metrics ( non_blocking_runtime. handle ( ) , "non_blocking" ) ;
108
119
runtimes. insert ( RuntimeType :: NonBlocking , non_blocking_runtime) ;
120
+
109
121
runtimes
110
122
}
111
123
@@ -135,6 +147,69 @@ impl RuntimeType {
135
147
}
136
148
}
137
149
150
+ /// Spawns a background task
151
+ pub fn scrape_tokio_runtime_metrics ( handle : & tokio:: runtime:: Handle , label : & ' static str ) {
152
+ let runtime_monitor = RuntimeMonitor :: new ( handle) ;
153
+ handle. spawn ( async move {
154
+ let mut interval = tokio:: time:: interval ( Duration :: from_secs ( 1 ) ) ;
155
+ let mut prometheus_runtime_metrics = PrometheusRuntimeMetrics :: new ( label) ;
156
+
157
+ for tokio_runtime_metrics in runtime_monitor. intervals ( ) {
158
+ interval. tick ( ) . await ;
159
+ prometheus_runtime_metrics. update ( & tokio_runtime_metrics) ;
160
+ }
161
+ } ) ;
162
+ }
163
+
164
+ struct PrometheusRuntimeMetrics {
165
+ scheduled_tasks : IntGauge ,
166
+ worker_busy_duration_milliseconds_total : IntCounter ,
167
+ worker_busy_ratio : Gauge ,
168
+ worker_threads : IntGauge ,
169
+ }
170
+
171
+ impl PrometheusRuntimeMetrics {
172
+ pub fn new ( label : & ' static str ) -> Self {
173
+ Self {
174
+ scheduled_tasks : new_gauge (
175
+ "tokio_scheduled_tasks" ,
176
+ "The total number of tasks currently scheduled in workers' local queues." ,
177
+ "runtime" ,
178
+ & [ ( "runtime_type" , label) ] ,
179
+ ) ,
180
+ worker_busy_duration_milliseconds_total : new_counter (
181
+ "tokio_worker_busy_duration_milliseconds_total" ,
182
+ " The total amount of time worker threads were busy." ,
183
+ "runtime" ,
184
+ & [ ( "runtime_type" , label) ] ,
185
+ ) ,
186
+ worker_busy_ratio : new_float_gauge (
187
+ "tokio_worker_busy_ratio" ,
188
+ "The ratio of time worker threads were busy since the last time runtime metrics \
189
+ were collected.",
190
+ "runtime" ,
191
+ & [ ( "runtime_type" , label) ] ,
192
+ ) ,
193
+ worker_threads : new_gauge (
194
+ "tokio_worker_threads" ,
195
+ "The number of worker threads used by the runtime." ,
196
+ "runtime" ,
197
+ & [ ( "runtime_type" , label) ] ,
198
+ ) ,
199
+ }
200
+ }
201
+
202
+ pub fn update ( & mut self , runtime_metrics : & RuntimeMetrics ) {
203
+ self . scheduled_tasks
204
+ . set ( runtime_metrics. total_local_queue_depth as i64 ) ;
205
+ self . worker_busy_duration_milliseconds_total
206
+ . inc_by ( runtime_metrics. total_busy_duration . as_millis ( ) as u64 ) ;
207
+ self . worker_busy_ratio . set ( runtime_metrics. busy_ratio ( ) ) ;
208
+ self . worker_threads
209
+ . set ( runtime_metrics. workers_count as i64 ) ;
210
+ }
211
+ }
212
+
138
213
#[ cfg( test) ]
139
214
mod tests {
140
215
use super :: * ;
0 commit comments