# Linux background changing daemon in Rust

I'm working on a program that updates the background of an x11 desktop at a specified interval. However, it eats large amounts of my CPU just sitting idle. I know this is due to the main loop running faster than I want it to. I've used a couple shameful hacks to quell usage down to about 15% but now I am searching for a long-term solution.

Here is the function that contains the main loop:

pub fn run_mapped(&mut self) {
info!(self.logger, "Running in mapped mode!");
let wait_d = Duration::new(0,500);
let long_wait_d = Duration::new(0,750);
loop {
self.img_dir.1 = Instant::now();
}
let cd = self.x.get_current_desktop();
// change background if timeout is reached
if self.since_timeout.elapsed() > self.timeout {
self.change_backgrounds();
let ref mut current_bg = self.image_map[cd];
self.since_timeout = Instant::now();
self.x.change_background(current_bg);
}
match self.x.next_event() {
Some(_) => {
let ref mut current_bg = self.image_map[cd];
self.x.change_background(current_bg);
},
None => { sleep(wait_d); }
}
sleep(long_wait_d);
}
}


Not shown, but I have additionally set process priority lower to give more important process priority over this one.

I added the sleep calls to prevent >50% CPU usage but it still consumes ~20% which seems a little excessive for what I want this program to do. I'm looking at some of the CPU usage from other programs I'm running in my DE (candybar) and they're nowhere near as resource-hungry as my program.

All that being said, my two questions are:

1. Why is this? Meaning, why is my program using so much CPU since it is basically 'sleeping' most of the time (in its current state)?

2. How can I fix this? The only thing I can think of now is scrapping it and abusing cron jobs to the same effect.

The full code can be found on Github.

• Does Rust have a Timer you can use that fires an event periodically? – user34073 Dec 30 '16 at 5:48
• I don't believe so and the only external timing library's appear to be basic fps counters :/. But i don't think that would work because it needs to monitor "_NET_CURRENT_DESKTOP" which could change at anytime. But i could be wrong? – user7008548 Dec 30 '16 at 5:55

since it is basically 'sleeping' most of the time

That's not really the most accurate thing...

impl Duration {
fn new(secs: u64, nanos: u32) -> Duration
}


Duration's second argument is nanoseconds, thus your "long wait" is 750 nanoseconds. That's 0.75 microseconds / 0.00075 milliseconds / 0.00000075 seconds. For reference, a cycle of a 3GHz computer is 0.3333 nanoseconds. If your code takes zero time, you are waking 1 million times per second!

This is the very definition of a busy wait loop.

So how do you fix it? You need to rearchitect. You state:

and abusing cron jobs to the same effect

Cron jobs have resolution of a minute (8×10^7 bigger!). If you can live with that, sleep for that long.

Another solution is to move to an event-driven system. You make some mention:

it needs to monitor _NET_CURRENT_DESKTOP which could change at anytime.

If that's the case, you'd have two sources of events: a timer and whatever provides the _NET_CURRENT_DESKTOP event. The current front-runners of this type of code in Rust are futures and mio. I don't know exactly how the X code works, but it's probably event driven (GUI code usually is), and there's probably some mio/futures periodic timer. You "simply" need to configure both of them and then respond whenever either triggers.