1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#[macro_use]
extern crate slog;
use slog::Logger;
use std::time;
use std::collections::HashMap;
pub struct TimeReporter {
times: HashMap<&'static str, time::Duration>,
cur_state_time: Option<(&'static str, time::Instant)>,
name: String,
log: Logger,
}
impl TimeReporter {
pub fn new<S : Into<String>>(name: S, log: Logger) -> TimeReporter {
TimeReporter {
times: HashMap::new(),
name: name.into(),
log: log,
cur_state_time: None,
}
}
pub fn start(&mut self, key: &'static str) {
let now = time::Instant::now();
self.save_current(now);
self.cur_state_time = Some((key, now))
}
pub fn start_with<F, R>(&mut self, key :&'static str, f: F) -> R
where F: FnOnce() -> R
{
self.start(key);
f()
}
fn save_current(&mut self, now: time::Instant) {
if let Some((key, prev)) = self.cur_state_time.take() {
*self.times
.entry(key)
.or_insert(time::Duration::new(0, 0)) += now - prev;
}
}
pub fn stop(&mut self) {
let now = time::Instant::now();
self.save_current(now);
}
pub fn finish(self) {}
}
struct TimeReporterDroper<'a> {
reporter: &'a TimeReporter,
}
impl<'a> slog::KV for TimeReporterDroper<'a> {
fn serialize(&self,
_record: &slog::Record,
ser: &mut slog::Serializer)
-> slog::Result {
let mut stats: Vec<(&'static str, time::Duration)> = self.reporter
.times
.iter()
.map(|(&k, &v)| (k, v))
.collect();
stats.sort_by_key(|s| s.1);
ser.emit_arguments(
"name", &format_args!("{}", self.reporter.name)
)?;
for &(state, dur) in stats.iter().rev() {
ser.emit_arguments(
state,
&format_args!("{}",
dur.as_secs() as f64
+ dur.subsec_nanos() as f64 / 1000000000f64)
)?;
}
Ok(())
}
}
impl Drop for TimeReporter {
fn drop(&mut self) {
self.stop();
debug_assert!(self.cur_state_time.is_none());
let lrd = TimeReporterDroper { reporter: &self };
info!(self.log, #"slog-perf", "time report"; lrd)
}
}