One of the tradeoffs for using Guix is that the processes for doing builds, upgrades, and such like tends to be CPU and I/O heavy. (Though, once a profile is built, switching to it is very fast.) I found that, on my less-than-bleeding-edge computers, running a guix build or upgrade can introduce a lot of latency into my desktop experience or even cause Gnome Shell to freeze up. So, I've always wanted some way to make Guix processes have less impact on my system, while still running them in the background.
Early on, I explored off-loading. The main problem with this approach is it would require me to operate another computer just for this task, which didn't appeal to me.
Something else we can do is to reduce the number of cpu cores and allowed build jobs, through --max-jobs and --cores. The guix daemon service conveniently allows us to set this as the default for all our builds. What I don't like about this approach is that it wastes a lot of build time when guix is running but I'm aren't doing anything with your computer. Also, I have a suspicion that these options don't benefit all build types (derivations, etc.) and maybe not all packages with various build systems.
Recently, reading an old QNX programming manual, I wondered if I could change the priority behavior of the guix-daemon process(es). And, indeed, it is possibly to do this on a GNU/linux system. This command will increase the "niceness" of process 213, which means that process 213 gets lower CPU priority than other processes:
renice 20 213
Also, one can lower the I/O priority of the process. This command lowers it to priority 7 (higher numbers are lower priority) and puts it in the best-effort I/O priority class:
ionice -c 2 -n 7 -P 213
Reading IONICE(1), we are tempted to use the IDLE class instead, but I found that on my system, in the IDLE class, a build process will be frozen altogether for long periods of time (indefinitely?) which is not good. Anyway, -c 2 -n 7 ensures we will still use the hard disk, while trying to give everyone else first access.
In practice, I find that these settings work great. I don't see any latency issues now, but I can still see the guix processes making progress, though a bit slower than normal.
The main problem here is that, each time you power up your computer, you have to figure out the PID of the first guix daemon. The guix daemon does spawn additional daemons, but thankfully it appears that the new daemons inherit the priority levels of the parent, as far as I can tell from my inspection of the processes. But it is not difficult to figure out the PID using the PS utility.
Also, it is a bother to type out the commands. This Emacs function does the job, with you providing the PID:
(defun very-low-priority (pid) "set a process to lowest nice value and lowest I/O priority level in the best-effort class" (interactive "nPID: ") (let ((pid-str (number-to-string pid))) (async-shell-command (concat "sudo renice 20 " pid-str " && sudo ionice -c 2 -n 7 -P " pid-str " && echo ionice succeeded"))))
Some more work could be added to this function, to have it figure out what the PID is using PS and some text manipulation. I did some investigation in the Guix manual, but it does not appear that there are any guix-service configuration options that would allow applying these commands at boot, or in some other way setting the niceness values.
This work © 2024 by Christopher Howard is licensed under Attribution-ShareAlike 4.0 International.