How to run commands and scripts on Efficiency cores

As I’ve been steadily documenting, on M1 Macs much of macOS and its many services and periodic activities are run on its Efficiency or Icestorm cores. That begs the question as to how we can run our own background tasks, using command tools and scripts, on those cores. This article tries to answer that question.

I’ve been unable to find any way of ensuring that normal commands and scripts run from Terminal are constrained to the Efficiency cores, although I may well be missing a trick here. If you run a processor-intensive command such as the new AppleArchive tool aa, then by default it’s given free rein of all eight cores in an M1, and there don’t appear to be any options to alter that behaviour, which seems strange.

When inside macOS, running from Swift, Objective-C or an equivalent language, there are several opportunities to set the Quality of Service when running command tools. For example, the common approach to these is through the Process (Swift) or NSTask (Objective-C) class, where there’s QualityOfService (Swift) or NSQualityOfService (Objective-C). Set that to background, the integer value 9, and the M1 will run that command entirely on its Efficiency cores.

Here’s an example of two different levels of QualityOfService when using aa to compress a file of more than 10 GB, seen in Activity Monitor.


The first run, at the left, shows all four Performance (Firestorm) cores maxing out, and the Efficiency (Icestorm) cores at well over 50%. That was the first compression, performed with a QualityOfService of userInteractive (33). The second compression, of the same large file, is seen only in the Efficiency cores, where it maxes them out for much longer without any of the load being shared by the Performance cores. That was run with a QualityOfService set to background.

QualityOfService is also available in other classes including OperationQueue, an easy way to put tasks in the background, and most of all in NSBackgroundActivityScheduler, which gives access to the DAS despatching system.

For those who want to try out running commands on different combinations of cores, I’ve made a new version of my exploratory utility DispatchRider, which has previously allowed you to explore running commands using NSBackgroundActivityScheduler and the DAS despatching system. It retains that previous function, but if you turn off the Repeat and set the Tolerance to 0, it will run your command immediately at the set Quality of Service, which can range from userInteractive (highest) to background (lowest).

If you try that out, there are two points that I’d like to emphasise from its short documentation:

  • the Command must be given as its full path, e.g. /usr/local/bin/mycommand
  • all parameters must be given in the Params box, using &arg: to separate them. For example -o myfile becomes -o&arg:myfile.

Inevitably, there is little point in running commands which complete in a second or two, as you’re then unlikely to see any significant loading on the cores.

DispatchRider version 1.0b7 is available from here: dispatchrider10b7

Have fun!