1use std::{
2 collections::VecDeque,
3 fmt::{Debug, Formatter},
4 sync::{Arc, OnceLock},
5};
6
7use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
8use turbo_rcstr::RcStr;
9
10use crate::{
11 FxIndexMap,
12 bottom_up::build_bottom_up_graph,
13 span::{SpanGraph, SpanGraphEvent},
14 span_bottom_up_ref::SpanBottomUpRef,
15 span_ref::{GroupNameToDirectAndRecusiveSpans, SpanRef},
16 store::{SpanId, Store},
17 timestamp::Timestamp,
18};
19
20#[derive(Clone)]
21pub struct SpanGraphRef<'a> {
22 pub(crate) graph: Arc<SpanGraph>,
23 pub(crate) store: &'a Store,
24}
25
26impl<'a> SpanGraphRef<'a> {
27 pub fn first_span(&self) -> SpanRef<'a> {
28 let index = self.graph.root_spans[0].get();
29 SpanRef {
30 span: &self.store.spans[index],
31 store: self.store,
32 index,
33 }
34 }
35
36 pub fn id(&self) -> SpanId {
37 unsafe { SpanId::new_unchecked((self.first_span().index << 1) | 1) }
38 }
39
40 pub fn nice_name(&self) -> (&RcStr, &RcStr) {
41 if self.count() == 1 {
42 self.first_span().nice_name()
43 } else {
44 self.first_span().group_name()
45 }
46 }
47
48 pub fn count(&self) -> usize {
49 self.graph.root_spans.len() + self.graph.recursive_spans.len()
50 }
51
52 pub fn root_spans(&self) -> impl DoubleEndedIterator<Item = SpanRef<'a>> + '_ {
53 self.graph.root_spans.iter().map(move |span| SpanRef {
54 span: &self.store.spans[span.get()],
55 store: self.store,
56 index: span.get(),
57 })
58 }
59
60 fn recursive_spans(&self) -> impl DoubleEndedIterator<Item = SpanRef<'a>> + '_ {
61 self.graph
62 .root_spans
63 .iter()
64 .chain(self.graph.recursive_spans.iter())
65 .map(move |span| SpanRef {
66 span: &self.store.spans[span.get()],
67 store: self.store,
68 index: span.get(),
69 })
70 }
71
72 fn recursive_spans_par(&self) -> impl ParallelIterator<Item = SpanRef<'a>> + '_ {
73 self.graph
74 .root_spans
75 .par_iter()
76 .chain(self.graph.recursive_spans.par_iter())
77 .map(move |span| SpanRef {
78 span: &self.store.spans[span.get()],
79 store: self.store,
80 index: span.get(),
81 })
82 }
83
84 fn events_vec_ref(&self) -> &Vec<SpanGraphEvent> {
85 self.graph.events.get_or_init(|| {
86 if self.count() == 1 {
87 let _ = self.first_span().graph();
88 self.first_span().extra().graph.get().unwrap().clone()
89 } else {
90 let self_group = self.first_span().group_name();
91 let mut map: GroupNameToDirectAndRecusiveSpans = FxIndexMap::default();
92 let mut queue = VecDeque::with_capacity(8);
93 for span in self.recursive_spans() {
94 for span in span.children() {
95 let name = span.group_name();
96 if name != self_group {
97 let (list, recursive_list) = map.entry(name).or_default();
98 list.push(span.index());
99 queue.push_back(span);
100 while let Some(child) = queue.pop_front() {
101 for nested_child in child.children() {
102 let nested_name = nested_child.group_name();
103 if name == nested_name {
104 recursive_list.push(nested_child.index());
105 queue.push_back(nested_child);
106 }
107 }
108 }
109 }
110 }
111 }
112 event_map_to_list(map)
113 }
114 })
115 }
116
117 pub fn events(&self) -> impl DoubleEndedIterator<Item = SpanGraphEventRef<'a>> + '_ {
118 self.events_vec_ref().iter().map(|graph| match graph {
119 SpanGraphEvent::SelfTime { duration } => SpanGraphEventRef::SelfTime {
120 duration: *duration,
121 },
122 SpanGraphEvent::Child { child } => SpanGraphEventRef::Child {
123 graph: SpanGraphRef {
124 graph: child.clone(),
125 store: self.store,
126 },
127 },
128 })
129 }
130
131 pub fn events_par(&self) -> impl ParallelIterator<Item = SpanGraphEventRef<'a>> + '_ {
132 self.events_vec_ref().par_iter().map(|graph| match graph {
133 SpanGraphEvent::SelfTime { duration } => SpanGraphEventRef::SelfTime {
134 duration: *duration,
135 },
136 SpanGraphEvent::Child { child } => SpanGraphEventRef::Child {
137 graph: SpanGraphRef {
138 graph: child.clone(),
139 store: self.store,
140 },
141 },
142 })
143 }
144
145 pub fn children(&self) -> impl DoubleEndedIterator<Item = SpanGraphRef<'a>> + '_ {
146 self.events().filter_map(|event| match event {
147 SpanGraphEventRef::SelfTime { .. } => None,
148 SpanGraphEventRef::Child { graph: span } => Some(span),
149 })
150 }
151
152 pub fn children_par(&self) -> impl ParallelIterator<Item = SpanGraphRef<'a>> + '_ {
153 self.events_par().filter_map(|event| match event {
154 SpanGraphEventRef::SelfTime { .. } => None,
155 SpanGraphEventRef::Child { graph: span } => Some(span),
156 })
157 }
158
159 pub fn bottom_up(&self) -> impl Iterator<Item = SpanBottomUpRef<'a>> + '_ {
160 self.graph
161 .bottom_up
162 .get_or_init(|| build_bottom_up_graph(self.root_spans()))
163 .iter()
164 .map(move |bottom_up| SpanBottomUpRef {
165 bottom_up: bottom_up.clone(),
166 store: self.store,
167 })
168 }
169
170 pub fn max_depth(&self) -> u32 {
171 *self.graph.max_depth.get_or_init(|| {
172 self.children()
173 .map(|graph| graph.max_depth() + 1)
174 .max()
175 .unwrap_or_default()
176 })
177 }
178
179 pub fn self_time(&self) -> Timestamp {
180 *self.graph.self_time.get_or_init(|| {
181 self.recursive_spans()
182 .map(|span| span.self_time())
183 .reduce(|a, b| a + b)
184 .unwrap_or_default()
185 })
186 }
187
188 pub fn total_time(&self) -> Timestamp {
189 *self.graph.total_time.get_or_init(|| {
190 self.children()
191 .map(|graph| graph.total_time())
192 .reduce(|a, b| a + b)
193 .unwrap_or_default()
194 + self.self_time()
195 })
196 }
197
198 pub fn self_allocations(&self) -> u64 {
199 *self.graph.self_allocations.get_or_init(|| {
200 self.recursive_spans()
201 .map(|span| span.self_allocations())
202 .reduce(|a, b| a + b)
203 .unwrap_or_default()
204 })
205 }
206
207 pub fn self_deallocations(&self) -> u64 {
208 *self.graph.self_deallocations.get_or_init(|| {
209 self.recursive_spans()
210 .map(|span| span.self_deallocations())
211 .reduce(|a, b| a + b)
212 .unwrap_or_default()
213 })
214 }
215
216 pub fn self_persistent_allocations(&self) -> u64 {
217 *self.graph.self_persistent_allocations.get_or_init(|| {
218 self.recursive_spans()
219 .map(|span| span.self_persistent_allocations())
220 .reduce(|a, b| a + b)
221 .unwrap_or_default()
222 })
223 }
224
225 pub fn self_allocation_count(&self) -> u64 {
226 *self.graph.self_allocation_count.get_or_init(|| {
227 self.recursive_spans()
228 .map(|span| span.self_allocation_count())
229 .reduce(|a, b| a + b)
230 .unwrap_or_default()
231 })
232 }
233
234 pub fn self_span_count(&self) -> u64 {
235 self.graph.root_spans.len() as u64 + self.graph.recursive_spans.len() as u64
236 }
237
238 pub fn total_allocations(&self) -> u64 {
239 *self.graph.total_allocations.get_or_init(|| {
240 self.children()
241 .map(|graph| graph.total_allocations())
242 .reduce(|a, b| a + b)
243 .unwrap_or_default()
244 + self.self_allocations()
245 })
246 }
247
248 pub fn total_deallocations(&self) -> u64 {
249 *self.graph.total_deallocations.get_or_init(|| {
250 self.children()
251 .map(|graph| graph.total_deallocations())
252 .reduce(|a, b| a + b)
253 .unwrap_or_default()
254 + self.self_deallocations()
255 })
256 }
257
258 pub fn total_persistent_allocations(&self) -> u64 {
259 *self.graph.total_persistent_allocations.get_or_init(|| {
260 self.children()
261 .map(|graph| graph.total_persistent_allocations())
262 .reduce(|a, b| a + b)
263 .unwrap_or_default()
264 + self.self_persistent_allocations()
265 })
266 }
267
268 pub fn total_allocation_count(&self) -> u64 {
269 *self.graph.total_allocation_count.get_or_init(|| {
270 self.children()
271 .map(|graph| graph.total_allocation_count())
272 .reduce(|a, b| a + b)
273 .unwrap_or_default()
274 + self.self_allocation_count()
275 })
276 }
277
278 pub fn total_span_count(&self) -> u64 {
279 *self.graph.total_span_count.get_or_init(|| {
280 self.children()
281 .map(|graph| graph.total_span_count())
282 .reduce(|a, b| a + b)
283 .unwrap_or_default()
284 + self.self_span_count()
285 })
286 }
287
288 pub fn corrected_self_time(&self) -> Timestamp {
289 *self.graph.corrected_self_time.get_or_init(|| {
290 self.recursive_spans_par()
291 .map(|span| span.corrected_self_time())
292 .sum::<Timestamp>()
293 })
294 }
295
296 pub fn corrected_total_time(&self) -> Timestamp {
297 *self.graph.corrected_total_time.get_or_init(|| {
298 self.children_par()
299 .map(|graph| graph.corrected_total_time())
300 .sum::<Timestamp>()
301 + self.corrected_self_time()
302 })
303 }
304}
305
306pub fn event_map_to_list(map: GroupNameToDirectAndRecusiveSpans) -> Vec<SpanGraphEvent> {
307 map.into_iter()
308 .map(|(_, (root_spans, recursive_spans))| {
309 let graph = SpanGraph {
310 root_spans,
311 recursive_spans,
312 max_depth: OnceLock::new(),
313 events: OnceLock::new(),
314 self_time: OnceLock::new(),
315 self_allocations: OnceLock::new(),
316 self_deallocations: OnceLock::new(),
317 self_persistent_allocations: OnceLock::new(),
318 self_allocation_count: OnceLock::new(),
319 total_time: OnceLock::new(),
320 total_allocations: OnceLock::new(),
321 total_deallocations: OnceLock::new(),
322 total_persistent_allocations: OnceLock::new(),
323 total_allocation_count: OnceLock::new(),
324 total_span_count: OnceLock::new(),
325 corrected_self_time: OnceLock::new(),
326 corrected_total_time: OnceLock::new(),
327 bottom_up: OnceLock::new(),
328 };
329 SpanGraphEvent::Child {
330 child: Arc::new(graph),
331 }
332 })
333 .collect()
334}
335
336impl Debug for SpanGraphRef<'_> {
337 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
338 f.debug_struct("SpanGraphRef")
339 .field("id", &self.id())
340 .field("name", &self.nice_name())
341 .field("count", &self.count())
342 .field("max_depth", &self.max_depth())
343 .field("self_time", &self.self_time())
344 .field("self_allocations", &self.self_allocations())
345 .field("total_time", &self.total_time())
346 .field("total_allocations", &self.total_allocations())
347 .finish()
348 }
349}
350
351#[allow(dead_code)]
353#[derive(Clone)]
354pub enum SpanGraphEventRef<'a> {
355 SelfTime { duration: Timestamp },
356 Child { graph: SpanGraphRef<'a> },
357}
358
359impl SpanGraphEventRef<'_> {
360 pub fn corrected_total_time(&self) -> Timestamp {
361 match self {
362 SpanGraphEventRef::SelfTime { duration } => *duration,
363 SpanGraphEventRef::Child { graph } => graph.corrected_total_time(),
364 }
365 }
366
367 pub fn total_time(&self) -> Timestamp {
368 match self {
369 SpanGraphEventRef::SelfTime { duration } => *duration,
370 SpanGraphEventRef::Child { graph } => graph.total_time(),
371 }
372 }
373
374 pub fn total_allocations(&self) -> u64 {
375 match self {
376 SpanGraphEventRef::SelfTime { .. } => 0,
377 SpanGraphEventRef::Child { graph } => graph.total_allocations(),
378 }
379 }
380
381 pub fn total_deallocations(&self) -> u64 {
382 match self {
383 SpanGraphEventRef::SelfTime { .. } => 0,
384 SpanGraphEventRef::Child { graph } => graph.total_deallocations(),
385 }
386 }
387
388 pub fn total_persistent_allocations(&self) -> u64 {
389 match self {
390 SpanGraphEventRef::SelfTime { .. } => 0,
391 SpanGraphEventRef::Child { graph } => graph.total_persistent_allocations(),
392 }
393 }
394
395 pub fn total_allocation_count(&self) -> u64 {
396 match self {
397 SpanGraphEventRef::SelfTime { .. } => 0,
398 SpanGraphEventRef::Child { graph } => graph.total_allocation_count(),
399 }
400 }
401
402 pub fn total_span_count(&self) -> u64 {
403 match self {
404 SpanGraphEventRef::SelfTime { .. } => 0,
405 SpanGraphEventRef::Child { graph } => graph.total_span_count(),
406 }
407 }
408}