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},
13    span_bottom_up_ref::SpanBottomUpRef,
14    span_ref::{GroupNameToDirectAndRecusiveSpans, 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: GroupNameToDirectAndRecusiveSpans = FxIndexMap::default();
91                let mut queue = VecDeque::with_capacity(8);
92                for span in self.recursive_spans() {
93                    for span in span.children() {
94                        let name = span.group_name();
95                        if name != self_group {
96                            let (list, recursive_list) = map.entry(name).or_default();
97                            list.push(span.index());
98                            queue.push_back(span);
99                            while let Some(child) = queue.pop_front() {
100                                for nested_child in child.children() {
101                                    let nested_name = nested_child.group_name();
102                                    if name == nested_name {
103                                        recursive_list.push(nested_child.index());
104                                        queue.push_back(nested_child);
105                                    }
106                                }
107                            }
108                        }
109                    }
110                }
111                event_map_to_list(map)
112            }
113        })
114    }
115
116    pub fn events(&self) -> impl DoubleEndedIterator<Item = SpanGraphEventRef<'a>> + '_ {
117        self.events_vec_ref().iter().map(|graph| match graph {
118            SpanGraphEvent::SelfTime { duration } => SpanGraphEventRef::SelfTime {
119                duration: *duration,
120            },
121            SpanGraphEvent::Child { child } => SpanGraphEventRef::Child {
122                graph: SpanGraphRef {
123                    graph: child.clone(),
124                    store: self.store,
125                },
126            },
127        })
128    }
129
130    pub fn events_par(&self) -> impl ParallelIterator<Item = SpanGraphEventRef<'a>> + '_ {
131        self.events_vec_ref().par_iter().map(|graph| match graph {
132            SpanGraphEvent::SelfTime { duration } => SpanGraphEventRef::SelfTime {
133                duration: *duration,
134            },
135            SpanGraphEvent::Child { child } => SpanGraphEventRef::Child {
136                graph: SpanGraphRef {
137                    graph: child.clone(),
138                    store: self.store,
139                },
140            },
141        })
142    }
143
144    pub fn children(&self) -> impl DoubleEndedIterator<Item = SpanGraphRef<'a>> + '_ {
145        self.events().filter_map(|event| match event {
146            SpanGraphEventRef::SelfTime { .. } => None,
147            SpanGraphEventRef::Child { graph: span } => Some(span),
148        })
149    }
150
151    pub fn children_par(&self) -> impl ParallelIterator<Item = SpanGraphRef<'a>> + '_ {
152        self.events_par().filter_map(|event| match event {
153            SpanGraphEventRef::SelfTime { .. } => None,
154            SpanGraphEventRef::Child { graph: span } => Some(span),
155        })
156    }
157
158    pub fn bottom_up(&self) -> impl Iterator<Item = SpanBottomUpRef<'a>> + '_ {
159        self.graph
160            .bottom_up
161            .get_or_init(|| build_bottom_up_graph(self.root_spans()))
162            .iter()
163            .map(move |bottom_up| SpanBottomUpRef {
164                bottom_up: bottom_up.clone(),
165                store: self.store,
166            })
167    }
168
169    pub fn max_depth(&self) -> u32 {
170        *self.graph.max_depth.get_or_init(|| {
171            self.children()
172                .map(|graph| graph.max_depth() + 1)
173                .max()
174                .unwrap_or_default()
175        })
176    }
177
178    pub fn self_time(&self) -> Timestamp {
179        *self.graph.self_time.get_or_init(|| {
180            self.recursive_spans()
181                .map(|span| span.self_time())
182                .reduce(|a, b| a + b)
183                .unwrap_or_default()
184        })
185    }
186
187    pub fn total_time(&self) -> Timestamp {
188        *self.graph.total_time.get_or_init(|| {
189            self.children()
190                .map(|graph| graph.total_time())
191                .reduce(|a, b| a + b)
192                .unwrap_or_default()
193                + self.self_time()
194        })
195    }
196
197    pub fn self_allocations(&self) -> u64 {
198        *self.graph.self_allocations.get_or_init(|| {
199            self.recursive_spans()
200                .map(|span| span.self_allocations())
201                .reduce(|a, b| a + b)
202                .unwrap_or_default()
203        })
204    }
205
206    pub fn self_deallocations(&self) -> u64 {
207        *self.graph.self_deallocations.get_or_init(|| {
208            self.recursive_spans()
209                .map(|span| span.self_deallocations())
210                .reduce(|a, b| a + b)
211                .unwrap_or_default()
212        })
213    }
214
215    pub fn self_persistent_allocations(&self) -> u64 {
216        *self.graph.self_persistent_allocations.get_or_init(|| {
217            self.recursive_spans()
218                .map(|span| span.self_persistent_allocations())
219                .reduce(|a, b| a + b)
220                .unwrap_or_default()
221        })
222    }
223
224    pub fn self_allocation_count(&self) -> u64 {
225        *self.graph.self_allocation_count.get_or_init(|| {
226            self.recursive_spans()
227                .map(|span| span.self_allocation_count())
228                .reduce(|a, b| a + b)
229                .unwrap_or_default()
230        })
231    }
232
233    pub fn self_span_count(&self) -> u64 {
234        self.graph.root_spans.len() as u64 + self.graph.recursive_spans.len() as u64
235    }
236
237    pub fn total_allocations(&self) -> u64 {
238        *self.graph.total_allocations.get_or_init(|| {
239            self.children()
240                .map(|graph| graph.total_allocations())
241                .reduce(|a, b| a + b)
242                .unwrap_or_default()
243                + self.self_allocations()
244        })
245    }
246
247    pub fn total_deallocations(&self) -> u64 {
248        *self.graph.total_deallocations.get_or_init(|| {
249            self.children()
250                .map(|graph| graph.total_deallocations())
251                .reduce(|a, b| a + b)
252                .unwrap_or_default()
253                + self.self_deallocations()
254        })
255    }
256
257    pub fn total_persistent_allocations(&self) -> u64 {
258        *self.graph.total_persistent_allocations.get_or_init(|| {
259            self.children()
260                .map(|graph| graph.total_persistent_allocations())
261                .reduce(|a, b| a + b)
262                .unwrap_or_default()
263                + self.self_persistent_allocations()
264        })
265    }
266
267    pub fn total_allocation_count(&self) -> u64 {
268        *self.graph.total_allocation_count.get_or_init(|| {
269            self.children()
270                .map(|graph| graph.total_allocation_count())
271                .reduce(|a, b| a + b)
272                .unwrap_or_default()
273                + self.self_allocation_count()
274        })
275    }
276
277    pub fn total_span_count(&self) -> u64 {
278        *self.graph.total_span_count.get_or_init(|| {
279            self.children()
280                .map(|graph| graph.total_span_count())
281                .reduce(|a, b| a + b)
282                .unwrap_or_default()
283                + self.self_span_count()
284        })
285    }
286
287    pub fn corrected_self_time(&self) -> Timestamp {
288        *self.graph.corrected_self_time.get_or_init(|| {
289            self.recursive_spans_par()
290                .map(|span| span.corrected_self_time())
291                .sum::<Timestamp>()
292        })
293    }
294
295    pub fn corrected_total_time(&self) -> Timestamp {
296        *self.graph.corrected_total_time.get_or_init(|| {
297            self.children_par()
298                .map(|graph| graph.corrected_total_time())
299                .sum::<Timestamp>()
300                + self.corrected_self_time()
301        })
302    }
303}
304
305pub fn event_map_to_list(map: GroupNameToDirectAndRecusiveSpans) -> Vec<SpanGraphEvent> {
306    map.into_iter()
307        .map(|(_, (root_spans, recursive_spans))| {
308            let graph = SpanGraph {
309                root_spans,
310                recursive_spans,
311                max_depth: OnceLock::new(),
312                events: OnceLock::new(),
313                self_time: OnceLock::new(),
314                self_allocations: OnceLock::new(),
315                self_deallocations: OnceLock::new(),
316                self_persistent_allocations: OnceLock::new(),
317                self_allocation_count: OnceLock::new(),
318                total_time: OnceLock::new(),
319                total_allocations: OnceLock::new(),
320                total_deallocations: OnceLock::new(),
321                total_persistent_allocations: OnceLock::new(),
322                total_allocation_count: OnceLock::new(),
323                total_span_count: OnceLock::new(),
324                corrected_self_time: OnceLock::new(),
325                corrected_total_time: OnceLock::new(),
326                bottom_up: OnceLock::new(),
327            };
328            SpanGraphEvent::Child {
329                child: Arc::new(graph),
330            }
331        })
332        .collect()
333}
334
335impl Debug for SpanGraphRef<'_> {
336    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
337        f.debug_struct("SpanGraphRef")
338            .field("id", &self.id())
339            .field("name", &self.nice_name())
340            .field("count", &self.count())
341            .field("max_depth", &self.max_depth())
342            .field("self_time", &self.self_time())
343            .field("self_allocations", &self.self_allocations())
344            .field("total_time", &self.total_time())
345            .field("total_allocations", &self.total_allocations())
346            .finish()
347    }
348}
349
350// TODO(sokra) use events instead of children for visualizing span graphs
351#[allow(dead_code)]
352#[derive(Clone)]
353pub enum SpanGraphEventRef<'a> {
354    SelfTime { duration: Timestamp },
355    Child { graph: SpanGraphRef<'a> },
356}
357
358impl SpanGraphEventRef<'_> {
359    pub fn corrected_total_time(&self) -> Timestamp {
360        match self {
361            SpanGraphEventRef::SelfTime { duration } => *duration,
362            SpanGraphEventRef::Child { graph } => graph.corrected_total_time(),
363        }
364    }
365
366    pub fn total_time(&self) -> Timestamp {
367        match self {
368            SpanGraphEventRef::SelfTime { duration } => *duration,
369            SpanGraphEventRef::Child { graph } => graph.total_time(),
370        }
371    }
372
373    pub fn total_allocations(&self) -> u64 {
374        match self {
375            SpanGraphEventRef::SelfTime { .. } => 0,
376            SpanGraphEventRef::Child { graph } => graph.total_allocations(),
377        }
378    }
379
380    pub fn total_deallocations(&self) -> u64 {
381        match self {
382            SpanGraphEventRef::SelfTime { .. } => 0,
383            SpanGraphEventRef::Child { graph } => graph.total_deallocations(),
384        }
385    }
386
387    pub fn total_persistent_allocations(&self) -> u64 {
388        match self {
389            SpanGraphEventRef::SelfTime { .. } => 0,
390            SpanGraphEventRef::Child { graph } => graph.total_persistent_allocations(),
391        }
392    }
393
394    pub fn total_allocation_count(&self) -> u64 {
395        match self {
396            SpanGraphEventRef::SelfTime { .. } => 0,
397            SpanGraphEventRef::Child { graph } => graph.total_allocation_count(),
398        }
399    }
400
401    pub fn total_span_count(&self) -> u64 {
402        match self {
403            SpanGraphEventRef::SelfTime { .. } => 0,
404            SpanGraphEventRef::Child { graph } => graph.total_span_count(),
405        }
406    }
407}