euv_ui/hook/profiler/impl.rs
1use super::*;
2
3/// Inherent implementation of [`ProfilerHandle`].
4impl ProfilerHandle {
5 /// Records a fresh measurement around the given closure.
6 ///
7 /// Captures the start timestamp, runs `f`, captures the
8 /// end timestamp, and pushes a `ProfileEntry { label,
9 /// elapsed_ms, timestamp_ms }` into the entries signal.
10 /// The `elapsed_ms` is `>= 0.0` by construction (start is
11 /// always captured before `f` runs).
12 ///
13 /// # Arguments
14 ///
15 /// - `&str` - The label for this measurement.
16 /// - `F: FnOnce() -> R` - The closure to measure. Can
17 /// return any type — the return value is forwarded to
18 /// the caller unchanged.
19 ///
20 /// # Returns
21 ///
22 /// - `R` - Whatever `f` returned.
23 pub fn measure<F, R>(&self, label: &str, f: F) -> R
24 where
25 F: FnOnce() -> R,
26 {
27 let started_ms: f64 = now_ms();
28 let result: R = f();
29 let ended_ms: f64 = now_ms();
30 let entry: ProfileEntry =
31 ProfileEntry::new(label.to_string(), ended_ms - started_ms, ended_ms);
32 // Push the entry onto the existing entries vector.
33 // Read-modify-write via `.get()` is necessary because
34 // `Signal<T>::set` requires `T: Clone` (which
35 // `Vec<ProfileEntry>` is) but does NOT take `&mut T`
36 // — the entire new value is supplied as the argument.
37 let mut current: Vec<ProfileEntry> = self.get_entries().get();
38 current.push(entry);
39 self.get_entries().set(current);
40 result
41 }
42
43 /// Starts a measurement that will end later.
44 ///
45 /// Use this when the measured region is not a single
46 /// closure — e.g. you want to bracket an async operation
47 /// or a callback fired from event handling. The returned
48 /// `ProfilerMark` knows the start timestamp and the
49 /// entries signal; pass it to `end()` when the work
50 /// completes.
51 ///
52 /// # Arguments
53 ///
54 /// - `&str` - The label for this measurement.
55 ///
56 /// # Returns
57 ///
58 /// - `ProfilerMark` - An RAII-ish guard. Call `mark.end()`
59 /// to push the `ProfileEntry`; drop without `end()` to
60 /// discard the measurement.
61 pub fn begin(&self, label: &str) -> ProfilerMark {
62 ProfilerMark::new(label.to_string(), now_ms(), *self.get_entries())
63 }
64
65 /// Empties the entries vector. Useful between benchmarks
66 /// ("measure just this call, not the previous ones too")
67 /// and in tests ("start from a clean slate").
68 pub fn clear(&self) {
69 self.get_entries().set(Vec::new());
70 }
71}
72
73/// Inherent implementation of [`ProfilerMark`].
74impl ProfilerMark {
75 /// Closes the measurement started by `begin()` and pushes
76 /// the resulting `ProfileEntry` into the entries signal.
77 ///
78 /// After calling `end()`, the marker is consumed and
79 /// cannot be reused. Calling `end()` twice is a no-op on
80 /// the second call — the marker is moved into the first
81 /// call, so the borrow checker prevents a second
82 /// invocation in well-typed code.
83 pub fn end(self) {
84 let ended_ms: f64 = now_ms();
85 let entry: ProfileEntry = ProfileEntry::new(
86 self.get_label().clone(),
87 ended_ms - self.get_started_ms(),
88 ended_ms,
89 );
90 let mut current: Vec<ProfileEntry> = self.get_entries().get();
91 current.push(entry);
92 self.get_entries().set(current);
93 }
94}