Skip to main content

kui_trace/
record.rs

1//! The records a recording is made of (ADR 0058, decision 2): each placed
2//! on one clock — µs since the recording began — and, where it says, on a
3//! track. Frames are intervals on that clock, not its unit: what happens
4//! after one frame ends and before the next begins is that next frame's
5//! gap.
6//!
7//! No record holds a payload, typed text or a concealed field's
8//! anything: kinds, keys, labels and times. A recording goes into bug
9//! reports.
10
11/// A string written once per recording by a [`Record::Name`]; `0` is the
12/// empty string, never written.
13pub type NameId = u32;
14
15/// A row of the timeline: [`Track::MAIN`] the thread the core runs on,
16/// [`Track::LOOP`] the driver's loop, and one per name `perf_measure` was
17/// given, declared by a [`Record::Track`].
18#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, PartialOrd, Ord)]
19pub struct Track(pub u32);
20
21impl Track {
22    pub const MAIN: Track = Track(0);
23    pub const LOOP: Track = Track(1);
24}
25
26/// Who a span or a measurement is for.
27#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
28pub enum Origin {
29    /// kui's own: `build`, `layout`, `emit`, the devtools, a fill.
30    Kui,
31    /// The app.
32    Host,
33    /// An extension, by its namespace.
34    Extension(NameId),
35}
36
37/// What the recording was made of, once, first.
38#[derive(Clone, Debug, Default, PartialEq)]
39pub struct Session {
40    /// The kui version that wrote it.
41    pub kui: String,
42    /// The app's name, as its window titled it.
43    pub app: String,
44    /// `macos`, `windows`, `linux`, …
45    pub platform: String,
46    /// The display's refresh rate, and the frame budget it makes.
47    pub refresh_hz: f32,
48    pub budget_ms: f32,
49    pub scale: f32,
50    /// The wall clock at 0, ms since the Unix epoch.
51    pub wall_ms: u64,
52}
53
54/// A span closed: a name, a start and a length on its track, nested in
55/// its parent.
56#[derive(Clone, Debug, PartialEq)]
57pub struct Span {
58    pub track: Track,
59    /// Unique in the recording; `0` is no span.
60    pub id: u32,
61    /// The span it was opened inside, or `0`.
62    pub parent: u32,
63    pub name: NameId,
64    pub origin: Origin,
65    pub start: u64,
66    pub dur: u64,
67    /// The thread's time on a CPU over it, where the platform reads one.
68    pub cpu: Option<u64>,
69    /// The key of the node the builder had open as it began, or `0`.
70    pub node: u64,
71    /// Left open when its frame ended, and closed there.
72    pub cut: bool,
73}
74
75impl Span {
76    pub fn end(&self) -> u64 {
77        self.start.saturating_add(self.dur)
78    }
79}
80
81/// What the driver's loop did.
82#[derive(Clone, Copy, Debug, PartialEq)]
83pub enum LoopEvent {
84    /// Went to sleep, until a time when there was one.
85    Sleep { until: Option<u64> },
86    /// Woke, and why (`input`, `wake`, `timer`, `redraw`, …).
87    Woke { by: NameId },
88    /// Handled an OS event that never became input.
89    Os { kind: NameId },
90}
91
92/// One record.
93#[derive(Clone, Debug, PartialEq)]
94pub enum Record {
95    Session(Session),
96    Name {
97        id: NameId,
98        text: String,
99    },
100    Track {
101        id: Track,
102        name: NameId,
103    },
104    /// A frame begun, with why it runs: the cause kinds and the named
105    /// ones (`wake: parser`, `request: caret blink`).
106    FrameBegin {
107        t: u64,
108        frame: u64,
109        causes: Vec<NameId>,
110    },
111    /// Who held the frame the last one left owed: what for and its name.
112    Holder {
113        frame: u64,
114        what: NameId,
115        name: NameId,
116        node: u64,
117    },
118    /// A frame finished: whether it drew what the one before drew, and
119    /// how many nodes it held.
120    FrameEnd {
121        t: u64,
122        frame: u64,
123        unchanged: Option<bool>,
124        nodes: u32,
125    },
126    /// A frame drawn: the driver's render and vsync's wait, µs.
127    Present {
128        t: u64,
129        frame: u64,
130        render: u64,
131        wait: u64,
132    },
133    Span(Span),
134    /// Input arriving: its kind and, for a run of one kind (pointer
135    /// moves), how many and until when — never before `t`, which is what
136    /// a single input's `until` is.
137    Input {
138        t: u64,
139        kind: NameId,
140        os_t: Option<u64>,
141        count: u32,
142        until: u64,
143    },
144    /// An event handed to the app: its kind and its node.
145    Event {
146        t: u64,
147        kind: NameId,
148        node: u64,
149    },
150    Wake {
151        t: u64,
152        name: NameId,
153    },
154    /// A frame asked for: why, and the source line that asked.
155    Request {
156        t: u64,
157        why: NameId,
158        at: NameId,
159    },
160    Loop {
161        t: u64,
162        event: LoopEvent,
163    },
164    /// A frame's counter: its total over the frame.
165    Counter {
166        t: u64,
167        frame: u64,
168        name: NameId,
169        value: i64,
170    },
171    /// A reading set.
172    Gauge {
173        t: u64,
174        name: NameId,
175        value: f64,
176    },
177    /// An instant.
178    Mark {
179        t: u64,
180        track: Track,
181        name: NameId,
182    },
183    /// A line the app wrote (`perf_note`): what the numbers beside it
184    /// cannot say — a pane's "editor moved, reads fs.stat".
185    Note {
186        t: u64,
187        text: String,
188    },
189    /// A component placed (ADR 0067): its kind, the node it is at, how
190    /// it was filled — `replayed`, or drawn fresh and why in a word
191    /// (`not-kept`, `params`, `reads`, `not-replayable`, `heard`) — and,
192    /// for `reads` and `not-replayable`, the fact that moved or what made
193    /// it unreplayable: `hover 00000000000000ab`, `the clock`. The fact's
194    /// kind and node, never what it read.
195    Placement {
196        t: u64,
197        node: u64,
198        component: NameId,
199        answer: NameId,
200        why: NameId,
201    },
202}
203
204impl Record {
205    /// The time it is placed at, for one that has one.
206    pub fn t(&self) -> Option<u64> {
207        Some(match self {
208            Record::Session(_)
209            | Record::Name { .. }
210            | Record::Track { .. }
211            | Record::Holder { .. } => return None,
212            Record::FrameBegin { t, .. }
213            | Record::FrameEnd { t, .. }
214            | Record::Present { t, .. }
215            | Record::Input { t, .. }
216            | Record::Event { t, .. }
217            | Record::Wake { t, .. }
218            | Record::Request { t, .. }
219            | Record::Loop { t, .. }
220            | Record::Counter { t, .. }
221            | Record::Gauge { t, .. }
222            | Record::Mark { t, .. }
223            | Record::Note { t, .. }
224            | Record::Placement { t, .. } => *t,
225            Record::Span(s) => s.start,
226        })
227    }
228}