1 // Copyright (c) 2023 Huawei Device Co., Ltd. 2 // Licensed under the Apache License, Version 2.0 (the "License"); 3 // you may not use this file except in compliance with the License. 4 // You may obtain a copy of the License at 5 // 6 // http://www.apache.org/licenses/LICENSE-2.0 7 // 8 // Unless required by applicable law or agreed to in writing, software 9 // distributed under the License is distributed on an "AS IS" BASIS, 10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 use crate::executor::async_pool::AsyncPoolSpawner; 15 use crate::executor::{AsyncHandle, Runtime}; 16 17 /// User can get some message from Runtime during running. 18 /// 19 /// # Example 20 /// ```no_run 21 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 22 /// .build() 23 /// .unwrap(); 24 /// let metrics = runtime.metrics(); 25 /// ``` 26 pub struct Metrics<'a> { 27 runtime: &'a Runtime, 28 } 29 30 /// List of workers state. 31 #[derive(Debug)] 32 pub struct WorkList { 33 /// The set of index of the park workers 34 pub park: Vec<usize>, 35 /// The set of index of the active workers 36 pub active: Vec<usize>, 37 } 38 39 impl Metrics<'_> { 40 const ACTIVE_STATE: usize = 3; 41 new(runtime: &Runtime) -> Metrics42 pub(crate) fn new(runtime: &Runtime) -> Metrics { 43 Metrics { runtime } 44 } 45 46 /// Returns workers num 47 /// 48 /// # Example 49 /// ``` 50 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 51 /// .build() 52 /// .unwrap(); 53 /// let metrics = runtime.metrics(); 54 /// println!("Runtime's workers_num:{}", metrics.workers_num()); 55 /// ``` workers_num(&self) -> usize56 pub fn workers_num(&self) -> usize { 57 match &self.runtime.async_spawner { 58 #[cfg(feature = "current_thread_runtime")] 59 AsyncHandle::CurrentThread(_) => 1, 60 AsyncHandle::MultiThread(spawner) => spawner.exe_mng_info.num_workers, 61 } 62 } 63 64 /// Returns park workers num 65 /// 66 /// Runtime build by `new_current_thread()` will return None. 67 /// 68 /// # Example 69 /// ``` 70 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 71 /// .build() 72 /// .unwrap(); 73 /// let metrics = runtime.metrics(); 74 /// println!( 75 /// "Runtime's park_workers_num:{:?}", 76 /// metrics.park_workers_num() 77 /// ); 78 /// ``` park_workers_num(&self) -> Option<usize>79 pub fn park_workers_num(&self) -> Option<usize> { 80 match &self.runtime.async_spawner { 81 #[cfg(feature = "current_thread_runtime")] 82 AsyncHandle::CurrentThread(_) => None, 83 AsyncHandle::MultiThread(spawner) => { 84 Some(Self::workers_state_statistic(spawner).park.len()) 85 } 86 } 87 } 88 89 /// Returns active workers num 90 /// 91 /// Runtime build by `new_current_thread()` will return None. 92 /// 93 /// # Example 94 /// ``` 95 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 96 /// .build() 97 /// .unwrap(); 98 /// let metrics = runtime.metrics(); 99 /// println!( 100 /// "Runtime's active_workers_num:{:?}", 101 /// metrics.active_workers_num() 102 /// ); 103 /// ``` active_workers_num(&self) -> Option<usize>104 pub fn active_workers_num(&self) -> Option<usize> { 105 match &self.runtime.async_spawner { 106 #[cfg(feature = "current_thread_runtime")] 107 AsyncHandle::CurrentThread(_) => None, 108 AsyncHandle::MultiThread(spawner) => { 109 Some(Self::workers_state_statistic(spawner).active.len()) 110 } 111 } 112 } 113 114 /// Returns park workers index list 115 /// 116 /// Runtime build by `new_current_thread()` will return None. 117 /// 118 /// # Example 119 /// ``` 120 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 121 /// .build() 122 /// .unwrap(); 123 /// let metrics = runtime.metrics(); 124 /// println!( 125 /// "Runtime's park_workers_list:{:?}", 126 /// metrics.park_workers_list() 127 /// ); 128 /// ``` park_workers_list(&self) -> Option<Vec<usize>>129 pub fn park_workers_list(&self) -> Option<Vec<usize>> { 130 match &self.runtime.async_spawner { 131 #[cfg(feature = "current_thread_runtime")] 132 AsyncHandle::CurrentThread(_) => None, 133 AsyncHandle::MultiThread(spawner) => Some(Self::workers_state_statistic(spawner).park), 134 } 135 } 136 137 /// Returns active workers index list 138 /// 139 /// Runtime build by `new_current_thread()` will return None. 140 /// 141 /// # Example 142 /// ``` 143 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 144 /// .build() 145 /// .unwrap(); 146 /// let metrics = runtime.metrics(); 147 /// println!( 148 /// "Runtime's active_workers_list:{:?}", 149 /// metrics.active_workers_list() 150 /// ); 151 /// ``` active_workers_list(&self) -> Option<Vec<usize>>152 pub fn active_workers_list(&self) -> Option<Vec<usize>> { 153 match &self.runtime.async_spawner { 154 #[cfg(feature = "current_thread_runtime")] 155 AsyncHandle::CurrentThread(_) => None, 156 AsyncHandle::MultiThread(spawner) => { 157 Some(Self::workers_state_statistic(spawner).active) 158 } 159 } 160 } 161 162 /// Returns park/active workers index list 163 /// 164 /// Runtime build by `new_current_thread()` will return None. 165 /// 166 /// # Example 167 /// ``` 168 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 169 /// .build() 170 /// .unwrap(); 171 /// let metrics = runtime.metrics(); 172 /// println!( 173 /// "Runtime's overall_workers_list:{:?}", 174 /// metrics.overall_workers_list() 175 /// ); 176 /// ``` overall_workers_list(&self) -> Option<WorkList>177 pub fn overall_workers_list(&self) -> Option<WorkList> { 178 match &self.runtime.async_spawner { 179 #[cfg(feature = "current_thread_runtime")] 180 AsyncHandle::CurrentThread(_) => None, 181 AsyncHandle::MultiThread(spawner) => Some(Self::workers_state_statistic(spawner)), 182 } 183 } 184 workers_state_statistic(spawner: &AsyncPoolSpawner) -> WorkList185 fn workers_state_statistic(spawner: &AsyncPoolSpawner) -> WorkList { 186 let mut park = vec![]; 187 let mut active = vec![]; 188 189 let parkers = spawner.exe_mng_info.get_handles().read().unwrap(); 190 for i in 0..parkers.len() { 191 match parkers.get(i).unwrap().get_state() { 192 Self::ACTIVE_STATE => active.push(i), 193 _ => park.push(i), 194 } 195 } 196 197 WorkList { park, active } 198 } 199 200 /// Returns global queue length 201 /// 202 /// # Example 203 /// ``` 204 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 205 /// .build() 206 /// .unwrap(); 207 /// let metrics = runtime.metrics(); 208 /// println!( 209 /// "Runtime's global_queue_length:{}", 210 /// metrics.global_queue_length() 211 /// ); 212 /// ``` global_queue_length(&self) -> usize213 pub fn global_queue_length(&self) -> usize { 214 match &self.runtime.async_spawner { 215 #[cfg(feature = "current_thread_runtime")] 216 AsyncHandle::CurrentThread(spawner) => spawner.scheduler.inner.lock().unwrap().len(), 217 AsyncHandle::MultiThread(spawner) => spawner.exe_mng_info.global.get_len(), 218 } 219 } 220 221 /// Returns the total number of task which has entered global queue 222 /// 223 /// This value will only increment, not decrease. 224 /// 225 /// # Example 226 /// ``` 227 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 228 /// .build() 229 /// .unwrap(); 230 /// let metrics = runtime.metrics(); 231 /// println!( 232 /// "Runtime's global_queue_total_task_count:{}", 233 /// metrics.global_queue_total_task_count() 234 /// ); 235 /// ``` global_queue_total_task_count(&self) -> u64236 pub fn global_queue_total_task_count(&self) -> u64 { 237 match &self.runtime.async_spawner { 238 #[cfg(feature = "current_thread_runtime")] 239 AsyncHandle::CurrentThread(spawner) => spawner 240 .scheduler 241 .count 242 .load(std::sync::atomic::Ordering::Acquire), 243 AsyncHandle::MultiThread(spawner) => spawner.exe_mng_info.global.get_count(), 244 } 245 } 246 247 /// Returns the given worker thread length 248 /// 249 /// Runtime build by `new_current_thread()` will return None. 250 /// 251 /// # Example 252 /// ``` 253 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 254 /// .build() 255 /// .unwrap(); 256 /// let metrics = runtime.metrics(); 257 /// println!("Runtime's worker_task_len:{:?}", metrics.worker_task_len(0)); 258 /// ``` worker_task_len(&self, index: usize) -> Option<usize>259 pub fn worker_task_len(&self, index: usize) -> Option<usize> { 260 match &self.runtime.async_spawner { 261 #[cfg(feature = "current_thread_runtime")] 262 AsyncHandle::CurrentThread(_) => None, 263 AsyncHandle::MultiThread(spawner) => match spawner.get_worker(index) { 264 Ok(worker) => { 265 let len = unsafe { worker.get_inner_ptr().run_queue.len() as usize }; 266 Some(len) 267 } 268 Err(_) => panic!("out of index"), 269 }, 270 } 271 } 272 273 /// Returns the total number of task which has entered the given worker 274 /// thread 275 /// 276 /// This value will only increment, not decrease. 277 /// Runtime build by `new_current_thread()` will return None. 278 /// 279 /// # Example 280 /// ``` 281 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 282 /// .build() 283 /// .unwrap(); 284 /// let metrics = runtime.metrics(); 285 /// println!( 286 /// "Runtime's worker_total_task_count:{:?}", 287 /// metrics.worker_total_task_count(0) 288 /// ); 289 /// ``` worker_total_task_count(&self, index: usize) -> Option<u64>290 pub fn worker_total_task_count(&self, index: usize) -> Option<u64> { 291 match &self.runtime.async_spawner { 292 #[cfg(feature = "current_thread_runtime")] 293 AsyncHandle::CurrentThread(_) => None, 294 AsyncHandle::MultiThread(spawner) => match spawner.get_worker(index) { 295 Ok(worker) => { 296 let len = unsafe { worker.get_inner_ptr().run_queue.count() }; 297 Some(len) 298 } 299 Err(_) => panic!("out of index"), 300 }, 301 } 302 } 303 304 /// Returns the number of task the given worker thread length has been 305 /// polled. 306 /// 307 /// This value will only increment, not decrease. 308 /// Runtime build by `new_current_thread()` will return None. 309 /// 310 /// # Example 311 /// ``` 312 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 313 /// .build() 314 /// .unwrap(); 315 /// let metrics = runtime.metrics(); 316 /// println!( 317 /// "Runtime's worker_poll_count:{:?}", 318 /// metrics.worker_poll_count(0) 319 /// ); 320 /// ``` worker_poll_count(&self, index: usize) -> Option<usize>321 pub fn worker_poll_count(&self, index: usize) -> Option<usize> { 322 match &self.runtime.async_spawner { 323 #[cfg(feature = "current_thread_runtime")] 324 AsyncHandle::CurrentThread(_) => None, 325 AsyncHandle::MultiThread(spawner) => match spawner.get_worker(index) { 326 Ok(worker) => { 327 let len = unsafe { worker.get_inner_ptr().count as usize }; 328 Some(len) 329 } 330 Err(_) => panic!("out of index"), 331 }, 332 } 333 } 334 335 /// Returns the times of steals. 336 /// 337 /// This value will only increment, not decrease. 338 /// Runtime build by `new_current_thread()` will return None. 339 /// 340 /// # Example 341 /// ``` 342 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 343 /// .build() 344 /// .unwrap(); 345 /// let metrics = runtime.metrics(); 346 /// println!("Runtime's steal_times:{:?}", metrics.steal_times()); 347 /// ``` steal_times(&self) -> Option<u64>348 pub fn steal_times(&self) -> Option<u64> { 349 match &self.runtime.async_spawner { 350 #[cfg(feature = "current_thread_runtime")] 351 AsyncHandle::CurrentThread(_) => None, 352 AsyncHandle::MultiThread(spawner) => Some(spawner.exe_mng_info.get_steal_times()), 353 } 354 } 355 356 /// Returns the number of times the given worker get tasks from the global 357 /// queue. 358 /// 359 /// This value will only increment, not decrease. 360 /// Runtime build by `new_current_thread()` will return None. 361 /// 362 /// # Example 363 /// ``` 364 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 365 /// .build() 366 /// .unwrap(); 367 /// let metrics = runtime.metrics(); 368 /// println!( 369 /// "Runtime's worker_get_task_from_global_count:{:?}", 370 /// metrics.worker_get_task_from_global_count(0) 371 /// ); 372 /// ``` worker_get_task_from_global_count(&self, index: usize) -> Option<u64>373 pub fn worker_get_task_from_global_count(&self, index: usize) -> Option<u64> { 374 match &self.runtime.async_spawner { 375 #[cfg(feature = "current_thread_runtime")] 376 AsyncHandle::CurrentThread(_) => None, 377 AsyncHandle::MultiThread(spawner) => match spawner.get_worker(index) { 378 Ok(worker) => { 379 let len = unsafe { worker.get_inner_ptr().run_queue.task_from_global_count() }; 380 Some(len) 381 } 382 Err(_) => panic!("out of index"), 383 }, 384 } 385 } 386 387 /// Returns the number of times the given worker push a task on the global 388 /// queue. 389 /// 390 /// This value will only increment, not decrease. 391 /// Runtime build by `new_current_thread()` will return None. 392 /// 393 /// # Example 394 /// ``` 395 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 396 /// .build() 397 /// .unwrap(); 398 /// let metrics = runtime.metrics(); 399 /// println!( 400 /// "Runtime's worker_push_task_to_global_count:{:?}", 401 /// metrics.worker_push_task_to_global_count(0) 402 /// ); 403 /// ``` worker_push_task_to_global_count(&self, index: usize) -> Option<u64>404 pub fn worker_push_task_to_global_count(&self, index: usize) -> Option<u64> { 405 match &self.runtime.async_spawner { 406 #[cfg(feature = "current_thread_runtime")] 407 AsyncHandle::CurrentThread(_) => None, 408 AsyncHandle::MultiThread(spawner) => match spawner.get_worker(index) { 409 Ok(worker) => { 410 let len = unsafe { worker.get_inner_ptr().run_queue.task_to_global_count() }; 411 Some(len) 412 } 413 Err(_) => panic!("out of index"), 414 }, 415 } 416 } 417 418 /// Returns the number of IO events which has been registered in Driver. 419 /// 420 /// This value will only increment, not decrease. 421 /// 422 /// # Example 423 /// ``` 424 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 425 /// .build() 426 /// .unwrap(); 427 /// let metrics = runtime.metrics(); 428 /// println!( 429 /// "Runtime's fd_registered_count:{}", 430 /// metrics.fd_registered_count() 431 /// ); 432 /// ``` 433 #[cfg(feature = "net")] fd_registered_count(&self) -> u64434 pub fn fd_registered_count(&self) -> u64 { 435 self.runtime.get_handle().get_registered_count() 436 } 437 438 /// Returns the number of IO events which has been readied in Driver. 439 /// 440 /// This value will only increment, not decrease. 441 /// 442 /// # Example 443 /// ``` 444 /// let runtime = ylong_runtime::builder::RuntimeBuilder::new_multi_thread() 445 /// .build() 446 /// .unwrap(); 447 /// let metrics = runtime.metrics(); 448 /// println!( 449 /// "Runtime's io_driver_ready_count:{}", 450 /// metrics.io_driver_ready_count() 451 /// ); 452 /// ``` 453 #[cfg(feature = "net")] io_driver_ready_count(&self) -> u64454 pub fn io_driver_ready_count(&self) -> u64 { 455 self.runtime.get_handle().get_ready_count() 456 } 457 } 458