perf(app): settle web poll cadence after load
This commit is contained in:
@@ -10,7 +10,9 @@ const FRAME_SETTLE_WINDOW: Duration = Duration::from_millis(250);
|
|||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
pub(super) struct WebSurfacePollCadence {
|
pub(super) struct WebSurfacePollCadence {
|
||||||
next_poll_at: Option<Instant>,
|
next_poll_at: Option<Instant>,
|
||||||
active_until: Option<Instant>,
|
load_active_until: Option<Instant>,
|
||||||
|
interaction_active_until: Option<Instant>,
|
||||||
|
settle_active_until: Option<Instant>,
|
||||||
last_render_phase: Option<WebSurfaceRenderPhase>,
|
last_render_phase: Option<WebSurfaceRenderPhase>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,15 +25,18 @@ impl WebSurfacePollCadence {
|
|||||||
) {
|
) {
|
||||||
if started_loading {
|
if started_loading {
|
||||||
self.last_render_phase = None;
|
self.last_render_phase = None;
|
||||||
self.boost_until(now + LOAD_BOOST_WINDOW);
|
self.settle_active_until = None;
|
||||||
|
extend_deadline(&mut self.load_active_until, now + LOAD_BOOST_WINDOW);
|
||||||
}
|
}
|
||||||
match input_kind {
|
match input_kind {
|
||||||
WebSurfaceInputKind::Idle => {}
|
WebSurfaceInputKind::Idle => {}
|
||||||
WebSurfaceInputKind::Hover => self.boost_until(now + HOVER_BOOST_WINDOW),
|
WebSurfaceInputKind::Hover => {
|
||||||
|
extend_deadline(&mut self.interaction_active_until, now + HOVER_BOOST_WINDOW);
|
||||||
|
}
|
||||||
WebSurfaceInputKind::Scroll
|
WebSurfaceInputKind::Scroll
|
||||||
| WebSurfaceInputKind::Click
|
| WebSurfaceInputKind::Click
|
||||||
| WebSurfaceInputKind::Text => {
|
| WebSurfaceInputKind::Text => {
|
||||||
self.boost_until(now + INPUT_BOOST_WINDOW);
|
extend_deadline(&mut self.interaction_active_until, now + INPUT_BOOST_WINDOW);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,15 +47,17 @@ impl WebSurfacePollCadence {
|
|||||||
WebSurfaceRenderPhase::Created | WebSurfaceRenderPhase::Loading
|
WebSurfaceRenderPhase::Created | WebSurfaceRenderPhase::Loading
|
||||||
if self.last_render_phase != Some(phase) =>
|
if self.last_render_phase != Some(phase) =>
|
||||||
{
|
{
|
||||||
self.boost_until(now + LOAD_BOOST_WINDOW);
|
extend_deadline(&mut self.load_active_until, now + LOAD_BOOST_WINDOW);
|
||||||
}
|
}
|
||||||
WebSurfaceRenderPhase::Created | WebSurfaceRenderPhase::Loading => {}
|
WebSurfaceRenderPhase::Created | WebSurfaceRenderPhase::Loading => {}
|
||||||
WebSurfaceRenderPhase::Complete if self.last_render_phase != Some(phase) => {
|
WebSurfaceRenderPhase::Complete if self.last_render_phase != Some(phase) => {
|
||||||
self.boost_until(now + FRAME_SETTLE_WINDOW);
|
self.load_active_until = None;
|
||||||
|
extend_deadline(&mut self.settle_active_until, now + FRAME_SETTLE_WINDOW);
|
||||||
}
|
}
|
||||||
WebSurfaceRenderPhase::Complete => {}
|
WebSurfaceRenderPhase::Complete => {}
|
||||||
WebSurfaceRenderPhase::Other if self.last_render_phase != Some(phase) => {
|
WebSurfaceRenderPhase::Other if self.last_render_phase != Some(phase) => {
|
||||||
self.boost_until(now + INPUT_BOOST_WINDOW);
|
self.load_active_until = None;
|
||||||
|
extend_deadline(&mut self.interaction_active_until, now + INPUT_BOOST_WINDOW);
|
||||||
}
|
}
|
||||||
WebSurfaceRenderPhase::Other => {}
|
WebSurfaceRenderPhase::Other => {}
|
||||||
}
|
}
|
||||||
@@ -70,17 +77,20 @@ impl WebSurfacePollCadence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn current_interval(&self, now: Instant) -> Duration {
|
fn current_interval(&self, now: Instant) -> Duration {
|
||||||
if self.active_until.is_some_and(|deadline| now < deadline) {
|
if self.has_active_window(now) { ACTIVE_POLL_INTERVAL } else { IDLE_POLL_INTERVAL }
|
||||||
ACTIVE_POLL_INTERVAL
|
|
||||||
} else {
|
|
||||||
IDLE_POLL_INTERVAL
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn boost_until(&mut self, deadline: Instant) {
|
fn has_active_window(&self, now: Instant) -> bool {
|
||||||
if self.active_until.is_none_or(|current| deadline > current) {
|
[self.load_active_until, self.interaction_active_until, self.settle_active_until]
|
||||||
self.active_until = Some(deadline);
|
.into_iter()
|
||||||
}
|
.flatten()
|
||||||
|
.any(|deadline| now < deadline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend_deadline(slot: &mut Option<Instant>, deadline: Instant) {
|
||||||
|
if slot.is_none_or(|current| deadline > current) {
|
||||||
|
*slot = Some(deadline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,6 +215,36 @@ mod tests {
|
|||||||
assert!(cadence.should_poll(start + Duration::from_millis(380)));
|
assert!(cadence.should_poll(start + Duration::from_millis(380)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn complete_frame_shortens_started_loading_boost() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let mut cadence = WebSurfacePollCadence::default();
|
||||||
|
|
||||||
|
cadence.note_ensure(WebSurfaceInputKind::Idle, true, start);
|
||||||
|
cadence.note_frame("complete", start + Duration::from_secs(1));
|
||||||
|
cadence.note_poll_submitted(start + Duration::from_millis(1_300));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
cadence.next_poll_delay(start + Duration::from_millis(1_300)),
|
||||||
|
IDLE_POLL_INTERVAL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn complete_frame_preserves_recent_input_boost() {
|
||||||
|
let start = Instant::now();
|
||||||
|
let mut cadence = WebSurfacePollCadence::default();
|
||||||
|
|
||||||
|
cadence.note_ensure(WebSurfaceInputKind::Scroll, false, start);
|
||||||
|
cadence.note_frame("complete", start + Duration::from_millis(100));
|
||||||
|
cadence.note_poll_submitted(start + Duration::from_millis(500));
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
cadence.next_poll_delay(start + Duration::from_millis(500)),
|
||||||
|
ACTIVE_POLL_INTERVAL
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn repeated_complete_frames_do_not_extend_settle_window() {
|
fn repeated_complete_frames_do_not_extend_settle_window() {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
|
|||||||
Reference in New Issue
Block a user