mix mob.battery_bench_ios (mob_dev v0.3.37)

Copy Markdown View Source

Builds a benchmark app, deploys it to a physical iPhone/iPad, and measures battery drain over time.

Run this from your Mob app project directory (the one containing ios/, mob.exs, and your Elixir source). It requires bundle_id to be set in mob.exs:

config :mob_dev,
  mob_dir:   "/path/to/mob",
  bundle_id: "com.example.myapp"

Prerequisites

libimobiledevice is required for battery readings:

brew install libimobiledevice

The device must be trusted on this Mac (accept "Trust This Computer" when connecting via USB). Xcode 15 or later is required for xcrun devicectl.

Battery measurement

iOS exposes battery capacity via libimobiledevice's ideviceinfo tool. If the device reports BatteryMaxCapacity (mAh), drain is shown in mAh like the Android benchmark. Otherwise, it falls back to percentage points (1% ≈ 40–60 mAh on most iPhones).

WiFi-only measurements are not possible on iOS — USB-connected readings are skewed because the cable can trickle-charge. To minimise this, use a USB-only data cable (no charging), or note the baseline with and without cable.

Mob projects use ios/build_device.sh rather than a full Xcode project, which means the bench task's xcodebuild path doesn't apply. Use this two-step pattern instead:

# 1. Push BEAM flags via mob.deploy (no native rebuild — ~5 sec).
mix mob.deploy --beam-flags "" --ios               # tuned (Nerves)
mix mob.deploy --beam-flags "-S 6:6 -A 8" --ios    # untuned variant

# 2. Run the bench with --no-build, specifying the phone's WiFi IP.
mix mob.battery_bench_ios --no-build --wifi-ip 10.0.0.120

Find the phone's WiFi IP in Settings → Wi-Fi → (i) → IP Address.

See README.md for the full rationale and recovery procedure if a flag combination crashes the BEAM (which can happen if you request more threads than iOS allows per process).

Usage (with built-in Xcode build path)

mix mob.battery_bench_ios
mix mob.battery_bench_ios --no-beam
mix mob.battery_bench_ios --preset nerves
mix mob.battery_bench_ios --flags "-sbwt none -S 1:1"
mix mob.battery_bench_ios --duration 3600 --device UDID
mix mob.battery_bench_ios --no-build   # re-run without rebuilding

Options

  • --duration N — benchmark duration in seconds (default: 1800 = 30 min)
  • --device UDID — device UDID (auto-detected if one device connected)
  • --wifi-ip IP — phone's WiFi IPv4 (recommended; bypasses auto-discovery)
  • --no-beam — baseline: build without starting the BEAM at all
  • --no-keep-alive — skip the silent-audio background keep-alive call
  • --preset NAME — named BEAM flag preset (Xcode-build path only)
  • --flags "..." — arbitrary BEAM VM flags (Xcode-build path only)
  • --no-build — skip Xcode build and install; benchmark current install
  • --scheme NAME — Xcode scheme name (default: camelized app name)
  • --log-path PATH — override CSV log location (default: _build/bench/run_<ts>.csv)
  • --no-csv — skip CSV logging
  • --skip-preflight — bypass the preflight checks (USB/app/BEAM/RPC/NIF/keep-alive)

What the presets do

  • untuned — raw BEAM with no tuning flags (highest power use baseline)
  • sbwt — only busy-wait disabled (-sbwt none)
  • nerves — full Nerves set: single scheduler + busy-wait off + multi_time_warp
  • (default) — same as nerves (production default)

Understanding the results

iOS battery percentage resolution is coarse. A 30-minute run should produce 2–5% drain, enough to see the difference between no-BEAM and tuned-BEAM. Run at a fixed screen brightness or with the screen locked for reproducible results across runs.

Under the hood

mix mob.battery_bench_ios orchestrates the following commands:

# Build
xcodebuild -workspace ios/*.xcworkspace -scheme SCHEME \
  -configuration Debug -sdk iphoneos \
  -derivedDataPath /tmp/mob_bench_ios_STAMP \
  [OTHER_CFLAGS='$(inherited) -DFLAG']

# Install and launch
xcrun devicectl device install app --device UDID /path/to/App.app
xcrun devicectl device process launch --terminate-existing --device UDID \
  com.example.myapp                   # → captures PID

# Lock screen
idevicediagnostics -u UDID sleep

# Poll battery every 10s
ideviceinfo -u UDID -q com.apple.mobile.battery -k BatteryCurrentCapacity
ideviceinfo -u UDID -q com.apple.mobile.battery -k BatteryMaxCapacity

# Stop app
xcrun devicectl device process terminate --device UDID --pid PID

BEAM tuning flags are injected as OTHER_CFLAGS build settings passed to xcodebuild, matching the same C preprocessor defines used in the Android build.