Reduce polling retries and repeated compositor lookups

This commit is contained in:
Samuel Onoja committed 2026-09-27 06:58:09 +01:00
1 parent dcca5fec88
commit 917379d548
4 files changed
+146 -24

No files matched your search

+32 -6
View File
@@ -1,4 +1,7 @@
use std::time::{Duration, Instant};
use std::{
collections::VecDeque,
time::{Duration, Instant},
};
use smithay::utils::{Physical, Rectangle};
@@ -16,7 +19,7 @@ pub(crate) struct RenderMetrics {
damaged_pixels: u64,
total_render_time: Duration,
longest_render_time: Duration,
frame_times: Vec<Duration>,
frame_times: VecDeque<Duration>,
}
impl RenderMetrics {
@@ -37,7 +40,7 @@ impl RenderMetrics {
damaged_pixels: 0,
total_render_time: Duration::ZERO,
longest_render_time: Duration::ZERO,
frame_times: Vec::new(),
frame_times: VecDeque::new(),
}
}
@@ -57,9 +60,9 @@ impl RenderMetrics {
self.total_render_time += render_time;
self.longest_render_time = self.longest_render_time.max(render_time);
if self.frame_times.len() == 512 {
self.frame_times.remove(0);
self.frame_times.pop_front();
}
self.frame_times.push(render_time);
self.frame_times.push_back(render_time);
let now = Instant::now();
let elapsed = now.saturating_duration_since(self.interval_started);
@@ -72,7 +75,7 @@ impl RenderMetrics {
.as_micros()
.checked_div(u128::from(self.rendered_frames))
.unwrap_or(0);
self.frame_times.sort_unstable();
self.frame_times.make_contiguous().sort_unstable();
let percentile = |percent: usize| {
let index = (self.frame_times.len() * percent)
.div_ceil(100)
@@ -159,4 +162,27 @@ mod tests {
}
assert_eq!(metrics.frame_times.len(), 512);
}
#[test]
fn profiling_retains_the_most_recent_samples_in_order() {
let mut metrics = RenderMetrics::new("test", true, Instant::now());
for micros in 0..600 {
metrics.record_frame(Duration::from_micros(micros), &[], 0, FrameEffectMetrics);
}
assert_eq!(
metrics.frame_times.front(),
Some(&Duration::from_micros(88))
);
assert_eq!(
metrics.frame_times.back(),
Some(&Duration::from_micros(599))
);
assert!(
metrics
.frame_times
.iter()
.copied()
.eq((88..600).map(Duration::from_micros))
);
}
}
+48 -6
View File
@@ -1,4 +1,5 @@
use ferese_layout::WindowId;
use std::collections::HashMap;
pub(crate) fn layer_priority(floating: bool, zooming: bool, fullscreen: bool) -> u8 {
if fullscreen {
@@ -16,17 +17,24 @@ pub(crate) fn layer_priority(floating: bool, zooming: bool, fullscreen: bool) ->
#[derive(Default)]
pub(crate) struct WindowStack {
order: Vec<WindowId>,
ranks: HashMap<WindowId, usize>,
}
impl WindowStack {
pub fn insert(&mut self, id: WindowId) {
if !self.order.contains(&id) {
if let std::collections::hash_map::Entry::Vacant(entry) = self.ranks.entry(id) {
entry.insert(self.order.len());
self.order.push(id);
}
}
pub fn remove(&mut self, id: WindowId) {
self.order.retain(|candidate| *candidate != id);
if let Some(rank) = self.ranks.remove(&id) {
self.order.remove(rank);
for (rank, candidate) in self.order.iter().enumerate().skip(rank) {
self.ranks.insert(*candidate, rank);
}
}
}
pub fn raise(&mut self, id: WindowId) {
@@ -35,10 +43,7 @@ impl WindowStack {
}
pub fn rank(&self, id: WindowId) -> usize {
self.order
.iter()
.position(|candidate| *candidate == id)
.unwrap_or(usize::MAX)
self.ranks.get(&id).copied().unwrap_or(usize::MAX)
}
}
@@ -46,6 +51,43 @@ impl WindowStack {
mod tests {
use super::*;
#[test]
fn cached_ranks_match_reference_order_after_mixed_operations() {
let mut stack = WindowStack::default();
let mut reference = Vec::new();
let mut random = 42_u64;
for _ in 0..2000 {
random = random.wrapping_mul(6364136223846793005).wrapping_add(1);
let id = WindowId((random >> 32) % 32);
match random % 3 {
0 => {
stack.insert(id);
if !reference.contains(&id) {
reference.push(id);
}
}
1 => {
stack.remove(id);
reference.retain(|candidate| *candidate != id);
}
_ => {
stack.raise(id);
reference.retain(|candidate| *candidate != id);
reference.push(id);
}
}
for id in (0..33).map(WindowId) {
assert_eq!(
stack.rank(id),
reference
.iter()
.position(|candidate| *candidate == id)
.unwrap_or(usize::MAX)
);
}
}
}
#[test]
fn floating_windows_stay_above_tiled_and_maximized_windows() {
assert!(layer_priority(true, false, false) > layer_priority(false, true, false));
+9 -6
View File
@@ -1428,6 +1428,13 @@ fn overview_strip_elements(
let cards = state.overview_workspace_cards(output);
let mut elements = Vec::new();
let programs = rounded_clip_program(state, renderer);
// Resolve IDs once per strip, rather than scanning all managed windows
// separately for every miniature. Own the handles so rendering can mutate state.
let windows_by_id: std::collections::HashMap<_, _> = state
.window_ids
.iter()
.map(|(window, id)| (*id, window.clone()))
.collect();
for card in cards {
// Front-to-back: outline and live miniatures above each card, all above
// the strip. Nothing is painted behind the main overview window grid.
@@ -1451,14 +1458,10 @@ fn overview_strip_elements(
}
if let Some(programs) = &programs {
for (id, rect) in &card.windows {
if let Some(window) = state
.window_ids
.iter()
.find_map(|(window, candidate)| (*candidate == *id).then(|| window.clone()))
{
if let Some(window) = windows_by_id.get(id) {
elements.extend(rounded_window_elements(
renderer,
&window,
window,
rounded_visual_rect(*rect, output_geometry.loc),
physical_rect(*rect, output_geometry.loc, scale),
scale,