| I don’t know what’s wrong yet.Freezes & stalls | Time Profiler | It is the stated first step; it orients you before you commit to a specialized tool. Not this — Not System Trace, which buries you in kernel detail before you know where to look. WWDC26 268@1:53exact time |
|---|
| The app froze for a moment during a tap or button press.Freezes & stalls | Hangs instrument | Hangs are about discrete interactions and the 250 ms responsiveness threshold. Not this — Not the Hitches instrument, which is for continuous motion. WWDC22 10082@1:35exact time |
|---|
| It hangs and the main thread is near 100% CPU.Freezes & stalls | Time Profiler call tree → Top Functions | This is a code bottleneck; either optimize the algorithm or offload the work. Not this — Not System Trace: nothing is blocked. WWDC26 268@2:05exact timeWWDC26 268@2:18exact time |
|---|
| It hangs and the main thread is near 0% CPU.Freezes & stalls | System Trace (Thread States + Narrative) | The thread is off-CPU waiting on I/O, a lock, or IPC. Not this — Not Time Profiler, whose call tree will be nearly empty and tell you nothing — it is structurally blind to off-CPU time. WWDC26 268@2:33exact timeWWDC26 268@2:54exact time |
|---|
It hangs, main thread is ~100% CPU, and the codebase is async.Freezes & stalls | Swift Concurrency / Swift executors | This is actor congestion from inherited isolation, and the fix is relocating the work, not making it faster. Not this — Not plain Time Profiler, which shows the busy stacks but not why they are on the main actor. WWDC26 268@25:51exact timeWWDC23 10248@32:28exact time |
|---|
| Which thread is holding my main thread up?Freezes & stalls | System Trace → “made runnable by” | It names the thread that released the lock. Not this — Not the Hangs instrument, which tells you that you hung, not who caused it. WWDC16 411@17:01exact time |
|---|
| I suspect a priority inversion or non-UI work on the main thread.Freezes & stalls | Thread Performance Checker | It finds both without any tracing at all, so it costs nothing to leave on. Not this — Not Instruments, which is the heavier follow-up once it flags something. WWDC22 10082@4:49exact time |
|---|
| It’s fine at my desk but users complain.Freezes & stalls | On-device hang detection (iOS) | Settings › Developer on a TestFlight build, under real network conditions. Not this — Not a desk repro — the desk environment structurally cannot reproduce it. WWDC22 10082@11:33exact time |
|---|
| Scrolling stutters but the app never freezes.Stutter & scrolling | Animation Hitches template / Hitches instrument | A missed frame deadline in the render loop, not an unresponsive main thread. Not this — Not the Hangs instrument — the deciding question is continuous motion versus discrete interaction. Tech Talks 10855@1:33exact time |
|---|
| Scrolling stutters and no individual view body is slow.Stutter & scrolling | Lazy-stack structure review | The cost is subview resolution, retention and prefetch loss. Not this — Not the Long View Body Updates lane — none of those costs appears as a long body. WWDC26 321@10:34exact time |
|---|
| My main thread looks fine and it still stutters.Stutter & scrolling | Render-phase analysis (layer tree, view debugger) | A render hitch happens in the render server, on your layer tree, in another process entirely. Not this — Not a main-thread call tree — it will look innocent. Tech Talks 10855@3:57exact timeTech Talks 10857@6:43exact time |
|---|
| Cells resize mid-list and scrolling degrades.Stutter & scrolling | Constant cell sizes | When something mid-list resizes, everything below moves, forcing recalculation of what is on screen and defeating SwiftUI’s caching. Not this — Not a profiler finding — this is structural, and the panel answered it as such. WWDC26 8003@39:13exact timeWWDC26 8003@39:37exact time |
|---|
| Which code burns the most CPU? (throughput, not responsiveness)CPU & throughput | CPU Profiler | It samples per-CPU by clock frequency and avoids Time Profiler’s aliasing and its bias against faster-running cores. Not this — Not Time Profiler — Apple explicitly prefers CPU Profiler for CPU optimization since WWDC25. WWDC25 308@10:12exact time |
|---|
| How work is distributed over time / which threads are active at once.CPU & throughput | Time Profiler | This is Time Profiler’s stated remaining strength. Not this — Not CPU Profiler, which is the better choice for “which code burns CPU” but not for this question. WWDC25 308@9:31exact time |
|---|
| Sampling isn’t resolving it; I need every call.CPU & throughput | Processor Trace | A complete user-space instruction trace at ~1% overhead, including compiler-generated ARC and C++ code. M4 / A18-class hardware, a few seconds. Not this — Not CPU Profiler, which estimates from samples. WWDC25 308@14:09exact time |
|---|
| My hot loop is as tight as I can make it — what is the CPU stalling on?CPU & throughput | CPU Counters with preset modes | It converts hardware counters into bottleneck percentages. Not this — Not Processor Trace, which shows what ran, not which microarchitectural resource stalled. WWDC25 308@22:35exact time |
|---|
| No single function is hot but it’s still slow.CPU & throughput | Top Functions view | It surfaces diffuse cost summed across many code paths. Not this — Not a call tree or flame graph, which hide exactly this shape. WWDC26 268@11:10exact time |
|---|
| How long does this specific function take?CPU & throughput | os_signpost / OSSignposter interval | Time Profiler gives sample counts, which cannot distinguish one slow call from many fast ones. Not this — Not the call tree’s weight column — it is a statistical estimate, not a stopwatch. WWDC23 10248@16:50exact time |
|---|
| My call tree is all system frames or unreadable names.CPU & throughput | Symbolication and debug info | A missing dSYM makes every other tool in this list useless. Not this — Not a tooling bug — fix the debug information first. WWDC21 10211@0:34exact time |
|---|
| CPU is high while the UI is idle.SwiftUI updates | SwiftUI instrument → Update Groups lane | It tells you in one glance whether SwiftUI is even involved. Not this — If the lane is empty it is not a SwiftUI problem — go to Time Profiler or Hangs/Hitches instead. WWDC25 306@3:00exact time |
|---|
| This view redraws constantly and I don’t know which input causes it.SwiftUI updates | Cause & Effect graph | It attributes the update to a gesture, state write or environment change. Not this — Prefer it over _printChanges when you do not yet know which view to suspect; a raw backtrace is useless here because the frames are system frames. WWDC25 306@25:14exact timeWWDC25 306@20:15exact time |
|---|
| I know which view, I just want the reason, now.SwiftUI updates | Self._printChanges() | Inline and instant, no trace — and it can be invoked from LLDB without editing the file. Not this — Prefer it over the instrument when you already have a hypothesis and a fast reproduction. WWDC23 10160@7:46exact time |
|---|
| Is this view re-evaluating at all?SwiftUI updates | Random background or border colour | No API, no tooling, visible at a glance during resize or scroll — the SwiftUI team’s own habit. Not this — Not an instrument run: this answers where and how often, not how expensive. WWDC26 8006@30:18exact time |
|---|
| A formatter, date or number call might be the cost.SwiftUI updates | SwiftUI instrument → Set Inspection Range and Zoom → Time Profiler | The handoff is the point — the SwiftUI instrument alone does not show you the function. Not this — Not the SwiftUI lanes by themselves, which stop at “this body was long”. WWDC25 306@7:19exact timeWWDC25 306@8:05exact time |
|---|
| Too many layers are compositing and the screen is heavy.SwiftUI updates | drawingGroup() | It flattens the rendered layers onto one, and can help even when the same number of SwiftUI views update. Not this — Not compositingGroup(), which is about applying an effect to a combined result, not performance. WWDC26 8006@57:29exact timeWWDC26 8006@56:26exact time |
|---|
| Launch feels slow.Launch | Instruments App Launch template | The only tool that attributes time to launch phases and shows thread state, which is what exposes blocking. Not this — Not Time Profiler alone — it will not show the main thread waiting. DocsReducing your app's launch timedoc |
|---|
I suspect pre-main() cost from static initializers.Launch | dyld Activity instrument | It specifically measures time spent running static initializers — a direct measurement rather than inference from phase durations. Not this — Not the launch-phase breakdown, which tells you dyld was slow but not which initializer. DocsReducing your app's launch timedoc |
|---|
| Launch regressed and I don’t know when.Launch | XCTest launch test with a baseline | The free UI-test launch measurement fails the build on regression. Not this — Not the Organizer, which only tells you after you ship. WWDC19 417@14:18exact time |
|---|
| Memory climbs and never comes back down (stair-step).Memory | Allocations + Mark Generation, then the Memory Graph Debugger | Generations isolate which interval grew; the graph answers why it is still alive. Not this — Not Leaks — it will not find it if the memory is reachable. WWDC24 10173@14:01exact timeWWDC24 10173@18:04exact time |
|---|
| Memory spikes and recovers (sawtooth).Memory | Allocations, Lifespan = Created & Destroyed, call-tree view | You want the churn’s backtrace, not a snapshot. Not this — Not a memory graph taken after the spike — it shows nothing, because the memory is already gone. WWDC24 10173@9:06exact time |
|---|
| Huge transient spike inside a loop, autorelease-pool content visible.Memory | Nested autoreleasepool in the loop body | The fix is scope, not allocation count. Not this — Not an algorithmic change — the allocations are fine, their lifetime is not. WWDC24 10173@11:58exact time |
|---|
| Is this object leaked or just retained?Memory | Memory Graph Debugger leak filter, then reachability reasoning | Leaked means unreachable; abandoned means reachable-but-useless. Not this — Not a tool at all for the second case — abandoned memory needs human judgement. WWDC24 10173@20:26exact time |
|---|
| Leak count fluctuates run to run.Memory | Do not chase it | It is conservative-reference noise — the tool is telling you about its own uncertainty, not about your code. Not this — Not a real regression signal; a program leaking five objects may legitimately report five, then four. WWDC24 10173@25:15exact time |
|---|
Crash from EXC_RESOURCE.Memory | Xcode pauses the app — open the Memory Graph Debugger immediately, then vmmap --summary | You want the footprint breakdown at the moment of death. Not this — Not a fresh run, which will not be in the same state. WWDC18 416@10:11exact time |
|---|
| Regression between two builds, with a memgraph from each.Memory | heap -diffFrom | It is the only tool that answers “what is in B that was not in A” directly. Not this — Not vmmap, which sizes regions but does not diff object types. WWDC21 10180@16:35exact time |
|---|
| Where is the memory, if not the heap?Memory | vmmap --summary on a memgraph, then VM Tracker | vmmap names the VM region (CG image, IOSurface, mapped file).
Not this — Not Allocations, which only sees the heap plus anonymous VM. WWDC18 416@17:30exact time |
|---|
| Footprint high but heap small.Memory | VM Tracker / footprint | Allocations do not equal footprint — this is the explicit reason VM Tracker exists. Not this — Not Allocations totals, which answer “what churned”, not “what am I charged for”. WWDC22 10106@13:19exact time |
|---|
| Footprint high, heap total looks fine, long-running process.Memory | vmmap --summary, bottom per-zone table, % FRAG | Fragmentation is a footprint multiplier invisible to every other view. Not this — Not a leak hunt — nothing is leaked, the pages are just badly packed. WWDC21 10180@24:34exact time |
|---|
| Memory grows on a Mac or Simulator process with no Xcode session.Memory | leaks attached directly | It is the one CLI path that does not need a captured graph. Not this — Not the Memory Graph Debugger, which needs an Xcode debug session. WWDC24 10173@4:43exact time |
|---|
| Image-heavy screen uses far more memory than the file sizes suggest.Memory | Arithmetic, then ImageIO downsampling | Image memory tracks dimensions, not file size: width × height × bytes-per-pixel. Not this — Not a tool — the gauge will confirm it, but the diagnosis is dimensional. WWDC18 416@17:51exact timeWWDC18 416@22:35exact time |
|---|
| Xcode shows high energy impact but I don’t know which subsystem.Battery & thermal | Power Profiler | Its whole purpose is to rank CPU / GPU / display / networking impact so you know where to aim. Not this — Not the Energy Gauge, which flags “high” without localising it. WWDC25 226@1:54exact time |
|---|
| Battery complaint I cannot reproduce at my desk.Battery & thermal | On-device Performance Trace in Power Profiler mode | A tethered session cannot see commuting, CarPlay, outdoors or hours-long background behaviour — and tethering also zeroes the system power lane. Not this — Not borrowing the device: have the colleague capture and share the trace file. WWDC25 226@10:31exact time |
|---|
| Power Profiler points at CPU.Battery & thermal | Hand off to CPU Profiler / Time Profiler | Power is the prioritiser; the profiler is the locator. Not this — Not more power profiling — you already know the subsystem. DocsMeasuring your app's power use with Po… § Make changes to reduce power usagedoc |
|---|
| Power Profiler points at networking.Battery & thermal | HTTP Traffic + Network Connections | This pairing is documented; reduce connection frequency or bytes. Not this — Not a CPU profile — the cost is radio time, not compute. DocsMeasuring your app's power use with Po… § Make changes to reduce power usagedoc |
|---|
| Power Profiler points at display.Battery & thermal | Reduce average pixel luminance / support dark appearance | On OLED this is a direct, measurable lever. Not this — Not a code optimisation — the cost is the pixels you are lighting. WWDC19 417@7:31exact time |
|---|
| Choosing between two implementations.Battery & thermal | Multiple Power Profiler runs of each, averaged | A single comparison is dominated by thermal and device state. Not this — Not one run each — Apple explicitly recommends averaging across varying conditions. WWDC25 226@17:44exact time |
|---|
| Is my idle app really idle?Battery & thermal | Energy Gauge in the Debug navigator | The >20%-CPU and should-be-near-zero-when-idle heuristics are the cheapest check available. Not this — Not Instruments — this needs no trace, no baseline and no instrumentation. WWDC21 10181@4:30exact time |
|---|
| Battery reported high, but the foreground screen looks innocent.Battery & thermal | Power Profiler, untethered | SwiftUI and UIKit compute should show up as foreground energy, so background drain points at scheduled background tasks or location use. Not this — Not the visible screen — reading the gauge as a verdict on it is the specific mistake. WWDC26 8003@18:37exact timeWWDC26 8003@18:43exact time |
|---|
| App degrades outdoors or in sunlight.Battery & thermal | Thermal-state notifications + Xcode device conditions | You cannot reliably test thermal defences by warming a device; condition inducers make the device report the state safely. Not this — Not a dummy CPU load — the session names that as the bad practice this replaces. WWDC19 422@24:30exact timeWWDC19 422@24:52exact time |
|---|
| Screen loads slowly, many requests.Network | HTTP Traffic, HTTP Transactions by Connection view | The staircase of blocked states is only visible grouped by connection. Not this — Not the Tasks view, which hides head-of-line blocking. WWDC21 10212@12:18exact time |
|---|
| A request appears not to reach the server.Network | HTTP Transactions by Connection — look for Local Cache | A missing “waiting for response” state means no server was involved. Not this — Not a packet capture, which cannot see a cache hit at all. WWDC21 10212@23:56exact timeWWDC21 10212@24:51exact time |
|---|
| Auth works once then re-prompts.Network | Interval labels (cookie icon) + transaction extended detail | The icons narrow it in seconds; the header view proves it — often a server-side expiry, not your networking code. Not this — Not your client code first — absence of the cookie icon means the client correctly declined to send. WWDC21 10212@20:33exact time |
|---|
| What is this third-party SDK actually sending?Network | HTTP Traffic, sessions grouped by process; read bodies and resume backtraces | This is the audit case the instrument was built for — the trace itself becomes the bug report. Not this — Not a packet capture, which cannot attribute traffic to a process or show you the resume backtrace. WWDC21 10212@29:28exact time |
|---|
| I need to hand networking evidence to someone without Instruments.Network | xctrace export to HAR | Portable and scriptable. Not this — At the cost of URLSession structure and backtraces, which HAR does not carry. WWDC21 10212@31:55exact timeWWDC21 10212@32:42exact time |
|---|
| I need to test behaviour on a bad network.Network | Xcode device conditions or Network Link Conditioner | Remembering it is a ceiling, it is system-wide, and the status bar will not reflect it. Not this — Not a real bad network you cannot reproduce on demand. WWDC19 422@13:05exact timeWWDC19 422@13:28exact time |
|---|
| I suspect excessive writes.Disk | File Activity template, suggestions track first | It is the only tool that names known anti-patterns instead of making you count syscalls. Not this — Not counting syscalls by hand — and remember zero suggestions is not zero I/O. WWDC19 419@28:04exact timeWWDC19 419@32:32exact time |
|---|
| Did that write actually hit the device?Disk | Compare file system activity (logical) with disk usage (physical) | The logical/physical gap is the signal. Not this — Not either track alone — both are misleading in isolation. WWDC19 419@33:16exact time |
|---|
| Shipped app is writing too much.Disk | Organizer disk-writes reports → top signatures → insights, then validate with File Activity | The field tells you what and how much; the instrument tells you whether your fix worked. Not this — Not File Activity alone, which cannot see your users; and no report may just mean you did not cross 1 GB / 24 h. WWDC21 10087@8:50exact timeWWDC21 10087@11:13exact timeWWDC21 10181@14:50exact time |
|---|
Deciding between fsync, F_FULLFSYNC and F_BARRIERFSYNC.Disk | Decide from the requirement, not the tool | Durability versus ordering. If ordering, use F_BARRIERFSYNC. Not this — Not F_FULLFSYNC for ordering — it flushes the whole disk cache, punishing the system. WWDC19 419@13:17exact timeWWDC19 419@12:09exact time |
|---|
| Storing small, frequently-changing state in a plist.Disk | Stop; use Core Data or SQLite with WAL | Whole-file replacement plus an fsync per write is the documented anti-pattern. Not this — Not “it’s only one write” — the demo measured 12 I/O operations for roughly four lines of code. WWDC19 419@14:02exact timeWWDC19 419@14:23exact time |
|---|
| I want to prevent disk regressions in CI.Disk | XCTStorageMetric with a baseline | The only disk-specific gating mechanism named in this material. Not this — Not a manual re-trace each release. WWDC21 10181@14:01exact time |
|---|
| Is my shipped version worse than the last one?Field & regressions | Xcode Organizer Insights | The only source of real-user, real-device, version-over-version data. Not this — Not a local trace, which cannot see your users. WWDC21 10181@6:33exact time |
|---|
| Organizer says there’s a hang but not where.Field & regressions | MetricKit diagnostics (or Organizer’s Generate Recommendations) | Diagnostics carry call-stack trees. Not this — Not metrics, which never identify a code path. WWDC20 10081@2:11exact timeWWDC26 258@20:32exact time |
|---|
| I need field data segmented by what the user was doing.Field & regressions | MetricKit + StateReporting | The Organizer cannot segment by your app’s own states. Not this — Not an Organizer metric filter, which segments by device and OS, not by your flows. WWDC26 8003@22:47exact timeWWDC26 222@10:03exact time |
|---|
| I need to stop this regressing again.Field & regressions | XCTest performance test with a baseline, or Thread Performance Checker set to fail tests | The only two gates in this material. Not this — Not a dashboard you have to remember to check. WWDC19 417@15:49exact timeDocsDiagnosing performance issues earlydoc |
|---|
| Something feels slow but I have no hypothesis yet.Method & proof | Xcode debug gauges | Zero setup, running already; use the idle-should-be-near-zero test. Not this — Not the Organizer, which only reflects shipped versions, and not Instruments yet, which needs a hypothesis. WWDC21 10181@4:50exact time |
|---|
| Which of my app’s operations was running when things went bad?Method & proof | Points of Interest track | Signpost with the points-of-interest category — the category is what auto-surfaces your data. Not this — Not the system tracks: the Points of Interest track is empty until you instrument it. WWDC26 268@6:09exact timeWWDC16 411@3:37exact time |
|---|
| I need to prove my fix actually helped.Method & proof | Run Comparisons, filtered to the same signpost interval in both runs | Red/green per-function deltas instead of eyeballing two traces. New at WWDC26. Not this — Not two traces side by side, and not two unfiltered runs — the comparison needs identical intervals to be honest. WWDC26 268@13:30exact timeWWDC26 268@14:08exact time |
|---|
| I want to profile exactly one workload with nothing else in the trace.Method & proof | Launch from the test navigator’s per-test Profile item | The recording then contains your workload and almost nothing else. Not this — Not a full app launch followed by manual navigation, which fills the trace with noise. WWDC25 308@10:51exact time |