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, SpanIndex},
13 span_bottom_up_ref::SpanBottomUpRef,
14 span_ref::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: FxIndexMap<&str, (Vec<SpanIndex>, Vec<SpanIndex>)> =
91 FxIndexMap::default();
92 let mut queue = VecDeque::with_capacity(8);
93 for span in self.recursive_spans() {
94 for span in span.children() {
95 let name = span.group_name();
96 if name != self_group {
97 let (list, recursive_list) = map.entry(name).or_default();
98 list.push(span.index());
99 queue.push_back(span);
100 while let Some(child) = queue.pop_front() {
101 for nested_child in child.children() {
102 let nested_name = nested_child.group_name();
103 if name == nested_name {
104 recursive_list.push(nested_child.index());
105 queue.push_back(nested_child);
106 }
107 }
108 }
109 }
110 }
111 }
112 event_map_to_list(map)
113 }
114 })
115 }
116
117 pub fn events(&self) -> impl DoubleEndedIterator<Item = SpanGraphEventRef<'a>> + '_ {
118 self.events_vec_ref().iter().map(|graph| match graph {
119 SpanGraphEvent::SelfTime { duration } => SpanGraphEventRef::SelfTime {
120 duration: *duration,
121 },
122 SpanGraphEvent::Child { child } => SpanGraphEventRef::Child {
123 graph: SpanGraphRef {
124 graph: child.clone(),
125 store: self.store,
126 },
127 },
128 })
129 }
130
131 pub fn events_par(&self) -> impl ParallelIterator<Item = SpanGraphEventRef<'a>> + '_ {
132 self.events_vec_ref().par_iter().map(|graph| match graph {
133 SpanGraphEvent::SelfTime { duration } => SpanGraphEventRef::SelfTime {
134 duration: *duration,
135 },
136 SpanGraphEvent::Child { child } => SpanGraphEventRef::Child {
137 graph: SpanGraphRef {
138 graph: child.clone(),
139 store: self.store,
140 },
141 },
142 })
143 }
144
145 pub fn children(&self) -> impl DoubleEndedIterator<Item = SpanGraphRef<'a>> + '_ {
146 self.events().filter_map(|event| match event {
147 SpanGraphEventRef::SelfTime { .. } => None,
148 SpanGraphEventRef::Child { graph: span } => Some(span),
149 })
150 }
151
152 pub fn children_par(&self) -> impl ParallelIterator<Item = SpanGraphRef<'a>> + '_ {
153 self.events_par().filter_map(|event| match event {
154 SpanGraphEventRef::SelfTime { .. } => None,
155 SpanGraphEventRef::Child { graph: span } => Some(span),
156 })
157 }
158
159 pub fn bottom_up(&self) -> impl Iterator<Item = SpanBottomUpRef<'a>> + '_ {
160 self.graph
161 .bottom_up
162 .get_or_init(|| build_bottom_up_graph(self.root_spans()))
163 .iter()
164 .map(move |bottom_up| SpanBottomUpRef {
165 bottom_up: bottom_up.clone(),
166 store: self.store,
167 })
168 }
169
170 pub fn max_depth(&self) -> u32 {
171 *self.graph.max_depth.get_or_init(|| {
172 self.children()
173 .map(|graph| graph.max_depth() + 1)
174 .max()
175 .unwrap_or_default()
176 })
177 }
178
179 pub fn self_time(&self) -> Timestamp {
180 *self.graph.self_time.get_or_init(|| {
181 self.recursive_spans()
182 .map(|span| span.self_time())
183 .reduce(|a, b| a + b)
184 .unwrap_or_default()
185 })
186 }
187
188 pub fn total_time(&self) -> Timestamp {
189 *self.graph.total_time.get_or_init(|| {
190 self.children()
191 .map(|graph| graph.total_time())
192 .reduce(|a, b| a + b)
193 .unwrap_or_default()
194 + self.self_time()
195 })
196 }
197
198 pub fn self_allocations(&self) -> u64 {
199 *self.graph.self_allocations.get_or_init(|| {
200 self.recursive_spans()
201 .map(|span| span.self_allocations())
202 .reduce(|a, b| a + b)
203 .unwrap_or_default()
204 })
205 }
206
207 pub fn self_deallocations(&self) -> u64 {
208 *self.graph.self_deallocations.get_or_init(|| {
209 self.recursive_spans()
210 .map(|span| span.self_deallocations())
211 .reduce(|a, b| a + b)
212 .unwrap_or_default()
213 })
214 }
215
216 pub fn self_persistent_allocations(&self) -> u64 {
217 *self.graph.self_persistent_allocations.get_or_init(|| {
218 self.recursive_spans()
219 .map(|span| span.self_persistent_allocations())
220 .reduce(|a, b| a + b)
221 .unwrap_or_default()
222 })
223 }
224
225 pub fn self_allocation_count(&self) -> u64 {
226 *self.graph.self_allocation_count.get_or_init(|| {
227 self.recursive_spans()
228 .map(|span| span.self_allocation_count())
229 .reduce(|a, b| a + b)
230 .unwrap_or_default()
231 })
232 }
233
234 pub fn self_span_count(&self) -> u64 {
235 self.graph.root_spans.len() as u64 + self.graph.recursive_spans.len() as u64
236 }
237
238 pub fn total_allocations(&self) -> u64 {
239 *self.graph.total_allocations.get_or_init(|| {
240 self.children()
241 .map(|graph| graph.total_allocations())
242 .reduce(|a, b| a + b)
243 .unwrap_or_default()
244 + self.self_allocations()
245 })
246 }
247
248 pub fn total_deallocations(&self) -> u64 {
249 *self.graph.total_deallocations.get_or_init(|| {
250 self.children()
251 .map(|graph| graph.total_deallocations())
252 .reduce(|a, b| a + b)
253 .unwrap_or_default()
254 + self.self_deallocations()
255 })
256 }
257
258 pub fn total_persistent_allocations(&self) -> u64 {
259 *self.graph.total_persistent_allocations.get_or_init(|| {
260 self.children()
261 .map(|graph| graph.total_persistent_allocations())
262 .reduce(|a, b| a + b)
263 .unwrap_or_default()
264 + self.self_persistent_allocations()
265 })
266 }
267
268 pub fn total_allocation_count(&self) -> u64 {
269 *self.graph.total_allocation_count.get_or_init(|| {
270 self.children()
271 .map(|graph| graph.total_allocation_count())
272 .reduce(|a, b| a + b)
273 .unwrap_or_default()
274 + self.self_allocation_count()
275 })
276 }
277
278 pub fn total_span_count(&self) -> u64 {
279 *self.graph.total_span_count.get_or_init(|| {
280 self.children()
281 .map(|graph| graph.total_span_count())
282 .reduce(|a, b| a + b)
283 .unwrap_or_default()
284 + self.self_span_count()
285 })
286 }
287
288 pub fn corrected_self_time(&self) -> Timestamp {
289 *self.graph.corrected_self_time.get_or_init(|| {
290 self.recursive_spans_par()
291 .map(|span| span.corrected_self_time())
292 .sum::<Timestamp>()
293 })
294 }
295
296 pub fn corrected_total_time(&self) -> Timestamp {
297 *self.graph.corrected_total_time.get_or_init(|| {
298 self.children_par()
299 .map(|graph| graph.corrected_total_time())
300 .sum::<Timestamp>()
301 + self.corrected_self_time()
302 })
303 }
304}
305
306pub fn event_map_to_list(
307 map: FxIndexMap<&str, (Vec<SpanIndex>, Vec<SpanIndex>)>,
308) -> Vec<SpanGraphEvent> {
309 map.into_iter()
310 .map(|(_, (root_spans, recursive_spans))| {
311 let graph = SpanGraph {
312 root_spans,
313 recursive_spans,
314 max_depth: OnceLock::new(),
315 events: OnceLock::new(),
316 self_time: OnceLock::new(),
317 self_allocations: OnceLock::new(),
318 self_deallocations: OnceLock::new(),
319 self_persistent_allocations: OnceLock::new(),
320 self_allocation_count: OnceLock::new(),
321 total_time: OnceLock::new(),
322 total_allocations: OnceLock::new(),
323 total_deallocations: OnceLock::new(),
324 total_persistent_allocations: OnceLock::new(),
325 total_allocation_count: OnceLock::new(),
326 total_span_count: OnceLock::new(),
327 corrected_self_time: OnceLock::new(),
328 corrected_total_time: OnceLock::new(),
329 bottom_up: OnceLock::new(),
330 };
331 SpanGraphEvent::Child {
332 child: Arc::new(graph),
333 }
334 })
335 .collect()
336}
337
338impl Debug for SpanGraphRef<'_> {
339 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
340 f.debug_struct("SpanGraphRef")
341 .field("id", &self.id())
342 .field("name", &self.nice_name())
343 .field("count", &self.count())
344 .field("max_depth", &self.max_depth())
345 .field("self_time", &self.self_time())
346 .field("self_allocations", &self.self_allocations())
347 .field("total_time", &self.total_time())
348 .field("total_allocations", &self.total_allocations())
349 .finish()
350 }
351}
352
353#[allow(dead_code)]
355#[derive(Clone)]
356pub enum SpanGraphEventRef<'a> {
357 SelfTime { duration: Timestamp },
358 Child { graph: SpanGraphRef<'a> },
359}
360
361impl SpanGraphEventRef<'_> {
362 pub fn corrected_total_time(&self) -> Timestamp {
363 match self {
364 SpanGraphEventRef::SelfTime { duration } => *duration,
365 SpanGraphEventRef::Child { graph } => graph.corrected_total_time(),
366 }
367 }
368
369 pub fn total_time(&self) -> Timestamp {
370 match self {
371 SpanGraphEventRef::SelfTime { duration } => *duration,
372 SpanGraphEventRef::Child { graph } => graph.total_time(),
373 }
374 }
375
376 pub fn total_allocations(&self) -> u64 {
377 match self {
378 SpanGraphEventRef::SelfTime { .. } => 0,
379 SpanGraphEventRef::Child { graph } => graph.total_allocations(),
380 }
381 }
382
383 pub fn total_deallocations(&self) -> u64 {
384 match self {
385 SpanGraphEventRef::SelfTime { .. } => 0,
386 SpanGraphEventRef::Child { graph } => graph.total_deallocations(),
387 }
388 }
389
390 pub fn total_persistent_allocations(&self) -> u64 {
391 match self {
392 SpanGraphEventRef::SelfTime { .. } => 0,
393 SpanGraphEventRef::Child { graph } => graph.total_persistent_allocations(),
394 }
395 }
396
397 pub fn total_allocation_count(&self) -> u64 {
398 match self {
399 SpanGraphEventRef::SelfTime { .. } => 0,
400 SpanGraphEventRef::Child { graph } => graph.total_allocation_count(),
401 }
402 }
403
404 pub fn total_span_count(&self) -> u64 {
405 match self {
406 SpanGraphEventRef::SelfTime { .. } => 0,
407 SpanGraphEventRef::Child { graph } => graph.total_span_count(),
408 }
409 }
410}