mmtk/util/statistics/
stats.rs1use crate::mmtk::MMTK;
2use crate::util::options::Options;
3use crate::util::statistics::counter::*;
4use crate::util::statistics::Timer;
5use crate::vm::VMBinding;
6
7#[cfg(feature = "perf_counter")]
8use pfm::Perfmon;
9use std::collections::HashMap;
10use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
11use std::sync::Arc;
12use std::sync::Mutex;
13use std::time::Duration;
14
15pub const DEFAULT_NUM_PHASES: usize = 1 << 12;
17pub const MAX_COUNTERS: usize = 100;
18
19pub struct SharedStats {
21 phase: AtomicUsize,
22 gathering_stats: AtomicBool,
23}
24
25impl SharedStats {
26 fn increment_phase(&self) {
27 self.phase.fetch_add(1, Ordering::SeqCst);
28 }
29
30 pub fn get_phase(&self) -> usize {
31 self.phase.load(Ordering::SeqCst)
32 }
33
34 pub fn get_gathering_stats(&self) -> bool {
35 self.gathering_stats.load(Ordering::SeqCst)
36 }
37
38 fn set_gathering_stats(&self, val: bool) {
39 self.gathering_stats.store(val, Ordering::SeqCst);
40 }
41}
42
43pub struct Stats {
48 gc_count: AtomicUsize,
49 total_time: Arc<Mutex<Timer>>,
50 #[cfg(feature = "perf_counter")]
53 perfmon: Perfmon,
54 pub shared: Arc<SharedStats>,
55 counters: Mutex<Vec<Arc<Mutex<dyn Counter + Send>>>>,
56 time_to_yield: Arc<Mutex<LatencySampler>>,
57 pause_time: Arc<Mutex<LatencySampler>>,
58}
59
60impl Stats {
61 #[allow(unused)]
62 pub fn new(options: &Options) -> Self {
63 #[cfg(feature = "perf_counter")]
66 let perfmon = {
67 let mut perfmon: Perfmon = Default::default();
68 perfmon.initialize().expect("Perfmon failed to initialize");
69 perfmon
70 };
71 let shared = Arc::new(SharedStats {
72 phase: AtomicUsize::new(0),
73 gathering_stats: AtomicBool::new(false),
74 });
75 let mut counters: Vec<Arc<Mutex<dyn Counter + Send>>> = vec![];
76 let t = Arc::new(Mutex::new(LongCounter::new(
78 "time".to_string(),
79 shared.clone(),
80 true,
81 false,
82 MonotoneNanoTime {},
83 )));
84 counters.push(t.clone());
85 let time_to_yield = Arc::new(Mutex::new(LatencySampler::new(
87 "time-to-yield",
88 shared.clone(),
89 true,
90 )));
91 counters.push(time_to_yield.clone());
92 let pause_time = Arc::new(Mutex::new(LatencySampler::new(
94 "pause-time",
95 shared.clone(),
96 true,
97 )));
98 counters.push(pause_time.clone());
99 #[cfg(feature = "perf_counter")]
102 for e in &options.phase_perf_events.events {
103 counters.push(Arc::new(Mutex::new(LongCounter::new(
104 e.0.clone(),
105 shared.clone(),
106 true,
107 false,
108 PerfEventDiffable::new(&e.0, *options.perf_exclude_kernel),
109 ))));
110 }
111 Stats {
112 gc_count: AtomicUsize::new(0),
113 total_time: t,
114 #[cfg(feature = "perf_counter")]
115 perfmon,
116 shared,
117 counters: Mutex::new(counters),
118 time_to_yield,
119 pause_time,
120 }
121 }
122
123 pub fn record_time_to_yield(&self, duration: Duration) {
126 self.time_to_yield
127 .lock()
128 .unwrap()
129 .record(duration.as_nanos() as u64);
130 }
131
132 pub fn record_pause_time(&self, duration: Duration) {
135 self.pause_time
136 .lock()
137 .unwrap()
138 .record(duration.as_nanos() as u64);
139 }
140
141 pub fn new_event_counter(
142 &self,
143 name: &str,
144 implicit_start: bool,
145 merge_phases: bool,
146 ) -> Arc<Mutex<EventCounter>> {
147 let mut guard = self.counters.lock().unwrap();
148 let counter = Arc::new(Mutex::new(EventCounter::new(
149 name.to_string(),
150 self.shared.clone(),
151 implicit_start,
152 merge_phases,
153 )));
154 guard.push(counter.clone());
155 counter
156 }
157
158 pub fn new_size_counter(
159 &self,
160 name: &str,
161 implicit_start: bool,
162 merge_phases: bool,
163 ) -> Mutex<SizeCounter> {
164 let u = self.new_event_counter(name, implicit_start, merge_phases);
165 let v = self.new_event_counter(&format!("{}.volume", name), implicit_start, merge_phases);
166 Mutex::new(SizeCounter::new(u, v))
167 }
168
169 pub fn new_timer(
170 &self,
171 name: &str,
172 implicit_start: bool,
173 merge_phases: bool,
174 ) -> Arc<Mutex<Timer>> {
175 let mut guard = self.counters.lock().unwrap();
176 let counter = Arc::new(Mutex::new(Timer::new(
177 name.to_string(),
178 self.shared.clone(),
179 implicit_start,
180 merge_phases,
181 MonotoneNanoTime {},
182 )));
183 guard.push(counter.clone());
184 counter
185 }
186
187 pub fn start_gc(&self) {
188 self.gc_count.fetch_add(1, Ordering::SeqCst);
189 if !self.get_gathering_stats() {
190 return;
191 }
192 let counters = self.counters.lock().unwrap();
193 for counter in &(*counters) {
194 counter.lock().unwrap().phase_change(self.get_phase());
195 }
196 self.shared.increment_phase();
197 }
198
199 pub fn end_gc(&self) {
200 if !self.get_gathering_stats() {
201 return;
202 }
203 let counters = self.counters.lock().unwrap();
204 for counter in &(*counters) {
205 counter.lock().unwrap().phase_change(self.get_phase());
206 }
207 self.shared.increment_phase();
208 }
209
210 pub fn print_stats<VM: VMBinding>(&self, mmtk: &'static MMTK<VM>) {
211 println!(
212 "============================ MMTk Statistics Totals ============================"
213 );
214 let scheduler_stat = mmtk.scheduler.statistics();
215 self.print_column_names(&scheduler_stat);
216 print!("{}\t", self.get_phase() / 2);
217 let counter = self.counters.lock().unwrap();
218 for iter in &(*counter) {
219 let c = iter.lock().unwrap();
220 if c.merge_phases() {
221 c.print_total(None);
222 } else {
223 c.print_total(Some(true));
224 print!("\t");
225 c.print_total(Some(false));
226 }
227 print!("\t");
228 }
229 for value in scheduler_stat.values() {
230 print!("{}\t", value);
231 }
232 println!();
233 print!("Total time: ");
234 self.total_time.lock().unwrap().print_total(None);
235 println!(" ms");
236 println!("------------------------------ End MMTk Statistics -----------------------------")
237 }
238
239 pub fn print_column_names(&self, scheduler_stat: &HashMap<String, String>) {
240 print!("GC\t");
241 let counter = self.counters.lock().unwrap();
242 for iter in &(*counter) {
243 let c = iter.lock().unwrap();
244 if c.merge_phases() {
245 print!("{}\t", c.name());
246 } else {
247 print!("{}.other\t{}.stw\t", c.name(), c.name());
248 }
249 }
250 for name in scheduler_stat.keys() {
251 print!("{}\t", name);
252 }
253 println!();
254 }
255
256 pub fn start_all(&self) {
257 let counters = self.counters.lock().unwrap();
258 if self.get_gathering_stats() {
259 panic!("calling Stats.startAll() while stats running");
260 }
261 self.shared.set_gathering_stats(true);
262
263 for c in &(*counters) {
264 let mut ctr = c.lock().unwrap();
265 if ctr.implicitly_start() {
266 ctr.start();
267 }
268 }
269 }
270
271 pub fn stop_all<VM: VMBinding>(&self, mmtk: &'static MMTK<VM>) {
272 self.stop_all_counters();
273 self.print_stats(mmtk);
274 }
275
276 fn stop_all_counters(&self) {
277 let counters = self.counters.lock().unwrap();
278 for c in &(*counters) {
279 c.lock().unwrap().stop();
280 }
281 self.shared.set_gathering_stats(false);
282 }
283
284 fn get_phase(&self) -> usize {
285 self.shared.get_phase()
286 }
287
288 pub fn get_gathering_stats(&self) -> bool {
289 self.shared.get_gathering_stats()
290 }
291}