Skip to main content
ClaudeWave
Skill1.1k repo starsupdated 1mo ago

ios-ettrace-performance

Use 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 verification. Use debugging-instruments or swiftui-performance for generic profiling instead.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/dpearson2699/swift-ios-skills /tmp/ios-ettrace-performance && cp -r /tmp/ios-ettrace-performance/skills/ios-ettrace-performance ~/.claude/skills/ios-ettrace-performance
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# iOS ETTrace Performance

Use ETTrace for a bounded, symbolicated sampling experiment. Treat capture
conditions and symbolication as part of the evidence, not as setup trivia.

## Contents

- [Boundary](#boundary)
- [Capture Contract](#capture-contract)
- [Workflow](#workflow)
- [Interpret the Report](#interpret-the-report)
- [Common Mistakes](#common-mistakes)
- [Review Checklist](#review-checklist)
- [References](#references)

## Boundary

This skill owns ETTrace framework/CLI capture, exact-build dSYMs, processed
flamegraph JSON, and like-for-like verification. Use Instruments for broad CPU,
hitch, energy, or concurrency triage. Use SwiftUI performance guidance for view
identity, invalidation, and layout remediation.

ETTrace periodically samples thread stacks. Its durations reconstruct sampled
attribution from those intervals; do not present them as wall-clock production
timings or compare them directly with a differently configured profiler.

## Capture Contract

Write these down before capturing:

- one exact user flow and its start/stop boundary;
- launch capture or already-running runtime capture;
- app commit, build configuration, optimization settings, and architecture;
- ETTrace runner and framework versions, plus single-thread or multi-thread mode;
- simulator/device model and OS build;
- launch method, data state, cache state, and repetition count.

Reject a before/after claim when any of these materially differ. Rebuild and
repeat under one contract instead.

## Workflow

### 1. Triage before instrumenting

Confirm that ETTrace's sampled flamechart is the right next tool. Prefer
Instruments first when the slow interval is unknown, spans many subsystems, or
needs system-level blocking, I/O, hitch, or concurrency context.

Choose one flow small enough to repeat. Launch, first screen construction,
opening one document, or applying one edit are useful boundaries; "use the app"
is not.

### 2. Record and hold ETTrace versions fixed

Install the runner from the official tap and link the ETTrace package product
into the app target being measured. Record the runner version and the framework
revision or tag separately, then keep both fixed across compared captures. The
bundled analyzer supports the verified v1.1.1 processed output shape; re-check
upstream and the parser before using a different format.

```bash
brew install emergetools/homebrew-tap/ettrace
```

Run the instrumented app once and confirm the `Starting ETTrace` log. Absence of
that message means capture evidence is not trustworthy. Keep this wiring out of
shipping configurations unless the project deliberately owns that tradeoff.

### 3. Build first, then collect matching dSYMs

Use the final instrumented build for both capture and dSYM collection. Never
choose a dSYM by filename, modification time, or Derived Data proximity.

```bash
mkdir -p /tmp/myapp-ettrace
python3 scripts/collect_dsyms.py \
  --app /path/to/Build/Products/Release-iphonesimulator/MyApp.app \
  --search-root /path/to/Build/Products \
  --search-root /path/to/Archives \
  --output /tmp/myapp-ettrace/dsyms \
  --pretty > /tmp/myapp-ettrace/dsym-report.json
```

The helper compares `dwarfdump --uuid` output for the app executable and
embedded binaries. Missing or ambiguous UUID matches stop the run by default.
Read and preserve `dsym-report.json` rather than assuming every copied symbol
file is relevant. The helper fails when UUID matches cannot be copied to unique
flat destination names that ETTrace 1.1.1 can discover.

### 4. Capture from a clean artifact directory

Run ETTrace from an empty directory because processed files are written to the
current working directory. Use `--simulator` for Simulator and `--dsyms` for the
exact dSYM directory. Add `--launch` only for launch work, and follow the
runner's two-launch prompts exactly.

```bash
mkdir -p /tmp/myapp-ettrace
mkdir /tmp/myapp-ettrace/run-01
cd /tmp/myapp-ettrace/run-01
ettrace --simulator --dsyms /tmp/myapp-ettrace/dsyms
```

The second `mkdir` must fail if that per-run directory already exists. Choose a
new run name instead of mixing processed captures from retries.

Launch by tapping the app on the Home Screen when the runner asks. Launching
from Xcode can change the launch path and timing. For device capture, omit
`--simulator`; keep all other experiment fields stable.

Stop immediately after the bounded flow and preserve every fresh
`output_<threadId>.json` with the capture contract. ETTrace 1.1.1 creates these
processed files after symbolication. Its internal raw runner `output.json` is a
different artifact and is not accepted by the analyzer below.

### 5. Validate and summarize processed output

```bash
python3 scripts/analyze_ettrace.py \
  /tmp/myapp-ettrace/run-01/output_*.json \
  --top 25 --pretty > /tmp/myapp-ettrace/run-01/summary.json
```

The helper validates the v1.1.1 processed node shape, rejects duplicate inputs
or mixed `osBuild`/`device`/`isSimulator` metadata, handles the serializer's
object-or-array `children` field, and emits deterministic JSON. It does not
rewrite the capture files. Keep those originals beside the summary.

Stop and repair symbolication when important app frames are `<unknown>`, raw
addresses, or attributed to the wrong binary. An unsymbolicated hot address is
an evidence gap, not a code recommendation. ETTrace 1.1.1 address-bearing nodes
are listed under `unresolved_frames` and excluded from ordinary hotspots.

### 6. Change one cause and repeat

Make the smallest code or configuration change supported by a hot app-owned
path. Rebuild, recollect UUID-matched dSYMs, and capture the same flow at least
twice. Report variance and the full capture contract with the result.

## Interpret the Report

- **Exclusive seconds** approximate sampled time charged directly to a symbol
  after subtracting direct child durations. Start with high exclusive app-owned
  work.
- **Inclusive seconds** show the weight of an entire call subtree. Use them to
  find expe
accessorysetupkitSkill

Discover and configure Bluetooth and Wi-Fi accessories using AccessorySetupKit. Use when presenting a privacy-preserving accessory picker, defining discovery descriptors for BLE or Wi-Fi devices, handling accessory session events, migrating from CoreBluetooth permission-based scanning, or setting up accessories without requiring broad Bluetooth permissions.

activitykitSkill

Implement, review, or improve Live Activities and Dynamic Island experiences in iOS apps using ActivityKit. Use when building real-time updating widgets for the Lock Screen and Dynamic Island — delivery tracking, sports scores, ride-sharing status, workout timers, media playback, or any time-sensitive information that updates in real time. Also use when working with ActivityKit, ActivityAttributes, Activity lifecycle (request/update/end), Dynamic Island layouts (compact/minimal/expanded), push-to-update Live Activities, or Lock Screen live widgets.

adattributionkitSkill

Measure ad effectiveness with privacy-preserving attribution using AdAttributionKit. Use when registering ad impressions, handling attribution postbacks, updating conversion values, implementing re-engagement attribution, configuring publisher or advertiser apps, or replacing SKAdNetwork with AdAttributionKit for ad measurement.

alarmkitSkill

Implement AlarmKit alarms and countdown timers for iOS and iPadOS with Lock Screen, Dynamic Island, StandBy, and paired Apple Watch system UI. Covers AlarmManager scheduling, AlarmAttributes and AlarmPresentation, system Stop and AlarmButton secondary actions, authorization, state observation, countdown widget-extension handoff, and Live Activity integration. Use when building wake-up alarms, countdown timers, or alarm-style alerts that need Apple's system alarm experience.

app-clipsSkill

Build iOS App Clips with invocation URLs, App Clip Codes, NFC, QR codes, Safari banners, Maps, Messages, target setup, App Store Connect experiences, size/capability constraints, NSUserActivity routing, SKOverlay promotion, App Group/keychain handoff, ephemeral notifications, location confirmation, and full-app migration. Use when creating App Clips or wiring App Clip invocation, experience configuration, or full-app handoff.

app-intentsSkill

Implement App Intents for Siri, Shortcuts, Spotlight, widgets, Control Center, and Apple Intelligence on iOS. Covers AppIntent actions, AppEntity and EntityQuery models, AppShortcutsProvider phrases, IndexedEntity Spotlight indexing, WidgetConfigurationIntent, SnippetIntent, and assistant schemas. Use when exposing app actions or entities to system surfaces.

app-store-optimizationSkill

Optimize App Store product pages for search visibility and conversion. Use for App Store Optimization (ASO), keyword research, app name/subtitle/keyword-field strategy, conversion-focused descriptions and promotional text, screenshot captions and ordering, Custom Product Pages with assigned search keywords, In-App Events, Product Page Optimization tests, localized metadata, ratings/review strategy, and in-app review prompt timing with RequestReviewAction or AppStore.requestReview. Also use when routing ASO vs App Store review, privacy/ATT, or StoreKit implementation boundaries.

app-store-reviewSkill

Audits App Store submission readiness and rejection risk across current review guidelines, PrivacyInfo.xcprivacy and required-reason APIs, privacy labels, ATT, StoreKit payments, metadata, entitlements, widgets, and Live Activities. Use when preparing a submission, responding to rejection, reconciling privacy evidence, or separating upload blockers from cleanup.