]> git.proxmox.com Git - rustc.git/blob - src/librustc/util/common.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / librustc / util / common.rs
1 #![allow(non_camel_case_types)]
2
3 use rustc_data_structures::sync::Lock;
4
5 use std::cell::Cell;
6 use std::fmt::Debug;
7 use std::time::{Duration, Instant};
8
9 use syntax::symbol::{Symbol, sym};
10 use crate::session::Session;
11
12 #[cfg(test)]
13 mod tests;
14
15 // The name of the associated type for `Fn` return types.
16 pub const FN_OUTPUT_NAME: Symbol = sym::Output;
17
18 pub use errors::ErrorReported;
19
20 thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0));
21
22 #[allow(nonstandard_style)]
23 #[derive(Clone, Debug, PartialEq, Eq)]
24 pub struct QueryMsg {
25 pub query: &'static str,
26 pub msg: Option<String>,
27 }
28
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
35 /// Sets the current depth of `time()` calls. The idea is to call
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
42 pub fn time<T, F>(sess: &Session, what: &str, f: F) -> T where
43 F: FnOnce() -> T,
44 {
45 time_ext(sess.time_passes(), what, f)
46 }
47
48 pub fn time_ext<T, F>(do_it: bool, what: &str, f: F) -> T where
49 F: FnOnce() -> T,
50 {
51 if !do_it { return f(); }
52
53 let old = TIME_DEPTH.with(|slot| {
54 let r = slot.get();
55 slot.set(r + 1);
56 r
57 });
58
59 let start = Instant::now();
60 let rv = f();
61 let dur = start.elapsed();
62
63 print_time_passes_entry(true, what, dur);
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
75 let indentation = TIME_DEPTH.with(|slot| slot.get());
76
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 }
82 None => String::new(),
83 };
84 println!("{}time: {}{}\t{}",
85 " ".repeat(indentation),
86 duration_to_secs_str(dur),
87 mem_string,
88 what);
89 }
90
91 pub use rustc_session::utils::duration_to_secs_str;
92
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 {
101 groups.push(group.to_string());
102 break;
103 } else {
104 groups.push(format!("{:03}", group));
105 }
106 }
107
108 groups.reverse();
109
110 groups.join("_")
111 }
112
113 pub fn record_time<T, F>(accu: &Lock<Duration>, f: F) -> T where
114 F: FnOnce() -> T,
115 {
116 let start = Instant::now();
117 let rv = f();
118 let duration = start.elapsed();
119 let mut accu = accu.lock();
120 *accu = *accu + duration;
121 rv
122 }
123
124 // Memory reporting
125 #[cfg(unix)]
126 fn get_resident() -> Option<usize> {
127 use std::fs;
128
129 let field = 1;
130 let contents = fs::read("/proc/self/statm").ok()?;
131 let contents = String::from_utf8(contents).ok()?;
132 let s = contents.split_whitespace().nth(field)?;
133 let npages = s.parse::<usize>().ok()?;
134 Some(npages * 4096)
135 }
136
137 #[cfg(windows)]
138 fn get_resident() -> Option<usize> {
139 type BOOL = i32;
140 type DWORD = u32;
141 type HANDLE = *mut u8;
142 use libc::size_t;
143 use std::mem;
144 #[repr(C)]
145 #[allow(non_snake_case)]
146 struct PROCESS_MEMORY_COUNTERS {
147 cb: DWORD,
148 PageFaultCount: DWORD,
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,
157 }
158 type PPROCESS_MEMORY_COUNTERS = *mut PROCESS_MEMORY_COUNTERS;
159 #[link(name = "psapi")]
160 extern "system" {
161 fn GetCurrentProcess() -> HANDLE;
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
174 pub fn indent<R, F>(op: F) -> R where
175 R: Debug,
176 F: FnOnce() -> R,
177 {
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();
182 debug!("<< (Result = {:?})", r);
183 r
184 }
185
186 pub struct Indenter {
187 _cannot_construct_outside_of_this_module: (),
188 }
189
190 impl Drop for Indenter {
191 fn drop(&mut self) { debug!("<<"); }
192 }
193
194 pub fn indenter() -> Indenter {
195 debug!(">>");
196 Indenter { _cannot_construct_outside_of_this_module: () }
197 }