iced_runtime/debug/
basic.rs

1#![allow(missing_docs)]
2use crate::core::time;
3
4use std::collections::VecDeque;
5
6/// A bunch of time measurements for debugging purposes.
7#[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    /// Creates a new [`struct@Debug`].
38    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}