puffin/
global_profiler.rs1use std::{collections::BTreeMap, sync::Arc};
2
3use once_cell::sync::Lazy;
4
5use crate::{
6 fetch_add_scope_id, Error, FrameData, FrameIndex, FrameSinkId, ScopeCollection, ScopeDetails,
7 ScopeId, StreamInfo, StreamInfoRef, ThreadInfo,
8};
9
10pub type FrameSink = Box<dyn Fn(Arc<FrameData>) + Send>;
12
13pub struct GlobalProfiler {
16 current_frame_index: FrameIndex,
17 current_frame: BTreeMap<ThreadInfo, StreamInfo>,
18
19 next_sink_id: FrameSinkId,
20 sinks: std::collections::HashMap<FrameSinkId, FrameSink>,
21 propagate_all_scope_details: bool,
23 new_scopes: Vec<Arc<ScopeDetails>>,
25 scope_collection: ScopeCollection,
28}
29
30impl Default for GlobalProfiler {
31 fn default() -> Self {
32 Self {
33 current_frame_index: 0,
34 current_frame: Default::default(),
35 next_sink_id: FrameSinkId(1),
36 sinks: Default::default(),
37 propagate_all_scope_details: Default::default(),
38 new_scopes: Default::default(),
39 scope_collection: Default::default(),
40 }
41 }
42}
43
44impl GlobalProfiler {
45 pub fn lock() -> parking_lot::MutexGuard<'static, Self> {
47 static GLOBAL_PROFILER: Lazy<parking_lot::Mutex<GlobalProfiler>> =
48 Lazy::new(Default::default);
49 GLOBAL_PROFILER.lock()
50 }
51
52 pub fn new_frame(&mut self) {
59 let current_frame_index = self.current_frame_index;
60 self.current_frame_index += 1;
61
62 let mut scope_deltas = Vec::with_capacity(self.new_scopes.len());
63
64 for scope_detail in self.new_scopes.drain(..) {
66 scope_deltas.push(scope_detail);
67 }
68
69 let current_frame_scope = std::mem::take(&mut self.current_frame);
70
71 let propagate_full_delta = std::mem::take(&mut self.propagate_all_scope_details);
74
75 if propagate_full_delta {
76 scope_deltas.extend(self.scope_collection.scopes_by_id().values().cloned());
77 }
78
79 let new_frame = match FrameData::new(
80 current_frame_index,
81 current_frame_scope,
82 scope_deltas,
83 propagate_full_delta,
84 ) {
85 Ok(new_frame) => Arc::new(new_frame),
86 Err(Error::Empty) => {
87 return; }
89 Err(err) => {
90 eprintln!("puffin ERROR: Bad frame: {err:?}");
91 return;
92 }
93 };
94
95 self.add_frame(new_frame);
96 }
97
98 pub fn add_frame(&mut self, new_frame: Arc<FrameData>) {
100 for delta in &new_frame.scope_delta {
101 self.scope_collection.insert(delta.clone());
102 }
103
104 for sink in self.sinks.values() {
105 sink(new_frame.clone());
106 }
107 }
108
109 pub fn register_user_scopes(&mut self, scopes: &[ScopeDetails]) -> Vec<ScopeId> {
116 let mut new_scopes = Vec::with_capacity(scopes.len());
117 for scope_detail in scopes {
118 let new_scope_id = fetch_add_scope_id();
119 let scope = self.scope_collection.insert(Arc::new(
120 (*scope_detail).clone().with_scope_id(new_scope_id),
121 ));
122 new_scopes.push(scope);
123 }
124 let new_scope_ids = new_scopes.iter().filter_map(|x| x.scope_id).collect();
125 self.new_scopes.extend(new_scopes);
126 new_scope_ids
127 }
128
129 pub fn report(
131 &mut self,
132 info: ThreadInfo,
133 scope_details: &[ScopeDetails],
134 stream_scope_times: &StreamInfoRef<'_>,
135 ) {
136 if !scope_details.is_empty() {
137 self.new_scopes
139 .extend(scope_details.iter().map(|x| Arc::new(x.clone())));
140 }
141
142 self.current_frame
143 .entry(info)
144 .or_default()
145 .extend(stream_scope_times);
146 }
147
148 pub fn report_user_scopes(&mut self, info: ThreadInfo, stream_scope_times: &StreamInfoRef<'_>) {
151 self.current_frame
152 .entry(info)
153 .or_default()
154 .extend(stream_scope_times);
155 }
156
157 pub fn add_sink(&mut self, sink: FrameSink) -> FrameSinkId {
162 let id = self.next_sink_id;
163 self.next_sink_id.0 += 1;
164 self.sinks.insert(id, sink);
165 id
166 }
167
168 pub fn remove_sink(&mut self, id: FrameSinkId) -> Option<FrameSink> {
170 self.sinks.remove(&id)
171 }
172
173 pub fn emit_scope_snapshot(&mut self) {
176 self.propagate_all_scope_details = true;
177 }
178}