After upgrading to Mountain Lion I have been hitting some problems with my Mac sleeping when I was expecting it be doing some work. Typically this happens when I leave it running a script that I expect to take several hours. On my return I find the network connection has dropped and the machine has gone to sleep leaving the job unfinished. The explanation and solution lies in the changes to power management that Mountain Lion introduced.
You can read more about the power management changes in John Siracusa's epic Mountain Lion review and also in WWDC 2012 session 711. In short, Mountain Lion is noticeably more aggressive when deciding to sleep compared to previous releases. In particular my problem is caused because disk activity is no longer sufficient to prevent the computer sleeping. One way to prevent the problem is by setting the computer sleep time to “Never” in the Energy Saver system preferences pane:
That however means that the system will never sleep which is certainly not what I want. When the system is truly idle I want it to save power by shutting down. A better approach is to use Power Assertions to tell the system when I have some work and I that I would prefer it not to sleep.
A power assertion is way to provide a hint to OS X that you are busy doing something. If possible it should not allow the computer to sleep when the user is idle. Apple provides SDK calls to allow an application to create and release power assertions but in my case there are two command-line utilities that will do the job.
The pmset command (
/usr/bin/pmset) provides command-line access to many of the power management settings that are visible in the Energy Saver preferences pane. In addition it provides a way to view and manage power assertions. For example if I use iTunes to play some music it allows the display to sleep but a power assertion prevents the system from entering the idle sleep mode. You can see this using the pmset command as follows:
$ pmset -g assertions 08/08/2012 23:41:20 BST Assertion status system-wide: PreventUserIdleDisplaySleep 0 PreventSystemSleep 0 PreventUserIdleSystemSleep 1 ExternalMedia 1 DisableLowPowerBatteryWarnings 0 UserIsActive 0 ApplePushServiceTask 0 BackgroundTask 0 Listed by owning process: pid 5871(iTunes): [0x000000010000093e] 00:00:08 PreventUserIdleSystemSleep named: "Nameless (via IOPMAssertionCreate)" pid 29(powerd): [0x000000090000012c] 61:28:54 ExternalMedia named: "com.apple.powermanagement.externalmediamounted"
Note that the 0 and 1 indicate the state of the assertion not the total count of assertions. A list of processes owning the assertions is also displayed so you can check who created each assertion. In this case there is also an assertion created by the powerd process for an external drive that is attached. Note that this ExternalMedia assertion will not prevent the system from sleeping.
You can also view the power management log to see the create and release power assertion events:
$ pmset -g log 08/08/2012 23:41:17 BST Assertions PID 5871(iTunes) Created PreventUserIdleSystemSleep "Nameless (via IOPMAssertionCreate)" 00:00:08 id:0x100000984 Aggregate:0x100242 08/08/2012 23:41:35 BST Assertions PID 5871(iTunes) Released PreventUserIdleSystemSleep "Nameless (via IOPMAssertionCreate)" 00:00:26 id:0x100000984 Aggregate:0x100242
If you want to create a power management assertion to prevent the computer entering the idle sleep mode you can use the following command in a terminal session:
$ pmset noidle Preventing idle sleep (^C to exit)...
As we have already seen you can check that the power assertion has been created using the pmset command from a second terminal window:
$ pmset -g assertions ... PreventUserIdleSystemSleep 1 ... Listed by owning process: pid 25194(pmset): [0x00000001000014ff] 00:00:51 NoIdleSleepAssertion named: "pmset prevent sleep"
When you are done you can hit control-C to exit and release the power assertion. The pmset command is fine but not the most convenient solution when you want a power assertion that lasts for the duration of a script execution.
If you want to prevent the system from sleeping whilst you run a script or utility there is a better option with Mountain Lion. The caffeinate (
/usr/bin/caffeinate) command allows you create an assertion like pmset. Where caffeinate gets more useful is that it takes an optional argument specifying a script or utility it should execute. The power assertion is then maintained until the script completes. For example, to create a power assertion that prevents idle sleep whilst the script longtask.sh executes:
$ caffeinate ./longtask.sh
As before you can use pmset to see this assertion:
$ pmset -g assertions ... PreventUserIdleSystemSleep 1 ... Listed by owning process: pid 26187(caffeinate): [0x00000001000015cd] 00:00:11 PreventUserIdleSystemSleep named: "caffeinate command-line tool" Details: caffeinate asserting on behalf of ./longtask.sh Localized=THE CAFFEINATE TOOL IS PREVENTING SLEEP.
The caffeinate command has a number of other useful options to prevent the display from sleeping and to create timed power assertions (use
man caffeinate for further details). If you are interested Apple has also open sourced the code, you can find it on the Apple Source Code Site.