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