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};
8
9use crate::{
10    FxIndexMap,
11    bottom_up::build_bottom_up_graph,
12    span::{SpanGraph, SpanGraphEvent, SpanIndex},
13    span_bottom_up_ref::SpanBottomUpRef,
14    span_ref::SpanRef,
15    store::{SpanId, Store},
16    timestamp::Timestamp,
17};
18
19#[derive(Clone)]
20pub struct SpanGraphRef<'a> {
21    pub(crate) graph: Arc<SpanGraph>,
22    pub(crate) store: &'a Store,
23}
24
25impl<'a> SpanGraphRef<'a> {
26    pub fn first_span(&self) -> SpanRef<'a> {
27        let index = self.graph.root_spans[0].get();
28        SpanRef {
29            span: &self.store.spans[index],
30            store: self.store,
31            index,
32        }
33    }
34
35    pub fn id(&self) -> SpanId {
36        unsafe { SpanId::new_unchecked((self.first_span().index << 1) | 1) }
37    }
38
39    pub fn nice_name(&self) -> (&str, &str) {
40        if self.count() == 1 {
41            self.first_span().nice_name()
42        } else {
43            ("", self.first_span().group_name())
44        }
45    }
46
47    pub fn count(&self) -> usize {
48        self.graph.root_spans.len() + self.graph.recursive_spans.len()
49    }
50
51    pub fn root_spans(&self) -> impl DoubleEndedIterator<Item = SpanRef<'a>> + '_ {
52        self.graph.root_spans.iter().map(move |span| SpanRef {
53            span: &self.store.spans[span.get()],
54            store: self.store,
55            index: span.get(),
56        })
57    }
58
59    fn recursive_spans(&self) -> impl DoubleEndedIterator<Item = SpanRef<'a>> + '_ {
60        self.graph
61            .root_spans
62            .iter()
63            .chain(self.graph.recursive_spans.iter())
64            .map(move |span| SpanRef {
65                span: &self.store.spans[span.get()],
66                store: self.store,
67                index: span.get(),
68            })
69    }
70
71    fn recursive_spans_par(&self) -> impl ParallelIterator<Item = SpanRef<'a>> + '_ {
72        self.graph
73            .root_spans
74            .par_iter()
75            .chain(self.graph.recursive_spans.par_iter())
76            .map(move |span| SpanRef {
77                span: &self.store.spans[span.get()],
78                store: self.store,
79                index: span.get(),
80            })
81    }
82
83    fn events_vec_ref(&self) -> &Vec<SpanGraphEvent> {
84        self.graph.events.get_or_init(|| {
85            if self.count() == 1 {
86                let _ = self.first_span().graph();
87                self.first_span().extra().graph.get().unwrap().clone()
88            } else {
89                let self_group = self.first_span().group_name();
90                let mut map: FxIndexMap<&str, (Vec<SpanIndex>, Vec<SpanIndex>)> =
91                    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(
307    map: FxIndexMap<&str, (Vec<SpanIndex>, Vec<SpanIndex>)>,
308) -> Vec<SpanGraphEvent> {
309    map.into_iter()
310        .map(|(_, (root_spans, recursive_spans))| {
311            let graph = SpanGraph {
312                root_spans,
313                recursive_spans,
314                max_depth: OnceLock::new(),
315                events: OnceLock::new(),
316                self_time: OnceLock::new(),
317                self_allocations: OnceLock::new(),
318                self_deallocations: OnceLock::new(),
319                self_persistent_allocations: OnceLock::new(),
320                self_allocation_count: OnceLock::new(),
321                total_time: OnceLock::new(),
322                total_allocations: OnceLock::new(),
323                total_deallocations: OnceLock::new(),
324                total_persistent_allocations: OnceLock::new(),
325                total_allocation_count: OnceLock::new(),
326                total_span_count: OnceLock::new(),
327                corrected_self_time: OnceLock::new(),
328                corrected_total_time: OnceLock::new(),
329                bottom_up: OnceLock::new(),
330            };
331            SpanGraphEvent::Child {
332                child: Arc::new(graph),
333            }
334        })
335        .collect()
336}
337
338impl Debug for SpanGraphRef<'_> {
339    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
340        f.debug_struct("SpanGraphRef")
341            .field("id", &self.id())
342            .field("name", &self.nice_name())
343            .field("count", &self.count())
344            .field("max_depth", &self.max_depth())
345            .field("self_time", &self.self_time())
346            .field("self_allocations", &self.self_allocations())
347            .field("total_time", &self.total_time())
348            .field("total_allocations", &self.total_allocations())
349            .finish()
350    }
351}
352
353// TODO(sokra) use events instead of children for visualizing span graphs
354#[allow(dead_code)]
355#[derive(Clone)]
356pub enum SpanGraphEventRef<'a> {
357    SelfTime { duration: Timestamp },
358    Child { graph: SpanGraphRef<'a> },
359}
360
361impl SpanGraphEventRef<'_> {
362    pub fn corrected_total_time(&self) -> Timestamp {
363        match self {
364            SpanGraphEventRef::SelfTime { duration } => *duration,
365            SpanGraphEventRef::Child { graph } => graph.corrected_total_time(),
366        }
367    }
368
369    pub fn total_time(&self) -> Timestamp {
370        match self {
371            SpanGraphEventRef::SelfTime { duration } => *duration,
372            SpanGraphEventRef::Child { graph } => graph.total_time(),
373        }
374    }
375
376    pub fn total_allocations(&self) -> u64 {
377        match self {
378            SpanGraphEventRef::SelfTime { .. } => 0,
379            SpanGraphEventRef::Child { graph } => graph.total_allocations(),
380        }
381    }
382
383    pub fn total_deallocations(&self) -> u64 {
384        match self {
385            SpanGraphEventRef::SelfTime { .. } => 0,
386            SpanGraphEventRef::Child { graph } => graph.total_deallocations(),
387        }
388    }
389
390    pub fn total_persistent_allocations(&self) -> u64 {
391        match self {
392            SpanGraphEventRef::SelfTime { .. } => 0,
393            SpanGraphEventRef::Child { graph } => graph.total_persistent_allocations(),
394        }
395    }
396
397    pub fn total_allocation_count(&self) -> u64 {
398        match self {
399            SpanGraphEventRef::SelfTime { .. } => 0,
400            SpanGraphEventRef::Child { graph } => graph.total_allocation_count(),
401        }
402    }
403
404    pub fn total_span_count(&self) -> u64 {
405        match self {
406            SpanGraphEventRef::SelfTime { .. } => 0,
407            SpanGraphEventRef::Child { graph } => graph.total_span_count(),
408        }
409    }
410}