App Nap, Battery Endurance, and Grand Central Dispatch

Apple must have been more than a bit miffed when its shiny new MacBook Pro models were criticised for their poor battery life, because of the effort which it has put into giving its laptops, and those models in particular, the greatest endurance possible. Its software engineers even invented a whole new part of macOS to achieve that: Grand Central Dispatch (GCD).

If you thought that GCD was all about getting the most out of multi-core processors, you’re only partly right: that is but one of its functions. This article explores more of what GCD does, and why it now controls so much.

Older versions of Mac OS X and OS X followed the generic Unix approach to background and periodic tasks, and using multiple processors and cores. Apple started to diverge when it gave task launching to launchd. But it wanted smarter systems which could manage core load better, could run heavyweight background tasks such as making Time Machine backups without slowing everything else to a crawl, and above all which could eke out the charge in a slimline laptop, iPhone, or iPad battery.

They came up with GCD, which has evolved greatly since its introduction in Snow Leopard in August 2009. The way that it works is to take tasks from apps and services, and run them in parallel. GCD manages the priorities of those tasks in queues, so that the tasks are executed in turn, according to their priorities and available resources.

Developers are provided with a lightweight scheme to encourage them to use GCD as much as possible in their software. This is explained briefly in Wikipedia, used to be documented in Apple’s GCD reference (which has since vanished without replacement), and in the Dispatch API and related material. Jonathan Levin has provided additional details for OS X 10.9.

Outside such explanations of concurrency in macOS, the other place that you’ll find information about GCD is in Apple’s Energy Efficiency Guides, such as that for Mac Apps. This is because GCD manages its tasks and queues to attain maximum energy efficiency, which translates in portable devices to battery endurance.

GCD is therefore concerned with achieving high energy efficiency in order to prolong battery endurance, delivering maximum performance when it’s needed, ensuring a highly responsive user interface at all times, and keeping hardware as cool and quiet as possible.

In addition to providing apps and services with support for concurrency and smart scheduling of tasks, GCD and its related systems use Quality of Service techniques to ensure that tasks most obvious to the user take priority, delivery of events without waking processors, and App Nap as a means of conserving energy.

When investigating a bug which caused Time Machine backups to become irregular, I saw in Sierra’s new logs the evidence of these sophisticated systems at work. One way to view them is in comparison with conventional scheduled tasks.

If you add a task, such as running a command every hour, as a Launch Agent, every hour that will be run as a new task by launchd. Even if your Mac is overloaded with tasks and hungry for more physical memory at the time, when the clock comes round to the scheduled time, your command will be run.

Hourly Time Machine backups work completely differently. The activity is one of many listed by the Duet Activity Scheduler (DAS). Each activity has a score, which is reassessed periodically. The closer the score is to 0.0, the more likely it is not to be run at that time – indeed, a score of 0.0 makes DAS decide that the task must not run at that time. The higher the score, closer to 1.0, the more likely the task is to be run.

Once DAS has decided to run one of the tasks from its list, it hands the job over to Centralised Task Scheduling (CTS), which then uses lightweight inter-process communication (XPC) to start the process. In the case of Time Machine backups, that involves running the backupd-auto daemon, which in turn invokes backupd itself to do the heavy lifting.

With the backup in progress, the backup task is now set to a score of 0.0 in the list maintained by DAS, so that it will not be run for the next hour.

Apple’s Energy Efficiency Guide for Mac Apps details how developers can use GCD to schedule background activities which can be deferred to the best moment, using the NSBackgroundActivityScheduler API.

At the moment, although users can install their own Launch Daemons and Launch Agents which are scheduled and run using launchd, using a property list, there is no similar method for using GCD to schedule and run tasks without writing the task specifically for GCD. As a result, Apple’s services and apps make most use of GCD, and third parties do so far less.

There are two tools which give insight into how apps and services are working with (or without) GCD to achieve energy efficiency and its other benefits.

gcdenergysaving1

The Energy tab in Activity Monitor shows current and averaged ‘energy impact’, whether a task is able to use App Nap, and whether it is preventing system sleep. Its scrolling graph displays the total ‘energy impact’ being borne by that Mac over time. It is worth following this during periods of activity, such as a Time Machine backup, perhaps.

gcdenergysaving2

When you run your own app in Xcode’s debug environment, the project window can display an Energy Report for that app. This highly detailed view goes well beyond that in Activity Scheduler, but is only available when you have the project source code, so is not a tool for users to analyse apps and services with. Xcode’s Tools also provide additional support to its projects.

Having gone to these lengths to obtain optimum performance and battery endurance, I think that it is understandable that Apple was seriously upset when it was all screwed up by a somewhat devious test method which happened to trip over a bug in a feature not intended for users in Safari. Now that GCD itself appears more stable, let’s hope that it pays off better for all macOS and iOS products.