parent
99da733f7f
commit
56e434d84d
16 changed files with 208 additions and 474 deletions
|
|
@ -1,14 +1,20 @@
|
|||
use std::borrow::Cow;
|
||||
use std::fs;
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::mem;
|
||||
use std::error::Error;
|
||||
use std::mem::{self, Discriminant};
|
||||
use std::process;
|
||||
use std::thread::ThreadId;
|
||||
use std::time::{Duration, Instant, SystemTime};
|
||||
use std::u32;
|
||||
|
||||
use crate::session::config::Options;
|
||||
use crate::ty::query::QueryName;
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use measureme::{StringId, TimestampKind};
|
||||
|
||||
/// MmapSerializatioSink is faster on macOS and Linux
|
||||
/// but FileSerializationSink is faster on Windows
|
||||
#[cfg(not(windows))]
|
||||
type Profiler = measureme::Profiler<measureme::MmapSerializationSink>;
|
||||
#[cfg(windows)]
|
||||
type Profiler = measureme::Profiler<measureme::FileSerializationSink>;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
|
||||
pub enum ProfileCategory {
|
||||
|
|
@ -35,409 +41,129 @@ pub enum ProfilerEvent {
|
|||
QueryBlockedEnd { query_name: &'static str, category: ProfileCategory, time: u64 },
|
||||
}
|
||||
|
||||
impl ProfilerEvent {
|
||||
fn timestamp(&self) -> u64 {
|
||||
use self::ProfilerEvent::*;
|
||||
|
||||
match self {
|
||||
QueryStart { time, .. } |
|
||||
QueryEnd { time, .. } |
|
||||
GenericActivityStart { time, .. } |
|
||||
GenericActivityEnd { time, .. } |
|
||||
QueryCacheHit { time, .. } |
|
||||
QueryCount { time, .. } |
|
||||
IncrementalLoadResultStart { time, .. } |
|
||||
IncrementalLoadResultEnd { time, .. } |
|
||||
QueryBlockedStart { time, .. } |
|
||||
QueryBlockedEnd { time, .. } => *time
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn thread_id_to_u64(tid: ThreadId) -> u64 {
|
||||
unsafe { mem::transmute::<ThreadId, u64>(tid) }
|
||||
}
|
||||
|
||||
pub struct SelfProfiler {
|
||||
events: FxHashMap<ThreadId, Vec<ProfilerEvent>>,
|
||||
start_time: SystemTime,
|
||||
start_instant: Instant,
|
||||
profiler: Profiler,
|
||||
query_event_kind: StringId,
|
||||
generic_activity_event_kind: StringId,
|
||||
incremental_load_result_event_kind: StringId,
|
||||
query_blocked_event_kind: StringId,
|
||||
query_cache_hit_event_kind: StringId,
|
||||
}
|
||||
|
||||
impl SelfProfiler {
|
||||
pub fn new() -> SelfProfiler {
|
||||
let profiler = SelfProfiler {
|
||||
events: Default::default(),
|
||||
start_time: SystemTime::now(),
|
||||
start_instant: Instant::now(),
|
||||
pub fn new() -> Result<SelfProfiler, Box<dyn Error>> {
|
||||
let filename = format!("pid-{}.rustc_profile", process::id());
|
||||
let path = std::path::Path::new(&filename);
|
||||
let profiler = Profiler::new(path)?;
|
||||
|
||||
let query_event_kind = profiler.alloc_string("Query");
|
||||
let generic_activity_event_kind = profiler.alloc_string("GenericActivity");
|
||||
let incremental_load_result_event_kind = profiler.alloc_string("IncrementalLoadResult");
|
||||
let query_blocked_event_kind = profiler.alloc_string("QueryBlocked");
|
||||
let query_cache_hit_event_kind = profiler.alloc_string("QueryCacheHit");
|
||||
|
||||
Ok(SelfProfiler {
|
||||
profiler,
|
||||
query_event_kind,
|
||||
generic_activity_event_kind,
|
||||
incremental_load_result_event_kind,
|
||||
query_blocked_event_kind,
|
||||
query_cache_hit_event_kind,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_query_name_string_id(query_name: QueryName) -> StringId {
|
||||
let discriminant = unsafe {
|
||||
mem::transmute::<Discriminant<QueryName>, u64>(mem::discriminant(&query_name))
|
||||
};
|
||||
|
||||
profiler
|
||||
StringId::reserved(discriminant as u32)
|
||||
}
|
||||
|
||||
pub fn register_query_name(&self, query_name: QueryName) {
|
||||
let id = SelfProfiler::get_query_name_string_id(query_name);
|
||||
|
||||
self.profiler.alloc_string_with_reserved_id(id, query_name.as_str());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn start_activity(
|
||||
&mut self,
|
||||
category: ProfileCategory,
|
||||
&self,
|
||||
label: impl Into<Cow<'static, str>>,
|
||||
) {
|
||||
self.record(ProfilerEvent::GenericActivityStart {
|
||||
category,
|
||||
label: label.into(),
|
||||
time: self.get_time_from_start(),
|
||||
})
|
||||
self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::Start);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn end_activity(
|
||||
&mut self,
|
||||
category: ProfileCategory,
|
||||
&self,
|
||||
label: impl Into<Cow<'static, str>>,
|
||||
) {
|
||||
self.record(ProfilerEvent::GenericActivityEnd {
|
||||
category,
|
||||
label: label.into(),
|
||||
time: self.get_time_from_start(),
|
||||
})
|
||||
self.record(&label.into(), self.generic_activity_event_kind, TimestampKind::End);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn record_computed_queries(
|
||||
&mut self,
|
||||
query_name: &'static str,
|
||||
category: ProfileCategory,
|
||||
count: usize)
|
||||
{
|
||||
self.record(ProfilerEvent::QueryCount {
|
||||
pub fn record_query_hit(&self, query_name: QueryName) {
|
||||
self.record_query(query_name, self.query_cache_hit_event_kind, TimestampKind::Instant);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn start_query(&self, query_name: QueryName) {
|
||||
self.record_query(query_name, self.query_event_kind, TimestampKind::Start);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn end_query(&self, query_name: QueryName) {
|
||||
self.record_query(query_name, self.query_event_kind, TimestampKind::End);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn incremental_load_result_start(&self, query_name: QueryName) {
|
||||
self.record_query(
|
||||
query_name,
|
||||
category,
|
||||
count,
|
||||
time: self.get_time_from_start(),
|
||||
})
|
||||
self.incremental_load_result_event_kind,
|
||||
TimestampKind::Start
|
||||
);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn record_query_hit(&mut self, query_name: &'static str, category: ProfileCategory) {
|
||||
self.record(ProfilerEvent::QueryCacheHit {
|
||||
query_name,
|
||||
category,
|
||||
time: self.get_time_from_start(),
|
||||
})
|
||||
pub fn incremental_load_result_end(&self, query_name: QueryName) {
|
||||
self.record_query(query_name, self.incremental_load_result_event_kind, TimestampKind::End);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn start_query(&mut self, query_name: &'static str, category: ProfileCategory) {
|
||||
self.record(ProfilerEvent::QueryStart {
|
||||
query_name,
|
||||
category,
|
||||
time: self.get_time_from_start(),
|
||||
});
|
||||
pub fn query_blocked_start(&self, query_name: QueryName) {
|
||||
self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::Start);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn end_query(&mut self, query_name: &'static str, category: ProfileCategory) {
|
||||
self.record(ProfilerEvent::QueryEnd {
|
||||
query_name,
|
||||
category,
|
||||
time: self.get_time_from_start(),
|
||||
})
|
||||
pub fn query_blocked_end(&self, query_name: QueryName) {
|
||||
self.record_query(query_name, self.query_blocked_event_kind, TimestampKind::End);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn incremental_load_result_start(&mut self, query_name: &'static str) {
|
||||
self.record(ProfilerEvent::IncrementalLoadResultStart {
|
||||
query_name,
|
||||
time: self.get_time_from_start(),
|
||||
})
|
||||
fn record(&self, event_id: &str, event_kind: StringId, timestamp_kind: TimestampKind) {
|
||||
let thread_id = thread_id_to_u64(std::thread::current().id());
|
||||
|
||||
let event_id = self.profiler.alloc_string(event_id);
|
||||
self.profiler.record_event(event_kind, event_id, thread_id, timestamp_kind);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn incremental_load_result_end(&mut self, query_name: &'static str) {
|
||||
self.record(ProfilerEvent::IncrementalLoadResultEnd {
|
||||
query_name,
|
||||
time: self.get_time_from_start(),
|
||||
})
|
||||
}
|
||||
fn record_query(
|
||||
&self,
|
||||
query_name: QueryName,
|
||||
event_kind: StringId,
|
||||
timestamp_kind: TimestampKind,
|
||||
) {
|
||||
let dep_node_name = SelfProfiler::get_query_name_string_id(query_name);
|
||||
|
||||
#[inline]
|
||||
pub fn query_blocked_start(&mut self, query_name: &'static str, category: ProfileCategory) {
|
||||
self.record(ProfilerEvent::QueryBlockedStart {
|
||||
query_name,
|
||||
category,
|
||||
time: self.get_time_from_start(),
|
||||
})
|
||||
}
|
||||
let thread_id = thread_id_to_u64(std::thread::current().id());
|
||||
|
||||
#[inline]
|
||||
pub fn query_blocked_end(&mut self, query_name: &'static str, category: ProfileCategory) {
|
||||
self.record(ProfilerEvent::QueryBlockedEnd {
|
||||
query_name,
|
||||
category,
|
||||
time: self.get_time_from_start(),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_time_from_start(&self) -> u64 {
|
||||
let duration = Instant::now() - self.start_instant;
|
||||
duration.as_nanos() as u64
|
||||
}
|
||||
|
||||
pub fn dump_raw_events(&self, opts: &Options) {
|
||||
use self::ProfilerEvent::*;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
let (secs, nanos) = {
|
||||
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())
|
||||
};
|
||||
|
||||
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(),
|
||||
GenericActivityStart { category, label, time: _ } =>
|
||||
write!(file,
|
||||
"{{
|
||||
\"GenericActivityStart\": {{\
|
||||
\"category\": \"{:?}\",\
|
||||
\"label\": \"{}\",\
|
||||
\"time\": {{\
|
||||
\"secs\": {},\
|
||||
\"nanos\": {}\
|
||||
}},\
|
||||
\"thread_id\": {}\
|
||||
}}\
|
||||
}}",
|
||||
category,
|
||||
label,
|
||||
secs,
|
||||
nanos,
|
||||
thread_id,
|
||||
).unwrap(),
|
||||
GenericActivityEnd { category, label, time: _ } =>
|
||||
write!(file,
|
||||
"{{\
|
||||
\"GenericActivityEnd\": {{\
|
||||
\"category\": \"{:?}\",\
|
||||
\"label\": \"{}\",\
|
||||
\"time\": {{\
|
||||
\"secs\": {},\
|
||||
\"nanos\": {}\
|
||||
}},\
|
||||
\"thread_id\": {}\
|
||||
}}\
|
||||
}}",
|
||||
category,
|
||||
label,
|
||||
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,
|
||||
).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
write!(file, "] }}").unwrap();
|
||||
self.profiler.record_event(event_kind, dep_node_name, thread_id, timestamp_kind);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue