Mobile Performance Profiling

Production engineering guide for mobile performance profiling covering patterns, implementation strategies, and operational best practices.

Mobile Performance Profiling is the process of measuring, analysing, and diagnosing the responsiveness, memory usage, CPU efficiency, and network behaviour of a mobile application across real devices and network conditions. It matters when users report lag, app crashes, or slow startup, and when performance metrics deviate from expected baselines—particularly during feature rollouts, app updates, or changes to backend APIs.

Identifying Performance Bottlenecks

Profile the app during real user workflows: cold startup, scrolling through a feed, loading a complex screen, and handling background tasks. Use device-level tools to capture data across both CPU and memory, and correlate events with user interactions.

Capture a Trace on Android

Use systrace from Android SDK to generate a timeline of system and app-level events.


adb shell am start -W -n com.example.app/.MainActivity
adb shell am profile start --time 30 --output /sdcard/perf-trace.trace com.example.app
sleep 30
adb shell am profile stop com.example.app
adb pull /sdcard/perf-trace.trace ./perf-trace.trace

Open the .trace file in the Chrome DevTools, where events appear as stacked bars: frame, render, input, GC, JNI, ViewRootImpl, Activity.onCreate, Activity.onResume.

Capture a Trace on iOS

Use Instruments via command line with xcrun.

# Launch app and record a trace for 30 seconds
xcrun instruments -t "Time Profiler" -D ./perf-instrumentation.trace \
  -k "com.example.app" -w "iPhone 15 Pro" \
  -e "Launch" --launch-args "com.example.app" \
  --time 30 --wait-for-app

After capture, open the .trace file in Instruments or export to .csv for analysis.

Measuring Startup Time

Startup time is a key signal of user perception. Profile startup from cold boot to first renderable frame.

Cold Startup with Android

Use adb shell am to measure time from boot to first frame.

# Boot the app and measure time to first frame
adb shell am start -S -W -n com.example.app/.MainActivity

Output includes:

Total: 2345 ms
Startup: 1823 ms
Launch: 1823 ms

Use systrace to correlate startup with ViewRootImpl, WindowManager, and View.measure().

Cold Startup with iOS

Use Xcode’s Time Profiler with Instruments to capture time from main() to didFinishLaunching.

Memory Profiling

Track memory usage over time, especially during user interactions and long-lived sessions.

Capture a Memory Snapshot on Android

Use adb shell dumpsys meminfo and adb shell am dumpheap.

# Dump heap at current state
adb shell am dumpheap com.example.app /sdcard/app.hprof
adb pull /sdcard/app.hprof ./app.hprof

# Analyze with MAT (Memory Analyzer Tool)
# Or use CLI tool `hprof-conv` from Android SDK
hprof-conv app.hprof app-conv.hprof

In the .hprof file:

Capture a Memory Snapshot on iOS

Use Instruments with Allocations and VM Tracker instruments.

# Start recording with Instruments
xcrun instruments -t "Allocations" -D ./memory.allocations.trace \
  -k "com.example.app" -w "iPhone 15 Pro" \
  --time 60 --wait-for-app

After recording:

Network Performance Profiling

Measure network requests and their impact on app responsiveness.

Capture Network Traffic with Wireshark

Use tshark to capture HTTP traffic from device to server.

# Capture all HTTP traffic on device
sudo tshark -i en0 -f "host 192.168.1.10" -Y "http" -T fields \
  -e frame.time -e http.request.method -e http.request.uri \
  -e http.response.code -e http.content_length -e tcp.analysis.ack_rtt \
  -e http.response.time -E separator=, > network.csv

Profile API Latency with curl

Use curl with --write-out to collect detailed timing metrics.

curl -v -w '
    time_namelookup: %{time_namelookup}s
    time_connect: %{time_connect}s
    time_appconnect: %{time_appconnect}s
    time_pretransfer: %{time_pretransfer}s
    time_starttransfer: %{time_starttransfer}s
    time_total: %{time_total}s
    size_download: %{size_download} bytes
    speed_download: %{speed_download} bytes/s
    ' \
    -H "Authorization: Bearer $TOKEN" \
    https://api.example.com/v1/feed \
    -o feed.json

Output includes:

time_namelookup: 0.150s
time_connect: 0.230s
time_appconnect: 0.310s
time_pretransfer: 0.420s
time_starttransfer: 0.680s
time_total: 1.250s
size_download: 143200 bytes
speed_download: 114560 bytes/s

Correlating Events Across Systems

Performance issues often span app, network, and backend. Correlate events across devices and services.

Use opentelemetry to Instrument Mobile App and Backend

Export traces using OpenTelemetry protocol.

{
  "name": "app.startup",
  "kind": "SpanKind.INTERNAL",
  "startTime": "2025-04-05T10:00:00.000Z",
  "endTime": "2025-04-05T10:00:03.500Z",
  "attributes": {
    "app.version": "2.3.1",
    "device.model": "iPhone 15 Pro",
    "network.type": "wifi",
    "memory.total": 4096,
    "memory.free": 2048
  },
  "events": [
    {
      "name": "frame.rendered",
      "timestamp": "2025-04-05T10:00:01.200Z",
      "attributes": {
        "frame.time": 15.4,
        "frame.dropped": true
      }
    }
  ]
}

Send to backend via curl:

curl -X POST -H "Content-Type: application/json" \
  -d @./traces.json \
  https://collector.example.com/v1/traces

Diagnosing Common Failure Modes

App Freezes on Main Thread

High Memory Usage Over Time

Slow API Response Times

Iterative Profiling Workflow

  1. Capture: Use systrace or Instruments for full timeline.
  2. Measure: Use adb am start -S, curl, tshark.
  3. Analyze: Compare memory, CPU, and network metrics.
  4. Diagnose: Correlate events across systems using shared timestamps.
  5. Iterate: Apply fixes, re-profile, and validate.

This workflow ensures that every performance issue is not just observed, but rooted in measurable data across device, app, and network layers.

This page was rewritten on 18 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.