1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use *;
/// A single recorded measurement.
///
/// Pushed onto the `ProfilerHandle`'s entries signal every time
/// the user calls `ProfilerHandle::measure(label, f)` (or
/// manually `begin` / `end`). Cheap to `Clone` (the inner
/// strings are small and `f64` is `Copy`).
///
/// Field-level semantics:
///
/// - `label`: free-form identifier — typically the call site name
/// (`"render-list"`, `"fetch-posts"`). Empty strings are
/// allowed but render as an empty chip in the UI, which makes
/// misconfigured measurements obvious in a profiler readout.
/// - `elapsed_ms`: wall-clock time between `begin()` and the
/// matching `end()` (or the duration of the measured closure),
/// in milliseconds. Always `>= 0.0` — `begin` is captured
/// before any user code runs, so the subtraction cannot
/// underflow.
/// - `timestamp_ms`: the wall-clock `now_ms()` value at the
/// instant the entry was recorded (NOT the start of the
/// measurement). This lets the UI sort / filter entries by
/// when they were committed, not by when the user started
/// the timer — which matters when entries are kept around
/// for "last N measurements" readouts.
/// A handle to the profiler registered against the current
/// hook context.
///
/// The handle owns the entries signal; calling
/// `ProfilerHandle::entries()` returns that signal so any
/// reactive read (`Signal::get()`) inside a closure subscribes
/// the enclosing render to new entries. The matching
/// measurement API is `ProfilerHandle::measure(label, f)`
/// (push-on-exit) or `ProfilerHandle::begin(label)` /
/// `ProfilerHandle::end()` (split-timer API for code paths
/// that don't fit inside a single closure).
///
/// # Lifecycle
///
/// The handle is obtained via `App::use_profiler()` (or
/// directly via `HookContext::profiler()`), which slots it into
/// the current hook context. On every render at the same hook
/// index, the same handle is returned — so measurements
/// recorded from a previous render remain visible in
/// `entries()`.
///
/// On hook-context teardown (component unmount, match-arm
/// switch, or explicit `clear()`), the handle is dropped and
/// its entries signal goes with it. If you need to keep
/// measurements alive past the lifetime of the component,
/// clone the entries vector out before the context is cleared.
/// `ProfilerHandle` is `Copy` because `Signal<Vec<ProfileEntry>>`
/// is itself `Copy` (the registry hands out cheap `usize`
/// addresses; the vector lives in the global signal store).
/// A `begin()` marker — RAII guard that records the start
/// timestamp and the label so the matching `end()` call can
/// compute the elapsed time.
///
/// Created by `ProfilerHandle::begin(label)`. Consume with
/// `end()` to push a `ProfileEntry` into the entries signal.
/// Dropping the marker without calling `end()` discards the
/// measurement silently (we don't have a place to push a
/// half-finished entry, and panicking on drop is hostile).