Agent skill

Performance Profiling

by conorluddy in conorluddy/xclaude-plugin

Instruments integration and performance analysis workflows for iOS apps.

MITAuto-check passedDevelopment

Install Performance Profiling

skills CLI
$ npx skills add conorluddy/xclaude-plugin --skill performance-profiling -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install conorluddy/xclaude-plugin performance-profiling --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/conorluddy/xclaude-plugin.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/performance-profiling .claude/skills/performance-profiling && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
performance-profiling
GitHub stars
183
Token cost
~7.3k tokens
SKILL.md length
1,955 words
Files
1
Skills in repo
8
Repo updated
First seen
Licence
MIT

At a glance

Instruments integration and performance analysis workflows for iOS apps.

  • Works in 5 steps: App Performance Issues → Memory Problems → Network Inefficiencies → …
  • Profiling CPU usage
  • SKILL.md covers Overview, When to Use This Skill, Key Concepts and Workflows, plus 4 more sections
  • Calls xcodebuild

What it does

Performance Profiling is an agent skill from conorluddy/xclaude-plugin. Instruments integration and performance analysis workflows for iOS apps. Use when profiling CPU usage, memory allocation, network activity, or energy consumption. Covers Time Profiler, Allocations, Leaks, Network instruments, and performance optimization strategies.

Its SKILL.md is about 7.3k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Development, covering Performance optimization and iOS development. It works with Xcode, Model Context Protocol and iOS. The repository describes itself as: iOS development ClaudeCode plugin for mindful token and context usage. Contains modular MCPs that group various Xcode/IDB tools based on your current workflow. The licence is MIT.

When your agent uses it

  • Profiling CPU usage
  • Memory allocation
  • Network activity
  • Energy consumption

Example prompts

  • “Use the performance-profiling skill to instrument integration and performance analysis workflows for iOS apps”
  • “/performance-profiling”

Workflow steps

5 steps, taken from the first numbered list in SKILL.md.

  1. App Performance Issues
  2. Memory Problems
  3. Network Inefficiencies
  4. Energy Consumption
  5. Pre-Release Optimization

What it can do on your machine

Read from SKILL.md and the folder at commit 6de4b2c. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • xcodebuild

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Performance Profiling loads about 7.3k tokens when it runs. Until then it costs about 72 tokens; SKILL.md has 1,955 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~72
When it runs · the whole SKILL.md, loaded when a task matches
~7.3k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from conorluddy/xclaude-plugin at commit 6de4b2c, republished under its MIT licence (© conorluddy). 1,955 words, ~7,293 tokens.

Download SKILL.mdSave it as .claude/skills/performance-profiling/SKILL.md (or your agent's skills folder).
name
performance-profiling
description
Instruments integration and performance analysis workflows for iOS apps. Use when profiling CPU usage, memory allocation, network activity, or energy consumption. Covers Time Profiler, Allocations, Leaks, Network instruments, and performance optimization strategies.
version
0.0.1
token_cost
~40

Performance Profiling Skill

Comprehensive guide to iOS performance analysis and optimization

Overview

Performance profiling is the systematic analysis of an iOS app's runtime behavior to identify bottlenecks, memory issues, network inefficiencies, and energy consumption patterns. This Skill guides you through using Instruments templates, interpreting profiling data, and applying optimization strategies.

Key Tools:

  • Instruments (Xcode's profiling suite)
  • xcodebuild for profiling builds
  • Performance metrics analysis
  • Memory graph debugging

When to Use This Skill

Use performance profiling when:

  1. App Performance Issues

    • Slow app launch times
    • Choppy scrolling or animations
    • UI freezing or unresponsiveness
    • High CPU usage
  2. Memory Problems

    • Memory leaks detected
    • Growing memory footprint
    • Memory warnings
    • App crashes due to memory pressure
  3. Network Inefficiencies

    • Slow data loading
    • Excessive network requests
    • Large payload sizes
    • Poor offline handling
  4. Energy Consumption

    • Battery drain complaints
    • Background processing issues
    • Thermal throttling
    • Energy impact reports
  5. Pre-Release Optimization

    • Performance regression detection
    • Baseline performance establishment
    • Release candidate validation
    • Performance budget enforcement

Key Concepts

Instruments Templates

Time Profiler

  • Measures CPU usage and call stacks
  • Identifies hot paths in code
  • Shows function-level performance
  • Best for: CPU-bound operations, algorithm optimization

Allocations

  • Tracks memory allocations and deallocations
  • Shows object lifetime and retention
  • Identifies memory growth patterns
  • Best for: Memory footprint analysis, allocation hotspots

Leaks

  • Detects memory leaks in real-time
  • Shows leaked objects and their origins
  • Identifies retain cycles
  • Best for: Finding memory leaks, debugging reference cycles

Network

  • Monitors HTTP/HTTPS traffic
  • Shows request/response timing
  • Tracks payload sizes
  • Best for: API optimization, bandwidth analysis

Energy Log

  • Measures energy consumption
  • Shows CPU, network, display impact
  • Identifies battery drain sources
  • Best for: Battery life optimization

Core Animation

  • Analyzes frame rate and rendering
  • Shows layer composition issues
  • Identifies off-screen rendering
  • Best for: Animation optimization, scrolling performance
Profiling Strategies

Sampling vs Tracing

Sampling (Time Profiler):

  • Periodically captures call stacks
  • Low overhead (~5-10%)
  • May miss short-lived operations
  • Best for: Production-like scenarios

Tracing (Most other instruments):

  • Records every event
  • Higher overhead (10-50%)
  • Complete event history
  • Best for: Detailed analysis
Performance Metrics

Launch Time

  • Pre-main time: Dynamic library loading, +load methods
  • Main to first frame: App initialization, first view load
  • Target: < 400ms total on device

Scrolling Performance

  • Frame rate: 60 FPS (16.67ms per frame)
  • Hitch ratio: < 5ms hitches per second
  • Target: 60 FPS sustained during scrolling

Memory Footprint

  • Resident memory: Actual physical RAM used
  • Dirty memory: Memory written to by app
  • Target: Depends on device (< 150MB for low-end devices)

Network Efficiency

  • Request latency: Time to first byte
  • Transfer size: Payload + overhead
  • Request frequency: Requests per minute
  • Target: < 100KB per request, batch when possible

Energy Impact

  • CPU time: Processor usage
  • Network bytes: Data transferred
  • Display time: Screen on time
  • Target: "Low" or "Medium" energy impact rating

Workflows

CPU Profiling (Time Profiler)

Goal: Identify CPU-intensive operations and optimize hot paths

Step 1: Build for Profiling

json
{
  "operation": "build",
  "scheme": "MyApp",
  "configuration": "Release",
  "destination": "platform=iOS,id=<device-udid>",
  "options": {
    "archive_for_profiling": true
  }
}

Why Release Configuration?

  • Enables optimizations
  • Reflects production performance
  • Removes debug overhead

Device vs Simulator:

  • Always profile on device for accurate CPU measurements
  • Simulator runs on Mac CPU (not representative)

Step 2: Profile with Instruments

bash
# Launch Instruments with Time Profiler template
instruments -t "Time Profiler" \
  -D /path/to/trace.trace \
  -w <device-udid> \
  com.example.MyApp

Manual Approach:

  1. Open Instruments (Xcode → Open Developer Tool → Instruments)
  2. Select "Time Profiler" template
  3. Choose device and app
  4. Click record, perform problematic operations
  5. Stop recording

Step 3: Analyze Call Tree

Call Tree Settings:

  • Enable "Separate by Thread"
  • Enable "Hide System Libraries" (initially)
  • Show "Heaviest Stack Trace"

Interpret Results:

  • Self Time: Time spent in function itself
  • Total Time: Time including called functions
  • Call Count: Number of times function called

Red Flags:

  • Self time > 50ms for UI operations
  • High call count for expensive operations
  • Unexpected functions in hot path

Step 4: Optimize

Common Optimizations:

  • Reduce algorithm complexity (O(n²) → O(n log n))
  • Cache expensive computations
  • Move work off main thread
  • Use lazy evaluation

Verification:

  • Profile again after changes
  • Compare before/after traces
  • Ensure optimization didn't break functionality
Memory Profiling (Allocations & Leaks)

Goal: Identify memory leaks and reduce memory footprint

Step 1: Build for Profiling

json
{
  "operation": "build",
  "scheme": "MyApp",
  "configuration": "Debug",
  "destination": "platform=iOS Simulator,name=iPhone 15",
  "options": {
    "enable_memory_debugging": true
  }
}

Note: Use Debug for better stack traces, Simulator acceptable for memory profiling

Step 2: Profile with Allocations

bash
# Launch Instruments with Allocations template
instruments -t "Allocations" \
  -D /path/to/allocations.trace \
  -w <simulator-udid> \
  com.example.MyApp

Step 3: Identify Memory Growth

Heap Growth Analysis:

  1. Take memory snapshot (Mark Generation)
  2. Perform operation (e.g., open/close view controller)
  3. Take another snapshot
  4. View "Growth" column

Expected: Minimal growth after repeated operations Red Flag: Continuous growth with each iteration

Step 4: Find Leaks

Switch to Leaks Instrument:

bash
instruments -t "Leaks" \
  -D /path/to/leaks.trace \
  -w <simulator-udid> \
  com.example.MyApp

Interpret Results:

  • Leaks shown in red
  • Click leak → See responsible stack trace
  • Common causes: Retain cycles, unregistered observers

Step 5: Debug Retain Cycles

Memory Graph Debugger:

  1. Run app in Xcode
  2. Click "Debug Memory Graph" button
  3. Filter by leaked objects
  4. Inspect retain cycle paths

Common Patterns:

  • Closure capturing self strongly
  • Delegate not marked weak
  • NSNotificationCenter observers not removed
  • Timer retaining target

Solutions:

  • Use [weak self] in closures
  • Mark delegates as weak
  • Remove observers in deinit
  • Invalidate timers properly
Network Profiling

Goal: Optimize network requests and reduce data usage

Step 1: Profile with Network Instrument

bash
instruments -t "Network" \
  -D /path/to/network.trace \
  -w <device-udid> \
  com.example.MyApp

Step 2: Analyze Network Activity

Key Metrics:

  • Request Count: Total number of requests
  • Bytes Transferred: Upload + download size
  • Duration: Time from request to completion
  • HTTP Status: Success/failure codes

Red Flags:

  • Many small requests (should batch)
  • Large payloads (should paginate)
  • Sequential requests (should parallelize)
  • Redundant requests (should cache)

Step 3: Optimize Requests

Batching:

swift
// Before: 10 separate requests
for item in items {
    fetchDetails(for: item)
}

// After: 1 batched request
fetchDetails(for: items)

Pagination:

swift
// Fetch 20 items at a time
func fetchItems(page: Int, pageSize: Int = 20) {
    let offset = page * pageSize
    api.fetch(limit: pageSize, offset: offset)
}

Caching:

swift
// Use URLCache or custom cache
let cache = URLCache.shared
cache.diskCapacity = 50 * 1024 * 1024 // 50MB

Compression:

swift
// Enable gzip compression
request.setValue("gzip", forHTTPHeaderField: "Accept-Encoding")
Energy Profiling

Goal: Reduce battery drain and thermal impact

Step 1: Profile with Energy Log

bash
instruments -t "Energy Log" \
  -D /path/to/energy.trace \
  -w <device-udid> \
  com.example.MyApp

Step 2: Analyze Energy Impact

Energy Sources:

  • CPU: Processing time
  • Network: Data transfer
  • Display: Screen updates
  • Location: GPS usage
  • Background: Background processing

Energy Levels:

  • Low: 0-10 energy units
  • Medium: 10-40 energy units
  • High: > 40 energy units

Target: Stay in "Low" or "Medium" most of the time

Step 3: Optimize Energy Usage

CPU Optimization:

  • Reduce background processing
  • Use efficient algorithms
  • Defer non-critical work

Network Optimization:

  • Batch requests
  • Use compression
  • Schedule background transfers

Display Optimization:

  • Reduce animation complexity
  • Dim screen when possible
  • Pause animations when offscreen

Location Optimization:

  • Use lowest accuracy needed
  • Stop updates when not needed
  • Use significant location changes

Common Profiling Patterns

Launch Time Optimization

Measurement Approach:

  1. Profile App Launch
bash
instruments -t "App Launch" \
  -D /path/to/launch.trace \
  -w <device-udid> \
  com.example.MyApp
  1. Analyze Pre-Main Time
    • Dynamic library loading
    • Objective-C class registration
    • +load method execution

Optimization Strategies:

  • Reduce number of dynamic libraries
  • Move +load work to +initialize
  • Lazy load unnecessary frameworks
  1. Analyze Main to First Frame
    • UIApplicationMain execution
    • didFinishLaunching execution
    • First view controller load

Optimization Strategies:

  • Defer heavy initialization
  • Load critical UI first
  • Use placeholders for slow content

Target: < 400ms total launch time on device

Scroll Performance Analysis

Measurement Approach:

  1. Profile Scrolling
bash
instruments -t "Core Animation" \
  -D /path/to/scroll.trace \
  -w <device-udid> \
  com.example.MyApp
  1. Check Frame Rate

    • Target: 60 FPS (16.67ms per frame)
    • Acceptable: 50-60 FPS
    • Poor: < 50 FPS
  2. Identify Frame Drops

    • Look for red/yellow bars in timeline
    • Check "Time Profiler" for main thread work

Optimization Strategies:

Cell Reuse:

swift
// Proper cell reuse
func tableView(_ tableView: UITableView,
               cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    configure(cell: cell, with: data[indexPath.row])
    return cell
}

Image Optimization:

swift
// Downsize images to display size
let size = imageView.bounds.size
let downsizedImage = image.resized(to: size)
imageView.image = downsizedImage

Layout Caching:

swift
// Cache calculated heights
private var heightCache: [IndexPath: CGFloat] = [:]

func tableView(_ tableView: UITableView,
               heightForRowAt indexPath: IndexPath) -> CGFloat {
    if let height = heightCache[indexPath] {
        return height
    }
    let height = calculateHeight(for: indexPath)
    heightCache[indexPath] = height
    return height
}

Off-Main-Thread Work:

swift
// Move image processing off main thread
DispatchQueue.global(qos: .userInitiated).async {
    let processedImage = self.processImage(image)
    DispatchQueue.main.async {
        self.imageView.image = processedImage
    }
}
Memory Leak Detection

Systematic Approach:

  1. Identify Suspect Feature

    • Feature that shows memory growth
    • Example: Opening/closing profile view
  2. Create Reproduction Steps

    1. Launch app
    2. Open profile view
    3. Close profile view
    4. Repeat 10 times
  3. Profile with Leaks

    • Use Leaks instrument
    • Follow reproduction steps
    • Check for leaks after each iteration
  4. Analyze Leak Origin

    • Click leaked object
    • View "Responsible Caller"
    • Trace back to source code
  5. Identify Leak Pattern

    • Closure capture: [weak self] missing
    • Delegate: Not marked weak
    • Notification: Observer not removed
    • Timer: Not invalidated
  6. Fix and Verify

    • Apply fix
    • Profile again
    • Confirm leak eliminated
Show full SKILL.md (779 more words)Show less
Network Request Optimization

Analysis Workflow:

  1. Baseline Measurement

    • Profile typical user session
    • Count total requests
    • Measure total bytes transferred
  2. Identify Inefficiencies

    • Too many requests: Batch or consolidate
    • Large payloads: Compress or paginate
    • Redundant data: Implement caching
    • Sequential requests: Parallelize when possible
  3. Optimization Strategies

Request Batching:

swift
// Batch multiple IDs into single request
func fetchUsers(ids: [String]) {
    let batchedIDs = ids.joined(separator: ",")
    api.get("/users?ids=\(batchedIDs)")
}

Response Pagination:

swift
// Implement cursor-based pagination
func fetchFeed(cursor: String? = nil, limit: Int = 20) {
    var params = ["limit": limit]
    if let cursor = cursor {
        params["cursor"] = cursor
    }
    api.get("/feed", parameters: params)
}

Intelligent Caching:

swift
// Cache with expiration
class APICache {
    private var cache: [String: CachedResponse] = [:]

    func get(url: String) -> Data? {
        guard let cached = cache[url],
              !cached.isExpired else { return nil }
        return cached.data
    }

    func set(url: String, data: Data, ttl: TimeInterval = 300) {
        cache[url] = CachedResponse(data: data, expiry: Date() + ttl)
    }
}

Request Coalescing:

swift
// Prevent duplicate in-flight requests
class RequestCoalescer {
    private var inFlightRequests: [String: Task<Data, Error>] = [:]

    func request(url: String) async throws -> Data {
        if let existing = inFlightRequests[url] {
            return try await existing.value
        }

        let task = Task {
            let data = try await performRequest(url)
            inFlightRequests[url] = nil
            return data
        }

        inFlightRequests[url] = task
        return try await task.value
    }
}

Analysis Techniques

Call Tree Interpretation

Understanding Call Tree Structure:

Total Time | Self Time | Symbol
-----------|-----------|--------
  1000ms   |   10ms    | -[UITableView reloadData]
   800ms   |   50ms    |  └─ -[MyCell configure]
   700ms   |  700ms    |     └─ -[ImageProcessor processImage]

Reading:

  • reloadData took 1000ms total
  • 10ms in reloadData itself
  • 800ms in configure (called from reloadData)
  • 700ms in processImage (called from configure)

Optimization Target: processImage (700ms self time)

Call Tree Filters:

Separate by Thread:

  • Shows which threads are busy
  • Identify main thread bottlenecks

Hide System Libraries:

  • Focus on your code
  • Re-enable to see system call overhead

Flatten Recursion:

  • Collapses recursive calls
  • Shows total time in recursive function

Show Obj-C Only / Swift Only:

  • Filter by language
  • Useful in mixed codebases
Flame Graph Reading

Visual Representation:

  • Width = Time spent
  • Height = Call stack depth
  • Color = Different functions

Interpretation:

  • Wide sections = Hot spots (spend optimization time here)
  • Tall stacks = Deep call chains (consider flattening)
  • Repeated patterns = Loop opportunities

Example:

[                    main                    ] ← 100% of time
[       viewDidLoad       ][    updateUI    ] ← 50% each
[loadData][parseJSON]      [layout][render] ← Breakdown

Optimization Strategy:

  • Focus on widest sections first
  • Consider parallelizing separate wide sections
  • Optimize functions appearing multiple times
Memory Graph Debugging

Workflow:

  1. Capture Memory Graph

    • Run app in Xcode
    • Click "Debug Memory Graph" button (or ⌘⌥M)
  2. Filter View

    • Filter by "Leaks" to see leaked objects
    • Filter by class name to find specific objects
  3. Inspect Object

    • Select object in left panel
    • View properties in right panel
    • See references in reference inspector
  4. Trace Retain Cycle

    • Follow strong references
    • Identify circular paths
    • Note where weak should be used

Example Cycle:

ViewController → (strong) Closure → (strong) ViewController

Fix:

swift
// Before (leak)
viewModel.onUpdate = {
    self.updateUI()
}

// After (no leak)
viewModel.onUpdate = { [weak self] in
    self?.updateUI()
}
Performance Regression Detection

Continuous Performance Testing:

  1. Establish Baseline

    • Profile app on reference device
    • Record key metrics (launch time, memory, FPS)
    • Store baseline measurements
  2. Automated Performance Tests

swift
func testLaunchPerformance() throws {
    measure(metrics: [XCTApplicationLaunchMetric()]) {
        XCUIApplication().launch()
    }
}

func testScrollPerformance() throws {
    let app = XCUIApplication()
    app.launch()

    measure(metrics: [XCTOSSignpostMetric.scrollDecelerationMetric]) {
        app.tables.firstMatch.swipeUp()
    }
}
  1. CI Integration

    • Run performance tests in CI
    • Compare results to baseline
    • Fail build if regression > threshold
  2. Regression Analysis

    • When regression detected, profile locally
    • Use Time Profiler to find changed code
    • Optimize or adjust baseline if intentional

Baseline Format:

json
{
  "launch_time_ms": 350,
  "memory_mb": 120,
  "scroll_fps": 59,
  "thresholds": {
    "launch_time_ms": 450,
    "memory_mb": 150,
    "scroll_fps": 55
  }
}

Troubleshooting

High CPU Usage Causes

Symptoms:

  • App feels sluggish
  • Device gets hot
  • Battery drains quickly
  • Fans spin up (Mac Catalyst)

Common Causes:

1. Main Thread Blocking

swift
// Problem: Heavy work on main thread
DispatchQueue.main.async {
    let result = expensiveCalculation() // Blocks UI
    updateUI(with: result)
}

// Solution: Move work off main thread
DispatchQueue.global(qos: .userInitiated).async {
    let result = expensiveCalculation()
    DispatchQueue.main.async {
        updateUI(with: result)
    }
}

2. Polling/Tight Loops

swift
// Problem: Constant polling
Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { _ in
    checkForUpdates() // Called 100 times per second!
}

// Solution: Reasonable interval or event-driven
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
    checkForUpdates() // Called once per second
}

3. Inefficient Algorithms

swift
// Problem: O(n²) complexity
for item in items {
    for other in items {
        compare(item, other) // n² comparisons
    }
}

// Solution: O(n log n) or O(n)
let sorted = items.sorted()
for (item, other) in zip(sorted, sorted.dropFirst()) {
    compare(item, other) // n comparisons
}
Memory Growth Patterns

Symptoms:

  • Memory usage increases over time
  • Memory warnings
  • App crashes after extended use

Common Patterns:

1. Unbounded Cache Growth

swift
// Problem: Cache grows indefinitely
class ImageCache {
    private var cache: [URL: UIImage] = [:] // Never clears!
}

// Solution: Use NSCache (auto-eviction)
class ImageCache {
    private let cache = NSCache<NSURL, UIImage>()

    init() {
        cache.countLimit = 100 // Max 100 images
    }
}

2. Event Listener Accumulation

swift
// Problem: Listeners never removed
override func viewWillAppear(_ animated: Bool) {
    NotificationCenter.default.addObserver(/* ... */) // Added every time!
}

// Solution: Remove in viewWillDisappear
override func viewWillDisappear(_ animated: Bool) {
    NotificationCenter.default.removeObserver(self)
}

3. Large Object Retention

swift
// Problem: Keeping large objects in memory
class ViewController: UIViewController {
    var cachedImage: UIImage? // Large image retained
}

// Solution: Cache only when needed, clear when done
class ViewController: UIViewController {
    private var cachedImage: UIImage?

    override func didReceiveMemoryWarning() {
        cachedImage = nil // Release when memory pressure
    }
}
Network Inefficiencies

Symptoms:

  • Slow data loading
  • High data usage
  • Poor offline experience

Common Issues:

1. Waterfall Requests

swift
// Problem: Sequential dependent requests
func loadProfile() async {
    let user = await fetchUser() // Wait...
    let posts = await fetchPosts(for: user) // Wait...
    let comments = await fetchComments(for: posts) // Wait...
}

// Solution: Parallel independent requests
func loadProfile() async {
    async let user = fetchUser()
    async let followers = fetchFollowers()
    async let settings = fetchSettings()

    let (u, f, s) = await (user, followers, settings)
}

2. No Request Deduplication

swift
// Problem: Same request made multiple times
func loadData() {
    fetchUsers() // Request 1
    fetchUsers() // Request 2 (redundant!)
}

// Solution: Deduplicate requests
class APIClient {
    private var pendingRequests: [String: Task<Data, Error>] = [:]

    func fetch(url: String) async throws -> Data {
        if let pending = pendingRequests[url] {
            return try await pending.value // Reuse
        }

        let task = Task { try await URLSession.shared.data(from: URL(string: url)!) }
        pendingRequests[url] = task
        defer { pendingRequests[url] = nil }
        return try await task.value
    }
}

3. Large Uncompressed Payloads

swift
// Problem: Sending/receiving uncompressed data
URLSession.shared.dataTask(with: url) // Default: no compression

// Solution: Enable compression
var request = URLRequest(url: url)
request.setValue("gzip, deflate", forHTTPHeaderField: "Accept-Encoding")
URLSession.shared.dataTask(with: request)
Battery Drain Issues

Symptoms:

  • User complaints of battery drain
  • Device thermal throttling
  • High energy impact in Settings

Common Causes:

1. Excessive Background Activity

swift
// Problem: Constant background work
func applicationDidEnterBackground(_ application: UIApplication) {
    Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { _ in
        syncData() // Drains battery in background
    }
}

// Solution: Use background tasks properly
func applicationDidEnterBackground(_ application: UIApplication) {
    let taskID = application.beginBackgroundTask {
        // Task expired, clean up
    }

    syncData {
        application.endBackgroundTask(taskID)
    }
}

2. Continuous Location Updates

swift
// Problem: Always requesting location
locationManager.startUpdatingLocation() // Continuous GPS drain

// Solution: Use appropriate accuracy
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.distanceFilter = 100 // Update every 100m
locationManager.startMonitoringSignificantLocationChanges() // Low power mode

3. Rendering Offscreen Content

swift
// Problem: Animating hidden views
override func viewDidDisappear(_ animated: Bool) {
    // Animations keep running! Wastes CPU/battery
}

// Solution: Pause animations when offscreen
override func viewDidDisappear(_ animated: Bool) {
    animationView.layer.pauseAnimations()
}

extension CALayer {
    func pauseAnimations() {
        let pausedTime = convertTime(CACurrentMediaTime(), from: nil)
        speed = 0.0
        timeOffset = pausedTime
    }
}

Best Practices

Profile on Device vs Simulator

Always profile on device for:

  • CPU performance (simulator uses Mac CPU)
  • Memory pressure (different memory characteristics)
  • Network latency (simulator uses Mac network)
  • Energy consumption (no battery in simulator)
  • GPU performance (different graphics hardware)

Simulator acceptable for:

  • Initial memory leak detection
  • Basic UI debugging
  • Quick iteration during development

Recommendation: Develop on simulator, validate on device, profile on device.

Release Configuration Profiling

Why Profile Release Builds:

  • Optimizations enabled: Swift optimizations, inlining, dead code elimination
  • Debug overhead removed: No assertions, no debug info
  • Represents production: Users run release builds

Debug vs Release Differences:

  • Release can be 5-10x faster
  • Memory patterns differ (ARC optimizations)
  • Some bugs only appear in release

How to Profile Release:

  1. Edit scheme → Run → Build Configuration → Release
  2. Enable "Debug executable" for debugging symbols
  3. Build and run
  4. Profile as normal

Warning: Some crashes only happen in release due to optimizations.

Continuous Performance Monitoring

Development Workflow:

  1. Baseline establishment: Profile app at start of sprint
  2. Feature development: Build features normally
  3. Pre-merge profiling: Profile before merging to main
  4. Regression check: Compare to baseline
  5. Optimization if needed: Fix regressions before merge

CI Integration:

yaml
# .github/workflows/performance.yml
name: Performance Tests

on: [pull_request]

jobs:
  performance:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v2

      - name: Run performance tests
        run: xcodebuild test -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'

      - name: Check for regressions
        run: ./scripts/check_performance_baseline.sh

Automated Performance Tests:

swift
class PerformanceTests: XCTestCase {
    func testLaunchPerformance() {
        measure(metrics: [XCTApplicationLaunchMetric()]) {
            XCUIApplication().launch()
        }
    }

    func testMemoryUsage() {
        let app = XCUIApplication()
        app.launch()

        measure(metrics: [XCTMemoryMetric()]) {
            // Perform memory-intensive operations
            for _ in 0..<100 {
                app.buttons["Load"].tap()
            }
        }
    }
}
Performance Budgets

Establish Budgets:

swift
// PerformanceBudgets.swift
enum PerformanceBudget {
    static let launchTime: TimeInterval = 0.4 // 400ms
    static let memoryFootprint: Int = 150 * 1024 * 1024 // 150MB
    static let scrollFrameTime: TimeInterval = 0.0167 // 16.67ms (60 FPS)
    static let networkRequestTimeout: TimeInterval = 5.0 // 5s
}

// Enforce in tests
func testLaunchBudget() {
    let launchTime = measureLaunchTime()
    XCTAssertLessThan(launchTime, PerformanceBudget.launchTime,
                      "Launch time exceeded budget: \(launchTime)s > \(PerformanceBudget.launchTime)s")
}

Budget Categories:

Launch Time:

  • Critical: < 400ms (excellent)
  • Acceptable: 400-800ms (good)
  • Poor: > 800ms (needs optimization)

Memory:

  • Low-end devices: < 100MB
  • Mid-range devices: < 150MB
  • High-end devices: < 200MB

Frame Rate:

  • Scrolling: 60 FPS (16.67ms/frame)
  • Animations: 60 FPS
  • Acceptable: 50+ FPS

Network:

  • API response: < 1s
  • Image load: < 2s
  • Timeout: 5s max

Monitor Budgets:

  • Track metrics over time
  • Alert when budget exceeded
  • Review budgets quarterly

Integration with Xcode Workflows

This Skill integrates with xcode-workflows Skill:

Build for Profiling:

json
{
  "operation": "build",
  "scheme": "MyApp",
  "configuration": "Release",
  "destination": "platform=iOS,id=<device-udid>",
  "options": {
    "clean_before_build": true
  }
}

Archive for Profiling:

bash
xcodebuild archive \
  -scheme MyApp \
  -configuration Release \
  -archivePath ./build/MyApp.xcarchive

Export for Profiling:

bash
xcodebuild -exportArchive \
  -archivePath ./build/MyApp.xcarchive \
  -exportPath ./build \
  -exportOptionsPlist ExportOptions.plist
  • xcode-workflows: Building and configuring apps for profiling
  • crash-debugging: Analyzing performance-related crashes
  • ios-testing-patterns: Performance testing strategies
  • xc://operations/xcode: Xcodebuild operations for profiling builds
  • xc://reference/instruments: Complete Instruments template reference
  • xc://reference/performance-metrics: Key performance indicators and targets

Tip: Profile on device, use Release configuration, focus on user-impacting metrics first.

© conorluddy, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in skills/performance-profiling of conorluddy/xclaude-plugin.

Open the folder on GitHubat commit 6de4b2c

Compare with similar skills

Performance Profiling next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Performance Profiling compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Performance Profiling this skillconorluddy/xclaude-plugin183—~7.3kAutomated safety check: PassMIT
iOS Memgraph Analysisdpearson2699/swift-ios-skills1.2k—~2.4kAutomated safety check: PassCustom licence
Mobile App Debuggingsecondsky/claude-skills227—~513Automated safety check: PassMIT
Update Swiftui APIsAvdLee/SwiftUI-Agent-Skill3.7k—~1.2kAutomated safety check: PassMIT
iOS Simulator Skillconorluddy/ios-simulator-skill1.3k—~5.7kAutomated safety check: PassMIT
Inspector MCPipedro/Inspector170—~3.4kAutomated safety check: PassMIT

Similar skills

  • iOS Memgraph Analysis

    dpearson2699/swift-ios-skills

    A skill your agent uses when capturing or analyzing an iOS .memgraph, especially when the task mentions a memory leak, heap growth, persistent memory increase, ownership path, or matched-capture…

    1.2k GitHub stars~2.4k tokensUpdated 2 mo ago
    MobileAuto-check passed
  • Mobile App Debugging

    secondsky/claude-skills

    Mobile app debugging for iOS, Android, cross-platform frameworks.

    227 GitHub stars~513 tokensUpdated 9 days ago
    MobileAuto-check passed
  • Update Swiftui APIs

    AvdLee/SwiftUI-Agent-Skill

    Scan Apple's SwiftUI documentation for deprecated APIs and update the SwiftUI Expert Skill with modern replacements.

    3.7k GitHub stars~1.2k tokensUpdated yesterday
    MobileAuto-check passed
  • iOS Simulator Skill

    conorluddy/ios-simulator-skill

    29 production-ready scripts for iOS app testing, building, and automation.

    1.3k GitHub stars~5.7k tokensUpdated yesterday
    MobileAuto-check passed
  • Inspector MCP

    ipedro/Inspector

    A skill your agent uses when an agent needs to inspect a live iOS app through the Inspector MCP bridge, register or troubleshoot InspectorMCPServer for a consumer Xcode project, or query, resolve…

    170 GitHub stars~3.4k tokensUpdated 5 mo ago
    MobileAuto-check passed
  • Xcode Build

    pzep1/xcode-build-skill

    Build and run iOS/macOS apps using xcodebuild and xcrun simctl directly.

    138 GitHub stars~1.5k tokensUpdated 8 mo ago
    MobileAuto-check: notes

More from conorluddy/xclaude-plugin

All 8 skills in this repo
  • iOS Accessibility Testing

    conorluddy/xclaude-plugin

    Guides WCAG 2.1 and VoiceOver accessibility testing for iOS apps, working from the accessibility tree and not from screenshots.

    183 GitHub stars~5k tokensUpdated 25 days ago
    Auto-check passed
  • iOS Crash Log Debugging

    conorluddy/xclaude-plugin

    Walks through retrieving, symbolicating and diagnosing iOS crash logs, turning a cryptic stack trace into the function names that actually failed.

    183 GitHub stars~4.9k tokensUpdated 25 days ago
    Auto-check passed
  • iOS Simulator Workflows

    conorluddy/xclaude-plugin

    Manages iOS Simulator devices and apps through the execute_simulator_command MCP tool instead of raw simctl: boot, create and delete devices, install and launch apps, screenshots and diagnostics.

    183 GitHub stars~3.3k tokensUpdated 25 days ago
    Auto-check passed
  • xc-plugin State Management

    conorluddy/xclaude-plugin

    Teaches how xc-plugin saves tokens with progressive disclosure, cached responses and consistent configuration, so large device lists and build logs arrive as summaries first.

    183 GitHub stars~4k tokensUpdated 25 days ago
    Auto-check passed
  • UI Automation Workflows

    conorluddy/xclaude-plugin

    Accessibility-first UI automation using IDB. An agent skill from conorluddy/xclaude-plugin.

    183 GitHub stars~2.2k tokensUpdated 25 days ago
    Auto-check passed
  • Xcode Build Workflows

    conorluddy/xclaude-plugin

    Directs iOS build, test and clean operations through the execute_xcode_command MCP tool instead of raw xcodebuild in the shell, with parameter-level retries on failure.

    183 GitHub stars~3k tokensUpdated 25 days ago
    Auto-check passed

Questions about Performance Profiling

What does Performance Profiling do?

Instruments integration and performance analysis workflows for iOS apps. Performance Profiling is an agent skill from conorluddy/xclaude-plugin. Instruments integration and performance analysis workflows for iOS apps.

When should I use Performance Profiling?

Performance Profiling fits situations like: profiling CPU usage; memory allocation; network activity; energy consumption.

How do I install Performance Profiling in Claude Code?

Run `npx skills add conorluddy/xclaude-plugin --skill performance-profiling -a claude-code`. Or copy the skill folder (skills/performance-profiling in conorluddy/xclaude-plugin) into .claude/skills/performance-profiling in your project. Claude Code loads it when a task matches its description.

How do I install Performance Profiling in Codex?

Run `npx skills add conorluddy/xclaude-plugin --skill performance-profiling -a codex`. Or copy the skill folder (skills/performance-profiling in conorluddy/xclaude-plugin) into .agents/skills/performance-profiling in your project. Codex loads it when a task matches its description.

Can I use Performance Profiling in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add conorluddy/xclaude-plugin --skill performance-profiling -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/performance-profiling, .gemini/skills/performance-profiling, .github/skills/performance-profiling and .opencode/skills/performance-profiling in your project.

What does Performance Profiling need to run?

Going by SKILL.md and its folder, Performance Profiling needs the command-line tools its instructions call (xcodebuild).

Does Performance Profiling access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Performance Profiling safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Performance Profiling use?

Performance Profiling is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Performance Profiling use?

About 7.3k tokens (SKILL.md is roughly 29k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Performance Profiling?

Skills that share tags, products or a category with Performance Profiling: iOS Memgraph Analysis (dpearson2699/swift-ios-skills, 1.2k stars), Mobile App Debugging (secondsky/claude-skills, 227 stars), Update Swiftui APIs (AvdLee/SwiftUI-Agent-Skill, 3.7k stars) and iOS Simulator Skill (conorluddy/ios-simulator-skill, 1.3k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Performance Profiling?

conorluddy (a GitHub user) maintains it in conorluddy/xclaude-plugin, which has 183 GitHub stars. The repository holds 8 skills in this directory. The repository was last updated on September 12, 2026.

Source: conorluddy/xclaude-plugin on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.