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#[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}