--- name: axiom-energy-diag description: Symptom-based energy troubleshooting - decision trees for 'app at top of battery settings', 'phone gets hot', 'background drain', 'high cellular usage', with time-cost analysis for each diagnosis path license: MIT metadata: version: "1.0.0" --- # Energy Diagnostics Symptom-based troubleshooting for energy issues. Start with your symptom, follow the decision tree, get the fix. **Related skills**: `axiom-energy` (patterns, checklists), `axiom-energy-ref` (API reference) --- ## Symptom 1: App at Top of Battery Settings Users or you notice your app consuming significant battery. ### Diagnosis Decision Tree ``` App at top of Battery Settings? │ ├─ Step 1: Run Power Profiler (15 min) │ ├─ CPU Power Impact high? │ │ ├─ Continuous? → Timer leak or polling loop │ │ │ └─ Fix: Check timers, add tolerance, convert to push │ │ └─ Spikes during actions? → Eager loading or repeated parsing │ │ └─ Fix: Use LazyVStack, cache parsed data │ │ │ ├─ Network Power Impact high? │ │ ├─ Many small requests? → Batching issue │ │ │ └─ Fix: Batch requests, use discretionary URLSession │ │ └─ Regular intervals? → Polling pattern │ │ └─ Fix: Convert to push notifications │ │ │ ├─ GPU Power Impact high? │ │ ├─ Animations? → Running when not visible │ │ │ └─ Fix: Stop in viewWillDisappear │ │ └─ Blur effects? → Over dynamic content │ │ └─ Fix: Remove or use static backgrounds │ │ │ └─ Display Power Impact high? │ └─ Light backgrounds on OLED? │ └─ Fix: Implement Dark Mode (up to 70% savings) │ └─ Step 2: Check background section in Battery Settings ├─ High background time? │ ├─ Location icon visible? → Continuous location │ │ └─ Fix: Switch to significant-change monitoring │ ├─ Audio active? → Session not deactivated │ │ └─ Fix: Deactivate audio session when not playing │ └─ BGTasks running long? → Not completing promptly │ └─ Fix: Call setTaskCompleted sooner │ └─ Background time appropriate? └─ Issue is in foreground usage → Focus on CPU/GPU fixes above ``` ### Time-Cost Analysis | Approach | Time | Accuracy | |----------|------|----------| | Run Power Profiler, identify subsystem | 15-20 min | High | | Guess and optimize random areas | 4+ hours | Low | | Read all code looking for issues | 2+ hours | Medium | **Recommendation**: Always use Power Profiler first. It costs 15 minutes but guarantees you optimize the right subsystem. --- ## Symptom 2: Device Gets Hot Device temperature increases noticeably during app use. ### Diagnosis Decision Tree ``` Device gets hot during app use? │ ├─ Hot during specific action? │ │ │ ├─ During video/camera use? │ │ ├─ Video encoding? → Expected, but check efficiency │ │ │ └─ Fix: Use hardware encoding, reduce resolution if possible │ │ └─ Camera active unnecessarily? → Not releasing session │ │ └─ Fix: Call stopRunning() when done │ │ │ ├─ During scroll/animation? │ │ ├─ GPU-intensive effects? → Blur, shadows, many layers │ │ │ └─ Fix: Reduce effects, cache rendered content │ │ └─ High frame rate? → Unnecessary 120fps │ │ └─ Fix: Use CADisplayLink preferredFrameRateRange │ │ │ └─ During data processing? │ ├─ JSON parsing? → Repeated or large payloads │ │ └─ Fix: Cache parsed results, paginate │ └─ Image processing? → Synchronous on main thread │ └─ Fix: Move to background, cache results │ ├─ Hot during normal use (no specific action)? │ │ │ ├─ Run Power Profiler to identify: │ │ ├─ CPU high continuously → Timer, polling, tight loop │ │ ├─ GPU high continuously → Animation leak │ │ └─ Network high continuously → Polling pattern │ │ │ └─ Check for infinite loops or runaway recursion │ └─ Use Time Profiler in Instruments │ └─ Hot only in background? ├─ Location updates continuous? → High accuracy or no stop │ └─ Fix: Reduce accuracy, stop when done ├─ Audio session active? → Hardware kept powered │ └─ Fix: Deactivate when not playing └─ BGTask running too long? → System may throttle └─ Fix: Complete tasks faster, use requiresExternalPower ``` ### Time-Cost Analysis | Approach | Time | Outcome | |----------|------|---------| | Power Profiler + Time Profiler | 20-30 min | Identifies exact cause | | Check code for obvious issues | 1-2 hours | May miss non-obvious causes | | Wait for user complaints | N/A | Reputation damage | --- ## Symptom 3: Background Battery Drain App drains battery even when user isn't actively using it. ### Diagnosis Decision Tree ``` High background battery usage? │ ├─ Step 1: Check Info.plist background modes │ │ │ ├─ "location" enabled? │ │ ├─ Actually need background location? │ │ │ ├─ YES → Use significant-change, lowest accuracy │ │ │ └─ NO → Remove background mode, use when-in-use only │ │ └─ Check: Is stopUpdatingLocation called? │ │ │ ├─ "audio" enabled? │ │ ├─ Audio playing? → Expected │ │ ├─ Audio NOT playing? → Session still active │ │ │ └─ Fix: Deactivate session, use autoShutdownEnabled │ │ └─ Playing silent audio? → Anti-pattern for keeping app alive │ │ └─ Fix: Use proper background API (BGTask) │ │ │ ├─ "fetch" enabled? │ │ └─ Check: Is earliestBeginDate reasonable? (not too frequent) │ │ │ └─ "remote-notification" enabled? │ └─ Expected for push updates, check didReceiveRemoteNotification efficiency │ ├─ Step 2: Check BGTaskScheduler usage │ │ │ ├─ BGAppRefreshTask scheduled too frequently? │ │ └─ Fix: Increase earliestBeginDate interval │ │ │ ├─ BGProcessingTask not using requiresExternalPower? │ │ └─ Fix: Add requiresExternalPower = true for non-urgent work │ │ │ └─ Tasks not completing? (setTaskCompleted not called) │ └─ Fix: Always call setTaskCompleted, implement expirationHandler │ └─ Step 3: Check beginBackgroundTask usage │ ├─ endBackgroundTask called promptly? │ └─ Fix: Call immediately after work completes, not at expiration │ └─ Multiple overlapping background tasks? └─ Fix: Track task IDs, ensure each is ended ``` ### Common Background Drain Patterns | Pattern | Power Profiler Signature | Fix | |---------|-------------------------|-----| | Continuous location | CPU lane + location icon | significant-change | | Audio session leak | CPU lane steady | setActive(false) | | Timer not invalidated | CPU spikes at intervals | invalidate in background | | Polling from background | Network lane at intervals | Push notifications | | BGTask too long | CPU sustained | Faster completion | ### Time-Cost Analysis | Approach | Time | Outcome | |----------|------|---------| | Check Info.plist + BGTask code | 30 min | Finds common issues | | On-device Power Profiler trace | 1-2 hours (real usage) | Captures real behavior | | User-collected trace | Variable | Best for unreproducible issues | --- ## Symptom 4: High Energy Only on Cellular Battery drains faster on cellular than WiFi. ### Diagnosis Decision Tree ``` High battery drain on cellular only? │ ├─ Expected: Cellular radio uses more power than WiFi │ └─ But: Excessive drain indicates optimization opportunity │ ├─ Check URLSession configuration │ │ │ ├─ allowsExpensiveNetworkAccess = true (default)? │ │ └─ Fix: Set to false for non-urgent requests │ │ │ ├─ isDiscretionary = false (default)? │ │ └─ Fix: Set to true for background downloads │ │ │ └─ waitsForConnectivity = false (default)? │ └─ Fix: Set to true to avoid failed connection retries │ ├─ Check request patterns │ │ │ ├─ Many small requests? → High connection overhead │ │ └─ Fix: Batch into fewer larger requests │ │ │ ├─ Polling? → Radio stays active │ │ └─ Fix: Push notifications │ │ │ └─ Large downloads in foreground? → Could wait for WiFi │ └─ Fix: Use background URLSession with discretionary │ └─ Check Low Data Mode handling ├─ Respecting allowsConstrainedNetworkAccess? │ └─ Fix: Set to false for non-essential requests │ └─ Checking ProcessInfo.processInfo.isLowDataModeEnabled? └─ Fix: Reduce payload sizes, defer non-essential transfers ``` ### Time-Cost Analysis | Approach | Time | Outcome | |----------|------|---------| | Review URLSession configs | 15 min | Quick wins | | Add discretionary flags | 30 min | Significant savings | | Convert poll to push | 2-4 hours | Largest impact | --- ## Symptom 5: Energy Spike During Specific Action Noticeable battery drain or heat when performing particular operation. ### Diagnosis Decision Tree ``` Energy spike during specific action? │ ├─ Step 1: Record Power Profiler during action │ └─ Note which subsystem spikes (CPU/GPU/Network/Display) │ ├─ CPU spike? │ │ │ ├─ Is it parsing data? │ │ ├─ Same data parsed repeatedly? │ │ │ └─ Fix: Cache parsed results (lazy var) │ │ └─ Large JSON/XML payload? │ │ └─ Fix: Paginate, stream parse, or use binary format │ │ │ ├─ Is it creating views? │ │ ├─ Many views at once? │ │ │ └─ Fix: Use LazyVStack/LazyHStack │ │ └─ Complex view hierarchies? │ │ └─ Fix: Simplify, use drawingGroup() │ │ │ └─ Is it image processing? │ ├─ On main thread? │ │ └─ Fix: Move to background queue │ └─ No caching? │ └─ Fix: Cache processed images │ ├─ GPU spike? │ │ │ ├─ Starting animation? │ │ └─ Fix: Ensure frame rate appropriate │ │ │ ├─ Showing blur effect? │ │ └─ Fix: Use solid color or pre-rendered blur │ │ │ └─ Complex render? (shadows, masks, many layers) │ └─ Fix: Simplify, use shouldRasterize, cache │ ├─ Network spike? │ │ │ ├─ Large download started? │ │ └─ Fix: Use background URLSession, show progress │ │ │ ├─ Many parallel requests? │ │ └─ Fix: Limit concurrency, batch │ │ │ └─ Retrying failed requests? │ └─ Fix: Exponential backoff, waitsForConnectivity │ └─ Display spike? └─ Unusual unless changing brightness programmatically └─ Fix: Don't modify brightness, let system control ``` ### Time-Cost Analysis | Approach | Time | Outcome | |----------|------|---------| | Power Profiler during action | 5-10 min | Identifies subsystem | | Time Profiler for CPU details | 10-15 min | Identifies function | | Code review without profiling | 1+ hours | May miss actual cause | --- ## Quick Diagnostic Checklist Use this when you need fast answers: ### 30-Second Check - [ ] Device plugged in? (Power metrics show 0) - [ ] Debug build? (Less optimized than release) - [ ] Low Power Mode on? (May affect measurements) ### 5-Minute Check (Power Profiler) - [ ] Which subsystem is dominant? (CPU/GPU/Network/Display) - [ ] Sustained or spiky? - [ ] Foreground or background? ### 15-Minute Investigation - [ ] If CPU: Run Time Profiler to identify function - [ ] If Network: Check request frequency and size - [ ] If GPU: Check animation frame rates - [ ] If Background: Check Info.plist modes ### Common Quick Fixes | Finding | Quick Fix | Time | |---------|-----------|------| | Timer without tolerance | Add `.tolerance = 0.1` | 1 min | | VStack with large ForEach | Change to LazyVStack | 1 min | | allowsExpensiveNetworkAccess = true | Set to false | 1 min | | Missing stopUpdatingLocation | Add stop call | 2 min | | No Dark Mode | Add asset variants | 30 min | | Audio session always active | Add setActive(false) | 5 min | --- ## When to Escalate ### Use `axiom-energy` skill when - Need full audit checklist - Want comprehensive patterns with code - Planning proactive optimization ### Use `axiom-energy-ref` skill when - Need specific API details - Want complete code examples - Implementing from scratch ### Use `energy-auditor` agent when - Want automated codebase scan - Looking for anti-patterns at scale - Pre-release energy audit Run: `/axiom:audit energy` --- **Last Updated**: 2025-12-26 **Platforms**: iOS 26+, iPadOS 26+