3 use std::io::{BufWriter, Write};
6 use std::thread::ThreadId;
7 use std::time::{Duration, Instant, SystemTime};
9 use crate::session::config::Options;
11 use rustc_data_structures::fx::FxHashMap;
13 #[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
14 pub enum ProfileCategory {
24 #[derive(Clone, Debug, Eq, PartialEq)]
25 pub enum ProfilerEvent {
26 QueryStart { query_name: &'static str, category: ProfileCategory, time: u64 },
27 QueryEnd { query_name: &'static str, category: ProfileCategory, time: u64 },
28 GenericActivityStart { category: ProfileCategory, label: Cow<'static, str>, time: u64 },
29 GenericActivityEnd { category: ProfileCategory, label: Cow<'static, str>, time: u64 },
30 IncrementalLoadResultStart { query_name: &'static str, time: u64 },
31 IncrementalLoadResultEnd { query_name: &'static str, time: u64 },
32 QueryCacheHit { query_name: &'static str, category: ProfileCategory, time: u64 },
33 QueryCount { query_name: &'static str, category: ProfileCategory, count: usize, time: u64 },
34 QueryBlockedStart { query_name: &'static str, category: ProfileCategory, time: u64 },
35 QueryBlockedEnd { query_name: &'static str, category: ProfileCategory, time: u64 },
39 fn timestamp(&self) -> u64 {
40 use self::ProfilerEvent::*;
43 QueryStart { time, .. } |
44 QueryEnd { time, .. } |
45 GenericActivityStart { time, .. } |
46 GenericActivityEnd { time, .. } |
47 QueryCacheHit { time, .. } |
48 QueryCount { time, .. } |
49 IncrementalLoadResultStart { time, .. } |
50 IncrementalLoadResultEnd { time, .. } |
51 QueryBlockedStart { time, .. } |
52 QueryBlockedEnd { time, .. } => *time
57 fn thread_id_to_u64(tid: ThreadId) -> u64 {
58 unsafe { mem::transmute::<ThreadId, u64>(tid) }
61 pub struct SelfProfiler {
62 events: FxHashMap<ThreadId, Vec<ProfilerEvent>>,
63 start_time: SystemTime,
64 start_instant: Instant,
68 pub fn new() -> SelfProfiler {
69 let profiler = SelfProfiler {
70 events: Default::default(),
71 start_time: SystemTime::now(),
72 start_instant: Instant::now(),
79 pub fn start_activity(
81 category: ProfileCategory,
82 label: impl Into<Cow<'static, str>>,
84 self.record(ProfilerEvent::GenericActivityStart {
87 time: self.get_time_from_start(),
94 category: ProfileCategory,
95 label: impl Into<Cow<'static, str>>,
97 self.record(ProfilerEvent::GenericActivityEnd {
100 time: self.get_time_from_start(),
105 pub fn record_computed_queries(
107 query_name: &'static str,
108 category: ProfileCategory,
111 self.record(ProfilerEvent::QueryCount {
115 time: self.get_time_from_start(),
120 pub fn record_query_hit(&mut self, query_name: &'static str, category: ProfileCategory) {
121 self.record(ProfilerEvent::QueryCacheHit {
124 time: self.get_time_from_start(),
129 pub fn start_query(&mut self, query_name: &'static str, category: ProfileCategory) {
130 self.record(ProfilerEvent::QueryStart {
133 time: self.get_time_from_start(),
138 pub fn end_query(&mut self, query_name: &'static str, category: ProfileCategory) {
139 self.record(ProfilerEvent::QueryEnd {
142 time: self.get_time_from_start(),
147 pub fn incremental_load_result_start(&mut self, query_name: &'static str) {
148 self.record(ProfilerEvent::IncrementalLoadResultStart {
150 time: self.get_time_from_start(),
155 pub fn incremental_load_result_end(&mut self, query_name: &'static str) {
156 self.record(ProfilerEvent::IncrementalLoadResultEnd {
158 time: self.get_time_from_start(),
163 pub fn query_blocked_start(&mut self, query_name: &'static str, category: ProfileCategory) {
164 self.record(ProfilerEvent::QueryBlockedStart {
167 time: self.get_time_from_start(),
172 pub fn query_blocked_end(&mut self, query_name: &'static str, category: ProfileCategory) {
173 self.record(ProfilerEvent::QueryBlockedEnd {
176 time: self.get_time_from_start(),
181 fn record(&mut self, event: ProfilerEvent) {
182 let thread_id = std::thread::current().id();
183 let events = self.events.entry(thread_id).or_default();
189 fn get_time_from_start(&self) -> u64 {
190 let duration = Instant::now() - self.start_instant;
191 duration.as_nanos() as u64
194 pub fn dump_raw_events(&self, opts: &Options) {
195 use self::ProfilerEvent::*;
197 let pid = process::id();
200 format!("{}.profile_events.json", opts.crate_name.clone().unwrap_or_default());
202 let mut file = BufWriter::new(fs::File::create(filename).unwrap());
204 let threads: Vec<_> =
208 .map(|tid| format!("{}", thread_id_to_u64(*tid)))
216 \"crate_name\": \"{}\",\
217 \"opt_level\": \"{:?}\",\
225 opts.crate_name.clone().unwrap_or_default(),
227 if opts.incremental.is_some() { "true" } else { "false" },
230 let mut is_first = true;
231 for (thread_id, events) in &self.events {
232 let thread_id = thread_id_to_u64(*thread_id);
234 for event in events {
238 writeln!(file, ",").unwrap();
241 let (secs, nanos) = {
242 let time = self.start_time + Duration::from_nanos(event.timestamp());
243 let time_since_unix =
244 time.duration_since(SystemTime::UNIX_EPOCH).unwrap_or_default();
245 (time_since_unix.as_secs(), time_since_unix.subsec_nanos())
249 QueryStart { query_name, category, time: _ } =>
253 \"query_name\": \"{}\",\
254 \"category\": \"{:?}\",\
268 QueryEnd { query_name, category, time: _ } =>
272 \"query_name\": \"{}\",\
273 \"category\": \"{:?}\",\
287 GenericActivityStart { category, label, time: _ } =>
290 \"GenericActivityStart\": {{\
291 \"category\": \"{:?}\",\
306 GenericActivityEnd { category, label, time: _ } =>
309 \"GenericActivityEnd\": {{\
310 \"category\": \"{:?}\",\
325 QueryCacheHit { query_name, category, time: _ } =>
328 \"QueryCacheHit\": {{\
329 \"query_name\": \"{}\",\
330 \"category\": \"{:?}\",\
344 QueryCount { query_name, category, count, time: _ } =>
348 \"query_name\": \"{}\",\
349 \"category\": \"{:?}\",\
365 IncrementalLoadResultStart { query_name, time: _ } =>
368 \"IncrementalLoadResultStart\": {{\
369 \"query_name\": \"{}\",\
382 IncrementalLoadResultEnd { query_name, time: _ } =>
385 \"IncrementalLoadResultEnd\": {{\
386 \"query_name\": \"{}\",\
399 QueryBlockedStart { query_name, category, time: _ } =>
402 \"QueryBlockedStart\": {{\
403 \"query_name\": \"{}\",\
404 \"category\": \"{:?}\",\
418 QueryBlockedEnd { query_name, category, time: _ } =>
421 \"QueryBlockedEnd\": {{\
422 \"query_name\": \"{}\",\
423 \"category\": \"{:?}\",\
441 write!(file, "] }}").unwrap();