1use std::collections::HashMap;
7
8use crate::codec::{Encoder, Error, Reader, header};
9use crate::record::{LoopEvent, NameId, Record, Session, Span, Track};
10
11const MAX_NAME_GAP: usize = 1 << 16;
15
16#[derive(Clone, Debug, Default)]
18pub struct Names {
19 map: HashMap<String, NameId>,
20 list: Vec<String>,
21}
22
23impl Names {
24 pub fn new() -> Self {
25 Names {
26 map: HashMap::new(),
27 list: vec![String::new()],
28 }
29 }
30
31 pub fn get(&mut self, s: &str) -> (NameId, bool) {
33 if s.is_empty() {
34 return (0, false);
35 }
36 if let Some(&id) = self.map.get(s) {
37 return (id, false);
38 }
39 if self.list.is_empty() {
40 self.list.push(String::new());
41 }
42 let id = self.list.len() as NameId;
43 self.list.push(s.to_string());
44 self.map.insert(s.to_string(), id);
45 (id, true)
46 }
47
48 pub fn text(&self, id: NameId) -> &str {
50 self.list.get(id as usize).map_or("", String::as_str)
51 }
52
53 pub fn all(&self) -> &[String] {
55 &self.list
56 }
57
58 fn set(&mut self, id: NameId, text: String) {
59 let i = id as usize;
60 if i > self.list.len() + MAX_NAME_GAP {
65 return;
66 }
67 if self.list.len() <= i {
68 self.list.resize(i + 1, String::new());
69 }
70 self.map.insert(text.clone(), id);
71 self.list[i] = text;
72 }
73}
74
75#[derive(Clone, Debug, Default)]
78pub struct Trace {
79 pub session: Option<Session>,
80 pub names: Names,
81 pub tracks: Vec<(Track, NameId)>,
82 pub records: Vec<Record>,
83}
84
85impl Trace {
86 pub fn new() -> Self {
87 Trace {
88 names: Names::new(),
89 ..Default::default()
90 }
91 }
92
93 pub fn from_bytes(b: &[u8]) -> Result<Trace, Error> {
95 let mut t = Trace::new();
96 for r in Reader::new(b)? {
97 t.push(r);
98 }
99 Ok(t)
100 }
101
102 pub fn push(&mut self, r: Record) {
105 match r {
106 Record::Session(s) => self.session = Some(s),
107 Record::Name { id, text } => self.names.set(id, text),
108 Record::Track { id, name } => {
109 if !self.tracks.iter().any(|(t, _)| *t == id) {
110 self.tracks.push((id, name));
111 }
112 }
113 other => self.records.push(other),
114 }
115 }
116
117 pub fn slice(&self, tl: &Timeline, first: usize, last: usize) -> Trace {
121 let f0 = &tl.frames[first];
122 let f1 = &tl.frames[last];
123 let from = f0.gap_from;
124 let to = f1
125 .present
126 .map_or(f1.end_or_begin(), |p| p.t.max(f1.end_or_begin()))
127 + 1;
128 let frames: std::collections::HashSet<u64> =
129 tl.frames[first..=last].iter().map(|f| f.frame).collect();
130 let records = self
131 .records
132 .iter()
133 .filter(|r| match (r.t(), r) {
134 (Some(t), _) => t >= from && t < to,
135 (None, Record::Holder { frame, .. }) => frames.contains(frame),
136 (None, _) => true,
137 })
138 .cloned()
139 .collect();
140 Trace {
141 session: self.session.clone(),
142 names: self.names.clone(),
143 tracks: self.tracks.clone(),
144 records,
145 }
146 }
147
148 pub fn name(&self, id: NameId) -> &str {
150 self.names.text(id)
151 }
152
153 pub fn track_name(&self, t: Track) -> &str {
155 match t {
156 Track::MAIN => "main",
157 Track::LOOP => "loop",
158 t => self
159 .tracks
160 .iter()
161 .find(|(id, _)| *id == t)
162 .map_or("", |(_, n)| self.name(*n)),
163 }
164 }
165
166 pub fn to_bytes(&self) -> Vec<u8> {
169 let mut out = header();
170 let mut enc = Encoder::new();
171 if let Some(s) = &self.session {
172 enc.encode(&Record::Session(s.clone()), &mut out);
173 }
174 for (id, text) in self.names.all().iter().enumerate().skip(1) {
175 if text.is_empty() {
177 continue;
178 }
179 enc.encode(
180 &Record::Name {
181 id: id as NameId,
182 text: text.clone(),
183 },
184 &mut out,
185 );
186 }
187 for (id, name) in &self.tracks {
188 enc.encode(
189 &Record::Track {
190 id: *id,
191 name: *name,
192 },
193 &mut out,
194 );
195 }
196 for r in &self.records {
197 enc.encode(r, &mut out);
198 }
199 out
200 }
201
202 pub fn timeline(&self) -> Timeline {
204 Timeline::of(&self.records)
205 }
206}
207
208#[derive(Clone, Debug, PartialEq)]
210pub struct Holder {
211 pub what: NameId,
212 pub name: NameId,
213 pub node: u64,
214}
215
216#[derive(Clone, Copy, Debug, PartialEq)]
218pub struct Present {
219 pub t: u64,
220 pub render: u64,
221 pub wait: u64,
222}
223
224#[derive(Clone, Debug, PartialEq)]
226pub struct Frame {
227 pub frame: u64,
228 pub begin: u64,
229 pub end: Option<u64>,
231 pub gap_from: u64,
234 pub causes: Vec<NameId>,
235 pub holders: Vec<Holder>,
236 pub present: Option<Present>,
237 pub unchanged: Option<bool>,
238 pub nodes: u32,
239 pub counters: Vec<(NameId, i64)>,
240}
241
242impl Frame {
243 pub fn end_or_begin(&self) -> u64 {
245 self.end.unwrap_or(self.begin)
246 }
247
248 pub fn core_us(&self) -> u64 {
250 self.end_or_begin().saturating_sub(self.begin)
251 }
252
253 pub fn work_us(&self) -> u64 {
256 self.core_us()
257 .saturating_add(self.present.map_or(0, |p| p.render))
258 }
259}
260
261#[derive(Clone, Copy, Debug, PartialEq)]
262pub struct Input {
263 pub t: u64,
264 pub kind: NameId,
265 pub os_t: Option<u64>,
266 pub count: u32,
267 pub until: u64,
268}
269
270#[derive(Clone, Copy, Debug, PartialEq)]
271pub struct Event {
272 pub t: u64,
273 pub kind: NameId,
274 pub node: u64,
275}
276
277#[derive(Clone, Copy, Debug, PartialEq)]
278pub struct Request {
279 pub t: u64,
280 pub why: NameId,
281 pub at: NameId,
282}
283
284#[derive(Clone, Copy, Debug, PartialEq)]
285pub struct Gauge {
286 pub t: u64,
287 pub name: NameId,
288 pub value: f64,
289}
290
291#[derive(Clone, Copy, Debug, PartialEq)]
292pub struct Mark {
293 pub t: u64,
294 pub track: Track,
295 pub name: NameId,
296}
297
298#[derive(Clone, Copy, Debug, PartialEq)]
300pub struct Placement {
301 pub t: u64,
302 pub node: u64,
303 pub component: NameId,
304 pub answer: NameId,
305 pub why: NameId,
306}
307
308#[derive(Clone, Debug, Default, PartialEq)]
311pub struct Timeline {
312 pub frames: Vec<Frame>,
313 pub spans: Vec<Span>,
315 pub inputs: Vec<Input>,
316 pub events: Vec<Event>,
317 pub wakes: Vec<(u64, NameId)>,
318 pub requests: Vec<Request>,
319 pub loops: Vec<(u64, LoopEvent)>,
320 pub gauges: Vec<Gauge>,
321 pub marks: Vec<Mark>,
322 pub notes: Vec<(u64, String)>,
323 pub placements: Vec<Placement>,
324 pub start: u64,
326 pub end: u64,
327 open: HashMap<u64, usize>,
330 placed: bool,
331}
332
333fn sort_tail<T, K: Ord>(v: &mut [T], old: usize, key: impl Fn(&T) -> K) {
336 let Some(least) = v[old..].iter().map(&key).min() else {
337 return;
338 };
339 let from = v[..old].partition_point(|x| key(x) <= least);
340 v[from..].sort_by_key(key);
341}
342
343impl Timeline {
344 pub fn of(records: &[Record]) -> Timeline {
345 let mut tl = Timeline::default();
346 tl.extend(records);
347 tl
348 }
349
350 pub fn extend(&mut self, records: &[Record]) {
354 let tl = self;
355 let was = [
356 tl.spans.len(),
357 tl.inputs.len(),
358 tl.events.len(),
359 tl.wakes.len(),
360 tl.requests.len(),
361 tl.loops.len(),
362 tl.gauges.len(),
363 tl.marks.len(),
364 tl.notes.len(),
365 tl.placements.len(),
366 ];
367 let open = &mut tl.open;
368 let (mut first, mut last) = if tl.placed {
369 (tl.start, tl.end)
370 } else {
371 (u64::MAX, 0)
372 };
373 for r in records {
374 if let Some(t) = r.t() {
375 first = first.min(t);
376 let e = match r {
377 Record::Span(s) => s.end(),
378 Record::Input { until, .. } => *until,
379 _ => t,
380 };
381 last = last.max(e);
382 }
383 match r {
384 Record::FrameBegin { t, frame, causes } => {
385 let gap_from = tl.frames.last().map_or(0, Frame::end_or_begin);
386 open.insert(*frame, tl.frames.len());
387 tl.frames.push(Frame {
388 frame: *frame,
389 begin: *t,
390 end: None,
391 gap_from,
392 causes: causes.clone(),
393 holders: Vec::new(),
394 present: None,
395 unchanged: None,
396 nodes: 0,
397 counters: Vec::new(),
398 });
399 }
400 Record::Holder {
401 frame,
402 what,
403 name,
404 node,
405 } => {
406 if let Some(&i) = open.get(frame) {
407 tl.frames[i].holders.push(Holder {
408 what: *what,
409 name: *name,
410 node: *node,
411 });
412 }
413 }
414 Record::FrameEnd {
415 t,
416 frame,
417 unchanged,
418 nodes,
419 } => {
420 if let Some(&i) = open.get(frame) {
421 let f = &mut tl.frames[i];
422 f.end = Some(*t);
423 f.unchanged = *unchanged;
424 f.nodes = *nodes;
425 }
426 }
427 Record::Present {
428 t,
429 frame,
430 render,
431 wait,
432 } => {
433 if let Some(&i) = open.get(frame) {
434 tl.frames[i].present = Some(Present {
435 t: *t,
436 render: *render,
437 wait: *wait,
438 });
439 }
440 }
441 Record::Counter {
442 frame, name, value, ..
443 } => {
444 if let Some(&i) = open.get(frame) {
445 tl.frames[i].counters.push((*name, *value));
446 }
447 }
448 Record::Span(s) => tl.spans.push(s.clone()),
449 Record::Input {
450 t,
451 kind,
452 os_t,
453 count,
454 until,
455 } => tl.inputs.push(Input {
456 t: *t,
457 kind: *kind,
458 os_t: *os_t,
459 count: *count,
460 until: *until,
461 }),
462 Record::Event { t, kind, node } => tl.events.push(Event {
463 t: *t,
464 kind: *kind,
465 node: *node,
466 }),
467 Record::Wake { t, name } => tl.wakes.push((*t, *name)),
468 Record::Request { t, why, at } => tl.requests.push(Request {
469 t: *t,
470 why: *why,
471 at: *at,
472 }),
473 Record::Loop { t, event } => tl.loops.push((*t, *event)),
474 Record::Gauge { t, name, value } => tl.gauges.push(Gauge {
475 t: *t,
476 name: *name,
477 value: *value,
478 }),
479 Record::Mark { t, track, name } => tl.marks.push(Mark {
480 t: *t,
481 track: *track,
482 name: *name,
483 }),
484 Record::Note { t, text } => tl.notes.push((*t, text.clone())),
485 Record::Placement {
486 t,
487 node,
488 component,
489 answer,
490 why,
491 } => tl.placements.push(Placement {
492 t: *t,
493 node: *node,
494 component: *component,
495 answer: *answer,
496 why: *why,
497 }),
498 Record::Session(_) | Record::Name { .. } | Record::Track { .. } => {}
499 }
500 }
501 sort_tail(&mut tl.spans, was[0], |s| {
505 (s.start, std::cmp::Reverse(s.dur))
506 });
507 sort_tail(&mut tl.inputs, was[1], |i| i.t);
508 sort_tail(&mut tl.events, was[2], |e| e.t);
509 sort_tail(&mut tl.wakes, was[3], |w| w.0);
510 sort_tail(&mut tl.requests, was[4], |r| r.t);
511 sort_tail(&mut tl.loops, was[5], |l| l.0);
512 sort_tail(&mut tl.gauges, was[6], |g| g.t);
513 sort_tail(&mut tl.marks, was[7], |m| m.t);
514 sort_tail(&mut tl.notes, was[8], |n| n.0);
515 sort_tail(&mut tl.placements, was[9], |p| p.t);
516 if first != u64::MAX {
517 tl.start = first;
518 tl.end = last;
519 tl.placed = true;
520 }
521 }
522
523 pub fn spans_in(&self, from: u64, to: u64) -> &[Span] {
525 if from >= to {
526 return &[];
527 }
528 let a = self.spans.partition_point(|s| s.start < from);
529 let b = self.spans.partition_point(|s| s.start < to);
530 &self.spans[a..b]
531 }
532
533 pub fn inputs_in(&self, from: u64, to: u64) -> &[Input] {
535 if from >= to {
536 return &[];
537 }
538 let a = self.inputs.partition_point(|i| i.t < from);
539 let b = self.inputs.partition_point(|i| i.t < to);
540 &self.inputs[a..b]
541 }
542
543 pub fn events_in(&self, from: u64, to: u64) -> &[Event] {
545 if from >= to {
546 return &[];
547 }
548 let a = self.events.partition_point(|e| e.t < from);
549 let b = self.events.partition_point(|e| e.t < to);
550 &self.events[a..b]
551 }
552
553 pub fn loops_in(&self, from: u64, to: u64) -> &[(u64, LoopEvent)] {
555 if from >= to {
556 return &[];
557 }
558 let a = self.loops.partition_point(|l| l.0 < from);
559 let b = self.loops.partition_point(|l| l.0 < to);
560 &self.loops[a..b]
561 }
562
563 pub fn wakes_in(&self, from: u64, to: u64) -> &[(u64, NameId)] {
565 if from >= to {
566 return &[];
567 }
568 let a = self.wakes.partition_point(|w| w.0 < from);
569 let b = self.wakes.partition_point(|w| w.0 < to);
570 &self.wakes[a..b]
571 }
572
573 pub fn marks_in(&self, from: u64, to: u64) -> &[Mark] {
575 if from >= to {
576 return &[];
577 }
578 let a = self.marks.partition_point(|m| m.t < from);
579 let b = self.marks.partition_point(|m| m.t < to);
580 &self.marks[a..b]
581 }
582
583 pub fn notes_in(&self, from: u64, to: u64) -> &[(u64, String)] {
585 if from >= to {
586 return &[];
587 }
588 let a = self.notes.partition_point(|n| n.0 < from);
589 let b = self.notes.partition_point(|n| n.0 < to);
590 &self.notes[a..b]
591 }
592
593 pub fn placements_in(&self, from: u64, to: u64) -> &[Placement] {
595 if from >= to {
596 return &[];
597 }
598 let a = self.placements.partition_point(|p| p.t < from);
599 let b = self.placements.partition_point(|p| p.t < to);
600 &self.placements[a..b]
601 }
602
603 pub fn requests_in(&self, from: u64, to: u64) -> &[Request] {
605 if from >= to {
606 return &[];
607 }
608 let a = self.requests.partition_point(|r| r.t < from);
609 let b = self.requests.partition_point(|r| r.t < to);
610 &self.requests[a..b]
611 }
612
613 pub fn has_loop(&self) -> bool {
615 !self.loops.is_empty()
616 }
617
618 pub fn self_us(&self, s: &Span) -> u64 {
620 let kids: u64 = self
623 .spans_in(s.start, s.end().max(s.start + 1))
624 .iter()
625 .filter(|k| k.parent == s.id && k.id != s.id)
626 .map(|k| k.end().min(s.end()).saturating_sub(k.start))
627 .sum();
628 s.dur.saturating_sub(kids)
629 }
630}