1 #![allow(non_camel_case_types)]
3 use rustc_data_structures::sync::Lock;
7 use std::time::{Duration, Instant};
9 use std::sync::mpsc::{Sender};
10 use syntax_pos::{SpanData};
11 use syntax::symbol::{Symbol, sym};
12 use rustc_macros::HashStable;
13 use crate::dep_graph::{DepNode};
14 use crate::session::Session;
19 // The name of the associated type for `Fn` return types.
20 pub const FN_OUTPUT_NAME: Symbol = sym::Output;
22 // Useful type to use with `Result<>` indicate that an error has already
23 // been reported to the user, so no need to continue checking.
24 #[derive(Clone, Copy, Debug, RustcEncodable, RustcDecodable, HashStable)]
25 pub struct ErrorReported;
27 thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0));
29 /// Parameters to the `Dump` variant of type `ProfileQueriesMsg`.
30 #[derive(Clone,Debug)]
31 pub struct ProfQDumpParams {
32 /// A base path for the files we will dump.
34 /// To ensure that the compiler waits for us to finish our dumps.
36 /// Toggle dumping a log file with every `ProfileQueriesMsg`.
37 pub dump_profq_msg_log:bool,
40 #[allow(nonstandard_style)]
41 #[derive(Clone, Debug, PartialEq, Eq)]
43 pub query: &'static str,
44 pub msg: Option<String>,
47 /// A sequence of these messages induce a trace of query-based incremental compilation.
48 // FIXME(matthewhammer): Determine whether we should include cycle detection here or not.
49 #[derive(Clone,Debug)]
50 pub enum ProfileQueriesMsg {
51 /// Begin a timed pass.
55 /// Begin a task (see `dep_graph::graph::with_task`).
59 /// Begin a new query.
60 /// Cannot use `Span` because queries are sent to other thread.
61 QueryBegin(SpanData, QueryMsg),
62 /// Query is satisfied by using an already-known value for the given key.
64 /// Query requires running a provider; providers may nest, permitting queries to nest.
66 /// Query is satisfied by a provider terminating with a value.
68 /// Dump a record of the queries to the given path.
69 Dump(ProfQDumpParams),
70 /// Halt the profiling/monitoring background thread.
74 /// If enabled, send a message to the profile-queries thread.
75 pub fn profq_msg(sess: &Session, msg: ProfileQueriesMsg) {
76 if let Some(s) = sess.profile_channel.borrow().as_ref() {
83 /// Set channel for profile queries channel.
84 pub fn profq_set_chan(sess: &Session, s: Sender<ProfileQueriesMsg>) -> bool {
85 let mut channel = sess.profile_channel.borrow_mut();
86 if channel.is_none() {
94 /// Read the current depth of `time()` calls. This is used to
95 /// encourage indentation across threads.
96 pub fn time_depth() -> usize {
97 TIME_DEPTH.with(|slot| slot.get())
100 /// Sets the current depth of `time()` calls. The idea is to call
101 /// `set_time_depth()` with the result from `time_depth()` in the
103 pub fn set_time_depth(depth: usize) {
104 TIME_DEPTH.with(|slot| slot.set(depth));
107 pub fn time<T, F>(sess: &Session, what: &str, f: F) -> T where
110 time_ext(sess.time_passes(), Some(sess), what, f)
113 pub fn time_ext<T, F>(do_it: bool, sess: Option<&Session>, what: &str, f: F) -> T where
116 if !do_it { return f(); }
118 let old = TIME_DEPTH.with(|slot| {
124 if let Some(sess) = sess {
125 if cfg!(debug_assertions) {
126 profq_msg(sess, ProfileQueriesMsg::TimeBegin(what.to_string()))
129 let start = Instant::now();
131 let dur = start.elapsed();
132 if let Some(sess) = sess {
133 if cfg!(debug_assertions) {
134 profq_msg(sess, ProfileQueriesMsg::TimeEnd)
138 print_time_passes_entry(true, what, dur);
140 TIME_DEPTH.with(|slot| slot.set(old));
145 pub fn print_time_passes_entry(do_it: bool, what: &str, dur: Duration) {
150 let indentation = TIME_DEPTH.with(|slot| slot.get());
152 let mem_string = match get_resident() {
154 let mb = n as f64 / 1_000_000.0;
155 format!("; rss: {}MB", mb.round() as usize)
157 None => String::new(),
159 println!("{}time: {}{}\t{}",
160 " ".repeat(indentation),
161 duration_to_secs_str(dur),
166 // Hack up our own formatting for the duration to make it easier for scripts
167 // to parse (always use the same number of decimal places and the same unit).
168 pub fn duration_to_secs_str(dur: Duration) -> String {
169 const NANOS_PER_SEC: f64 = 1_000_000_000.0;
170 let secs = dur.as_secs() as f64 +
171 dur.subsec_nanos() as f64 / NANOS_PER_SEC;
173 format!("{:.3}", secs)
176 pub fn to_readable_str(mut val: usize) -> String {
177 let mut groups = vec![];
179 let group = val % 1000;
184 groups.push(group.to_string());
187 groups.push(format!("{:03}", group));
196 pub fn record_time<T, F>(accu: &Lock<Duration>, f: F) -> T where
199 let start = Instant::now();
201 let duration = start.elapsed();
202 let mut accu = accu.lock();
203 *accu = *accu + duration;
209 fn get_resident() -> Option<usize> {
213 let contents = fs::read("/proc/self/statm").ok()?;
214 let contents = String::from_utf8(contents).ok()?;
215 let s = contents.split_whitespace().nth(field)?;
216 let npages = s.parse::<usize>().ok()?;
221 fn get_resident() -> Option<usize> {
224 type HANDLE = *mut u8;
228 #[allow(non_snake_case)]
229 struct PROCESS_MEMORY_COUNTERS {
231 PageFaultCount: DWORD,
232 PeakWorkingSetSize: size_t,
233 WorkingSetSize: size_t,
234 QuotaPeakPagedPoolUsage: size_t,
235 QuotaPagedPoolUsage: size_t,
236 QuotaPeakNonPagedPoolUsage: size_t,
237 QuotaNonPagedPoolUsage: size_t,
238 PagefileUsage: size_t,
239 PeakPagefileUsage: size_t,
241 type PPROCESS_MEMORY_COUNTERS = *mut PROCESS_MEMORY_COUNTERS;
242 #[link(name = "psapi")]
244 fn GetCurrentProcess() -> HANDLE;
245 fn GetProcessMemoryInfo(Process: HANDLE,
246 ppsmemCounters: PPROCESS_MEMORY_COUNTERS,
249 let mut pmc: PROCESS_MEMORY_COUNTERS = unsafe { mem::zeroed() };
250 pmc.cb = mem::size_of_val(&pmc) as DWORD;
251 match unsafe { GetProcessMemoryInfo(GetCurrentProcess(), &mut pmc, pmc.cb) } {
253 _ => Some(pmc.WorkingSetSize as usize),
257 pub fn indent<R, F>(op: F) -> R where
261 // Use in conjunction with the log post-processor like `src/etc/indenter`
262 // to make debug output more readable.
265 debug!("<< (Result = {:?})", r);
269 pub struct Indenter {
270 _cannot_construct_outside_of_this_module: (),
273 impl Drop for Indenter {
274 fn drop(&mut self) { debug!("<<"); }
277 pub fn indenter() -> Indenter {
279 Indenter { _cannot_construct_outside_of_this_module: () }