Skip to main content

turbo_trace_server/
span_graph_ref.rs

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// TODO(sokra) use events instead of children for visualizing span graphs
352#[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}