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},
10    span_graph_ref::{SpanGraphEventRef, SpanGraphRef, event_map_to_list},
11    span_ref::{GroupNameToDirectAndRecusiveSpans, 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, &'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: GroupNameToDirectAndRecusiveSpans = FxIndexMap::default();
89                    let mut queue = VecDeque::with_capacity(8);
90                    for child in self.spans() {
91                        let name = child.group_name();
92                        let (list, recursive_list) = map.entry(name).or_default();
93                        list.push(child.index());
94                        queue.push_back(child);
95                        while let Some(child) = queue.pop_front() {
96                            for nested_child in child.children() {
97                                let nested_name = nested_child.group_name();
98                                if name == nested_name {
99                                    recursive_list.push(nested_child.index());
100                                    queue.push_back(nested_child);
101                                }
102                            }
103                        }
104                    }
105                    event_map_to_list(map)
106                }
107            })
108            .iter()
109            .map(|graph| match graph {
110                SpanGraphEvent::SelfTime { duration } => SpanGraphEventRef::SelfTime {
111                    duration: *duration,
112                },
113                SpanGraphEvent::Child { child } => SpanGraphEventRef::Child {
114                    graph: SpanGraphRef {
115                        graph: child.clone(),
116                        store: self.store,
117                    },
118                },
119            })
120    }
121
122    pub fn max_depth(&self) -> u32 {
123        *self.bottom_up.max_depth.get_or_init(|| {
124            self.children()
125                .map(|bottom_up| bottom_up.max_depth() + 1)
126                .max()
127                .unwrap_or(0)
128        })
129    }
130
131    pub fn corrected_self_time(&self) -> Timestamp {
132        *self
133            .bottom_up
134            .corrected_self_time
135            .get_or_init(|| self.spans().map(|span| span.corrected_self_time()).sum())
136    }
137
138    pub fn self_time(&self) -> Timestamp {
139        *self
140            .bottom_up
141            .self_time
142            .get_or_init(|| self.spans().map(|span| span.self_time()).sum())
143    }
144
145    pub fn self_allocations(&self) -> u64 {
146        *self
147            .bottom_up
148            .self_allocations
149            .get_or_init(|| self.spans().map(|span| span.self_allocations()).sum())
150    }
151
152    pub fn self_deallocations(&self) -> u64 {
153        *self
154            .bottom_up
155            .self_deallocations
156            .get_or_init(|| self.spans().map(|span| span.self_deallocations()).sum())
157    }
158
159    pub fn self_persistent_allocations(&self) -> u64 {
160        *self.bottom_up.self_persistent_allocations.get_or_init(|| {
161            self.spans()
162                .map(|span| span.self_persistent_allocations())
163                .sum()
164        })
165    }
166
167    pub fn self_allocation_count(&self) -> u64 {
168        *self
169            .bottom_up
170            .self_allocation_count
171            .get_or_init(|| self.spans().map(|span| span.self_allocation_count()).sum())
172    }
173
174    pub fn self_span_count(&self) -> u64 {
175        self.bottom_up.self_spans.len() as u64
176    }
177}
178
179impl Debug for SpanBottomUpRef<'_> {
180    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
181        f.debug_struct("SpanBottomUpRef")
182            .field("group_name", &self.group_name())
183            .field("max_depth", &self.max_depth())
184            .field("corrected_self_time", &self.corrected_self_time())
185            .field("self_allocations", &self.self_allocations())
186            .field("self_deallocations", &self.self_deallocations())
187            .field(
188                "self_persistent_allocations",
189                &self.self_persistent_allocations(),
190            )
191            .field("self_allocation_count", &self.self_allocation_count())
192            .finish()
193    }
194}