iced_runtime/debug/
basic.rs
1#![allow(missing_docs)]
2use crate::core::time;
3
4use std::collections::VecDeque;
5
6#[derive(Debug)]
8pub struct Debug {
9 is_enabled: bool,
10
11 startup_start: time::Instant,
12 startup_duration: time::Duration,
13
14 update_start: time::Instant,
15 update_durations: TimeBuffer,
16
17 view_start: time::Instant,
18 view_durations: TimeBuffer,
19
20 layout_start: time::Instant,
21 layout_durations: TimeBuffer,
22
23 event_start: time::Instant,
24 event_durations: TimeBuffer,
25
26 draw_start: time::Instant,
27 draw_durations: TimeBuffer,
28
29 render_start: time::Instant,
30 render_durations: TimeBuffer,
31
32 message_count: usize,
33 last_messages: VecDeque<String>,
34}
35
36impl Debug {
37 pub fn new() -> Self {
39 let now = time::Instant::now();
40
41 Self {
42 is_enabled: false,
43 startup_start: now,
44 startup_duration: time::Duration::from_secs(0),
45
46 update_start: now,
47 update_durations: TimeBuffer::new(200),
48
49 view_start: now,
50 view_durations: TimeBuffer::new(200),
51
52 layout_start: now,
53 layout_durations: TimeBuffer::new(200),
54
55 event_start: now,
56 event_durations: TimeBuffer::new(200),
57
58 draw_start: now,
59 draw_durations: TimeBuffer::new(200),
60
61 render_start: now,
62 render_durations: TimeBuffer::new(50),
63
64 message_count: 0,
65 last_messages: VecDeque::new(),
66 }
67 }
68
69 pub fn toggle(&mut self) {
70 self.is_enabled = !self.is_enabled;
71 }
72
73 pub fn startup_started(&mut self) {
74 self.startup_start = time::Instant::now();
75 }
76
77 pub fn startup_finished(&mut self) {
78 self.startup_duration = self.startup_start.elapsed();
79 }
80
81 pub fn update_started(&mut self) {
82 self.update_start = time::Instant::now();
83 }
84
85 pub fn update_finished(&mut self) {
86 self.update_durations.push(self.update_start.elapsed());
87 }
88
89 pub fn view_started(&mut self) {
90 self.view_start = time::Instant::now();
91 }
92
93 pub fn view_finished(&mut self) {
94 self.view_durations.push(self.view_start.elapsed());
95 }
96
97 pub fn layout_started(&mut self) {
98 self.layout_start = time::Instant::now();
99 }
100
101 pub fn layout_finished(&mut self) {
102 self.layout_durations.push(self.layout_start.elapsed());
103 }
104
105 pub fn event_processing_started(&mut self) {
106 self.event_start = time::Instant::now();
107 }
108
109 pub fn event_processing_finished(&mut self) {
110 self.event_durations.push(self.event_start.elapsed());
111 }
112
113 pub fn draw_started(&mut self) {
114 self.draw_start = time::Instant::now();
115 }
116
117 pub fn draw_finished(&mut self) {
118 self.draw_durations.push(self.draw_start.elapsed());
119 }
120
121 pub fn render_started(&mut self) {
122 self.render_start = time::Instant::now();
123 }
124
125 pub fn render_finished(&mut self) {
126 self.render_durations.push(self.render_start.elapsed());
127 }
128
129 pub fn log_message<Message: std::fmt::Debug>(&mut self, message: &Message) {
130 self.last_messages.push_back(format!("{message:?}"));
131
132 if self.last_messages.len() > 10 {
133 let _ = self.last_messages.pop_front();
134 }
135
136 self.message_count += 1;
137 }
138
139 pub fn overlay(&self) -> Vec<String> {
140 if !self.is_enabled {
141 return Vec::new();
142 }
143
144 let mut lines = Vec::new();
145
146 fn key_value<T: std::fmt::Debug>(key: &str, value: T) -> String {
147 format!("{key} {value:?}")
148 }
149
150 lines.push(format!(
151 "{} {} - {}",
152 env!("CARGO_PKG_NAME"),
153 env!("CARGO_PKG_VERSION"),
154 env!("CARGO_PKG_REPOSITORY"),
155 ));
156 lines.push(key_value("Startup:", self.startup_duration));
157 lines.push(key_value("Update:", self.update_durations.average()));
158 lines.push(key_value("View:", self.view_durations.average()));
159 lines.push(key_value("Layout:", self.layout_durations.average()));
160 lines.push(key_value(
161 "Event processing:",
162 self.event_durations.average(),
163 ));
164 lines.push(key_value(
165 "Primitive generation:",
166 self.draw_durations.average(),
167 ));
168 lines.push(key_value("Render:", self.render_durations.average()));
169 lines.push(key_value("Message count:", self.message_count));
170 lines.push(String::from("Last messages:"));
171 lines.extend(self.last_messages.iter().map(|msg| {
172 if msg.len() <= 100 {
173 format!(" {msg}")
174 } else {
175 format!(" {msg:.100}...")
176 }
177 }));
178
179 lines
180 }
181}
182
183impl Default for Debug {
184 fn default() -> Self {
185 Self::new()
186 }
187}
188
189#[derive(Debug)]
190struct TimeBuffer {
191 head: usize,
192 size: usize,
193 contents: Vec<time::Duration>,
194}
195
196impl TimeBuffer {
197 fn new(capacity: usize) -> TimeBuffer {
198 TimeBuffer {
199 head: 0,
200 size: 0,
201 contents: vec![time::Duration::from_secs(0); capacity],
202 }
203 }
204
205 fn push(&mut self, duration: time::Duration) {
206 self.head = (self.head + 1) % self.contents.len();
207 self.contents[self.head] = duration;
208 self.size = (self.size + 1).min(self.contents.len());
209 }
210
211 fn average(&self) -> time::Duration {
212 let sum: time::Duration = if self.size == self.contents.len() {
213 self.contents[..].iter().sum()
214 } else {
215 self.contents[..self.size].iter().sum()
216 };
217
218 sum / self.size.max(1) as u32
219 }
220}