]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | #![allow(non_camel_case_types)] |
2 | ||
e74abb32 | 3 | use rustc_data_structures::sync::Lock; |
83c7162d | 4 | |
e74abb32 | 5 | use std::cell::Cell; |
85aaf69f | 6 | use std::fmt::Debug; |
9e0c209e | 7 | use std::time::{Duration, Instant}; |
223e47cc | 8 | |
48663c56 | 9 | use syntax::symbol::{Symbol, sym}; |
9fa01778 | 10 | use crate::session::Session; |
041b39d2 | 11 | |
416331ca XL |
12 | #[cfg(test)] |
13 | mod tests; | |
14 | ||
dc9dc135 | 15 | // The name of the associated type for `Fn` return types. |
48663c56 | 16 | pub const FN_OUTPUT_NAME: Symbol = sym::Output; |
85aaf69f | 17 | |
60c5eb7d | 18 | pub use errors::ErrorReported; |
1a4d82fc | 19 | |
32a655c1 SL |
20 | thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0)); |
21 | ||
b7449926 | 22 | #[allow(nonstandard_style)] |
83c7162d XL |
23 | #[derive(Clone, Debug, PartialEq, Eq)] |
24 | pub struct QueryMsg { | |
25 | pub query: &'static str, | |
26 | pub msg: Option<String>, | |
27 | } | |
28 | ||
32a655c1 SL |
29 | /// Read the current depth of `time()` calls. This is used to |
30 | /// encourage indentation across threads. | |
31 | pub fn time_depth() -> usize { | |
32 | TIME_DEPTH.with(|slot| slot.get()) | |
33 | } | |
34 | ||
9fa01778 | 35 | /// Sets the current depth of `time()` calls. The idea is to call |
32a655c1 SL |
36 | /// `set_time_depth()` with the result from `time_depth()` in the |
37 | /// parent thread. | |
38 | pub fn set_time_depth(depth: usize) { | |
39 | TIME_DEPTH.with(|slot| slot.set(depth)); | |
40 | } | |
41 | ||
0531ce1d XL |
42 | pub fn time<T, F>(sess: &Session, what: &str, f: F) -> T where |
43 | F: FnOnce() -> T, | |
44 | { | |
e74abb32 | 45 | time_ext(sess.time_passes(), what, f) |
0531ce1d XL |
46 | } |
47 | ||
e74abb32 | 48 | pub fn time_ext<T, F>(do_it: bool, what: &str, f: F) -> T where |
e9174d1e | 49 | F: FnOnce() -> T, |
1a4d82fc | 50 | { |
e9174d1e | 51 | if !do_it { return f(); } |
1a4d82fc | 52 | |
32a655c1 | 53 | let old = TIME_DEPTH.with(|slot| { |
1a4d82fc JJ |
54 | let r = slot.get(); |
55 | slot.set(r + 1); | |
56 | r | |
57 | }); | |
58 | ||
92a42be0 SL |
59 | let start = Instant::now(); |
60 | let rv = f(); | |
61 | let dur = start.elapsed(); | |
3b2f2976 | 62 | |
416331ca | 63 | print_time_passes_entry(true, what, dur); |
3b2f2976 XL |
64 | |
65 | TIME_DEPTH.with(|slot| slot.set(old)); | |
66 | ||
67 | rv | |
68 | } | |
69 | ||
70 | pub fn print_time_passes_entry(do_it: bool, what: &str, dur: Duration) { | |
71 | if !do_it { | |
72 | return | |
73 | } | |
74 | ||
3b2f2976 | 75 | let indentation = TIME_DEPTH.with(|slot| slot.get()); |
223e47cc | 76 | |
c1a9b12d SL |
77 | let mem_string = match get_resident() { |
78 | Some(n) => { | |
79 | let mb = n as f64 / 1_000_000.0; | |
80 | format!("; rss: {}MB", mb.round() as usize) | |
81 | } | |
b7449926 | 82 | None => String::new(), |
c1a9b12d | 83 | }; |
9e0c209e | 84 | println!("{}time: {}{}\t{}", |
8faf50e0 | 85 | " ".repeat(indentation), |
9e0c209e SL |
86 | duration_to_secs_str(dur), |
87 | mem_string, | |
88 | what); | |
223e47cc LB |
89 | } |
90 | ||
60c5eb7d | 91 | pub use rustc_session::utils::duration_to_secs_str; |
9e0c209e | 92 | |
c30ab7b3 SL |
93 | pub fn to_readable_str(mut val: usize) -> String { |
94 | let mut groups = vec![]; | |
95 | loop { | |
96 | let group = val % 1000; | |
97 | ||
98 | val /= 1000; | |
99 | ||
100 | if val == 0 { | |
8faf50e0 | 101 | groups.push(group.to_string()); |
cc61c64b | 102 | break; |
c30ab7b3 SL |
103 | } else { |
104 | groups.push(format!("{:03}", group)); | |
105 | } | |
106 | } | |
107 | ||
108 | groups.reverse(); | |
109 | ||
110 | groups.join("_") | |
111 | } | |
112 | ||
83c7162d | 113 | pub fn record_time<T, F>(accu: &Lock<Duration>, f: F) -> T where |
9e0c209e SL |
114 | F: FnOnce() -> T, |
115 | { | |
116 | let start = Instant::now(); | |
117 | let rv = f(); | |
118 | let duration = start.elapsed(); | |
83c7162d XL |
119 | let mut accu = accu.lock(); |
120 | *accu = *accu + duration; | |
9e0c209e SL |
121 | rv |
122 | } | |
123 | ||
c1a9b12d SL |
124 | // Memory reporting |
125 | #[cfg(unix)] | |
126 | fn get_resident() -> Option<usize> { | |
2c00a5a8 | 127 | use std::fs; |
c1a9b12d | 128 | |
e9174d1e | 129 | let field = 1; |
0531ce1d XL |
130 | let contents = fs::read("/proc/self/statm").ok()?; |
131 | let contents = String::from_utf8(contents).ok()?; | |
ff7c6d11 XL |
132 | let s = contents.split_whitespace().nth(field)?; |
133 | let npages = s.parse::<usize>().ok()?; | |
e9174d1e | 134 | Some(npages * 4096) |
c1a9b12d SL |
135 | } |
136 | ||
c1a9b12d | 137 | #[cfg(windows)] |
e9174d1e | 138 | fn get_resident() -> Option<usize> { |
92a42be0 SL |
139 | type BOOL = i32; |
140 | type DWORD = u32; | |
141 | type HANDLE = *mut u8; | |
142 | use libc::size_t; | |
c1a9b12d | 143 | use std::mem; |
cc61c64b XL |
144 | #[repr(C)] |
145 | #[allow(non_snake_case)] | |
c1a9b12d SL |
146 | struct PROCESS_MEMORY_COUNTERS { |
147 | cb: DWORD, | |
148 | PageFaultCount: DWORD, | |
92a42be0 SL |
149 | PeakWorkingSetSize: size_t, |
150 | WorkingSetSize: size_t, | |
151 | QuotaPeakPagedPoolUsage: size_t, | |
152 | QuotaPagedPoolUsage: size_t, | |
153 | QuotaPeakNonPagedPoolUsage: size_t, | |
154 | QuotaNonPagedPoolUsage: size_t, | |
155 | PagefileUsage: size_t, | |
156 | PeakPagefileUsage: size_t, | |
c1a9b12d SL |
157 | } |
158 | type PPROCESS_MEMORY_COUNTERS = *mut PROCESS_MEMORY_COUNTERS; | |
159 | #[link(name = "psapi")] | |
160 | extern "system" { | |
92a42be0 | 161 | fn GetCurrentProcess() -> HANDLE; |
c1a9b12d SL |
162 | fn GetProcessMemoryInfo(Process: HANDLE, |
163 | ppsmemCounters: PPROCESS_MEMORY_COUNTERS, | |
164 | cb: DWORD) -> BOOL; | |
165 | } | |
166 | let mut pmc: PROCESS_MEMORY_COUNTERS = unsafe { mem::zeroed() }; | |
167 | pmc.cb = mem::size_of_val(&pmc) as DWORD; | |
168 | match unsafe { GetProcessMemoryInfo(GetCurrentProcess(), &mut pmc, pmc.cb) } { | |
169 | 0 => None, | |
170 | _ => Some(pmc.WorkingSetSize as usize), | |
171 | } | |
172 | } | |
173 | ||
1a4d82fc | 174 | pub fn indent<R, F>(op: F) -> R where |
85aaf69f | 175 | R: Debug, |
1a4d82fc JJ |
176 | F: FnOnce() -> R, |
177 | { | |
223e47cc LB |
178 | // Use in conjunction with the log post-processor like `src/etc/indenter` |
179 | // to make debug output more readable. | |
180 | debug!(">>"); | |
181 | let r = op(); | |
1a4d82fc | 182 | debug!("<< (Result = {:?})", r); |
223e47cc LB |
183 | r |
184 | } | |
185 | ||
1a4d82fc | 186 | pub struct Indenter { |
cc61c64b | 187 | _cannot_construct_outside_of_this_module: (), |
223e47cc LB |
188 | } |
189 | ||
1a4d82fc JJ |
190 | impl Drop for Indenter { |
191 | fn drop(&mut self) { debug!("<<"); } | |
223e47cc LB |
192 | } |
193 | ||
1a4d82fc | 194 | pub fn indenter() -> Indenter { |
223e47cc | 195 | debug!(">>"); |
1a4d82fc | 196 | Indenter { _cannot_construct_outside_of_this_module: () } |
223e47cc | 197 | } |