$npx -y skills add dpearson2699/swift-ios-skills --skill ios-ettrace-performanceUse when capturing or analyzing ETTrace profiles for a focused iOS launch or runtime flow, including exact-build dSYM UUID matching, Simulator or device capture, processed per-thread flamegraph JSON, sampled inclusive/exclusive time, unresolved symbols, and comparable verificatio
| 1 | # iOS ETTrace Performance |
| 2 | |
| 3 | Use ETTrace for a bounded, symbolicated sampling experiment. Treat capture |
| 4 | conditions and symbolication as part of the evidence, not as setup trivia. |
| 5 | |
| 6 | ## Contents |
| 7 | |
| 8 | - [Boundary](#boundary) |
| 9 | - [Capture Contract](#capture-contract) |
| 10 | - [Workflow](#workflow) |
| 11 | - [Interpret the Report](#interpret-the-report) |
| 12 | - [Common Mistakes](#common-mistakes) |
| 13 | - [Review Checklist](#review-checklist) |
| 14 | - [References](#references) |
| 15 | |
| 16 | ## Boundary |
| 17 | |
| 18 | This skill owns ETTrace framework/CLI capture, exact-build dSYMs, processed |
| 19 | flamegraph JSON, and like-for-like verification. Use Instruments for broad CPU, |
| 20 | hitch, energy, or concurrency triage. Use SwiftUI performance guidance for view |
| 21 | identity, invalidation, and layout remediation. |
| 22 | |
| 23 | ETTrace periodically samples thread stacks. Its durations reconstruct sampled |
| 24 | attribution from those intervals; do not present them as wall-clock production |
| 25 | timings or compare them directly with a differently configured profiler. |
| 26 | |
| 27 | ## Capture Contract |
| 28 | |
| 29 | Write these down before capturing: |
| 30 | |
| 31 | - one exact user flow and its start/stop boundary; |
| 32 | - launch capture or already-running runtime capture; |
| 33 | - app commit, build configuration, optimization settings, and architecture; |
| 34 | - ETTrace runner and framework versions, plus single-thread or multi-thread mode; |
| 35 | - simulator/device model and OS build; |
| 36 | - launch method, data state, cache state, and repetition count. |
| 37 | |
| 38 | Reject a before/after claim when any of these materially differ. Rebuild and |
| 39 | repeat under one contract instead. |
| 40 | |
| 41 | ## Workflow |
| 42 | |
| 43 | ### 1. Triage before instrumenting |
| 44 | |
| 45 | Confirm that ETTrace's sampled flamechart is the right next tool. Prefer |
| 46 | Instruments first when the slow interval is unknown, spans many subsystems, or |
| 47 | needs system-level blocking, I/O, hitch, or concurrency context. |
| 48 | |
| 49 | Choose one flow small enough to repeat. Launch, first screen construction, |
| 50 | opening one document, or applying one edit are useful boundaries; "use the app" |
| 51 | is not. |
| 52 | |
| 53 | ### 2. Record and hold ETTrace versions fixed |
| 54 | |
| 55 | Install the runner from the official tap and link the ETTrace package product |
| 56 | into the app target being measured. Record the runner version and the framework |
| 57 | revision or tag separately, then keep both fixed across compared captures. The |
| 58 | bundled analyzer supports the verified v1.1.1 processed output shape; re-check |
| 59 | upstream and the parser before using a different format. |
| 60 | |
| 61 | ```bash |
| 62 | brew install emergetools/homebrew-tap/ettrace |
| 63 | ``` |
| 64 | |
| 65 | Run the instrumented app once and confirm the `Starting ETTrace` log. Absence of |
| 66 | that message means capture evidence is not trustworthy. Keep this wiring out of |
| 67 | shipping configurations unless the project deliberately owns that tradeoff. |
| 68 | |
| 69 | ### 3. Build first, then collect matching dSYMs |
| 70 | |
| 71 | Use the final instrumented build for both capture and dSYM collection. Never |
| 72 | choose a dSYM by filename, modification time, or Derived Data proximity. |
| 73 | |
| 74 | ```bash |
| 75 | mkdir -p /tmp/myapp-ettrace |
| 76 | python3 scripts/collect_dsyms.py \ |
| 77 | --app /path/to/Build/Products/Release-iphonesimulator/MyApp.app \ |
| 78 | --search-root /path/to/Build/Products \ |
| 79 | --search-root /path/to/Archives \ |
| 80 | --output /tmp/myapp-ettrace/dsyms \ |
| 81 | --pretty > /tmp/myapp-ettrace/dsym-report.json |
| 82 | ``` |
| 83 | |
| 84 | The helper compares `dwarfdump --uuid` output for the app executable and |
| 85 | embedded binaries. Missing or ambiguous UUID matches stop the run by default. |
| 86 | Read and preserve `dsym-report.json` rather than assuming every copied symbol |
| 87 | file is relevant. The helper fails when UUID matches cannot be copied to unique |
| 88 | flat destination names that ETTrace 1.1.1 can discover. |
| 89 | |
| 90 | ### 4. Capture from a clean artifact directory |
| 91 | |
| 92 | Run ETTrace from an empty directory because processed files are written to the |
| 93 | current working directory. Use `--simulator` for Simulator and `--dsyms` for the |
| 94 | exact dSYM directory. Add `--launch` only for launch work, and follow the |
| 95 | runner's two-launch prompts exactly. |
| 96 | |
| 97 | ```bash |
| 98 | mkdir -p /tmp/myapp-ettrace |
| 99 | mkdir /tmp/myapp-ettrace/run-01 |
| 100 | cd /tmp/myapp-ettrace/run-01 |
| 101 | ettrace --simulator --dsyms /tmp/myapp-ettrace/dsyms |
| 102 | ``` |
| 103 | |
| 104 | The second `mkdir` must fail if that per-run directory already exists. Choose a |
| 105 | new run name instead of mixing processed captures from retries. |
| 106 | |
| 107 | Launch by tapping the app on the Home Screen when the runner asks. Launching |
| 108 | from Xcode can change the launch path and timing. For device capture, omit |
| 109 | `--simulator`; keep all other experiment fields stable. |
| 110 | |
| 111 | Stop immediately after the bounded flow and preserve every fresh |
| 112 | `output_<threadId>.json` with the capture contract. ETTrace 1.1.1 creates these |
| 113 | processed files after symbolication. Its internal raw runner `output.json` is a |
| 114 | differ |