turbo_trace_server/
span_bottom_up_ref.rs1use 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}