atagen

monolith

public
Star0
Watch0

Commit 796c963a4b55

tarball

atagen <boss@atagen.co>2026-10-16 22:50 UTC

3 files changed+64-11
monolith: ask for realtime scheduling and a high priority GPU queue

On bare metal the compositor thread asks for SCHED_RR with reset-on-fork, and render-vk asks for a realtime, then high, global priority queue. NVIDIA refuses both priorities without CAP_SYS_NICE, as does the kernel for SCHED_RR, so every step falls back quietly to the old behaviour.
Modified file: crates/monolith/Cargo.toml+1 additions
@@ -21,6 +21,7 @@ monolith-motion.workspace = true
2121 monolith-planner.workspace = true
2222 monolith-protocols.workspace = true
2323 monolith-render-vk.workspace = true
24+libc = "0.2"
2425 pound = "0.5"
2526 profiling = "1"
2627 serde_json.workspace = true
Modified file: crates/monolith/src/main.rs+20 additions
@@ -131,6 +131,23 @@ fn main() -> ExitCode {
131131 }
132132 }
133133
134+/// Puts the compositor thread on SCHED_RR so a busy desktop cannot delay a
135+/// frame. Reset-on-fork keeps threads and programs it starts off realtime.
136+fn realtime() {
137+ let param = libc::sched_param { sched_priority: 2 };
138+ // SAFETY: plain syscall on the calling thread with a valid param.
139+ let rc =
140+ unsafe { libc::sched_setscheduler(0, libc::SCHED_RR | libc::SCHED_RESET_ON_FORK, &param) };
141+ if rc == 0 {
142+ tracing::info!("compositor thread runs SCHED_RR");
143+ } else {
144+ tracing::info!(
145+ "no realtime scheduling, it needs CAP_SYS_NICE or an rtprio limit: {}",
146+ std::io::Error::last_os_error()
147+ );
148+ }
149+}
150+
134151 /// Hands the session's variables to D-Bus and systemd activated services,
135152 /// which portals need to find the compositor and pick monolith-portals.conf.
136153 fn export_session(state: &State) {
@@ -169,6 +186,9 @@ fn run(
169186 Backend::Drm => Some(drm::primary()?),
170187 _ => None,
171188 };
189+ if gpu.is_some() {
190+ realtime();
191+ }
172192 let node = gpu
173193 .as_deref()
174194 .map(smithay::backend::drm::DrmNode::from_path)
Modified file: crates/render-vk/src/device.rs+43 additions−11 deletions
@@ -82,9 +82,6 @@ impl Shared {
8282 return Err(Error::NoSuitableDevice);
8383 };
8484 let priorities = [1.0];
85- let queues = [vk::DeviceQueueCreateInfo::default()
86- .queue_family_index(queue_family)
87- .queue_priorities(&priorities)];
8885 let available: Vec<_> = unsafe { instance.enumerate_device_extension_properties(physical) }
8986 .unwrap_or_default()
9087 .iter()
@@ -97,14 +94,49 @@ impl Shared {
9794 if has_dmabuf {
9895 extensions.extend(DMABUF_EXTENSIONS.iter().map(|n| n.as_ptr()));
9996 }
100- let mut features13 = vk::PhysicalDeviceVulkan13Features::default()
101- .dynamic_rendering(true)
102- .synchronization2(true);
103- let info = vk::DeviceCreateInfo::default()
104- .queue_create_infos(&queues)
105- .enabled_extension_names(&extensions)
106- .push_next(&mut features13);
107- let device = match unsafe { instance.create_device(physical, &info, None) } {
97+ let global_priority = [
98+ ash::khr::global_priority::NAME,
99+ ash::ext::global_priority::NAME,
100+ ]
101+ .into_iter()
102+ .find(|n| available.iter().any(|a| a.as_c_str() == *n));
103+ let mut priorities_to_try = vec![None];
104+ if let Some(name) = global_priority {
105+ extensions.push(name.as_ptr());
106+ priorities_to_try = vec![
107+ Some(vk::QueueGlobalPriorityKHR::REALTIME),
108+ Some(vk::QueueGlobalPriorityKHR::HIGH),
109+ None,
110+ ];
111+ }
112+ let mut created = Err(vk::Result::ERROR_INITIALIZATION_FAILED);
113+ for priority in priorities_to_try {
114+ let mut features13 = vk::PhysicalDeviceVulkan13Features::default()
115+ .dynamic_rendering(true)
116+ .synchronization2(true);
117+ let mut global = vk::DeviceQueueGlobalPriorityCreateInfoKHR::default()
118+ .global_priority(priority.unwrap_or(vk::QueueGlobalPriorityKHR::MEDIUM));
119+ let mut queue = vk::DeviceQueueCreateInfo::default()
120+ .queue_family_index(queue_family)
121+ .queue_priorities(&priorities);
122+ if priority.is_some() {
123+ queue = queue.push_next(&mut global);
124+ }
125+ let queues = [queue];
126+ let info = vk::DeviceCreateInfo::default()
127+ .queue_create_infos(&queues)
128+ .enabled_extension_names(&extensions)
129+ .push_next(&mut features13);
130+ created = unsafe { instance.create_device(physical, &info, None) };
131+ match &created {
132+ Ok(_) => {
133+ tracing::info!(?priority, "queue global priority");
134+ break;
135+ }
136+ Err(e) => tracing::debug!(?priority, "queue global priority refused: {e}"),
137+ }
138+ }
139+ let device = match created {
108140 Ok(d) => d,
109141 Err(e) => {
110142 unsafe { instance.destroy_instance(None) };