Skip to main content

tessera_ui/
work.rs

1//! Executed UI work by frame and phase.
2//!
3//! ## Usage
4//!
5//! Inspect actual component, layout, and paint dispatches in test sessions.
6
7use rustc_hash::FxHashMap;
8
9/// A runtime execution phase.
10#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
11pub enum WorkPhase {
12    /// A component body executed.
13    Build,
14    /// Final content was measured.
15    Measure,
16    /// Intrinsic content was measured.
17    IntrinsicMeasure,
18    /// Cached measurements were used to place children.
19    Place,
20    /// A placement modifier transformed geometry.
21    Transform,
22    /// A draw policy or modifier recorded paint.
23    Paint,
24}
25
26/// One component, policy, or modifier execution.
27#[derive(Clone, Debug)]
28pub struct WorkExecution {
29    /// Stable instance identity within the session.
30    pub instance: u64,
31    /// Dispatched phase.
32    pub phase: WorkPhase,
33    /// Component function name or concrete policy type name.
34    pub target: &'static str,
35}
36
37/// Actual work in a completed frame.
38#[derive(Clone, Debug, Default)]
39pub struct FrameWork {
40    /// Session that owns the observed instances.
41    pub session: Option<crate::RuntimeSessionId>,
42    executions: Vec<WorkExecution>,
43}
44
45impl FrameWork {
46    /// Returns dispatches in execution order.
47    pub fn executions(&self) -> &[WorkExecution] {
48        &self.executions
49    }
50
51    /// Returns dispatches for one phase.
52    pub fn phase(&self, phase: WorkPhase) -> impl Iterator<Item = &WorkExecution> {
53        self.executions
54            .iter()
55            .filter(move |entry| entry.phase == phase)
56    }
57
58    /// Counts named component or policy dispatches in a phase.
59    pub fn count(&self, target: &str, phase: WorkPhase) -> usize {
60        self.phase(phase)
61            .filter(|entry| entry.target == target)
62            .count()
63    }
64
65    /// Counts dispatches of a concrete policy or modifier type.
66    pub fn executed<T: 'static>(&self, phase: WorkPhase) -> usize {
67        self.count(std::any::type_name::<T>(), phase)
68    }
69
70    /// Counts dispatches for one stable instance.
71    pub fn for_instance(&self, instance: u64, phase: WorkPhase) -> usize {
72        self.phase(phase)
73            .filter(|entry| entry.instance == instance)
74            .count()
75    }
76}
77
78/// Cumulative work during a renderer or test session's lifetime.
79#[derive(Clone, Debug, Default)]
80pub struct WorkTotals {
81    /// Session that owns the observed instances.
82    pub session: Option<crate::RuntimeSessionId>,
83    counts: FxHashMap<&'static str, [usize; 6]>,
84}
85
86impl WorkTotals {
87    /// Counts named component or policy dispatches in a phase.
88    pub fn count(&self, target: &str, phase: WorkPhase) -> usize {
89        self.counts
90            .get(target)
91            .map_or(0, |counts| counts[phase as usize])
92    }
93
94    #[cfg(any(
95        test,
96        feature = "testing",
97        all(feature = "headless", not(target_family = "wasm"))
98    ))]
99    pub(crate) fn record(&mut self, frame: &FrameWork) {
100        self.session = frame.session;
101        for entry in frame.executions() {
102            let count = &mut self.counts.entry(entry.target).or_default()[entry.phase as usize];
103            *count = count.checked_add(1).expect("work count exhausted");
104        }
105    }
106}
107
108#[cfg(any(
109    test,
110    feature = "testing",
111    all(feature = "headless", not(target_family = "wasm"))
112))]
113mod collector {
114    use std::cell::RefCell;
115
116    use super::{FrameWork, WorkExecution, WorkPhase};
117
118    #[derive(Default)]
119    struct Observer(RefCell<Option<FrameWork>>);
120
121    pub(crate) fn begin() {
122        crate::local_runtime_resource::<Observer>()
123            .0
124            .replace(Some(FrameWork {
125                session: crate::RuntimeSession::current().map(|session| session.identity()),
126                ..Default::default()
127            }));
128    }
129
130    pub(crate) fn finish() -> FrameWork {
131        crate::local_runtime_resource::<Observer>()
132            .0
133            .take()
134            .unwrap_or_default()
135    }
136
137    pub(crate) fn record(instance: u64, phase: WorkPhase, target: &'static str) {
138        if crate::RuntimeSession::current().is_none() {
139            return;
140        }
141        if let Some(frame) = crate::local_runtime_resource::<Observer>()
142            .0
143            .borrow_mut()
144            .as_mut()
145        {
146            frame.executions.push(WorkExecution {
147                instance,
148                phase,
149                target,
150            });
151        }
152    }
153
154    pub(crate) fn record_policy<T>(phase: WorkPhase) {
155        if crate::RuntimeSession::current().is_none() {
156            return;
157        }
158        let instance = crate::execution_context::with_execution_context(|context| {
159            context.instance_logic_id_stack.last().copied().unwrap_or(0)
160        });
161        record(instance, phase, std::any::type_name::<T>());
162    }
163}
164
165#[cfg(any(
166    test,
167    feature = "testing",
168    all(feature = "headless", not(target_family = "wasm"))
169))]
170pub(crate) use collector::{begin, finish, record, record_policy};
171
172#[cfg(not(any(
173    test,
174    feature = "testing",
175    all(feature = "headless", not(target_family = "wasm"))
176)))]
177pub(crate) fn record(_instance: u64, _phase: WorkPhase, _target: &'static str) {}
178
179#[cfg(not(any(
180    test,
181    feature = "testing",
182    all(feature = "headless", not(target_family = "wasm"))
183)))]
184pub(crate) fn record_policy<T>(_phase: WorkPhase) {}