2019-02-13 07:13:30 -06:00
|
|
|
use std::borrow::Cow;
|
2018-06-05 22:05:30 -05:00
|
|
|
use std::fs;
|
2019-02-11 17:11:43 -06:00
|
|
|
use std::io::{BufWriter, Write};
|
|
|
|
use std::mem;
|
|
|
|
use std::process;
|
2019-01-27 12:52:17 -06:00
|
|
|
use std::thread::ThreadId;
|
2019-02-13 04:33:51 -06:00
|
|
|
use std::time::{Duration, Instant, SystemTime};
|
2018-05-19 12:50:58 -05:00
|
|
|
|
2019-02-11 17:11:43 -06:00
|
|
|
use crate::session::config::Options;
|
2019-01-27 12:52:17 -06:00
|
|
|
|
2019-02-25 17:46:53 -06:00
|
|
|
use rustc_data_structures::fx::FxHashMap;
|
|
|
|
|
2019-01-27 12:52:17 -06:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
|
|
|
|
pub enum ProfileCategory {
|
|
|
|
Parsing,
|
|
|
|
Expansion,
|
|
|
|
TypeChecking,
|
|
|
|
BorrowChecking,
|
|
|
|
Codegen,
|
|
|
|
Linking,
|
|
|
|
Other,
|
|
|
|
}
|
|
|
|
|
2019-02-13 07:13:30 -06:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2019-01-27 12:52:17 -06:00
|
|
|
pub enum ProfilerEvent {
|
2019-02-13 04:33:51 -06:00
|
|
|
QueryStart { query_name: &'static str, category: ProfileCategory, time: u64 },
|
|
|
|
QueryEnd { query_name: &'static str, category: ProfileCategory, time: u64 },
|
2019-02-13 07:13:30 -06:00
|
|
|
GenericActivityStart { category: ProfileCategory, label: Cow<'static, str>, time: u64 },
|
|
|
|
GenericActivityEnd { category: ProfileCategory, label: Cow<'static, str>, time: u64 },
|
2019-02-13 04:33:51 -06:00
|
|
|
IncrementalLoadResultStart { query_name: &'static str, time: u64 },
|
|
|
|
IncrementalLoadResultEnd { query_name: &'static str, time: u64 },
|
|
|
|
QueryCacheHit { query_name: &'static str, category: ProfileCategory, time: u64 },
|
|
|
|
QueryCount { query_name: &'static str, category: ProfileCategory, count: usize, time: u64 },
|
|
|
|
QueryBlockedStart { query_name: &'static str, category: ProfileCategory, time: u64 },
|
|
|
|
QueryBlockedEnd { query_name: &'static str, category: ProfileCategory, time: u64 },
|
2019-01-27 12:52:17 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
impl ProfilerEvent {
|
2019-02-13 04:33:51 -06:00
|
|
|
fn timestamp(&self) -> u64 {
|
2019-01-27 12:52:17 -06:00
|
|
|
use self::ProfilerEvent::*;
|
|
|
|
|
|
|
|
match self {
|
2019-02-11 17:11:43 -06:00
|
|
|
QueryStart { time, .. } |
|
|
|
|
QueryEnd { time, .. } |
|
|
|
|
GenericActivityStart { time, .. } |
|
|
|
|
GenericActivityEnd { time, .. } |
|
|
|
|
QueryCacheHit { time, .. } |
|
|
|
|
QueryCount { time, .. } |
|
|
|
|
IncrementalLoadResultStart { time, .. } |
|
|
|
|
IncrementalLoadResultEnd { time, .. } |
|
|
|
|
QueryBlockedStart { time, .. } |
|
|
|
|
QueryBlockedEnd { time, .. } => *time
|
2018-05-19 12:50:58 -05:00
|
|
|
}
|
2019-01-27 12:52:17 -06:00
|
|
|
}
|
|
|
|
}
|
2018-05-19 12:50:58 -05:00
|
|
|
|
2019-02-11 17:11:43 -06:00
|
|
|
fn thread_id_to_u64(tid: ThreadId) -> u64 {
|
|
|
|
unsafe { mem::transmute::<ThreadId, u64>(tid) }
|
2018-05-19 12:50:58 -05:00
|
|
|
}
|
|
|
|
|
2019-02-11 17:11:43 -06:00
|
|
|
pub struct SelfProfiler {
|
2019-02-25 17:46:53 -06:00
|
|
|
events: FxHashMap<ThreadId, Vec<ProfilerEvent>>,
|
2019-02-13 04:33:51 -06:00
|
|
|
start_time: SystemTime,
|
|
|
|
start_instant: Instant,
|
2018-05-19 12:50:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SelfProfiler {
|
|
|
|
pub fn new() -> SelfProfiler {
|
2019-02-13 04:33:51 -06:00
|
|
|
let profiler = SelfProfiler {
|
2019-02-25 17:46:53 -06:00
|
|
|
events: Default::default(),
|
2019-02-13 04:33:51 -06:00
|
|
|
start_time: SystemTime::now(),
|
|
|
|
start_instant: Instant::now(),
|
2018-05-19 12:50:58 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
profiler
|
|
|
|
}
|
|
|
|
|
2019-02-05 10:59:41 -06:00
|
|
|
#[inline]
|
2019-02-13 07:13:30 -06:00
|
|
|
pub fn start_activity(
|
|
|
|
&mut self,
|
|
|
|
category: ProfileCategory,
|
|
|
|
label: impl Into<Cow<'static, str>>,
|
|
|
|
) {
|
2019-01-27 12:52:17 -06:00
|
|
|
self.record(ProfilerEvent::GenericActivityStart {
|
|
|
|
category,
|
2019-02-13 07:13:30 -06:00
|
|
|
label: label.into(),
|
2019-02-13 04:33:51 -06:00
|
|
|
time: self.get_time_from_start(),
|
2019-01-27 12:52:17 -06:00
|
|
|
})
|
|
|
|
}
|
2018-05-19 12:50:58 -05:00
|
|
|
|
2019-02-05 10:59:41 -06:00
|
|
|
#[inline]
|
2019-02-13 07:13:30 -06:00
|
|
|
pub fn end_activity(
|
|
|
|
&mut self,
|
|
|
|
category: ProfileCategory,
|
|
|
|
label: impl Into<Cow<'static, str>>,
|
|
|
|
) {
|
2019-01-27 12:52:17 -06:00
|
|
|
self.record(ProfilerEvent::GenericActivityEnd {
|
|
|
|
category,
|
2019-02-13 07:13:30 -06:00
|
|
|
label: label.into(),
|
2019-02-13 04:33:51 -06:00
|
|
|
time: self.get_time_from_start(),
|
2019-01-27 12:52:17 -06:00
|
|
|
})
|
|
|
|
}
|
2018-05-19 12:50:58 -05:00
|
|
|
|
2019-02-05 10:59:41 -06:00
|
|
|
#[inline]
|
2019-01-27 12:52:17 -06:00
|
|
|
pub fn record_computed_queries(
|
|
|
|
&mut self,
|
|
|
|
query_name: &'static str,
|
|
|
|
category: ProfileCategory,
|
|
|
|
count: usize)
|
|
|
|
{
|
|
|
|
self.record(ProfilerEvent::QueryCount {
|
|
|
|
query_name,
|
|
|
|
category,
|
|
|
|
count,
|
2019-02-13 04:33:51 -06:00
|
|
|
time: self.get_time_from_start(),
|
2019-01-27 12:52:17 -06:00
|
|
|
})
|
2018-05-19 12:50:58 -05:00
|
|
|
}
|
|
|
|
|
2019-02-05 10:59:41 -06:00
|
|
|
#[inline]
|
2019-01-27 12:52:17 -06:00
|
|
|
pub fn record_query_hit(&mut self, query_name: &'static str, category: ProfileCategory) {
|
|
|
|
self.record(ProfilerEvent::QueryCacheHit {
|
|
|
|
query_name,
|
|
|
|
category,
|
2019-02-13 04:33:51 -06:00
|
|
|
time: self.get_time_from_start(),
|
2019-01-27 12:52:17 -06:00
|
|
|
})
|
2018-05-29 22:12:49 -05:00
|
|
|
}
|
|
|
|
|
2019-02-05 10:59:41 -06:00
|
|
|
#[inline]
|
2019-01-27 12:52:17 -06:00
|
|
|
pub fn start_query(&mut self, query_name: &'static str, category: ProfileCategory) {
|
|
|
|
self.record(ProfilerEvent::QueryStart {
|
|
|
|
query_name,
|
|
|
|
category,
|
2019-02-13 04:33:51 -06:00
|
|
|
time: self.get_time_from_start(),
|
2019-01-27 12:52:17 -06:00
|
|
|
});
|
2018-05-29 22:12:49 -05:00
|
|
|
}
|
|
|
|
|
2019-02-05 10:59:41 -06:00
|
|
|
#[inline]
|
2019-01-27 12:52:17 -06:00
|
|
|
pub fn end_query(&mut self, query_name: &'static str, category: ProfileCategory) {
|
|
|
|
self.record(ProfilerEvent::QueryEnd {
|
|
|
|
query_name,
|
|
|
|
category,
|
2019-02-13 04:33:51 -06:00
|
|
|
time: self.get_time_from_start(),
|
2019-01-27 12:52:17 -06:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-02-07 02:58:14 -06:00
|
|
|
#[inline]
|
|
|
|
pub fn incremental_load_result_start(&mut self, query_name: &'static str) {
|
|
|
|
self.record(ProfilerEvent::IncrementalLoadResultStart {
|
|
|
|
query_name,
|
2019-02-13 04:33:51 -06:00
|
|
|
time: self.get_time_from_start(),
|
2019-02-07 02:58:14 -06:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn incremental_load_result_end(&mut self, query_name: &'static str) {
|
|
|
|
self.record(ProfilerEvent::IncrementalLoadResultEnd {
|
|
|
|
query_name,
|
2019-02-13 04:33:51 -06:00
|
|
|
time: self.get_time_from_start(),
|
2019-02-07 02:58:14 -06:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-02-08 10:17:58 -06:00
|
|
|
#[inline]
|
|
|
|
pub fn query_blocked_start(&mut self, query_name: &'static str, category: ProfileCategory) {
|
|
|
|
self.record(ProfilerEvent::QueryBlockedStart {
|
|
|
|
query_name,
|
|
|
|
category,
|
2019-02-13 04:33:51 -06:00
|
|
|
time: self.get_time_from_start(),
|
2019-02-08 10:17:58 -06:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn query_blocked_end(&mut self, query_name: &'static str, category: ProfileCategory) {
|
|
|
|
self.record(ProfilerEvent::QueryBlockedEnd {
|
|
|
|
query_name,
|
|
|
|
category,
|
2019-02-13 04:33:51 -06:00
|
|
|
time: self.get_time_from_start(),
|
2019-02-08 10:17:58 -06:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-02-05 10:59:41 -06:00
|
|
|
#[inline]
|
2019-01-27 12:52:17 -06:00
|
|
|
fn record(&mut self, event: ProfilerEvent) {
|
|
|
|
let thread_id = std::thread::current().id();
|
|
|
|
let events = self.events.entry(thread_id).or_default();
|
|
|
|
|
|
|
|
events.push(event);
|
|
|
|
}
|
|
|
|
|
2019-02-13 04:33:51 -06:00
|
|
|
#[inline]
|
|
|
|
fn get_time_from_start(&self) -> u64 {
|
|
|
|
let duration = Instant::now() - self.start_instant;
|
|
|
|
duration.as_nanos() as u64
|
|
|
|
}
|
|
|
|
|
2019-02-11 17:11:43 -06:00
|
|
|
pub fn dump_raw_events(&self, opts: &Options) {
|
2019-01-27 12:52:17 -06:00
|
|
|
use self::ProfilerEvent::*;
|
|
|
|
|
2019-02-11 17:11:43 -06:00
|
|
|
let pid = process::id();
|
|
|
|
|
|
|
|
let filename =
|
|
|
|
format!("{}.profile_events.json", opts.crate_name.clone().unwrap_or_default());
|
|
|
|
|
|
|
|
let mut file = BufWriter::new(fs::File::create(filename).unwrap());
|
|
|
|
|
|
|
|
let threads: Vec<_> =
|
|
|
|
self.events
|
|
|
|
.keys()
|
|
|
|
.into_iter()
|
|
|
|
.map(|tid| format!("{}", thread_id_to_u64(*tid)))
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
write!(file,
|
|
|
|
"{{\
|
|
|
|
\"processes\": {{\
|
|
|
|
\"{}\": {{\
|
|
|
|
\"threads\": [{}],\
|
|
|
|
\"crate_name\": \"{}\",\
|
|
|
|
\"opt_level\": \"{:?}\",\
|
|
|
|
\"incremental\": {}\
|
|
|
|
}}\
|
|
|
|
}},\
|
|
|
|
\"events\": [\
|
|
|
|
",
|
|
|
|
pid,
|
|
|
|
threads.join(","),
|
|
|
|
opts.crate_name.clone().unwrap_or_default(),
|
|
|
|
opts.optimize,
|
|
|
|
if opts.incremental.is_some() { "true" } else { "false" },
|
|
|
|
).unwrap();
|
|
|
|
|
|
|
|
let mut is_first = true;
|
|
|
|
for (thread_id, events) in &self.events {
|
|
|
|
let thread_id = thread_id_to_u64(*thread_id);
|
|
|
|
|
|
|
|
for event in events {
|
|
|
|
if is_first {
|
|
|
|
is_first = false;
|
|
|
|
} else {
|
|
|
|
writeln!(file, ",").unwrap();
|
2019-01-27 12:52:17 -06:00
|
|
|
}
|
2018-05-19 12:50:58 -05:00
|
|
|
|
2019-02-11 17:11:43 -06:00
|
|
|
let (secs, nanos) = {
|
2019-02-13 04:33:51 -06:00
|
|
|
let time = self.start_time + Duration::from_nanos(event.timestamp());
|
|
|
|
let time_since_unix =
|
|
|
|
time.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default();
|
|
|
|
(time_since_unix.as_secs(), time_since_unix.subsec_nanos())
|
2019-02-11 17:11:43 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
match event {
|
|
|
|
QueryStart { query_name, category, time: _ } =>
|
|
|
|
write!(file,
|
|
|
|
"{{ \
|
|
|
|
\"QueryStart\": {{ \
|
|
|
|
\"query_name\": \"{}\",\
|
|
|
|
\"category\": \"{:?}\",\
|
|
|
|
\"time\": {{\
|
|
|
|
\"secs\": {},\
|
|
|
|
\"nanos\": {}\
|
|
|
|
}},\
|
|
|
|
\"thread_id\": {}\
|
|
|
|
}}\
|
|
|
|
}}",
|
|
|
|
query_name,
|
|
|
|
category,
|
|
|
|
secs,
|
|
|
|
nanos,
|
|
|
|
thread_id,
|
|
|
|
).unwrap(),
|
|
|
|
QueryEnd { query_name, category, time: _ } =>
|
|
|
|
write!(file,
|
|
|
|
"{{\
|
|
|
|
\"QueryEnd\": {{\
|
|
|
|
\"query_name\": \"{}\",\
|
|
|
|
\"category\": \"{:?}\",\
|
|
|
|
\"time\": {{\
|
|
|
|
\"secs\": {},\
|
|
|
|
\"nanos\": {}\
|
|
|
|
}},\
|
|
|
|
\"thread_id\": {}\
|
|
|
|
}}\
|
|
|
|
}}",
|
|
|
|
query_name,
|
|
|
|
category,
|
|
|
|
secs,
|
|
|
|
nanos,
|
|
|
|
thread_id,
|
|
|
|
).unwrap(),
|
2019-02-13 07:13:30 -06:00
|
|
|
GenericActivityStart { category, label, time: _ } =>
|
2019-02-11 17:11:43 -06:00
|
|
|
write!(file,
|
|
|
|
"{{
|
|
|
|
\"GenericActivityStart\": {{\
|
|
|
|
\"category\": \"{:?}\",\
|
2019-02-13 07:13:30 -06:00
|
|
|
\"label\": \"{}\",\
|
2019-02-11 17:11:43 -06:00
|
|
|
\"time\": {{\
|
|
|
|
\"secs\": {},\
|
|
|
|
\"nanos\": {}\
|
|
|
|
}},\
|
|
|
|
\"thread_id\": {}\
|
|
|
|
}}\
|
|
|
|
}}",
|
|
|
|
category,
|
2019-02-13 07:13:30 -06:00
|
|
|
label,
|
2019-02-11 17:11:43 -06:00
|
|
|
secs,
|
|
|
|
nanos,
|
|
|
|
thread_id,
|
|
|
|
).unwrap(),
|
2019-02-13 07:13:30 -06:00
|
|
|
GenericActivityEnd { category, label, time: _ } =>
|
2019-02-11 17:11:43 -06:00
|
|
|
write!(file,
|
|
|
|
"{{\
|
|
|
|
\"GenericActivityEnd\": {{\
|
|
|
|
\"category\": \"{:?}\",\
|
2019-02-13 07:13:30 -06:00
|
|
|
\"label\": \"{}\",\
|
2019-02-11 17:11:43 -06:00
|
|
|
\"time\": {{\
|
|
|
|
\"secs\": {},\
|
|
|
|
\"nanos\": {}\
|
|
|
|
}},\
|
|
|
|
\"thread_id\": {}\
|
|
|
|
}}\
|
|
|
|
}}",
|
|
|
|
category,
|
2019-02-13 07:13:30 -06:00
|
|
|
label,
|
2019-02-11 17:11:43 -06:00
|
|
|
secs,
|
|
|
|
nanos,
|
|
|
|
thread_id,
|
|
|
|
).unwrap(),
|
|
|
|
QueryCacheHit { query_name, category, time: _ } =>
|
|
|
|
write!(file,
|
|
|
|
"{{\
|
|
|
|
\"QueryCacheHit\": {{\
|
|
|
|
\"query_name\": \"{}\",\
|
|
|
|
\"category\": \"{:?}\",\
|
|
|
|
\"time\": {{\
|
|
|
|
\"secs\": {},\
|
|
|
|
\"nanos\": {}\
|
|
|
|
}},\
|
|
|
|
\"thread_id\": {}\
|
|
|
|
}}\
|
|
|
|
}}",
|
|
|
|
query_name,
|
|
|
|
category,
|
|
|
|
secs,
|
|
|
|
nanos,
|
|
|
|
thread_id,
|
|
|
|
).unwrap(),
|
|
|
|
QueryCount { query_name, category, count, time: _ } =>
|
|
|
|
write!(file,
|
|
|
|
"{{\
|
|
|
|
\"QueryCount\": {{\
|
|
|
|
\"query_name\": \"{}\",\
|
|
|
|
\"category\": \"{:?}\",\
|
|
|
|
\"count\": {},\
|
|
|
|
\"time\": {{\
|
|
|
|
\"secs\": {},\
|
|
|
|
\"nanos\": {}\
|
|
|
|
}},\
|
|
|
|
\"thread_id\": {}\
|
|
|
|
}}\
|
|
|
|
}}",
|
|
|
|
query_name,
|
|
|
|
category,
|
|
|
|
count,
|
|
|
|
secs,
|
|
|
|
nanos,
|
|
|
|
thread_id,
|
|
|
|
).unwrap(),
|
|
|
|
IncrementalLoadResultStart { query_name, time: _ } =>
|
|
|
|
write!(file,
|
|
|
|
"{{\
|
|
|
|
\"IncrementalLoadResultStart\": {{\
|
|
|
|
\"query_name\": \"{}\",\
|
|
|
|
\"time\": {{\
|
|
|
|
\"secs\": {},\
|
|
|
|
\"nanos\": {}\
|
|
|
|
}},\
|
|
|
|
\"thread_id\": {}\
|
|
|
|
}}\
|
|
|
|
}}",
|
|
|
|
query_name,
|
|
|
|
secs,
|
|
|
|
nanos,
|
|
|
|
thread_id,
|
|
|
|
).unwrap(),
|
|
|
|
IncrementalLoadResultEnd { query_name, time: _ } =>
|
|
|
|
write!(file,
|
|
|
|
"{{\
|
|
|
|
\"IncrementalLoadResultEnd\": {{\
|
|
|
|
\"query_name\": \"{}\",\
|
|
|
|
\"time\": {{\
|
|
|
|
\"secs\": {},\
|
|
|
|
\"nanos\": {}\
|
|
|
|
}},\
|
|
|
|
\"thread_id\": {}\
|
|
|
|
}}\
|
|
|
|
}}",
|
|
|
|
query_name,
|
|
|
|
secs,
|
|
|
|
nanos,
|
|
|
|
thread_id,
|
|
|
|
).unwrap(),
|
|
|
|
QueryBlockedStart { query_name, category, time: _ } =>
|
|
|
|
write!(file,
|
|
|
|
"{{\
|
|
|
|
\"QueryBlockedStart\": {{\
|
|
|
|
\"query_name\": \"{}\",\
|
|
|
|
\"category\": \"{:?}\",\
|
|
|
|
\"time\": {{\
|
|
|
|
\"secs\": {},\
|
|
|
|
\"nanos\": {}\
|
|
|
|
}},\
|
|
|
|
\"thread_id\": {}\
|
|
|
|
}}\
|
|
|
|
}}",
|
|
|
|
query_name,
|
|
|
|
category,
|
|
|
|
secs,
|
|
|
|
nanos,
|
|
|
|
thread_id,
|
|
|
|
).unwrap(),
|
|
|
|
QueryBlockedEnd { query_name, category, time: _ } =>
|
|
|
|
write!(file,
|
|
|
|
"{{\
|
|
|
|
\"QueryBlockedEnd\": {{\
|
|
|
|
\"query_name\": \"{}\",\
|
|
|
|
\"category\": \"{:?}\",\
|
|
|
|
\"time\": {{\
|
|
|
|
\"secs\": {},\
|
|
|
|
\"nanos\": {}\
|
|
|
|
}},\
|
|
|
|
\"thread_id\": {}\
|
|
|
|
}}\
|
|
|
|
}}",
|
|
|
|
query_name,
|
|
|
|
category,
|
|
|
|
secs,
|
|
|
|
nanos,
|
|
|
|
thread_id,
|
2019-02-13 07:13:30 -06:00
|
|
|
).unwrap(),
|
2019-01-27 12:52:17 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-05-19 12:50:58 -05:00
|
|
|
|
2019-02-11 17:11:43 -06:00
|
|
|
write!(file, "] }}").unwrap();
|
2018-06-05 22:05:30 -05:00
|
|
|
}
|
2018-06-20 06:57:22 -05:00
|
|
|
}
|