Skip to main content

turbo_trace_server/
span_bottom_up_ref.rs

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