near_delay_detector/
lib.rs1use cpu_time::ProcessTime;
2use log::{info, warn};
3use std::borrow::Cow;
4use std::time::{Duration, Instant};
5
6struct Snapshot {
7 real_time: Duration,
8 cpu_time: Duration,
9}
10
11struct SnapshotInstant {
12 real_time: Instant,
13 cpu_time: ProcessTime,
14}
15
16pub struct DelayDetector<'a> {
17 min_delay: Duration,
18 msg: Cow<'a, str>,
19 started: Instant,
20 started_cpu_time: ProcessTime,
21 snapshots: Vec<((String, String), Snapshot)>,
22 last_snapshot: Option<(String, SnapshotInstant)>,
23}
24
25impl<'a> DelayDetector<'a> {
26 pub fn new(msg: Cow<'a, str>) -> Self {
27 Self {
28 msg,
29 started: Instant::now(),
30 started_cpu_time: ProcessTime::now(),
31 snapshots: vec![],
32 last_snapshot: None,
33 min_delay: Duration::from_millis(50),
34 }
35 }
36
37 pub fn min_delay(mut self, min_delay: Duration) -> Self {
38 self.min_delay = min_delay;
39 self
40 }
41
42 pub fn snapshot(&mut self, msg: &str) {
43 let now = Instant::now();
44 let cpu_time = ProcessTime::now();
45 if let Some((s, started)) = self.last_snapshot.take() {
46 self.snapshots.push((
47 (s, msg.to_string()),
48 Snapshot {
49 real_time: now - started.real_time,
50 cpu_time: started.cpu_time.elapsed(),
51 },
52 ));
53 }
54 self.last_snapshot = Some((msg.to_string(), SnapshotInstant { real_time: now, cpu_time }));
55 }
56}
57
58impl<'a> Drop for DelayDetector<'a> {
59 fn drop(&mut self) {
60 let elapsed = self.started_cpu_time.elapsed();
61 let elapsed_real = self.started.elapsed();
62 let long_delay = self.min_delay * 10;
63 if self.min_delay < elapsed && elapsed <= long_delay {
64 info!(target: "delay_detector", "Took {:?} cpu_time, {:?} real_time processing {}", elapsed, elapsed_real, self.msg);
65 }
66 if elapsed > long_delay {
67 warn!(target: "delay_detector", "LONG DELAY! Took {:?} cpu_time, {:?} real_time processing {}", elapsed, elapsed_real, self.msg);
68 if self.last_snapshot.is_some() {
69 self.snapshot("end");
70 }
71 self.snapshots.sort_by(|a, b| b.1.cpu_time.cmp(&a.1.cpu_time));
72 for ((s1, s2), Snapshot { cpu_time, real_time }) in self.snapshots.drain(..) {
73 info!(target: "delay_detector", "Took {:?} cpu_time, {:?} real_time between {} and {}", cpu_time, real_time, s1, s2);
74 }
75 }
76 }
77}