mmtk/scheduler/
work_counter.rs1use std::time::Instant;
8
9#[derive(Copy, Clone, Debug)]
13pub(super) struct WorkCounterBase {
14 pub(super) total: f64,
15 pub(super) min: f64,
16 pub(super) max: f64,
17}
18
19pub(super) trait WorkCounterClone {
21 fn clone_box(&self) -> Box<dyn WorkCounter>;
23}
24
25impl<T: 'static + WorkCounter + Clone> WorkCounterClone for T {
26 fn clone_box(&self) -> Box<dyn WorkCounter> {
27 Box::new(self.clone())
28 }
29}
30
31pub(super) trait WorkCounter: WorkCounterClone + std::fmt::Debug + Send {
38 fn start(&mut self);
41 fn stop(&mut self);
43 fn name(&self) -> String;
45 fn get_base(&self) -> &WorkCounterBase;
47}
48
49impl Clone for Box<dyn WorkCounter> {
50 fn clone(&self) -> Box<dyn WorkCounter> {
51 self.clone_box()
52 }
53}
54
55impl Default for WorkCounterBase {
56 fn default() -> Self {
57 WorkCounterBase {
58 total: 0.0,
59 min: f64::INFINITY,
60 max: f64::NEG_INFINITY,
61 }
62 }
63}
64
65impl WorkCounterBase {
66 pub(super) fn merge(&self, other: &Self) -> Self {
69 let min = self.min.min(other.min);
70 let max = self.max.max(other.max);
71 let total = self.total + other.total;
72 WorkCounterBase { total, min, max }
73 }
74
75 pub(super) fn merge_inplace(&mut self, other: &Self) {
78 self.min = self.min.min(other.min);
79 self.max = self.max.max(other.max);
80 self.total += other.total;
81 }
82
83 pub(super) fn merge_val(&mut self, val: f64) {
85 self.min = self.min.min(val);
86 self.max = self.max.max(val);
87 self.total += val;
88 }
89}
90
91#[derive(Copy, Clone, Debug)]
95pub(super) struct WorkDuration {
96 base: WorkCounterBase,
97 start_value: Option<Instant>,
98 running: bool,
99}
100
101impl WorkDuration {
102 pub(super) fn new() -> Self {
103 WorkDuration {
104 base: Default::default(),
105 start_value: None,
106 running: false,
107 }
108 }
109}
110
111impl WorkCounter for WorkDuration {
112 fn start(&mut self) {
113 self.start_value = Some(Instant::now());
114 self.running = true;
115 }
116
117 fn stop(&mut self) {
118 let duration = self.start_value.unwrap().elapsed().as_nanos() as f64;
119 self.base.merge_val(duration);
120 }
121
122 fn name(&self) -> String {
123 "time".to_owned()
124 }
125
126 fn get_base(&self) -> &WorkCounterBase {
127 &self.base
128 }
129}
130
131#[cfg(feature = "perf_counter")]
132mod perf_event {
133 use super::*;
138 use libc::{c_int, pid_t};
139 use pfm::PerfEvent;
140 use std::fmt;
141
142 #[derive(Clone)]
144 pub struct WorkPerfEvent {
145 base: WorkCounterBase,
146 running: bool,
147 event_name: String,
148 pe: PerfEvent,
149 }
150
151 impl WorkPerfEvent {
152 pub fn new(name: &str, pid: pid_t, cpu: c_int, exclude_kernel: bool) -> WorkPerfEvent {
160 let mut pe = PerfEvent::new(name, false)
161 .unwrap_or_else(|_| panic!("Failed to create perf event {}", name));
162 pe.set_exclude_kernel(exclude_kernel as u64);
163 pe.open(pid, cpu)
164 .unwrap_or_else(|_| panic!("Failed to open perf event {}", name));
165 WorkPerfEvent {
166 base: Default::default(),
167 running: false,
168 event_name: name.to_string(),
169 pe,
170 }
171 }
172 }
173
174 impl fmt::Debug for WorkPerfEvent {
175 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
176 f.debug_struct("WorkPerfEvent")
177 .field("base", &self.base)
178 .field("running", &self.running)
179 .field("event_name", &self.event_name)
180 .finish()
181 }
182 }
183
184 impl WorkCounter for WorkPerfEvent {
185 fn start(&mut self) {
186 self.running = true;
187 self.pe.reset().expect("Failed to reset perf event");
188 self.pe.enable().expect("Failed to enable perf event");
189 }
190 fn stop(&mut self) {
191 self.running = true;
192 let perf_event_value = self.pe.read().unwrap();
193 self.base.merge_val(perf_event_value.value as f64);
194 assert_eq!(perf_event_value.time_enabled, perf_event_value.time_running);
196 self.pe.disable().expect("Failed to disable perf event");
197 }
198 fn name(&self) -> String {
199 self.event_name.to_owned()
200 }
201 fn get_base(&self) -> &WorkCounterBase {
202 &self.base
203 }
204 }
205}
206
207#[cfg(feature = "perf_counter")]
208pub(super) use perf_event::WorkPerfEvent;