fret_ui/tree/debug/frame_stats.rs
1use super::super::*;
2use fret_core::TimerToken;
3
4#[derive(Debug, Default, Clone, Copy)]
5pub struct UiDebugFrameStats {
6 pub frame_id: FrameId,
7 /// Approximate capacity retained by per-frame scratch (“frame arena”) containers.
8 ///
9 /// This is a coarse signal intended for diagnostics/triage: it tracks reserved capacity
10 /// (not current length) and intentionally underestimates hash table overhead.
11 pub frame_arena_capacity_estimate_bytes: u64,
12 /// Number of scratch containers that grew their capacity during the current frame.
13 ///
14 /// This is a proxy for allocator churn in hot paths that should ideally stabilize after
15 /// warmup.
16 pub frame_arena_grow_events: u32,
17 /// Number of child-element vectors reused from the per-window pool during element build.
18 ///
19 /// This is a proxy for “element tree arena” progress: higher reuse implies less allocator churn
20 /// while building the ephemeral declarative element tree.
21 pub element_children_vec_pool_reuses: u32,
22 /// Number of child-element vectors that had to be newly allocated during element build.
23 pub element_children_vec_pool_misses: u32,
24 /// Total time spent in event dispatch during the current frame.
25 ///
26 /// This includes pointer routing, capture/focus arbitration, and widget event hooks. It does
27 /// not include layout/prepaint/paint, which are tracked separately.
28 pub dispatch_time: Duration,
29 /// Number of pointer/drag events dispatched during the current frame.
30 pub dispatch_pointer_events: u32,
31 /// Total wall time spent dispatching pointer/drag events during the current frame.
32 pub dispatch_pointer_event_time: Duration,
33 /// Number of timer events dispatched during the current frame.
34 pub dispatch_timer_events: u32,
35 /// Total wall time spent dispatching timer events during the current frame.
36 pub dispatch_timer_event_time: Duration,
37 /// Number of timer events that resolved to an explicit element target.
38 pub dispatch_timer_targeted_events: u32,
39 /// Wall time spent dispatching explicitly targeted timer events.
40 pub dispatch_timer_targeted_time: Duration,
41 /// Number of timer events that fell back to broadcast delivery (no element target).
42 pub dispatch_timer_broadcast_events: u32,
43 /// Wall time spent in broadcast timer delivery (including layer scanning + dispatch).
44 pub dispatch_timer_broadcast_time: Duration,
45 /// Total number of layers visited during broadcast timer delivery.
46 pub dispatch_timer_broadcast_layers_visited: u32,
47 /// Time spent rebuilding the visible-layers scratch list for broadcast timer delivery.
48 pub dispatch_timer_broadcast_rebuild_visible_layers_time: Duration,
49 /// Time spent iterating candidate layers and dispatching broadcast timers.
50 pub dispatch_timer_broadcast_loop_time: Duration,
51 /// Slowest single timer event routing time observed in the current frame.
52 pub dispatch_timer_slowest_event_time: Duration,
53 /// Token of the slowest timer event observed in the current frame (if any).
54 pub dispatch_timer_slowest_token: Option<TimerToken>,
55 /// Whether the slowest timer event used the broadcast fallback.
56 pub dispatch_timer_slowest_was_broadcast: bool,
57 /// Number of non-pointer, non-timer events dispatched during the current frame.
58 pub dispatch_other_events: u32,
59 /// Total wall time spent dispatching non-pointer, non-timer events during the current frame.
60 pub dispatch_other_event_time: Duration,
61 /// Time spent inside hit-testing during the current frame (subset of `dispatch_time`).
62 pub hit_test_time: Duration,
63 /// Number of events dispatched during the current frame.
64 pub dispatch_events: u32,
65 /// Number of hit-test queries executed during the current frame.
66 pub hit_test_queries: u32,
67 /// Count of bounds-tree queries attempted during hit testing.
68 pub hit_test_bounds_tree_queries: u32,
69 /// Bounds-tree queries that were disabled (e.g. env-gated, layer not indexed, or unsupported transforms).
70 pub hit_test_bounds_tree_disabled: u32,
71 /// Bounds-tree queries that missed (no containing leaf).
72 pub hit_test_bounds_tree_misses: u32,
73 /// Bounds-tree queries that returned a candidate leaf.
74 pub hit_test_bounds_tree_hits: u32,
75 /// Bounds-tree candidates rejected by `hit_test_node_self_only`, forcing a fallback traversal.
76 pub hit_test_bounds_tree_candidate_rejected: u32,
77 /// Total bounds-tree nodes visited across all queries in the current frame.
78 pub hit_test_bounds_tree_nodes_visited: u32,
79 /// Total bounds-tree nodes pushed to the search stack across all queries in the current frame.
80 pub hit_test_bounds_tree_nodes_pushed: u32,
81 /// Number of hit-test queries that reused the cached path (no bounds-tree query needed).
82 pub hit_test_path_cache_hits: u32,
83 /// Number of hit-test queries that fell back to bounds-tree or full traversal (cache miss).
84 pub hit_test_path_cache_misses: u32,
85 /// Total wall time spent attempting the cached-path hit-test fast path in the current frame.
86 pub hit_test_cached_path_time: Duration,
87 /// Total wall time spent querying the bounds-tree index in the current frame.
88 pub hit_test_bounds_tree_query_time: Duration,
89 /// Total wall time spent validating bounds-tree candidates (`hit_test_node_self_only`) in the current frame.
90 pub hit_test_candidate_self_only_time: Duration,
91 /// Total wall time spent in full traversal fallback hit-testing in the current frame.
92 pub hit_test_fallback_traversal_time: Duration,
93 /// Total wall time spent updating hover state from pointer hit-testing in the current frame.
94 pub dispatch_hover_update_time: Duration,
95 /// Total wall time spent applying scroll-handle binding invalidations during event dispatch.
96 pub dispatch_scroll_handle_invalidation_time: Duration,
97 /// Total wall time spent computing active input layers and enforcing modal barrier scope.
98 pub dispatch_active_layers_time: Duration,
99 /// Total wall time spent constructing and publishing the window input context snapshot.
100 pub dispatch_input_context_time: Duration,
101 /// Total wall time spent building the event chain during dispatch.
102 pub dispatch_event_chain_build_time: Duration,
103 /// Total wall time spent delivering capture-phase widget events during dispatch.
104 pub dispatch_widget_capture_time: Duration,
105 /// Total wall time spent delivering bubble-phase widget events during dispatch.
106 pub dispatch_widget_bubble_time: Duration,
107 /// Total wall time spent computing the cursor icon from the pointer hit during dispatch.
108 pub dispatch_cursor_query_time: Duration,
109 /// Total wall time spent dispatching pointer-move layer observers (both post-dispatch and when
110 /// pointer dispatch is suppressed).
111 pub dispatch_pointer_move_layer_observers_time: Duration,
112 /// Total wall time spent dispatching the synthetic hover-move observer chain when the pointer crosses targets.
113 pub dispatch_synth_hover_observer_time: Duration,
114 /// Total wall time spent pushing cursor-icon effects during dispatch.
115 pub dispatch_cursor_effect_time: Duration,
116 /// Total wall time spent publishing post-dispatch window integration snapshots (input context,
117 /// command availability) during dispatch.
118 pub dispatch_post_dispatch_snapshot_time: Duration,
119 pub layout_time: Duration,
120 pub layout_collect_roots_time: Duration,
121 pub layout_invalidate_scroll_handle_bindings_time: Duration,
122 pub layout_expand_view_cache_invalidations_time: Duration,
123 pub layout_request_build_roots_time: Duration,
124 pub layout_pending_barrier_relayouts_time: Duration,
125 pub layout_repair_view_cache_bounds_time: Duration,
126 pub layout_contained_view_cache_roots_time: Duration,
127 pub layout_collapse_layout_observations_time: Duration,
128 /// Total wall time spent recording layout observations (`observed_in_layout` + globals).
129 pub layout_observation_record_time: Duration,
130 /// Total observed-model edges recorded into `observed_in_layout` during this frame.
131 pub layout_observation_record_models_items: u32,
132 /// Total observed-global edges recorded into `observed_globals_in_layout` during this frame.
133 pub layout_observation_record_globals_items: u32,
134 pub layout_prepaint_after_layout_time: Duration,
135 pub layout_skipped_engine_frame: bool,
136 pub layout_roots_time: Duration,
137 pub layout_barrier_relayouts_time: Duration,
138 pub layout_view_cache_time: Duration,
139 pub layout_semantics_refresh_time: Duration,
140 pub layout_focus_repair_time: Duration,
141 pub layout_deferred_cleanup_time: Duration,
142 pub prepaint_time: Duration,
143 pub paint_time: Duration,
144 pub paint_record_visual_bounds_time: Duration,
145 pub paint_record_visual_bounds_calls: u32,
146 /// Total wall time spent computing paint-cache keys and paint-cache enablement checks.
147 pub paint_cache_key_time: Duration,
148 /// Total wall time spent checking paint-cache hit eligibility (excluding replay itself).
149 pub paint_cache_hit_check_time: Duration,
150 /// Total wall time spent executing `Widget::paint()` (including push/pop transforms).
151 pub paint_widget_time: Duration,
152 /// Total wall time spent recording paint observations (`observed_in_paint` + globals).
153 pub paint_observation_record_time: Duration,
154 /// Total wall time spent iterating element-runtime observed models inside `ElementHostWidget::paint_impl`.
155 pub paint_host_widget_observed_models_time: Duration,
156 /// Total observed-model edges iterated inside `ElementHostWidget::paint_impl`.
157 pub paint_host_widget_observed_models_items: u32,
158 /// Total wall time spent iterating element-runtime observed globals inside `ElementHostWidget::paint_impl`.
159 pub paint_host_widget_observed_globals_time: Duration,
160 /// Total observed-global edges iterated inside `ElementHostWidget::paint_impl`.
161 pub paint_host_widget_observed_globals_items: u32,
162 /// Total wall time spent resolving the element instance (`ElementInstance`) inside `ElementHostWidget::paint_impl`.
163 pub paint_host_widget_instance_lookup_time: Duration,
164 /// Number of `ElementInstance` lookups performed inside `ElementHostWidget::paint_impl`.
165 pub paint_host_widget_instance_lookup_calls: u32,
166 /// Total wall time spent preparing text blobs (`TextSystem::prepare`) during `Widget::paint`.
167 pub paint_text_prepare_time: Duration,
168 /// Number of text blob preparations performed during `Widget::paint`.
169 pub paint_text_prepare_calls: u32,
170 /// Count of text prepares where the cached blob was missing.
171 pub paint_text_prepare_reason_blob_missing: u32,
172 /// Count of text prepares triggered by a scale factor change.
173 pub paint_text_prepare_reason_scale_changed: u32,
174 /// Count of text prepares triggered by a plain-text change.
175 pub paint_text_prepare_reason_text_changed: u32,
176 /// Count of text prepares triggered by an attributed-text change.
177 pub paint_text_prepare_reason_rich_changed: u32,
178 /// Count of text prepares triggered by a text-style change.
179 pub paint_text_prepare_reason_style_changed: u32,
180 /// Count of text prepares triggered by a wrap-mode change.
181 pub paint_text_prepare_reason_wrap_changed: u32,
182 /// Count of text prepares triggered by an overflow-mode change.
183 pub paint_text_prepare_reason_overflow_changed: u32,
184 /// Count of text prepares triggered by a max-width change.
185 pub paint_text_prepare_reason_width_changed: u32,
186 /// Count of text prepares triggered by a font-stack-key change.
187 pub paint_text_prepare_reason_font_stack_changed: u32,
188 pub paint_input_context_time: Duration,
189 pub paint_scroll_handle_invalidation_time: Duration,
190 pub paint_collect_roots_time: Duration,
191 pub paint_publish_text_input_snapshot_time: Duration,
192 pub paint_collapse_observations_time: Duration,
193 pub layout_nodes_visited: u32,
194 pub layout_nodes_performed: u32,
195 pub prepaint_nodes_visited: u32,
196 pub paint_nodes: u32,
197 pub paint_nodes_performed: u32,
198 pub paint_cache_hits: u32,
199 pub paint_cache_misses: u32,
200 pub paint_cache_replayed_ops: u32,
201 /// Paint-cache replay attempts that were allowed specifically by the
202 /// `FRET_UI_PAINT_CACHE_ALLOW_HIT_TEST_ONLY` gate.
203 pub paint_cache_hit_test_only_replay_allowed: u32,
204 /// Hit-test-only replay attempts rejected because the previous cache key did not match.
205 pub paint_cache_hit_test_only_replay_rejected_key_mismatch: u32,
206 pub paint_cache_replay_time: Duration,
207 pub paint_cache_bounds_translate_time: Duration,
208 pub paint_cache_bounds_translated_nodes: u32,
209 pub interaction_cache_hits: u32,
210 pub interaction_cache_misses: u32,
211 pub interaction_cache_replayed_records: u32,
212 pub interaction_records: u32,
213 /// Number of layout engine root solves performed during the current frame.
214 pub layout_engine_solves: u64,
215 /// Total time spent in layout engine solves during the current frame.
216 pub layout_engine_solve_time: Duration,
217 /// Total number of `layout_engine_child_local_rect` queries performed during the current frame.
218 pub layout_engine_child_rect_queries: u64,
219 /// Total wall time spent inside layout engine child-rect queries during the current frame.
220 pub layout_engine_child_rect_time: Duration,
221 /// Number of "widget-local" layout engine solves triggered as a fallback when a widget cannot
222 /// consume already-solved engine child rects.
223 ///
224 /// The goal for v2 is to keep this at `0` for normal UI trees by ensuring explicit layout
225 /// barriers (scroll/virtualization/splits/...) register viewport roots or explicitly solve
226 /// their child roots.
227 pub layout_engine_widget_fallback_solves: u64,
228 pub layout_fast_path_taken: bool,
229 pub layout_invalidations_count: u32,
230 pub layout_subtree_dirty_agg_enabled: bool,
231 /// Number of aggregation update operations performed during the current frame.
232 pub layout_subtree_dirty_agg_updates: u32,
233 /// Total number of nodes whose aggregation counter was updated during the current frame.
234 pub layout_subtree_dirty_agg_nodes_touched: u32,
235 /// Max parent-walk length observed in a single aggregation update during the current frame.
236 pub layout_subtree_dirty_agg_max_parent_walk: u32,
237 /// Total nodes processed by subtree rebuilds during the current frame.
238 pub layout_subtree_dirty_agg_rebuild_nodes: u32,
239 /// Count of validation failures observed during the current frame.
240 pub layout_subtree_dirty_agg_validation_failures: u32,
241 /// Unique nodes observed as invalidation roots for model changes during the current frame.
242 pub model_change_invalidation_roots: u32,
243 /// Count of changed models consumed for propagation during the current frame.
244 pub model_change_models: u32,
245 /// Total (model -> node) observation edges scanned during propagation.
246 pub model_change_observation_edges: u32,
247 /// Count of changed models with no observation edges.
248 pub model_change_unobserved_models: u32,
249 /// Unique nodes observed as invalidation roots for global changes during the current frame.
250 pub global_change_invalidation_roots: u32,
251 /// Count of changed globals consumed for propagation during the current frame.
252 pub global_change_globals: u32,
253 /// Total (global -> node) observation edges scanned during propagation.
254 pub global_change_observation_edges: u32,
255 /// Count of changed globals with no observation edges.
256 pub global_change_unobserved_globals: u32,
257 /// Total nodes visited across invalidation walks during the current frame.
258 pub invalidation_walk_nodes: u32,
259 /// Total invalidation walks performed during the current frame.
260 pub invalidation_walk_calls: u32,
261 /// Nodes visited across invalidation walks attributed to model changes.
262 pub invalidation_walk_nodes_model_change: u32,
263 /// Invalidation walks attributed to model changes.
264 pub invalidation_walk_calls_model_change: u32,
265 /// Nodes visited across invalidation walks attributed to global changes.
266 pub invalidation_walk_nodes_global_change: u32,
267 /// Invalidation walks attributed to global changes.
268 pub invalidation_walk_calls_global_change: u32,
269 /// Nodes visited across invalidation walks attributed to hover state changes.
270 pub invalidation_walk_nodes_hover: u32,
271 /// Invalidation walks attributed to hover state changes.
272 pub invalidation_walk_calls_hover: u32,
273 /// Nodes visited across invalidation walks attributed to focus changes.
274 pub invalidation_walk_nodes_focus: u32,
275 /// Invalidation walks attributed to focus changes.
276 pub invalidation_walk_calls_focus: u32,
277 /// Nodes visited across invalidation walks attributed to all other sources.
278 pub invalidation_walk_nodes_other: u32,
279 /// Invalidation walks attributed to all other sources.
280 pub invalidation_walk_calls_other: u32,
281 /// Count of hover target changes for `Pressable` instances during the current frame.
282 pub hover_pressable_target_changes: u32,
283 /// Count of hover target changes for `HoverRegion` instances during the current frame.
284 pub hover_hover_region_target_changes: u32,
285 /// Count of declarative instance changes that happened in a frame that also observed a hover
286 /// target change.
287 pub hover_declarative_instance_changes: u32,
288 /// Count of declarative `HitTest` invalidations attributed to hover during the current frame.
289 pub hover_declarative_hit_test_invalidations: u32,
290 /// Count of declarative `Layout` invalidations attributed to hover during the current frame.
291 pub hover_declarative_layout_invalidations: u32,
292 /// Count of declarative `Paint` invalidations attributed to hover during the current frame.
293 pub hover_declarative_paint_invalidations: u32,
294 /// Whether view-cache mode is active for this frame.
295 pub view_cache_active: bool,
296 /// How many invalidation walks were truncated by a view-cache boundary.
297 pub view_cache_invalidation_truncations: u32,
298 /// How many "contained" view-cache roots were re-laid out during the final pass.
299 pub view_cache_contained_relayouts: u32,
300 /// How many view-cache roots were observed during the current frame.
301 pub view_cache_roots_total: u32,
302 /// How many view-cache roots were reused during the current frame.
303 pub view_cache_roots_reused: u32,
304 /// View-cache roots that were not reused because they were mounted for the first time.
305 pub view_cache_roots_first_mount: u32,
306 /// View-cache roots that were not reused because their backing `NodeId` was recreated.
307 pub view_cache_roots_node_recreated: u32,
308 /// View-cache roots that were not reused because the declarative cache key did not match.
309 pub view_cache_roots_cache_key_mismatch: u32,
310 /// View-cache roots that were not reused because they were not marked as reuse roots.
311 ///
312 /// This is an authoring-level signal: either view-cache was not enabled, or reuse was gated off
313 /// by local state (e.g. `view_cache_needs_rerender` / layout invalidation) upstream.
314 pub view_cache_roots_not_marked_reuse_root: u32,
315 /// View-cache roots that were not reused because `view_cache_needs_rerender` was set.
316 pub view_cache_roots_needs_rerender: u32,
317 /// View-cache roots that were not reused because they had a layout invalidation.
318 pub view_cache_roots_layout_invalidated: u32,
319 /// View-cache roots recorded from retained/manual cache roots (non-declarative).
320 pub view_cache_roots_manual: u32,
321 /// How many times `set_children_barrier` was applied (structural changes without forcing
322 /// ancestor relayout).
323 pub set_children_barrier_writes: u32,
324 /// How many barrier relayout roots were scheduled via `set_children_barrier` in this frame.
325 pub barrier_relayouts_scheduled: u32,
326 /// How many barrier relayout roots were actually laid out in this frame.
327 pub barrier_relayouts_performed: u32,
328 /// How many VirtualList visible-range checks were evaluated (used to request rerenders under
329 /// view-cache reuse).
330 pub virtual_list_visible_range_checks: u32,
331 /// How many VirtualList visible-range checks requested a refresh (range delta outside the
332 /// currently mounted span).
333 pub virtual_list_visible_range_refreshes: u32,
334 /// How many VirtualList window shifts were observed during the current frame.
335 pub virtual_list_window_shifts_total: u32,
336 /// How many VirtualList window shifts required a non-retained cache-root rerender.
337 pub virtual_list_window_shifts_non_retained: u32,
338 /// How many retained VirtualList hosts were reconciled (attach/detach without rerendering the
339 /// parent view-cache root).
340 pub retained_virtual_list_reconciles: u32,
341 /// Total items attached across retained VirtualList reconciles (new keys mounted).
342 pub retained_virtual_list_attached_items: u32,
343 /// Total items detached across retained VirtualList reconciles (keys removed from children).
344 pub retained_virtual_list_detached_items: u32,
345 pub focus: Option<NodeId>,
346 pub captured: Option<NodeId>,
347}