sapient_telemetry/
profiler.rs1use std::fs;
7use std::path::Path;
8use std::sync::Mutex;
9use std::time::{Duration, Instant};
10
11use serde::Serialize;
12
13#[derive(Debug, Clone)]
16pub struct Span {
17 pub name: String,
18 pub category: String,
19 pub start_us: u64,
20 pub dur_us: u64,
21 pub pid: u32,
22 pub tid: u64,
23}
24
25impl Span {
26 pub fn new(
27 name: impl Into<String>,
28 category: impl Into<String>,
29 start: Instant,
30 dur: Duration,
31 ) -> Self {
32 Self {
33 name: name.into(),
34 category: category.into(),
35 start_us: start.elapsed().as_micros() as u64,
36 dur_us: dur.as_micros() as u64,
37 pid: std::process::id(),
38 tid: thread_id(),
39 }
40 }
41}
42
43fn thread_id() -> u64 {
44 use std::collections::hash_map::DefaultHasher;
46 use std::hash::{Hash, Hasher};
47 let mut h = DefaultHasher::new();
48 format!("{:?}", std::thread::current().id()).hash(&mut h);
49 h.finish()
50}
51
52#[derive(Debug, Default)]
56pub struct ChromeTracer {
57 spans: Mutex<Vec<Span>>,
58}
59
60impl ChromeTracer {
61 pub fn new() -> Self {
62 Self::default()
63 }
64
65 pub fn record(&self, span: Span) {
66 self.spans.lock().unwrap().push(span);
67 }
68
69 pub fn record_now(&self, name: impl Into<String>, category: impl Into<String>, dur: Duration) {
70 self.record(Span {
71 name: name.into(),
72 category: category.into(),
73 start_us: 0, dur_us: dur.as_micros() as u64,
75 pid: std::process::id(),
76 tid: thread_id(),
77 });
78 }
79
80 pub fn save(&self, path: &Path) -> std::io::Result<()> {
82 #[derive(Serialize)]
83 struct TraceEvent {
84 name: String,
85 cat: String,
86 ph: char,
87 ts: u64,
88 dur: u64,
89 pid: u32,
90 tid: u64,
91 }
92
93 let spans = self.spans.lock().unwrap();
94 let events: Vec<TraceEvent> = spans
95 .iter()
96 .map(|s| TraceEvent {
97 name: s.name.clone(),
98 cat: s.category.clone(),
99 ph: 'X', ts: s.start_us,
101 dur: s.dur_us,
102 pid: s.pid,
103 tid: s.tid,
104 })
105 .collect();
106
107 #[derive(Serialize)]
108 struct TraceFile {
109 #[serde(rename = "traceEvents")]
110 trace_events: Vec<TraceEvent>,
111 }
112 let json = serde_json::to_string_pretty(&TraceFile {
113 trace_events: events,
114 })
115 .map_err(std::io::Error::other)?;
116
117 fs::write(path, json)
118 }
119}