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
//! UI-thread stall detector. [`stall_guard`] wraps a Slint callback body's work
//! and logs a `tracing::warn!` naming the callback and its elapsed time whenever it
//! runs longer than [`STALL_THRESHOLD`] (the frame budget a 60 Hz UI needs to stay
//! responsive). The app's own `tracing` subscriber writes `indicatrix-cut.log`
//! beside the executable, so a stall shows up there without any new UI surface.
//!
//! # Why a plain wrapper function, not a macro or a `#[instrument]`-style attribute
//!
//! Every callback is registered the same way: `ui.global::<...>()
//! .on_some_callback(move |args| { ... })`. Wrapping the closure BODY in
//! `stall_guard::stall_guard("name", || { ... })` needs no new syntax at each call
//! site beyond the one added wrapper call, and keeps the callback's own early
//! returns (`let Some(x) = ... else { return; }`) working exactly as before -- the
//! closure `stall_guard` wraps still owns its own control flow, `stall_guard` only
//! measures how long it took.
//!
//! # Why not a stall reported for the WHOLE closure life, including a spawned worker
//!
//! A callback that dispatches work to a background thread (`SolveService`,
//! `deep_solve`, `optimize_solve`, `auto_solve::dispatch_background_solve`) returns
//! almost immediately once the dispatch itself is queued -- `stall_guard` measures
//! exactly that return, never the eventual `Weak::upgrade_in_event_loop` completion
//! closure's own (separately wrapped, if it is one) work.
use ;
/// A callback body running longer than this on the UI/event-loop thread is a
/// visible stall at 60 Hz (one frame is ~16.7 ms) -- see the module doc comment.
const STALL_THRESHOLD: Duration = from_millis;
/// Runs `body`, logging a `tracing::warn!` naming `name` and the elapsed time if it
/// took longer than [`STALL_THRESHOLD`]. Returns `body`'s own result unchanged --
/// see the module doc comment for why this is a plain wrapper, not a macro.
pub
/// The threshold check itself, pulled out so a test can drive it directly without
/// needing a closure that actually sleeps [`STALL_THRESHOLD`] or longer.
const