]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT |
223e47cc LB |
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 | ||
1a4d82fc JJ |
11 | #![allow(non_camel_case_types)] |
12 | ||
13 | use std::cell::{RefCell, Cell}; | |
14 | use std::collections::HashMap; | |
c34b1796 | 15 | use std::ffi::CString; |
85aaf69f | 16 | use std::fmt::Debug; |
9cc50fc6 | 17 | use std::hash::{Hash, BuildHasher}; |
1a4d82fc | 18 | use std::iter::repeat; |
c34b1796 | 19 | use std::path::Path; |
9e0c209e | 20 | use std::time::{Duration, Instant}; |
223e47cc | 21 | |
54a0048b SL |
22 | use hir; |
23 | use hir::intravisit; | |
24 | use hir::intravisit::Visitor; | |
1a4d82fc | 25 | |
85aaf69f SL |
26 | // The name of the associated type for `Fn` return types |
27 | pub const FN_OUTPUT_NAME: &'static str = "Output"; | |
28 | ||
1a4d82fc JJ |
29 | // Useful type to use with `Result<>` indicate that an error has already |
30 | // been reported to the user, so no need to continue checking. | |
85aaf69f | 31 | #[derive(Clone, Copy, Debug)] |
1a4d82fc JJ |
32 | pub struct ErrorReported; |
33 | ||
e9174d1e SL |
34 | pub fn time<T, F>(do_it: bool, what: &str, f: F) -> T where |
35 | F: FnOnce() -> T, | |
1a4d82fc | 36 | { |
c34b1796 | 37 | thread_local!(static DEPTH: Cell<usize> = Cell::new(0)); |
e9174d1e | 38 | if !do_it { return f(); } |
1a4d82fc JJ |
39 | |
40 | let old = DEPTH.with(|slot| { | |
41 | let r = slot.get(); | |
42 | slot.set(r + 1); | |
43 | r | |
44 | }); | |
45 | ||
92a42be0 SL |
46 | let start = Instant::now(); |
47 | let rv = f(); | |
48 | let dur = start.elapsed(); | |
223e47cc | 49 | |
c1a9b12d SL |
50 | let mem_string = match get_resident() { |
51 | Some(n) => { | |
52 | let mb = n as f64 / 1_000_000.0; | |
53 | format!("; rss: {}MB", mb.round() as usize) | |
54 | } | |
55 | None => "".to_owned(), | |
56 | }; | |
9e0c209e SL |
57 | println!("{}time: {}{}\t{}", |
58 | repeat(" ").take(old).collect::<String>(), | |
59 | duration_to_secs_str(dur), | |
60 | mem_string, | |
61 | what); | |
d9579d0f | 62 | |
1a4d82fc | 63 | DEPTH.with(|slot| slot.set(old)); |
223e47cc | 64 | |
223e47cc LB |
65 | rv |
66 | } | |
67 | ||
9e0c209e SL |
68 | // Hack up our own formatting for the duration to make it easier for scripts |
69 | // to parse (always use the same number of decimal places and the same unit). | |
70 | pub fn duration_to_secs_str(dur: Duration) -> String { | |
71 | const NANOS_PER_SEC: f64 = 1_000_000_000.0; | |
72 | let secs = dur.as_secs() as f64 + | |
73 | dur.subsec_nanos() as f64 / NANOS_PER_SEC; | |
74 | ||
75 | format!("{:.3}", secs) | |
76 | } | |
77 | ||
78 | pub fn record_time<T, F>(accu: &Cell<Duration>, f: F) -> T where | |
79 | F: FnOnce() -> T, | |
80 | { | |
81 | let start = Instant::now(); | |
82 | let rv = f(); | |
83 | let duration = start.elapsed(); | |
84 | accu.set(duration + accu.get()); | |
85 | rv | |
86 | } | |
87 | ||
e9174d1e SL |
88 | // Like std::macros::try!, but for Option<>. |
89 | macro_rules! option_try( | |
90 | ($e:expr) => (match $e { Some(e) => e, None => return None }) | |
91 | ); | |
92 | ||
c1a9b12d SL |
93 | // Memory reporting |
94 | #[cfg(unix)] | |
95 | fn get_resident() -> Option<usize> { | |
e9174d1e SL |
96 | use std::fs::File; |
97 | use std::io::Read; | |
c1a9b12d | 98 | |
e9174d1e SL |
99 | let field = 1; |
100 | let mut f = option_try!(File::open("/proc/self/statm").ok()); | |
101 | let mut contents = String::new(); | |
102 | option_try!(f.read_to_string(&mut contents).ok()); | |
103 | let s = option_try!(contents.split_whitespace().nth(field)); | |
104 | let npages = option_try!(s.parse::<usize>().ok()); | |
105 | Some(npages * 4096) | |
c1a9b12d SL |
106 | } |
107 | ||
c1a9b12d | 108 | #[cfg(windows)] |
e9174d1e | 109 | fn get_resident() -> Option<usize> { |
92a42be0 SL |
110 | type BOOL = i32; |
111 | type DWORD = u32; | |
112 | type HANDLE = *mut u8; | |
113 | use libc::size_t; | |
c1a9b12d SL |
114 | use std::mem; |
115 | #[repr(C)] #[allow(non_snake_case)] | |
116 | struct PROCESS_MEMORY_COUNTERS { | |
117 | cb: DWORD, | |
118 | PageFaultCount: DWORD, | |
92a42be0 SL |
119 | PeakWorkingSetSize: size_t, |
120 | WorkingSetSize: size_t, | |
121 | QuotaPeakPagedPoolUsage: size_t, | |
122 | QuotaPagedPoolUsage: size_t, | |
123 | QuotaPeakNonPagedPoolUsage: size_t, | |
124 | QuotaNonPagedPoolUsage: size_t, | |
125 | PagefileUsage: size_t, | |
126 | PeakPagefileUsage: size_t, | |
c1a9b12d SL |
127 | } |
128 | type PPROCESS_MEMORY_COUNTERS = *mut PROCESS_MEMORY_COUNTERS; | |
129 | #[link(name = "psapi")] | |
130 | extern "system" { | |
92a42be0 | 131 | fn GetCurrentProcess() -> HANDLE; |
c1a9b12d SL |
132 | fn GetProcessMemoryInfo(Process: HANDLE, |
133 | ppsmemCounters: PPROCESS_MEMORY_COUNTERS, | |
134 | cb: DWORD) -> BOOL; | |
135 | } | |
136 | let mut pmc: PROCESS_MEMORY_COUNTERS = unsafe { mem::zeroed() }; | |
137 | pmc.cb = mem::size_of_val(&pmc) as DWORD; | |
138 | match unsafe { GetProcessMemoryInfo(GetCurrentProcess(), &mut pmc, pmc.cb) } { | |
139 | 0 => None, | |
140 | _ => Some(pmc.WorkingSetSize as usize), | |
141 | } | |
142 | } | |
143 | ||
1a4d82fc | 144 | pub fn indent<R, F>(op: F) -> R where |
85aaf69f | 145 | R: Debug, |
1a4d82fc JJ |
146 | F: FnOnce() -> R, |
147 | { | |
223e47cc LB |
148 | // Use in conjunction with the log post-processor like `src/etc/indenter` |
149 | // to make debug output more readable. | |
150 | debug!(">>"); | |
151 | let r = op(); | |
1a4d82fc | 152 | debug!("<< (Result = {:?})", r); |
223e47cc LB |
153 | r |
154 | } | |
155 | ||
1a4d82fc JJ |
156 | pub struct Indenter { |
157 | _cannot_construct_outside_of_this_module: () | |
223e47cc LB |
158 | } |
159 | ||
1a4d82fc JJ |
160 | impl Drop for Indenter { |
161 | fn drop(&mut self) { debug!("<<"); } | |
223e47cc LB |
162 | } |
163 | ||
1a4d82fc | 164 | pub fn indenter() -> Indenter { |
223e47cc | 165 | debug!(">>"); |
1a4d82fc | 166 | Indenter { _cannot_construct_outside_of_this_module: () } |
223e47cc LB |
167 | } |
168 | ||
e9174d1e | 169 | struct LoopQueryVisitor<P> where P: FnMut(&hir::Expr_) -> bool { |
1a4d82fc JJ |
170 | p: P, |
171 | flag: bool, | |
223e47cc LB |
172 | } |
173 | ||
e9174d1e SL |
174 | impl<'v, P> Visitor<'v> for LoopQueryVisitor<P> where P: FnMut(&hir::Expr_) -> bool { |
175 | fn visit_expr(&mut self, e: &hir::Expr) { | |
1a4d82fc | 176 | self.flag |= (self.p)(&e.node); |
223e47cc LB |
177 | match e.node { |
178 | // Skip inner loops, since a break in the inner loop isn't a | |
179 | // break inside the outer loop | |
e9174d1e | 180 | hir::ExprLoop(..) | hir::ExprWhile(..) => {} |
92a42be0 | 181 | _ => intravisit::walk_expr(self, e) |
223e47cc | 182 | } |
1a4d82fc | 183 | } |
223e47cc LB |
184 | } |
185 | ||
186 | // Takes a predicate p, returns true iff p is true for any subexpressions | |
187 | // of b -- skipping any inner loops (loop, while, loop_body) | |
e9174d1e | 188 | pub fn loop_query<P>(b: &hir::Block, p: P) -> bool where P: FnMut(&hir::Expr_) -> bool { |
1a4d82fc JJ |
189 | let mut v = LoopQueryVisitor { |
190 | p: p, | |
191 | flag: false, | |
223e47cc | 192 | }; |
92a42be0 | 193 | intravisit::walk_block(&mut v, b); |
1a4d82fc JJ |
194 | return v.flag; |
195 | } | |
196 | ||
e9174d1e | 197 | struct BlockQueryVisitor<P> where P: FnMut(&hir::Expr) -> bool { |
1a4d82fc JJ |
198 | p: P, |
199 | flag: bool, | |
223e47cc LB |
200 | } |
201 | ||
e9174d1e SL |
202 | impl<'v, P> Visitor<'v> for BlockQueryVisitor<P> where P: FnMut(&hir::Expr) -> bool { |
203 | fn visit_expr(&mut self, e: &hir::Expr) { | |
1a4d82fc | 204 | self.flag |= (self.p)(e); |
92a42be0 | 205 | intravisit::walk_expr(self, e) |
223e47cc LB |
206 | } |
207 | } | |
208 | ||
1a4d82fc JJ |
209 | // Takes a predicate p, returns true iff p is true for any subexpressions |
210 | // of b -- skipping any inner loops (loop, while, loop_body) | |
e9174d1e | 211 | pub fn block_query<P>(b: &hir::Block, p: P) -> bool where P: FnMut(&hir::Expr) -> bool { |
1a4d82fc JJ |
212 | let mut v = BlockQueryVisitor { |
213 | p: p, | |
214 | flag: false, | |
215 | }; | |
7453a54e | 216 | intravisit::walk_block(&mut v, &b); |
1a4d82fc JJ |
217 | return v.flag; |
218 | } | |
219 | ||
9cc50fc6 SL |
220 | pub trait MemoizationMap { |
221 | type Key: Clone; | |
222 | type Value: Clone; | |
223 | ||
224 | /// If `key` is present in the map, return the valuee, | |
225 | /// otherwise invoke `op` and store the value in the map. | |
226 | /// | |
227 | /// NB: if the receiver is a `DepTrackingMap`, special care is | |
228 | /// needed in the `op` to ensure that the correct edges are | |
229 | /// added into the dep graph. See the `DepTrackingMap` impl for | |
230 | /// more details! | |
231 | fn memoize<OP>(&self, key: Self::Key, op: OP) -> Self::Value | |
232 | where OP: FnOnce() -> Self::Value; | |
233 | } | |
234 | ||
235 | impl<K, V, S> MemoizationMap for RefCell<HashMap<K,V,S>> | |
236 | where K: Hash+Eq+Clone, V: Clone, S: BuildHasher | |
85aaf69f | 237 | { |
9cc50fc6 SL |
238 | type Key = K; |
239 | type Value = V; | |
240 | ||
241 | fn memoize<OP>(&self, key: K, op: OP) -> V | |
242 | where OP: FnOnce() -> V | |
243 | { | |
244 | let result = self.borrow().get(&key).cloned(); | |
245 | match result { | |
246 | Some(result) => result, | |
247 | None => { | |
248 | let result = op(); | |
249 | self.borrow_mut().insert(key, result.clone()); | |
250 | result | |
251 | } | |
85aaf69f SL |
252 | } |
253 | } | |
254 | } | |
c34b1796 AL |
255 | |
256 | #[cfg(unix)] | |
257 | pub fn path2cstr(p: &Path) -> CString { | |
258 | use std::os::unix::prelude::*; | |
259 | use std::ffi::OsStr; | |
260 | let p: &OsStr = p.as_ref(); | |
261 | CString::new(p.as_bytes()).unwrap() | |
262 | } | |
263 | #[cfg(windows)] | |
264 | pub fn path2cstr(p: &Path) -> CString { | |
265 | CString::new(p.to_str().unwrap()).unwrap() | |
1a4d82fc | 266 | } |