Skip to main content

kui_trace/
dump.rs

1//! A recording as text, one record a line (`kui-trace dump`): for a diff
2//! between two runs, a grep, a bug report's body.
3
4use std::fmt::Write;
5
6use crate::model::Trace;
7use crate::record::{LoopEvent, Origin, Record};
8
9fn ms(us: u64) -> String {
10    format!("{:>10.3}", us as f64 / 1000.0)
11}
12
13/// `trace` as text: the session, then every record in the order written,
14/// its time in ms first.
15pub fn dump(trace: &Trace) -> String {
16    let mut out = String::new();
17    let n = |id| trace.name(id);
18    if let Some(s) = &trace.session {
19        let _ = writeln!(
20            out,
21            "session kui {} · {} · {} · {:.0} Hz ({:.2} ms) · @{} · wall {}",
22            s.kui, s.app, s.platform, s.refresh_hz, s.budget_ms, s.scale, s.wall_ms
23        );
24    }
25    for (id, name) in &trace.tracks {
26        let _ = writeln!(out, "track {} {}", id.0, n(*name));
27    }
28    for r in &trace.records {
29        let line = match r {
30            Record::FrameBegin { t, frame, causes } => format!(
31                "{} frame+ #{frame} {}",
32                ms(*t),
33                causes.iter().map(|c| n(*c)).collect::<Vec<_>>().join(",")
34            ),
35            Record::Holder {
36                frame,
37                what,
38                name,
39                node,
40            } => format!(
41                "{:>10} holder #{frame} {} {}{}",
42                "",
43                n(*what),
44                n(*name),
45                if *node != 0 {
46                    format!(" node {node:016x}")
47                } else {
48                    String::new()
49                }
50            ),
51            Record::FrameEnd {
52                t,
53                frame,
54                unchanged,
55                nodes,
56            } => format!(
57                "{} frame- #{frame} {nodes} nodes{}",
58                ms(*t),
59                match unchanged {
60                    Some(true) => " unchanged",
61                    Some(false) => "",
62                    None => " (untraced)",
63                }
64            ),
65            Record::Present {
66                t,
67                frame,
68                render,
69                wait,
70            } => format!(
71                "{} present #{frame} render {:.3} wait {:.3}",
72                ms(*t),
73                *render as f64 / 1000.0,
74                *wait as f64 / 1000.0
75            ),
76            Record::Span(s) => format!(
77                "{} span {} [{}] {} {:.3} ms{}{}{}{}",
78                ms(s.start),
79                trace.track_name(s.track),
80                match s.origin {
81                    Origin::Kui => "kui".to_string(),
82                    Origin::Host => "host".to_string(),
83                    Origin::Extension(ns) => n(ns).to_string(),
84                },
85                n(s.name),
86                s.dur as f64 / 1000.0,
87                s.cpu
88                    .map_or(String::new(), |c| format!(" cpu {:.3}", c as f64 / 1000.0)),
89                if s.parent != 0 {
90                    format!(" in {}", s.parent)
91                } else {
92                    String::new()
93                },
94                if s.node != 0 {
95                    format!(" node {:016x}", s.node)
96                } else {
97                    String::new()
98                },
99                if s.cut { " cut" } else { "" }
100            ),
101            Record::Input {
102                t,
103                kind,
104                os_t,
105                count,
106                until,
107            } => format!(
108                "{} input {}{}{}",
109                ms(*t),
110                n(*kind),
111                if *count > 1 {
112                    format!(" ×{count} until {}", ms(*until).trim())
113                } else {
114                    String::new()
115                },
116                os_t.map_or(String::new(), |o| format!(" os {}", ms(o).trim()))
117            ),
118            Record::Event { t, kind, node } => {
119                format!("{} event {} node {node:016x}", ms(*t), n(*kind))
120            }
121            Record::Wake { t, name } => format!("{} wake {}", ms(*t), n(*name)),
122            Record::Request { t, why, at } => {
123                format!("{} request {} at {}", ms(*t), n(*why), n(*at))
124            }
125            Record::Loop { t, event } => match event {
126                LoopEvent::Sleep { until } => format!(
127                    "{} loop sleep{}",
128                    ms(*t),
129                    until.map_or(String::new(), |u| format!(" until {}", ms(u).trim()))
130                ),
131                LoopEvent::Woke { by } => format!("{} loop woke {}", ms(*t), n(*by)),
132                LoopEvent::Os { kind } => format!("{} loop os {}", ms(*t), n(*kind)),
133            },
134            Record::Counter {
135                t,
136                frame,
137                name,
138                value,
139            } => format!("{} counter #{frame} {} {value}", ms(*t), n(*name)),
140            Record::Gauge { t, name, value } => {
141                format!("{} gauge {} {value}", ms(*t), n(*name))
142            }
143            Record::Mark { t, track, name } => {
144                format!("{} mark {} {}", ms(*t), trace.track_name(*track), n(*name))
145            }
146            Record::Note { t, text } => format!("{} note {text}", ms(*t)),
147            Record::Placement {
148                t,
149                node,
150                component,
151                answer,
152                why,
153            } => format!(
154                "{} placed {} {}{} node {node:016x}",
155                ms(*t),
156                n(*component),
157                n(*answer),
158                match n(*why) {
159                    "" => String::new(),
160                    w => format!(" ({w})"),
161                }
162            ),
163            Record::Session(_) | Record::Name { .. } | Record::Track { .. } => continue,
164        };
165        out.push_str(&line);
166        out.push('\n');
167    }
168    out
169}