1use std::{
2 cmp::max,
3 collections::VecDeque,
4 fmt::{Debug, Formatter},
5 vec,
6};
7
8use hashbrown::HashMap;
9use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
10use rustc_hash::FxHashSet;
11
12use crate::{
13 FxIndexMap,
14 bottom_up::build_bottom_up_graph,
15 span::{Span, SpanEvent, SpanExtra, SpanGraphEvent, SpanIndex, SpanNames, SpanTimeData},
16 span_bottom_up_ref::SpanBottomUpRef,
17 span_graph_ref::{SpanGraphEventRef, SpanGraphRef, event_map_to_list},
18 store::{SpanId, Store},
19 timestamp::Timestamp,
20};
21
22pub type GroupNameToDirectAndRecusiveSpans<'l> =
23 FxIndexMap<(&'l str, &'l str), (Vec<SpanIndex>, Vec<SpanIndex>)>;
24
25#[derive(Copy, Clone)]
26pub struct SpanRef<'a> {
27 pub(crate) span: &'a Span,
28 pub(crate) store: &'a Store,
29 pub(crate) index: usize,
30}
31
32impl<'a> SpanRef<'a> {
33 pub fn id(&self) -> SpanId {
34 unsafe { SpanId::new_unchecked(self.index << 1) }
35 }
36
37 pub fn index(&self) -> SpanIndex {
38 SpanIndex::new(self.index).unwrap()
39 }
40
41 pub fn parent(&self) -> Option<SpanRef<'a>> {
42 self.span.parent.map(|index| SpanRef {
43 span: &self.store.spans[index.get()],
44 store: self.store,
45 index: index.get(),
46 })
47 }
48
49 pub fn start(&self) -> Timestamp {
50 self.span.start
51 }
52
53 pub fn time_data(&self) -> &'a SpanTimeData {
54 self.span.time_data()
55 }
56
57 pub fn extra(&self) -> &'a SpanExtra {
58 self.span.extra()
59 }
60
61 pub fn names(&self) -> &'a SpanNames {
62 self.span.names()
63 }
64
65 pub fn end(&self) -> Timestamp {
66 let time_data = self.time_data();
67 *time_data.end.get_or_init(|| {
68 max(
69 time_data.self_end,
70 self.children()
71 .map(|child| child.end())
72 .max()
73 .unwrap_or_default(),
74 )
75 })
76 }
77
78 pub fn is_complete(&self) -> bool {
79 self.span.is_complete
80 }
81
82 pub fn is_root(&self) -> bool {
83 self.index == 0
84 }
85
86 pub fn nice_name(&self) -> (&'a str, &'a str) {
87 let (category, title) = self.names().nice_name.get_or_init(|| {
88 if let Some(name) = self
89 .span
90 .args
91 .iter()
92 .find(|&(k, _)| k == "name")
93 .map(|(_, v)| v.as_str())
94 {
95 if matches!(self.span.name.as_str(), "turbo_tasks::function") {
96 (self.span.name.clone(), name.to_string())
97 } else if matches!(
98 self.span.name.as_str(),
99 "turbo_tasks::resolve_call" | "turbo_tasks::resolve_trait_call"
100 ) {
101 (self.span.name.clone(), format!("*{name}"))
102 } else {
103 (
104 self.span.category.clone(),
105 format!("{} {name}", self.span.name),
106 )
107 }
108 } else {
109 (self.span.category.to_string(), self.span.name.to_string())
110 }
111 });
112 (category, title)
113 }
114
115 pub fn group_name(&self) -> (&'a str, &'a str) {
116 let (category, title) = self.names().group_name.get_or_init(|| {
117 if matches!(self.span.name.as_str(), "turbo_tasks::function") {
118 let name = self
119 .span
120 .args
121 .iter()
122 .find(|&(k, _)| k == "name")
123 .map(|(_, v)| v.to_string())
124 .unwrap_or_else(|| self.span.name.to_string());
125 (self.span.name.clone(), name)
126 } else if matches!(
127 self.span.name.as_str(),
128 "turbo_tasks::resolve_call" | "turbo_tasks::resolve_trait_call"
129 ) {
130 let name = self
131 .span
132 .args
133 .iter()
134 .find(|&(k, _)| k == "name")
135 .map(|(_, v)| format!("*{v}"))
136 .unwrap_or_else(|| self.span.name.to_string());
137 (
138 self.span.category.clone(),
139 format!("{} {name}", self.span.name),
140 )
141 } else {
142 (self.span.category.clone(), self.span.name.clone())
143 }
144 });
145 (category.as_str(), title.as_str())
146 }
147
148 pub fn args(&self) -> impl Iterator<Item = (&str, &str)> {
149 self.span.args.iter().map(|(k, v)| (k.as_str(), v.as_str()))
150 }
151
152 pub fn self_time(&self) -> Timestamp {
153 self.time_data().self_time
154 }
155
156 pub fn self_allocations(&self) -> u64 {
157 self.span.self_allocations.saturating_sub(32)
159 }
160
161 pub fn self_deallocations(&self) -> u64 {
162 self.span.self_deallocations
163 }
164
165 pub fn self_persistent_allocations(&self) -> u64 {
166 self.self_allocations()
167 .saturating_sub(self.span.self_deallocations)
168 }
169
170 pub fn self_allocation_count(&self) -> u64 {
171 self.span.self_allocation_count.saturating_sub(4)
173 }
174
175 pub fn self_span_count(&self) -> u64 {
176 1
177 }
178
179 #[allow(dead_code)]
181 pub fn events(&self) -> impl DoubleEndedIterator<Item = SpanEventRef<'a>> {
182 self.span.events.iter().map(|event| match event {
183 &SpanEvent::SelfTime { start, end } => SpanEventRef::SelfTime {
184 store: self.store,
185 start,
186 end,
187 },
188 SpanEvent::Child { index } => SpanEventRef::Child {
189 span: SpanRef {
190 span: &self.store.spans[index.get()],
191 store: self.store,
192 index: index.get(),
193 },
194 },
195 })
196 }
197
198 pub fn children(&self) -> impl DoubleEndedIterator<Item = SpanRef<'a>> + 'a + use<'a> {
199 self.span.events.iter().filter_map(|event| match event {
200 SpanEvent::SelfTime { .. } => None,
201 SpanEvent::Child { index } => Some(SpanRef {
202 span: &self.store.spans[index.get()],
203 store: self.store,
204 index: index.get(),
205 }),
206 })
207 }
208
209 pub fn children_par(&self) -> impl ParallelIterator<Item = SpanRef<'a>> + 'a {
210 self.span.events.par_iter().filter_map(|event| match event {
211 SpanEvent::SelfTime { .. } => None,
212 SpanEvent::Child { index } => Some(SpanRef {
213 span: &self.store.spans[index.get()],
214 store: self.store,
215 index: index.get(),
216 }),
217 })
218 }
219
220 pub fn total_time(&self) -> Timestamp {
221 *self.time_data().total_time.get_or_init(|| {
222 self.children()
223 .map(|child| child.total_time())
224 .reduce(|a, b| a + b)
225 .unwrap_or_default()
226 + self.self_time()
227 })
228 }
229
230 pub fn total_allocations(&self) -> u64 {
231 *self.span.total_allocations.get_or_init(|| {
232 self.children()
233 .map(|child| child.total_allocations())
234 .reduce(|a, b| a + b)
235 .unwrap_or_default()
236 + self.self_allocations()
237 })
238 }
239
240 pub fn total_deallocations(&self) -> u64 {
241 *self.span.total_deallocations.get_or_init(|| {
242 self.children()
243 .map(|child| child.total_deallocations())
244 .reduce(|a, b| a + b)
245 .unwrap_or_default()
246 + self.self_deallocations()
247 })
248 }
249
250 pub fn total_persistent_allocations(&self) -> u64 {
251 *self.span.total_persistent_allocations.get_or_init(|| {
252 self.children()
253 .map(|child| child.total_persistent_allocations())
254 .reduce(|a, b| a + b)
255 .unwrap_or_default()
256 + self.self_persistent_allocations()
257 })
258 }
259
260 pub fn total_allocation_count(&self) -> u64 {
261 *self.span.total_allocation_count.get_or_init(|| {
262 self.children()
263 .map(|child| child.total_allocation_count())
264 .reduce(|a, b| a + b)
265 .unwrap_or_default()
266 + self.self_allocation_count()
267 })
268 }
269
270 pub fn total_span_count(&self) -> u64 {
271 *self.span.total_span_count.get_or_init(|| {
272 self.children()
273 .map(|child| child.total_span_count())
274 .reduce(|a, b| a + b)
275 .unwrap_or_default()
276 + 1
277 })
278 }
279
280 pub fn corrected_self_time(&self) -> Timestamp {
281 let store = self.store;
282 *self.time_data().corrected_self_time.get_or_init(|| {
283 let mut self_time = self
284 .span
285 .events
286 .par_iter()
287 .filter_map(|event| {
288 if let SpanEvent::SelfTime { start, end } = event {
289 let duration = *end - *start;
290 if !duration.is_zero() {
291 store.set_max_self_time_lookup(*end);
292 let corrected_time =
293 store.self_time_tree.as_ref().map_or(duration, |tree| {
294 tree.lookup_range_corrected_time(*start, *end)
295 });
296 return Some(corrected_time);
297 }
298 }
299 None
300 })
301 .sum();
302 if self.children().next().is_none() {
303 self_time = max(self_time, Timestamp::from_value(1));
304 }
305 self_time
306 })
307 }
308
309 pub fn corrected_total_time(&self) -> Timestamp {
310 *self.time_data().corrected_total_time.get_or_init(|| {
311 self.children_par()
312 .map(|child| child.corrected_total_time())
313 .sum::<Timestamp>()
314 + self.corrected_self_time()
315 })
316 }
317
318 pub fn max_depth(&self) -> u32 {
319 *self.span.max_depth.get_or_init(|| {
320 self.children()
321 .map(|child| child.max_depth() + 1)
322 .max()
323 .unwrap_or_default()
324 })
325 }
326
327 pub fn graph(&self) -> impl Iterator<Item = SpanGraphEventRef<'a>> + '_ {
328 self.extra()
329 .graph
330 .get_or_init(|| {
331 struct Entry<'a> {
332 span: SpanRef<'a>,
333 recursive: Vec<SpanIndex>,
334 }
335 let entries = self
336 .children_par()
337 .map(|span| {
338 let name = span.group_name();
339 let mut recursive = Vec::new();
340 let mut queue = VecDeque::with_capacity(0);
341 for nested_child in span.children() {
342 let nested_name = nested_child.group_name();
343 if name == nested_name {
344 recursive.push(nested_child.index());
345 queue.push_back(nested_child);
346 }
347 }
348 while let Some(child) = queue.pop_front() {
349 for nested_child in child.children() {
350 let nested_name = nested_child.group_name();
351 if name == nested_name {
352 recursive.push(nested_child.index());
353 queue.push_back(nested_child);
354 }
355 }
356 }
357 Entry { span, recursive }
358 })
359 .collect_vec_list();
360 let mut map: GroupNameToDirectAndRecusiveSpans = FxIndexMap::default();
361 for Entry {
362 span,
363 mut recursive,
364 } in entries.into_iter().flatten()
365 {
366 let name = span.group_name();
367 let (list, recursive_list) = map.entry(name).or_default();
368 list.push(span.index());
369 recursive_list.append(&mut recursive);
370 }
371 event_map_to_list(map)
372 })
373 .iter()
374 .map(|event| match event {
375 SpanGraphEvent::SelfTime { duration } => SpanGraphEventRef::SelfTime {
376 duration: *duration,
377 },
378 SpanGraphEvent::Child { child } => SpanGraphEventRef::Child {
379 graph: SpanGraphRef {
380 graph: child.clone(),
381 store: self.store,
382 },
383 },
384 })
385 }
386
387 pub fn bottom_up(self) -> impl Iterator<Item = SpanBottomUpRef<'a>> {
388 self.extra()
389 .bottom_up
390 .get_or_init(|| build_bottom_up_graph([self].into_iter()))
391 .iter()
392 .map(move |bottom_up| SpanBottomUpRef {
393 bottom_up: bottom_up.clone(),
394 store: self.store,
395 })
396 }
397
398 pub fn search(&self, query: &str) -> impl Iterator<Item = SpanRef<'a>> {
399 let mut query_items = query.split(",").map(str::trim);
400 let index = self.search_index();
401 let mut result = FxHashSet::default();
402 let query = query_items.next().unwrap();
403 for (key, spans) in index {
404 if key.contains(query) {
405 result.extend(spans.iter().copied());
406 }
407 }
408 for query in query_items {
409 let mut and_result = FxHashSet::default();
410 for (key, spans) in index {
411 if key.contains(query) {
412 and_result.extend(spans.iter().copied());
413 }
414 }
415 result.retain(|index| and_result.contains(index));
416 }
417 let store = self.store;
418 result.into_iter().map(move |index| SpanRef {
419 span: &store.spans[index.get()],
420 store,
421 index: index.get(),
422 })
423 }
424
425 fn search_index(&self) -> &HashMap<String, Vec<SpanIndex>> {
426 self.extra().search_index.get_or_init(|| {
427 let mut all_spans = Vec::new();
428 all_spans.push(self.index);
429 let mut i = 0;
430 while i < all_spans.len() {
431 let index = all_spans[i];
432 let span = SpanRef {
433 span: &self.store.spans[index],
434 store: self.store,
435 index,
436 };
437 for child in span.children() {
438 all_spans.push(child.index);
439 }
440 i += 1;
441 }
442
443 enum SpanOrMap<'a> {
444 Span(SpanRef<'a>),
445 Map(HashMap<String, Vec<SpanIndex>>),
446 }
447
448 fn add_span_to_map<'a>(index: &mut HashMap<String, Vec<SpanIndex>>, span: SpanRef<'a>) {
449 if !span.is_root() {
450 let (cat, name) = span.nice_name();
451 if !cat.is_empty() {
452 index
453 .raw_entry_mut()
454 .from_key(cat)
455 .and_modify(|_, v| v.push(span.index()))
456 .or_insert_with(|| (cat.to_string(), vec![span.index()]));
457 }
458 if !name.is_empty() {
459 index
460 .raw_entry_mut()
461 .from_key(name)
462 .and_modify(|_, v| v.push(span.index()))
463 .or_insert_with(|| (format!("name={name}"), vec![span.index()]));
464 }
465 for (name, value) in span.span.args.iter() {
466 index
467 .raw_entry_mut()
468 .from_key(value)
469 .and_modify(|_, v| v.push(span.index()))
470 .or_insert_with(|| (format!("{name}={value}"), vec![span.index()]));
471 }
472 if !span.is_complete() && span.span.name != "thread" {
473 let name = "incomplete_span";
474 index
475 .raw_entry_mut()
476 .from_key(name)
477 .and_modify(|_, v| v.push(span.index()))
478 .or_insert_with(|| (name.to_string(), vec![span.index()]));
479 }
480 }
481 }
482
483 let result = all_spans
484 .into_par_iter()
485 .map(|index| {
486 SpanOrMap::Span(SpanRef {
487 span: &self.store.spans[index],
488 store: self.store,
489 index,
490 })
491 })
492 .reduce(
493 || SpanOrMap::Map(HashMap::default()),
494 |a, b| {
495 let mut map = match a {
496 SpanOrMap::Span(span) => {
497 let mut map = HashMap::default();
498 add_span_to_map(&mut map, span);
499 map
500 }
501 SpanOrMap::Map(map) => map,
502 };
503 match b {
504 SpanOrMap::Span(span) => {
505 add_span_to_map(&mut map, span);
506 }
507 SpanOrMap::Map(other_map) => {
508 for (name, value) in other_map {
509 map.entry(name).or_default().extend(value);
510 }
511 }
512 }
513 SpanOrMap::Map(map)
514 },
515 );
516 match result {
517 SpanOrMap::Span(span) => {
518 let mut map = HashMap::default();
519 add_span_to_map(&mut map, span);
520 map
521 }
522 SpanOrMap::Map(map) => map,
523 }
524 })
525 }
526}
527
528impl Debug for SpanRef<'_> {
529 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
530 f.debug_struct("SpanRef")
531 .field("id", &self.id())
532 .field("name", &self.nice_name())
533 .field("start", &self.start())
534 .field("end", &self.end())
535 .field("is_complete", &self.is_complete())
536 .field("self_time", &self.self_time())
537 .field("total_time", &self.total_time())
538 .field("max_depth", &self.max_depth())
539 .finish()
540 }
541}
542
543#[allow(dead_code)]
544#[derive(Copy, Clone)]
545pub enum SpanEventRef<'a> {
546 SelfTime {
547 store: &'a Store,
548 start: Timestamp,
549 end: Timestamp,
550 },
551 Child {
552 span: SpanRef<'a>,
553 },
554}
555
556impl SpanEventRef<'_> {
557 pub fn start(&self) -> Timestamp {
558 match self {
559 SpanEventRef::SelfTime { start, .. } => *start,
560 SpanEventRef::Child { span } => span.start(),
561 }
562 }
563
564 pub fn total_time(&self) -> Timestamp {
565 match self {
566 SpanEventRef::SelfTime { start, end, .. } => end.saturating_sub(*start),
567 SpanEventRef::Child { span } => span.total_time(),
568 }
569 }
570
571 pub fn corrected_self_time(&self) -> Timestamp {
572 match self {
573 SpanEventRef::SelfTime { store, start, end } => {
574 let duration = *end - *start;
575 if !duration.is_zero() {
576 store.set_max_self_time_lookup(*end);
577 store.self_time_tree.as_ref().map_or(duration, |tree| {
578 tree.lookup_range_corrected_time(*start, *end)
579 })
580 } else {
581 Timestamp::ZERO
582 }
583 }
584 SpanEventRef::Child { span } => span.corrected_self_time(),
585 }
586 }
587}