turbo_trace_server/
span_bottom_up_ref.rs

1use std::{
2    collections::VecDeque,
3    fmt::{Debug, Formatter},
4    sync::Arc,
5};
6
7use crate::{
8    FxIndexMap,
9    span::{SpanBottomUp, SpanGraphEvent, SpanIndex},
10    span_graph_ref::{SpanGraphEventRef, SpanGraphRef, event_map_to_list},
11    span_ref::SpanRef,
12    store::{SpanId, Store},
13    timestamp::Timestamp,
14};
15
16pub struct SpanBottomUpRef<'a> {
17    pub(crate) bottom_up: Arc<SpanBottomUp>,
18    pub(crate) store: &'a Store,
19}
20
21impl<'a> SpanBottomUpRef<'a> {
22    pub fn id(&self) -> SpanId {
23        unsafe { SpanId::new_unchecked((self.bottom_up.example_span.get() << 1) | 1) }
24    }
25
26    fn first_span(&self) -> SpanRef<'a> {
27        let index = self.bottom_up.self_spans[0].get();
28        SpanRef {
29            span: &self.store.spans[index],
30            store: self.store,
31            index,
32        }
33    }
34
35    fn example_span(&self) -> SpanRef<'a> {
36        let index = self.bottom_up.example_span.get();
37        SpanRef {
38            span: &self.store.spans[index],
39            store: self.store,
40            index,
41        }
42    }
43
44    pub fn spans(&self) -> impl Iterator<Item = SpanRef<'a>> + '_ {
45        let store = self.store;
46        self.bottom_up.self_spans.iter().map(move |span| SpanRef {
47            span: &store.spans[span.get()],
48            store,
49            index: span.get(),
50        })
51    }
52
53    pub fn count(&self) -> usize {
54        self.bottom_up.self_spans.len()
55    }
56
57    pub fn group_name(&self) -> &'a str {
58        self.first_span().group_name()
59    }
60
61    pub fn nice_name(&self) -> (&'a str, &'a str) {
62        if self.count() == 1 {
63            self.example_span().nice_name()
64        } else {
65            ("", self.example_span().group_name())
66        }
67    }
68
69    pub fn children(&self) -> impl Iterator<Item = SpanBottomUpRef<'a>> + '_ {
70        self.bottom_up
71            .children
72            .iter()
73            .map(|bottom_up| SpanBottomUpRef {
74                bottom_up: bottom_up.clone(),
75                store: self.store,
76            })
77    }
78
79    #[allow(dead_code)]
80    pub fn graph(&self) -> impl Iterator<Item = SpanGraphEventRef<'a>> + '_ {
81        self.bottom_up
82            .events
83            .get_or_init(|| {
84                if self.count() == 1 {
85                    let _ = self.first_span().graph();
86                    self.first_span().extra().graph.get().unwrap().clone()
87                } else {
88                    let mut map: FxIndexMap<&str, (Vec<SpanIndex>, Vec<SpanIndex>)> =
89                        FxIndexMap::default();
90                    let mut queue = VecDeque::with_capacity(8);
91                    for child in self.spans() {
92                        let name = child.group_name();
93                        let (list, recursive_list) = map.entry(name).or_default();
94                        list.push(child.index());
95                        queue.push_back(child);
96                        while let Some(child) = queue.pop_front() {
97                            for nested_child in child.children() {
98                                let nested_name = nested_child.group_name();
99                                if name == nested_name {
100                                    recursive_list.push(nested_child.index());
101                                    queue.push_back(nested_child);
102                                }
103                            }
104                        }
105                    }
106                    event_map_to_list(map)
107                }
108            })
109            .iter()
110            .map(|graph| match graph {
111                SpanGraphEvent::SelfTime { duration } => SpanGraphEventRef::SelfTime {
112                    duration: *duration,
113                },
114                SpanGraphEvent::Child { child } => SpanGraphEventRef::Child {
115                    graph: SpanGraphRef {
116                        graph: child.clone(),
117                        store: self.store,
118                    },
119                },
120            })
121    }
122
123    pub fn max_depth(&self) -> u32 {
124        *self.bottom_up.max_depth.get_or_init(|| {
125            self.children()
126                .map(|bottom_up| bottom_up.max_depth() + 1)
127                .max()
128                .unwrap_or(0)
129        })
130    }
131
132    pub fn corrected_self_time(&self) -> Timestamp {
133        *self
134            .bottom_up
135            .corrected_self_time
136            .get_or_init(|| self.spans().map(|span| span.corrected_self_time()).sum())
137    }
138
139    pub fn self_time(&self) -> Timestamp {
140        *self
141            .bottom_up
142            .self_time
143            .get_or_init(|| self.spans().map(|span| span.self_time()).sum())
144    }
145
146    pub fn self_allocations(&self) -> u64 {
147        *self
148            .bottom_up
149            .self_allocations
150            .get_or_init(|| self.spans().map(|span| span.self_allocations()).sum())
151    }
152
153    pub fn self_deallocations(&self) -> u64 {
154        *self
155            .bottom_up
156            .self_deallocations
157            .get_or_init(|| self.spans().map(|span| span.self_deallocations()).sum())
158    }
159
160    pub fn self_persistent_allocations(&self) -> u64 {
161        *self.bottom_up.self_persistent_allocations.get_or_init(|| {
162            self.spans()
163                .map(|span| span.self_persistent_allocations())
164                .sum()
165        })
166    }
167
168    pub fn self_allocation_count(&self) -> u64 {
169        *self
170            .bottom_up
171            .self_allocation_count
172            .get_or_init(|| self.spans().map(|span| span.self_allocation_count()).sum())
173    }
174
175    pub fn self_span_count(&self) -> u64 {
176        self.bottom_up.self_spans.len() as u64
177    }
178}
179
180impl Debug for SpanBottomUpRef<'_> {
181    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
182        f.debug_struct("SpanBottomUpRef")
183            .field("group_name", &self.group_name())
184            .field("max_depth", &self.max_depth())
185            .field("corrected_self_time", &self.corrected_self_time())
186            .field("self_allocations", &self.self_allocations())
187            .field("self_deallocations", &self.self_deallocations())
188            .field(
189                "self_persistent_allocations",
190                &self.self_persistent_allocations(),
191            )
192            .field("self_allocation_count", &self.self_allocation_count())
193            .finish()
194    }
195}