Building Nicely With Rust And Nix

This will help Rust or Nix users push their CPU heavy processes to the back of the line, keeping machines snappy even under heavy load. If your OS doesn't know which processes need priority CPU, builds and language servers etc might take all of it.

Context: Burning Up At Launch

Around the launch of the PrizeForge MVP, my machine was beginning to grind to a halt in ways that were beginning make it worth it to drop what I was doing. There was a lot going on:

My machine isn't bad. It's amazing by 2018 standards. The problem is that when all of this automation cascades into a huge spike all at once, not enough CPU goes to moving windows on my Desktop UI. Things are humming along, but I'm contending with lots of processes that are less urgent than making the UI respond.

Summary of Improvements

Nice Nix Builds

When I load dev shells with direnv automations, I want to keep running other commands and not have a huge lag spike regardless of what nix builders are doing.

systemd.services.nix-daemon.serviceConfig = {
  Nice = lib.mkForce 15;
  IOSchedulingClass = lib.mkForce "idle";
  IOSchedulingPriority = lib.mkForce 7;
};

Nicing the nix daemon is a great way to let it automatically get pushed to the back of the line when you're using the machine while still being able to utilize all of it for builds that are holding up your launch.

Nice Cargo

This is some bashrcExtra in my home manager configuration. You can throw something like this in a bashrc to basically wrap all cargo commands in nice.

cargo() {
    local cargo_path
    cargo_path=$(command -v cargo)
    nice -n 5 ionice -c2 -n7 "$cargo_path" "$@"
}

Nice Rust Analyzer

Some Lispers say that Elisp is the worst of the Lisps. They are right. Nonetheless, this element of eglot-server-programs makes our LSP run nicely.

((rust-ts-mode rust-mode) "/bin/sh" "-c"
 "exec ionice -c3 nice -n10 rust-analyzer"
 :initializationOptions (:cargo (:allFeatures t :targetDir t)))

Cargo Lock Held?

Rust Analyzer is the culprit. Note the :targetDir t above. This tells RA to use its own target directory so it never blocks cargo completely. They just fight each other for CPU while staying out of my way.

Crate Collecting

Many have already noted that splitting crates makes Rust build times a lot faster. Lately my habit is, when I start working on part of the site, I put that part into a crate at the beginning of the cycle. I don't care of the rest of the program builds slow because it doesn't build often. The biggest gains come from the part I'm actually rebuilding a lot.

Mold RAM Spikes

I tried mold out as a linker. Went back to ldd, which soon became the default for Rust. Mold is fast, but just watch the RAM usage. Memory spikes make machines I/O limited. It also managed to produce some WASM binaries that would run on Firefox but not Chromium. Not worth it IMO.

Along the way, discovered Zswap and it has been a game changer for mitigating worst-case situations, which seem to have just vanished. I researched it to tune settings only to find a promising improvement called Ariadne. I've opened a PrizeForge stream so that someday someone might be encouraged to land this in mainline.

Would Recommend

Solid 10/10 overall. I can build 2-3 Nix containers concurrently while Rust Analyzer tries to evaluate proc macros and cargo leptos rebuilds wasm before refreshing the page. The machine is still responsive.

Want to Work With Nix and Rust?

Check our careers page. The basic plan is to pull in a lot of B2B money for various kinds of support and feature consulting done by users. The only requirement is that the money is smartly spent on open source that those businesses rely on, directly or indirectly. Follow our socials. Sign up for PrizeForge and help make it work.