axiom-concurrency-profiling
Use when profiling async/await performance, diagnosing actor contention, or investigating thread pool exhaustion. Covers Swift Concurrency Instruments template, task visualization, actor contention analysis, thread pool debugging.
Best use case
axiom-concurrency-profiling is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Use when profiling async/await performance, diagnosing actor contention, or investigating thread pool exhaustion. Covers Swift Concurrency Instruments template, task visualization, actor contention analysis, thread pool debugging.
Teams using axiom-concurrency-profiling should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/axiom-concurrency-profiling/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How axiom-concurrency-profiling Compares
| Feature / Agent | axiom-concurrency-profiling | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Use when profiling async/await performance, diagnosing actor contention, or investigating thread pool exhaustion. Covers Swift Concurrency Instruments template, task visualization, actor contention analysis, thread pool debugging.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Concurrency Profiling — Instruments Workflows
Profile and optimize Swift async/await code using Instruments.
## When to Use
✅ **Use when:**
- UI stutters during async operations
- Suspecting actor contention
- Tasks queued but not executing
- Main thread blocked during async work
- Need to visualize task execution flow
❌ **Don't use when:**
- Issue is pure CPU performance (use Time Profiler)
- Memory issues unrelated to concurrency (use Allocations)
- Haven't confirmed concurrency is the bottleneck
## Swift Concurrency Template
### What It Shows
| Track | Information |
|-------|-------------|
| **Swift Tasks** | Task lifetimes, parent-child relationships |
| **Swift Actors** | Actor access, contention visualization |
| **Thread States** | Blocked vs running vs suspended |
### Statistics
- **Running Tasks**: Tasks currently executing
- **Alive Tasks**: Tasks present at a point in time
- **Total Tasks**: Cumulative count created
### Color Coding
- **Blue**: Task executing
- **Red**: Task waiting (contention)
- **Gray**: Task suspended (awaiting)
## Workflow 1: Diagnose Main Thread Blocking
**Symptom**: UI freezes, main thread timeline full
1. Profile with Swift Concurrency template
2. Look at main thread → "Swift Tasks" lane
3. Find long blue bars (task executing on main)
4. Check if work could be offloaded
**Solution patterns**:
```swift
// ❌ Heavy work on MainActor
@MainActor
class ViewModel: ObservableObject {
func process() {
let result = heavyComputation() // Blocks UI
self.data = result
}
}
// ✅ Offload heavy work
@MainActor
class ViewModel: ObservableObject {
func process() async {
let result = await Task.detached {
heavyComputation()
}.value
self.data = result
}
}
```
## Workflow 2: Find Actor Contention
**Symptom**: Tasks serializing unexpectedly, parallel work running sequentially
1. Enable "Swift Actors" instrument
2. Look for serialized access patterns
3. Red = waiting, Blue = executing
4. High red:blue ratio = contention problem
**Solution patterns**:
```swift
// ❌ All work serialized through actor
actor DataProcessor {
func process(_ data: Data) -> Result {
heavyProcessing(data) // All callers wait
}
}
// ✅ Mark heavy work as nonisolated
actor DataProcessor {
nonisolated func process(_ data: Data) -> Result {
heavyProcessing(data) // Runs in parallel
}
func storeResult(_ result: Result) {
// Only actor state access serialized
}
}
```
**More fixes**:
- Split actor into multiple (domain separation)
- Use Mutex for hot paths (faster than actor hop)
- Reduce actor scope (fewer isolated properties)
## Workflow 3: Thread Pool Exhaustion
**Symptom**: Tasks queued but not executing, gaps in task execution
**Cause**: Blocking calls exhaust cooperative pool
1. Look for gaps in task execution across all threads
2. Check for blocking primitives
3. Replace with async equivalents
**Common culprits**:
```swift
// ❌ Blocks cooperative thread
Task {
semaphore.wait() // NEVER do this
// ...
semaphore.signal()
}
// ❌ Synchronous file I/O in async context
Task {
let data = Data(contentsOf: fileURL) // Blocks
}
// ✅ Use async APIs
Task {
let (data, _) = try await URLSession.shared.data(from: fileURL)
}
```
**Debug flag**:
```
SWIFT_CONCURRENCY_COOPERATIVE_THREAD_BOUNDS=1
```
Detects unsafe blocking in async context.
## Workflow 4: Priority Inversion
**Symptom**: High-priority task waits for low-priority
1. Inspect task priorities in Instruments
2. Follow wait chains
3. Ensure critical paths use appropriate priority
```swift
// ✅ Explicit priority for critical work
Task(priority: .userInitiated) {
await criticalUIUpdate()
}
```
## Thread Pool Model
Swift uses a **cooperative thread pool** matching CPU core count:
| Aspect | GCD | Swift Concurrency |
|--------|-----|-------------------|
| Threads | Grows unbounded | Fixed to core count |
| Blocking | Creates new threads | Suspends, frees thread |
| Dependencies | Hidden | Runtime-tracked |
| Context switch | Full kernel switch | Lightweight continuation |
**Why blocking is catastrophic**:
- Each blocked thread holds memory + kernel structures
- Limited threads means blocked = no progress
- Pool exhaustion deadlocks the app
## Quick Checks (Before Profiling)
Run these checks first:
1. **Is work actually async?**
- Look for suspension points (`await`)
- Sync code in async function still blocks
2. **Holding locks across await?**
```swift
// ❌ Deadlock risk
mutex.withLock {
await something() // Never!
}
```
3. **Tasks in tight loops?**
```swift
// ❌ Overhead may exceed benefit
for item in items {
Task { process(item) }
}
// ✅ Structured concurrency
await withTaskGroup(of: Void.self) { group in
for item in items {
group.addTask { process(item) }
}
}
```
4. **DispatchSemaphore in async context?**
- Always unsafe — use `withCheckedContinuation` instead
## Common Issues Summary
| Issue | Symptom in Instruments | Fix |
|-------|------------------------|-----|
| MainActor overload | Long blue bars on main | `Task.detached`, `nonisolated` |
| Actor contention | High red:blue ratio | Split actors, use `nonisolated` |
| Thread exhaustion | Gaps in all threads | Remove blocking calls |
| Priority inversion | High-pri waits for low-pri | Check task priorities |
| Too many tasks | Task creation overhead | Use task groups |
## Safe vs Unsafe Primitives
**Safe with cooperative pool**:
- `await`, actors, task groups
- `os_unfair_lock`, `NSLock` (short critical sections)
- `Mutex` (iOS 18+)
**Unsafe (violate forward progress)**:
- `DispatchSemaphore.wait()`
- `pthread_cond_wait`
- Sync file/network I/O
- `Thread.sleep()` in Task
## Resources
**WWDC**: 2022-110350, 2021-10254
**Docs**: /xcode/improving-app-responsiveness
**Skills**: axiom-swift-concurrency, axiom-performance-profiling, axiom-synchronization, axiom-lldb (interactive thread state inspection)Related Skills
profiling-application-performance
Execute this skill enables AI assistant to profile application performance, analyzing cpu usage, memory consumption, and execution time. it is triggered when the user requests performance analysis, bottleneck identification, or optimization recommendations. the... Use when optimizing performance. Trigger with phrases like 'optimize', 'performance', or 'speed up'.
go-concurrency
Use when writing concurrent Go code — goroutines, channels, mutexes, or thread-safety guarantees. Also use when parallelizing work, fixing data races, or protecting shared state, even if the user doesn't explicitly mention concurrency primitives. Does not cover context.Context patterns (see go-context).
when-profiling-performance-use-performance-profiler
Comprehensive performance profiling, bottleneck detection, and optimization system
swift-concurrency-expert
Swift Concurrency review and remediation for Swift 6.2+. Use when asked to review Swift Concurrency usage, improve concurrency compliance, or fix Swift concurrency compiler errors in a feature or file.
axiom-audit
Audit Axiom logs to identify and prioritize errors and warnings, research probable causes, and flag log smells. Use when user asks to check Axiom logs, analyze production errors, investigate log issues, or audit logging patterns.
swift-concurrency-6-2
Swift 6.2 Approachable Concurrency — single-threaded by default, @concurrent for explicit background offloading, isolated conformances for main actor types.
Axiom — Serverless Log Analytics
## Overview
php-concurrency
Handling concurrency and non-blocking I/O in modern PHP. Use when implementing concurrent requests, async processing, or non-blocking I/O in PHP. (triggers: **/*.php, Fiber, suspend, resume, non-blocking, async)
java-concurrency
Modern concurrency patterns using Virtual Threads and Structured Concurrency. Use when implementing Java Virtual Threads (Java 21), Structured Concurrency with StructuredTaskScope, CompletableFuture pipelines, or debugging race conditions. (triggers: **/*.java, Thread, Executor, synchronized, lock, CompletableFuture, StructuredTaskScope, VirtualThread, AtomicInteger, async, race condition)
android-concurrency
Standards for Coroutines, Flow, and Threading. Use when writing suspend functions, choosing coroutine scopes, switching between StateFlow and SharedFlow, injecting Dispatchers for testability, or debugging threading issues in Android. (triggers: **/*ViewModel.kt, **/*UseCase.kt, **/*Repository.kt, suspend, viewModelScope, lifecycleScope, Flow, coroutine, Dispatcher, DispatcherProvider, GlobalScope)
golang-concurrency
Golang concurrency patterns. Use when writing or reviewing concurrent Go code involving goroutines, channels, select, locks, sync primitives, errgroup, singleflight, worker pools, or fan-out/fan-in pipelines. Also triggers when you detect goroutine leaks, race conditions, channel ownership issues, or need to choose between channels and mutexes.
go-concurrency-patterns
Master Go concurrency with goroutines, channels, sync primitives, and context. Use when building concurrent Go applications, implementing worker pools, or debugging race conditions.