]> git.proxmox.com Git - rustc.git/blame - src/librustc/util/common.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / librustc / util / common.rs
CommitLineData
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
13use std::cell::{RefCell, Cell};
14use std::collections::HashMap;
c34b1796 15use std::ffi::CString;
85aaf69f 16use std::fmt::Debug;
9cc50fc6 17use std::hash::{Hash, BuildHasher};
1a4d82fc 18use std::iter::repeat;
c34b1796 19use std::path::Path;
9e0c209e 20use std::time::{Duration, Instant};
223e47cc 21
54a0048b
SL
22use hir;
23use hir::intravisit;
24use hir::intravisit::Visitor;
1a4d82fc 25
85aaf69f
SL
26// The name of the associated type for `Fn` return types
27pub 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
32pub struct ErrorReported;
33
e9174d1e
SL
34pub 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).
70pub 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
78pub 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<>.
89macro_rules! option_try(
90 ($e:expr) => (match $e { Some(e) => e, None => return None })
91);
92
c1a9b12d
SL
93// Memory reporting
94#[cfg(unix)]
95fn 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 109fn 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 144pub 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
156pub struct Indenter {
157 _cannot_construct_outside_of_this_module: ()
223e47cc
LB
158}
159
1a4d82fc
JJ
160impl Drop for Indenter {
161 fn drop(&mut self) { debug!("<<"); }
223e47cc
LB
162}
163
1a4d82fc 164pub fn indenter() -> Indenter {
223e47cc 165 debug!(">>");
1a4d82fc 166 Indenter { _cannot_construct_outside_of_this_module: () }
223e47cc
LB
167}
168
e9174d1e 169struct LoopQueryVisitor<P> where P: FnMut(&hir::Expr_) -> bool {
1a4d82fc
JJ
170 p: P,
171 flag: bool,
223e47cc
LB
172}
173
e9174d1e
SL
174impl<'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 188pub 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 197struct BlockQueryVisitor<P> where P: FnMut(&hir::Expr) -> bool {
1a4d82fc
JJ
198 p: P,
199 flag: bool,
223e47cc
LB
200}
201
e9174d1e
SL
202impl<'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 211pub 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
220pub 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
235impl<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)]
257pub 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)]
264pub fn path2cstr(p: &Path) -> CString {
265 CString::new(p.to_str().unwrap()).unwrap()
1a4d82fc 266}