How do you approach a performance problem, and which kinds of problem are there?
Predict first
You tune a screen and it “feels faster”. What is the correct next step?
// A: ship it, the feel is the metric
// B: re-run the same scenario and the same metric you started with, and compare
// C: profile again after changing three more things
- A
- B
- C
Mental model. A doctor does not operate because you say “it hurts”. They take a measurement, find the cause, treat one thing, and check the measurement again.
Work in a loop and do not skip steps: 1) reproduce the problem on a stable scenario (a script, a UI test, a fixed data set), 2) pick one metric that defines “slow” (launch to first frame, p95 scroll hitch rate, peak memory, bytes written, battery percent per hour), 3) profile to find where the time or resource goes instead of guessing, 4) change one thing, and 5) measure again under the same conditions. If the number did not move, the change was not the cause, whatever your instinct said. Keep the baseline so a later regression is visible, and stop when you hit the target, because every optimisation adds code that someone must maintain.
It also helps to know which kind of problem you have, because each kind has its own metric and its own tool. A launch problem is time to first usable frame. A hang is a blocked main thread (the app ignores input); a hitch is a missed frame deadline while scrolling or animating, and Q287 explains the difference. A memory problem is footprint and peak, which ends in a jetsam kill rather than a slow screen (Q162). Disk is bytes written and I/O wait, battery is energy over time, and binary size is the download and install cost. Start from the symptom the user sees, map it to the metric, then open the matching instrument.
A change is only an improvement if the agreed number moved under the same conditions; feeling is not evidence.
| Typical metric | First tool | |
|---|---|---|
| Launch | time to first usable frame, p50 and p90 | App Launch instrument, MetricKit launch histograms |
| Hang | main-thread blockage over about 250 ms | Hangs instrument, Time Profiler |
| Hitch | hitch time ratio while scrolling | Animation Hitches instrument |
| Memory | peak and steady footprint, jetsam kills | Allocations, VM Tracker, memory graph |
| Disk | bytes written per day, I/O wait | File Activity, MetricKit disk-write diagnostics |
| Battery | energy per hour of use | Power Profiler, Energy gauge, Organizer |
| Binary size | download and install size | App Thinning size report, link map |
Common traps
- Optimising on a hunch. Most of the time is in a place nobody guessed; profile first.
- Changing several things at once. You cannot tell which one helped, or which one hurt.
They might follow up with
- When do you stop? When the metric meets the target, or the next gain costs more complexity than it is worth.
- What do you do if the profile shows nothing obvious? Look at a different dimension (wall time versus CPU time, main thread versus others, I/O or waiting) before deciding the app is “just slow”.
Related questions
- 21.1.2 How do you measure performance reliably: what makes numbers lie, and why do percentiles beat averages?
- 21.2.1 Which Instruments templates do you reach for, how do you read a Time Profiler trace, and where can a sampling…
- 9.7.1 What is a hitch versus a hang, how does ProMotion change the budget, and how do you measure and fix them?
- 3.7.5 What is memory footprint, and what gets an iOS app killed?
- 6.4.3 Your app launches slowly. How do you find out why and what do you cut?
How do you measure performance reliably: what makes numbers lie, and… →