How to limit CPU usage by process

27 Jan 2023

I have a 2019 MacBook Pro, and it’s a nice machine for its time; with an i9 processor it handles most tasks quite well. However, for some reason Apple decided to give it a battery that doesn’t have enough power to supply what the CPU needs when it’s using all 16 cores, such as when I’m transcoding video with ffmpeg. Even using a 140W power supply, it will slowly drain the battery when at full speed, and with a large enough encoding job (such as encoding AV1 content) it could easily drain it all the way and shut down.

If only there were a way I could tell ffmpeg to slow down a bit, just enough to let the battery at least stay at a constant level while the transcoding is happening…

Well, fortunately I, and anyone else with this problem, are in luck. There’s a utility called cpulimit which does exactly what the situation calls for. It’s available on most Linux distributions, and also, thanks to some kind soul that created a formula for it, is available on homebrew as itself.

All one has to do (if you have homebrew already installed) is brew install cpulimit. One caveat, however, and this is most unfortunate: it’s only functional on Intel CPUs at the moment. Apparently no one has recompiled it for ARM yet, or the necessary hooks aren’t there for the M series CPUs. My sympathies to those of you stuck with fabulously high-powered new machines. (If anyone has mad skillz and feels like being heroic, the source code for cpulimit can be found here)

In any case, to use cpulimit one has to look up the process ID (PID) of the program that’s eating all the CPU. This can be done with ps; just look for the number in the leftmost column; that’s the PID. If the process isn’t one of your own, you might want to use ps ax in order to see all processes, but in that case you might also want to filter the list to find what you’re looking for: ps ax | grep <programname>. Also, the top, htop, or the wonderful bpytop utility, can show you which processes are taking all the CPU.

Once you have the PID, you run cpulimit, telling it how much CPU to give the process, anywhere from 1 to 1600:

cpulimit -l <cpu amount> -p <PID>

The cpulimit process will stay active, rather than setting something and exiting immediately. To undo the limit and release the process to use as much CPU as it wants again, just use Ctrl-C to stop cpulimit.

Note that the percentage of CPU you give to cpulimit doesn’t necessarily behave like you think it might, especially with highly multithreaded programs like ffmpeg. On my machine, limiting ffmpeg with a parameter of -l 50 actually results in an overall CPU usage of about 15%, much lower than perhaps would be expected. So, you will probably need to experiment to find a level that will keep your battery from draining without the process taking forever and a day to finish.

An extra tidbit

If you want to just completely pause a process temporarily, you can use the STOP and CONT signals to do this:

kill -STOP <pid>  # This will completely stop a process without killing it (temporarily)

kill -CONT <pid>  # This will resume a process stopped by the above command

(Hint: this works quite well with annoying processes in Mac OS like photoanalysisd and corespotlightd.)

Share and enjoy…