2 use std::io::{BufWriter, Write};
5 use std::thread::ThreadId;
6 use std::time::{Duration, Instant, SystemTime};
8 use crate::session::config::Options;
10 use rustc_data_structures::fx::FxHashMap;
12 #[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
13 pub enum ProfileCategory {
23 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
24 pub enum ProfilerEvent {
25 QueryStart { query_name: &'static str, category: ProfileCategory, time: u64 },
26 QueryEnd { query_name: &'static str, category: ProfileCategory, time: u64 },
27 GenericActivityStart { category: ProfileCategory, time: u64 },
28 GenericActivityEnd { category: ProfileCategory, time: u64 },
29 IncrementalLoadResultStart { query_name: &'static str, time: u64 },
30 IncrementalLoadResultEnd { query_name: &'static str, time: u64 },
31 QueryCacheHit { query_name: &'static str, category: ProfileCategory, time: u64 },
32 QueryCount { query_name: &'static str, category: ProfileCategory, count: usize, time: u64 },
33 QueryBlockedStart { query_name: &'static str, category: ProfileCategory, time: u64 },
34 QueryBlockedEnd { query_name: &'static str, category: ProfileCategory, time: u64 },
38 fn timestamp(&self) -> u64 {
39 use self::ProfilerEvent::*;
42 QueryStart { time, .. } |
43 QueryEnd { time, .. } |
44 GenericActivityStart { time, .. } |
45 GenericActivityEnd { time, .. } |
46 QueryCacheHit { time, .. } |
47 QueryCount { time, .. } |
48 IncrementalLoadResultStart { time, .. } |
49 IncrementalLoadResultEnd { time, .. } |
50 QueryBlockedStart { time, .. } |
51 QueryBlockedEnd { time, .. } => *time
56 fn thread_id_to_u64(tid: ThreadId) -> u64 {
57 unsafe { mem::transmute::<ThreadId, u64>(tid) }
60 pub struct SelfProfiler {
61 events: FxHashMap<ThreadId, Vec<ProfilerEvent>>,
62 start_time: SystemTime,
63 start_instant: Instant,
67 pub fn new() -> SelfProfiler {
68 let profiler = SelfProfiler {
69 events: Default::default(),
70 start_time: SystemTime::now(),
71 start_instant: Instant::now(),
78 pub fn start_activity(&mut self, category: ProfileCategory) {
79 self.record(ProfilerEvent::GenericActivityStart {
81 time: self.get_time_from_start(),
86 pub fn end_activity(&mut self, category: ProfileCategory) {
87 self.record(ProfilerEvent::GenericActivityEnd {
89 time: self.get_time_from_start(),
94 pub fn record_computed_queries(
96 query_name: &'static str,
97 category: ProfileCategory,
100 self.record(ProfilerEvent::QueryCount {
104 time: self.get_time_from_start(),
109 pub fn record_query_hit(&mut self, query_name: &'static str, category: ProfileCategory) {
110 self.record(ProfilerEvent::QueryCacheHit {
113 time: self.get_time_from_start(),
118 pub fn start_query(&mut self, query_name: &'static str, category: ProfileCategory) {
119 self.record(ProfilerEvent::QueryStart {
122 time: self.get_time_from_start(),
127 pub fn end_query(&mut self, query_name: &'static str, category: ProfileCategory) {
128 self.record(ProfilerEvent::QueryEnd {
131 time: self.get_time_from_start(),
136 pub fn incremental_load_result_start(&mut self, query_name: &'static str) {
137 self.record(ProfilerEvent::IncrementalLoadResultStart {
139 time: self.get_time_from_start(),
144 pub fn incremental_load_result_end(&mut self, query_name: &'static str) {
145 self.record(ProfilerEvent::IncrementalLoadResultEnd {
147 time: self.get_time_from_start(),
152 pub fn query_blocked_start(&mut self, query_name: &'static str, category: ProfileCategory) {
153 self.record(ProfilerEvent::QueryBlockedStart {
156 time: self.get_time_from_start(),
161 pub fn query_blocked_end(&mut self, query_name: &'static str, category: ProfileCategory) {
162 self.record(ProfilerEvent::QueryBlockedEnd {
165 time: self.get_time_from_start(),
170 fn record(&mut self, event: ProfilerEvent) {
171 let thread_id = std::thread::current().id();
172 let events = self.events.entry(thread_id).or_default();
178 fn get_time_from_start(&self) -> u64 {
179 let duration = Instant::now() - self.start_instant;
180 duration.as_nanos() as u64
183 pub fn dump_raw_events(&self, opts: &Options) {
184 use self::ProfilerEvent::*;
186 let pid = process::id();
189 format!("{}.profile_events.json", opts.crate_name.clone().unwrap_or_default());
191 let mut file = BufWriter::new(fs::File::create(filename).unwrap());
193 let threads: Vec<_> =
197 .map(|tid| format!("{}", thread_id_to_u64(*tid)))
205 \"crate_name\": \"{}\",\
206 \"opt_level\": \"{:?}\",\
214 opts.crate_name.clone().unwrap_or_default(),
216 if opts.incremental.is_some() { "true" } else { "false" },
219 let mut is_first = true;
220 for (thread_id, events) in &self.events {
221 let thread_id = thread_id_to_u64(*thread_id);
223 for event in events {
227 writeln!(file, ",").unwrap();
230 let (secs, nanos) = {
231 let time = self.start_time + Duration::from_nanos(event.timestamp());
232 let time_since_unix =
233 time.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default();
234 (time_since_unix.as_secs(), time_since_unix.subsec_nanos())
238 QueryStart { query_name, category, time: _ } =>
242 \"query_name\": \"{}\",\
243 \"category\": \"{:?}\",\
257 QueryEnd { query_name, category, time: _ } =>
261 \"query_name\": \"{}\",\
262 \"category\": \"{:?}\",\
276 GenericActivityStart { category, time: _ } =>
279 \"GenericActivityStart\": {{\
280 \"category\": \"{:?}\",\
293 GenericActivityEnd { category, time: _ } =>
296 \"GenericActivityEnd\": {{\
297 \"category\": \"{:?}\",\
310 QueryCacheHit { query_name, category, time: _ } =>
313 \"QueryCacheHit\": {{\
314 \"query_name\": \"{}\",\
315 \"category\": \"{:?}\",\
329 QueryCount { query_name, category, count, time: _ } =>
333 \"query_name\": \"{}\",\
334 \"category\": \"{:?}\",\
350 IncrementalLoadResultStart { query_name, time: _ } =>
353 \"IncrementalLoadResultStart\": {{\
354 \"query_name\": \"{}\",\
367 IncrementalLoadResultEnd { query_name, time: _ } =>
370 \"IncrementalLoadResultEnd\": {{\
371 \"query_name\": \"{}\",\
384 QueryBlockedStart { query_name, category, time: _ } =>
387 \"QueryBlockedStart\": {{\
388 \"query_name\": \"{}\",\
389 \"category\": \"{:?}\",\
403 QueryBlockedEnd { query_name, category, time: _ } =>
406 \"QueryBlockedEnd\": {{\
407 \"query_name\": \"{}\",\
408 \"category\": \"{:?}\",\
426 write!(file, "] }}").unwrap();