Optimizing Code for Power Consumption
- Know Your Device
- Use Custom Hardware
- Burn Memory
- Check the Status
- Don't Poll
- Test First
When people talk about optimization, they usually mean improving either the speed or the space requirements of a program. Often, these two aims are opposites: You can make a program faster at the cost of more memory, or vice versa.
In recent years, another kind of optimization has become increasingly important: optimizing for low power usage. Every operation of a mobile application consumes power; the more power the app consumes, the shorter the device's battery life will be. Use too much power, and people will avoid using your app unless they're near a power adaptor.
Know Your Device
When you're trying to create power-efficient code, just as when creating fast or memory-efficient code, the most important thing to remember is that the characteristics of devices are not universal. My previous article "How Not to Optimize" looked at optimization tricks that used to be important, but are no longer relevant on modern hardware.
This principle is even more important when it comes to power consumption. A good example is persistent storage. Most handheld devices now come with flash memory for persistent storage. A very small number come with microdrives, and a lot of laptops still use rotating storage. The power requirements of all these systems are very different. The most expensive thing to do with a hard drive is start the platters spinning. If the drive is idle for a while, it's using (almost) no power. The next time you access the drive, however, these stationary platters must be spun up to at least around 3,600 RPM before you can start reading or writing.
A lot of operating systems will put the disk to sleep after a period of inactivity. If the OS is sleeping the disk after 10 minutes, and you have a program that's writing every 11 minutes, each write will come just after the disk has spun down, giving your app the worst possible power usage. If you write every 10 minutes, you'll prevent the disk from ever sleeping, which is a bit better but still quite bad. If you can defer writes much longer, then you get better power usage, because the drive can spend more time idle.
You may be able to query the state of the drive by using some OS-specific calls. If the drive is already spinning, write immediately. If it's spun down, defer writes for a bit, if it's safe to do so.
Flash memory's power characteristics are very different: The transition between powered up and powered down for flash takes very little energy and can happen very quickly, so a well-designed flash controller will turn off the flash chips whenever they're not being accessed. Unlike a hard disk, writing to flash uses a lot more power than having it sitting idle, and small writes can take considerably more power if they require a complete cell to be erased.
Ideally, with flash, you want sequential writes and random reads. Some systems come with a log-structured filesystem designed for flash that does this in the background anyway. Other systems don't have this setup, and it can be worth designing your files around this possibility. One technique, used by both Word documents and PDF files, is to append a description of the changes to a file with every save, and then periodically write out the entire file. The small incremental writes don't necessarily require an erase on flash. Unfortunately, the paging mechanism typically works against you when using this trick, but if you have direct low-level access to the flash then you can sometimes avoid the extra erase cycles.