7

My current project is a constant-presence application (think Tinder or Foursquare), and the battery consumption is through the roof. We think the main draw on power are the GPS and WiFi antennas. We'd like to be able to measure our app's energy usage under several different configurations.

But how to do this? We want a process that:

  • Can be used with the phone disconnected from the computer (so we know we're using battery rather than drawing power over USB),
  • Has sufficient granularity to allow us to correlate energy spikes to application events (launching the app, updating the location, sending analytics information to Mixpanel, etc),
  • Can be run overnight without babysitting,
  • Can be exported as CSV or whatever for statistical analysis.

Quite the list, I know.

Those are the requirements, and here are the options that I'm aware of:

1. Turning on untethered Energy Diagnostics Logging on an iOS device, and exporting to Instruments

This is the obvious answer, but it has one gigantic flaw.

Pros:

  • Uses battery instead of USB power.
  • Excellent granularity (1sec time series data, 20 discrete energy usage levels),
  • Correlated to other device events like GPS antenna usage etc.

Cons:

2. Monitoring a plugged-in phone through Instruments

Pros:

  • Same excellent granularity and correlation to other device events.
  • Battery can't run out.

Cons:

  • Doesn't use the battery, so the energy consumption is incomparable to real-world usage.
  • Instruments doesn't even reliably show energy usage. Sometimes it's just blank.
  • Can't export to CSV.

3. Using public Cocoa APIs to record energy usage in our app – [UIDevice.currentDevice batteryLevel]

This is the most common answer on SO. I've looked at Estimated battery time on iOS, iphone: Calculating battery life and about a dozen others.

Pros:

  • Arbitrarily small time between measurements.
  • Can persist data even if the battery dies by writing to disk somehow (CoreData, defaults, network, whatever).
  • Can choose arbitrary format for the data, say CSV.

Cons:

  • A lot more work than the other approaches.
  • Public API only gives you battery level to 5% accuracy. This is essentially the time integral of the instantaneous power consumption data we get from approaches 1 and 2. Not nearly granular enough to correlate with other device events (but maybe enough to get a gross estimate for device battery life).

4. Using private Cocoa APIs to record energy usage

As we'll only ever be doing this during development, it doesn't matter if Apple would reject the app for using a private API. Presumably there's some private API for this, as Apple is able to record the data with Untethered Energy Diagnostics turned on.

Pros:

  • Arbitrarily granularity, arbitrary file format, arbitrary persistence.

Cons:

  • Waaaaay more work to figure out how to use it. Maybe not even possible.

5. Combined approach

We could use the untethered diagnostics to quantify the marginal energy cost for each action. "Ok, spinning up the GPS antenna takes 150mW•H. Calculating position takes 50mW•H. Sending a Mixpanel event takes 25mW•H, unless we made another network call within the previous 30sec, in which case it takes 15mW•H." (all numbers invented on the spot.) Then we can use the tethered monitoring to record when each of those actions takes place, plug into a linear equation, and estimate the amount of energy it should have taken.

Pros:

  • Flexible. Arbitrary everything.

Cons:

  • Maths.
  • Very easy to miss non-linear contributions. Getting something like E = k0/(gps poll interval) + k1*(number of analytics calls) is easy, but what if the cost of spinning up both antennas is less than the sum of spinning them each up separately?
  • Ignores any caching strategies that Apple might make internally in Location Services.
  • Not even remotely close to real-world utilization.

Anyhow, I've blathered enough. Has anybody done this before? How?

Community
  • 1
  • 1

3 Answers3

3

Not sure if this is applicable to this exact use-case, but I've developed a library called UIDeviceListener that allows you to easily (basically with one line of code), retrieve data from the operating system regarding power consumption and many other battery/charging related data points: https://github.com/eldoogy/PowerData

Here is a sample dictionary to give you an idea of the kind of information you can get. I will point your attention to the InstantAmperage key. This shows real-time power consumption in mA for the entire device (while the device is unplugged). That might help accomplish what you're looking for here.

{
AdapterDetails =     {
    Amperage = 1000;
    Description = "usb host";
    FamilyCode = "-536854528";
    PMUConfiguration = 1000;
    Watts = 5;
};
AdapterInfo = 16384;
Amperage = 1000;
AppleRawCurrentCapacity = 1279;
AppleRawMaxCapacity = 1275;
AtCriticalLevel = 0;
AtWarnLevel = 0;
BatteryData =     {
    BatterySerialNumber = REDACTED;
    ChemID = 355;
    CycleCount = 524;
    DesignCapacity = 1420;
    Flags = 640;
    FullAvailableCapacity = 1325;
    ManufactureDate = REDACTED;
    MaxCapacity = 1273;
    MfgData = REDACTED;
    QmaxCell0 = 1350;
    StateOfCharge = 100;
    Voltage = 4194;
};
BatteryInstalled = 1;
BatteryKey = "0003-default";
BootBBCapacity = 52;
BootCapacityEstimate = 2;
BootVoltage = 3518;
CFBundleIdentifier = "com.apple.driver.AppleD1815PMU";
ChargerConfiguration = 990;
CurrentCapacity = 1275;
CycleCount = 524;
DesignCapacity = 1420;
ExternalChargeCapable = 1;
ExternalConnected = 1;
FullyCharged = 1;
IOClass = AppleD1815PMUPowerSource;
IOFunctionParent64000000 = <>;
IOGeneralInterest = "IOCommand is not serializable";
IOInterruptControllers =     (
    IOInterruptController34000000,
    IOInterruptController34000000,
    IOInterruptController34000000,
    IOInterruptController34000000
);
IOInterruptSpecifiers =     (
    <03000000>,
    <26000000>,
    <04000000>,
    <24000000>
);
IOMatchCategory = AppleD1815PMUPowerSource;
IOPowerManagement =     {
    CurrentPowerState = 2;
    DevicePowerState = 2;
    MaxPowerState = 2;
};
IOProbeScore = 0;
IOProviderClass = AppleD1815PMU;
InstantAmperage = 0;
IsCharging = 0;
Location = 0;
Manufacturer = A;
MaxCapacity = 1275;
Model = "0003-A";
Serial = REDACTED;
Temperature = 2590;
TimeRemaining = 0;
UpdateTime = 1461830702;
Voltage = 4182;
"battery-data" =     {
    "0003-default" = <...>;
    "0004-default" = <...>;
    "0005-default" = <...};
"built-in" = 1;
}

UIDeviceListener supports regular, non jailbroken iOS devices and does not invoke any private APIs.

ldoogy
  • 2,819
  • 1
  • 24
  • 38
1

GPS needs 10% battery per hour, so will last about 10h of high precise location recording once a second. location polling intervall has nothing to do with battery consumption. either the GPS chip is enabled or not. There is no low power gps mode!! you can disable gps if you know that the user does not need it.

for permanent recording of location data, you can only save battery if you decide to go with low accuarcy ( 1000m cell tower or wlan locationing) instead of high (3-6m = GPS)

of course during measurement you wil kill all 3d party apps, especially messenger apps, the most famous one connects to internet every each second!!

AlexWien
  • 28,470
  • 6
  • 53
  • 83
1

I can't make suggestions on making power measurements on iOS, but can point out some possible sources of power consumption, as well as point out some issues to think about when making measurements.

Common sources of excessive power consumption:

  • Polling instead of using interrupts. this prevents the processor from entering lower power states. Low power states can reduce processor consumption by over an order of magnitude

  • Using interrupt intervals that are too small. A common mistake is believing that a smaller polling interval, say 10ms, results in faster response. If the ability of your app/user to respond is 500ms, then 10ms serves only to keep the processor awake and chewing up energy.

  • Anything that transmits is a hog, receiving less so but still bad (WiFi, GPS, Bluetooth, etc as said above). Minimize their usage.

  • Peripherals also have low power states. Uses them sparingly to keep them in a lower power state.

Comments on measuring power consumption:

  • Monitoring itself can cause excessive power consumption. Monitoring power is very tricky. Monitoring uses interrupts or polling which keep the processor/device awake and in a high power state.

  • Most monitoring is from the OS, which may or may not be from "real" HW measurements vs SW "guesses".

  • Trying to be really really accurate means more frequent measurements which cause, you guessed it, the processor and devices to stay awake.

I suggest you take a close look at what sampling interval you really need, and design your app to allow the processor and devices to rest as much as possible.

Taylor Kidd
  • 1,463
  • 1
  • 9
  • 11