1use std::io::{self, Write};
8use std::{fs, path};
9
10use base::cross_process_instant::CrossProcessInstant;
11use profile_traits::time::{ProfilerCategory, TimerMetadata};
12use serde::Serialize;
13
14#[derive(Debug)]
16pub struct TraceDump {
17 file: fs::File,
18}
19
20#[derive(Debug, Serialize)]
21struct TraceEntry {
22 category: ProfilerCategory,
23 metadata: Option<TimerMetadata>,
24
25 #[serde(rename = "startTime")]
26 start_time: u64,
27
28 #[serde(rename = "endTime")]
29 end_time: u64,
30}
31
32impl TraceDump {
33 pub fn new<P>(trace_file_path: P) -> io::Result<TraceDump>
36 where
37 P: AsRef<path::Path>,
38 {
39 let mut file = fs::File::create(trace_file_path)?;
40 write_prologue(&mut file)?;
41 Ok(TraceDump { file })
42 }
43
44 pub fn write_one(
46 &mut self,
47 category: &(ProfilerCategory, Option<TimerMetadata>),
48 start_time: CrossProcessInstant,
49 end_time: CrossProcessInstant,
50 ) {
51 let entry = TraceEntry {
52 category: category.0,
53 metadata: category.1.clone(),
54 start_time: (start_time - CrossProcessInstant::epoch()).whole_nanoseconds() as u64,
55 end_time: (end_time - CrossProcessInstant::epoch()).whole_nanoseconds() as u64,
56 };
57 serde_json::to_writer(&mut self.file, &entry).unwrap();
58 writeln!(&mut self.file, ",").unwrap();
59 }
60}
61
62impl Drop for TraceDump {
63 fn drop(&mut self) {
66 write_epilogue(&mut self.file).unwrap();
67 }
68}
69
70fn write_prologue(file: &mut fs::File) -> io::Result<()> {
71 writeln!(file, "{}", include_str!("./trace-dump-prologue-1.html"))?;
72 writeln!(file, "{}", include_str!("./trace-dump.css"))?;
73 writeln!(file, "{}", include_str!("./trace-dump-prologue-2.html"))
74}
75
76fn write_epilogue(file: &mut fs::File) -> io::Result<()> {
77 writeln!(file, "{}", include_str!("./trace-dump-epilogue-1.html"))?;
78 writeln!(file, "{}", include_str!("./trace-dump.js"))?;
79 writeln!(file, "{}", include_str!("./trace-dump-epilogue-2.html"))
80}