100% CPU usage when not dropping OutputStream, in Ubuntu Linux, using ALSA
The following program uses 100% of a CPU, according to htop, in release mode, whether any key on the keyboard is pressed or not.
use winit::{
event::{Event, WindowEvent},
event_loop::{EventLoop, ControlFlow},
window::WindowBuilder,
event::ElementState,
};
fn main() {
let (sender, receiver) = std::sync::mpsc::channel();
std::thread::spawn(move || {
let output = match rodio::OutputStream::try_default() {
Ok(output) => output,
Err(_) => return,
};
while let Ok(_message) = receiver.recv() {
// In a real application play a sound selected by the message
}
});
let event_loop = EventLoop::new();
let window = WindowBuilder::new()
.build(&event_loop)
.unwrap();
event_loop.run(move |event, _, control_flow| {
match event {
Event::WindowEvent {
event: WindowEvent::CloseRequested,
window_id,
} if window_id == window.id() => *control_flow = ControlFlow::Exit,
Event::WindowEvent {
event: WindowEvent::KeyboardInput{
input: winit::event::KeyboardInput {
state: ElementState::Released,
..
},
..
},
window_id,
} if window_id == window.id() => {
let _ = sender.send(());
}
Event::MainEventsCleared => {
std::thread::sleep(std::time::Duration::from_millis(16));
}
_ => (),
}
});
}
If I comment out these lines, then the CPU usage drops down to near 0% :
let output = match rodio::OutputStream::try_default() {
Ok(output) => output,
Err(_) => return,
};
Am I using the library in a strange way? If so, I don't understand what the preferred way is to mix together an unknown number of sounds, starting at different times, in response to user input, given that the sounds stop when the OutputStream is dropped,
Some versions that may be relevant:
[dependencies]
rodio = "0.15.0"
winit = "0.26.1"
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 20.04.4 LTS
Release: 20.04
Codename: focal
$ cat /proc/asound/version
Advanced Linux Sound Architecture Driver Version k5.13.0-48-generic.
$ aplay --version
aplay: version 1.2.2 by Jaroslav Kysela <[email protected]>
I've since had the chance to try this program on some other machines running Linux. On those other machines the CPU usage was much lower. But on the original machine, (hereafter "Machine A") the 100% CPU behaviour persists.
I've also tried this CPAL example, (extending the time so I could get a CPU measurement) and found it also used 100% CPU on Machine A. CPAL relies on the alsa crate. I additionally tried the PCM example from the alsa docs, (again extending the time,) and found that it did not use 100% CPU, but instead used a much more reasonable amount.
Combining the previous two paragraphs, I am lead to the conclusion that some weird combination of what Rodio/CPAL is doing, and Machine A's sound hardware/driver is causing the issue.
Have you considered using receiver.try_recv() with a sleep if the receiver is empty? recv() blocks the thread until an object is received.
The goal I had that lead me to run into this issue was to have a dedicated thread to play sounds in response to messages. I wanted the thread to be running for as long as the entire program was running, so I can just send a message without blocking the main thread, or waiting for the thread to start up before the sound is played.
So, I'd need to keep the thread alive somehow. Given that, I'm not sure how using try_recv would help, since the only way I can think of to keep the thread alive with try_recv would be to loop around and try it again, maybe after a sleep. But if it sleeps, then that introduces latency, and if it doesn't sleep, isn't that just busy-waiting, which would then again use 100% of a CPU?
Somewhat frustratingly, I've now tried the above program on Machine A, and it no longer consumes as much CPU. I guess my audio driver must have been updated automatically or something? I do not recall doing anything that seems like it should have affected this myself. As of this writing, Machine A is still using Rust 1.62.0, for example.
So, it's mysterious to me why this problem appeared and then disappeared, but I suppose it has disappeared.