Add scan flow MVP and local Axiom skill workspace
This snapshot establishes the camera-to-result recognition flow and related tests while checking in the project skill/docs assets required for the configured local tooling.
This commit is contained in:
249
.claude/skills/axiom-concurrency-profiling/SKILL.md
Normal file
249
.claude/skills/axiom-concurrency-profiling/SKILL.md
Normal file
@@ -0,0 +1,249 @@
|
||||
---
|
||||
name: axiom-concurrency-profiling
|
||||
description: 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.
|
||||
license: MIT
|
||||
metadata:
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# 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)
|
||||
Reference in New Issue
Block a user