]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/time_graph.rs
Auto merge of #43648 - RalfJung:jemalloc-debug, r=alexcrichton
[rust.git] / src / librustc_trans / time_graph.rs
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use std::collections::HashMap;
12 use std::marker::PhantomData;
13 use std::sync::{Arc, Mutex};
14 use std::time::Instant;
15 use std::io::prelude::*;
16 use std::fs::File;
17
18 const OUTPUT_WIDTH_IN_PX: u64 = 1000;
19 const TIME_LINE_HEIGHT_IN_PX: u64 = 7;
20 const TIME_LINE_HEIGHT_STRIDE_IN_PX: usize = 10;
21
22 #[derive(Clone)]
23 struct Timing {
24     start: Instant,
25     end: Instant,
26     work_package_kind: WorkPackageKind,
27 }
28
29 #[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
30 pub struct TimelineId(pub usize);
31
32 #[derive(Clone)]
33 struct PerThread {
34     timings: Vec<Timing>,
35     open_work_package: Option<(Instant, WorkPackageKind)>,
36 }
37
38 #[derive(Clone)]
39 pub struct TimeGraph {
40     data: Arc<Mutex<HashMap<TimelineId, PerThread>>>,
41 }
42
43 #[derive(Clone, Copy)]
44 pub struct WorkPackageKind(pub &'static [&'static str]);
45
46 pub struct RaiiToken {
47     graph: TimeGraph,
48     timeline: TimelineId,
49     // The token must not be Send:
50     _marker: PhantomData<*const ()>
51 }
52
53
54 impl Drop for RaiiToken {
55     fn drop(&mut self) {
56         self.graph.end(self.timeline);
57     }
58 }
59
60 impl TimeGraph {
61     pub fn new() -> TimeGraph {
62         TimeGraph {
63             data: Arc::new(Mutex::new(HashMap::new()))
64         }
65     }
66
67     pub fn start(&self,
68                  timeline: TimelineId,
69                  work_package_kind: WorkPackageKind) -> RaiiToken {
70         {
71             let mut table = self.data.lock().unwrap();
72
73             let data = table.entry(timeline).or_insert(PerThread {
74                 timings: Vec::new(),
75                 open_work_package: None,
76             });
77
78             assert!(data.open_work_package.is_none());
79             data.open_work_package = Some((Instant::now(), work_package_kind));
80         }
81
82         RaiiToken {
83             graph: self.clone(),
84             timeline,
85             _marker: PhantomData,
86         }
87     }
88
89     fn end(&self, timeline: TimelineId) {
90         let end = Instant::now();
91
92         let mut table = self.data.lock().unwrap();
93         let data = table.get_mut(&timeline).unwrap();
94
95         if let Some((start, work_package_kind)) = data.open_work_package {
96             data.timings.push(Timing {
97                 start,
98                 end,
99                 work_package_kind,
100             });
101         } else {
102             bug!("end timing without start?")
103         }
104
105         data.open_work_package = None;
106     }
107
108     pub fn dump(&self, output_filename: &str) {
109         let table = self.data.lock().unwrap();
110
111         for data in table.values() {
112             assert!(data.open_work_package.is_none());
113         }
114
115         let mut timelines: Vec<PerThread> =
116             table.values().map(|data| data.clone()).collect();
117
118         timelines.sort_by_key(|timeline| timeline.timings[0].start);
119
120         let earliest_instant = timelines[0].timings[0].start;
121         let latest_instant = timelines.iter()
122                                        .map(|timeline| timeline.timings
123                                                                .last()
124                                                                .unwrap()
125                                                                .end)
126                                        .max()
127                                        .unwrap();
128         let max_distance = distance(earliest_instant, latest_instant);
129
130         let mut file = File::create(format!("{}.html", output_filename)).unwrap();
131
132         writeln!(file, "<html>").unwrap();
133         writeln!(file, "<head></head>").unwrap();
134         writeln!(file, "<body>").unwrap();
135
136         let mut color = 0;
137
138         for (line_index, timeline) in timelines.iter().enumerate() {
139             let line_top = line_index * TIME_LINE_HEIGHT_STRIDE_IN_PX;
140
141             for span in &timeline.timings {
142                 let start = distance(earliest_instant, span.start);
143                 let end = distance(earliest_instant, span.end);
144
145                 let start = normalize(start, max_distance, OUTPUT_WIDTH_IN_PX);
146                 let end = normalize(end, max_distance, OUTPUT_WIDTH_IN_PX);
147
148                 let colors = span.work_package_kind.0;
149
150                 writeln!(file, "<div style='position:absolute; \
151                                             top:{}px; \
152                                             left:{}px; \
153                                             width:{}px; \
154                                             height:{}px; \
155                                             background:{};'></div>",
156                     line_top,
157                     start,
158                     end - start,
159                     TIME_LINE_HEIGHT_IN_PX,
160                     colors[color % colors.len()]
161                     ).unwrap();
162
163                 color += 1;
164             }
165         }
166
167         writeln!(file, "</body>").unwrap();
168         writeln!(file, "</html>").unwrap();
169     }
170 }
171
172 fn distance(zero: Instant, x: Instant) -> u64 {
173
174     let duration = x.duration_since(zero);
175     (duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64) // / div
176 }
177
178 fn normalize(distance: u64, max: u64, max_pixels: u64) -> u64 {
179     (max_pixels * distance) / max
180 }
181