Feature: Adaptive Frame Rate and Battery Management #1

Open
opened 2025-12-13 22:49:27 +00:00 by siennathesane · 0 comments
siennathesane commented 2025-12-13 22:49:27 +00:00 (Migrated from github.com)

User Story

As a Marathon application user
I want the app to intelligently manage performance based on power source and thermal state
So that I can enjoy maximum performance when plugged in while preserving battery life and preventing thermal throttling when on battery power

Background

Currently, the executor runs in unbounded mode (ControlFlow::Poll) which provides maximum performance but drains battery quickly and can cause thermal issues on laptops and mobile devices. We need adaptive behavior that balances performance with power efficiency.

Acceptance Criteria

Scenario 1: Plugged In Mode - Maximum Performance

Given the device is connected to external power
When the application is running
Then the executor should run in unbounded mode
And both the window event loop and ECS should run without frame rate caps
And GPU rendering should proceed at maximum rate

Scenario 2: Battery Mode - Efficient Operation

Given the device is running on battery power
When the application is running
Then the executor should cap the frame rate at 60fps
And the ECS tick rate should be reduced to 30-60Hz (configurable)
And unnecessary redraws should be skipped

Scenario 3: Thermal Throttling - Prevent Overheating

Given the device temperature exceeds safe thresholds
When the application is running
Then the executor should reduce frame rate below battery mode caps
And the system should log thermal throttling events
And performance should gradually restore as temperature normalizes

Scenario 4: Power Source Change - Seamless Transition

Given the application is running in battery mode at 60fps
When the user plugs in external power
Then the executor should transition to unbounded mode within 1 second
And no frames should be dropped during transition
And no visible artifacts or stuttering should occur

Scenario 5: Configuration - User Control

Given a user wants custom performance settings
When they configure frame rate caps in settings
Then the executor should respect user-defined limits
And configuration should persist across app restarts
And configuration should override default battery/plugged behavior if specified

Technical Requirements

Power Detection

  • Detect power source on macOS (IOKit)
  • Detect power source on iOS (UIDevice batteryState)
  • Detect power source on Windows (Windows API)
  • Detect power source on Linux (upower/sysfs)
  • Subscribe to power source change notifications

Thermal Monitoring

  • Monitor CPU/GPU temperature on macOS (IOKit sensors)
  • Monitor thermal state on iOS (ProcessInfo.thermalState)
  • Monitor thermal state on Windows (WMI)
  • Monitor thermal state on Linux (hwmon/thermal zones)
  • Define safe temperature thresholds per platform

Frame Rate Limiting

  • Implement frame pacing with vsync when capped
  • Implement ECS tick rate decoupling from render rate
  • Add configurable FPS targets (30, 60, 120, 144, unlimited)
  • Measure actual frame times and adjust dynamically
  • Log performance metrics for debugging

Configuration

  • Add `ExecutorConfig` struct with battery/power/thermal settings
  • Serialize/deserialize config to TOML
  • Add runtime config update without restart
  • Add command-line flags for testing (--force-battery-mode, --fps-cap=N)

Definition of Done

  • Power source detection works on all target platforms (macOS, iOS, Windows, Linux)
  • Frame rate capping reduces battery drain by at least 40% compared to unbounded
  • Thermal throttling prevents sustained temperatures above safe thresholds
  • Transition between modes is imperceptible to users (<100ms latency)
  • Configuration persists and applies correctly on app restart
  • Unit tests cover power detection logic
  • Integration tests verify frame rate limiting accuracy (±5fps)
  • Documentation updated with battery management guide
  • TODO comments at `crates/app/src/executor.rs:319-322` are resolved

Implementation Notes

Current Code Location

The executor unbounded mode is implemented in `crates/app/src/executor.rs`:

  • Line 325: `event_loop.set_control_flow(ControlFlow::Poll);`
  • Lines 319-322: TODO comment for battery detection

Suggested Architecture

```rust
pub struct ExecutorConfig {
/// Frame rate cap when on battery (0 = unlimited)
pub battery_fps_cap: u32,

/// Frame rate cap when plugged in (0 = unlimited)
pub power_fps_cap: u32,

/// ECS tick rate independent of render rate
pub ecs_tick_rate: u32,

/// Enable thermal throttling
pub enable_thermal_throttling: bool,

/// Temperature threshold for throttling (Celsius)
pub thermal_threshold_celsius: f32,

}

pub struct PowerMonitor {
current_source: PowerSource,
thermal_state: ThermalState,
// Platform-specific fields
}

enum PowerSource {
Battery { percent: f32 },
ExternalPower,
Unknown,
}

enum ThermalState {
Nominal,
Fair,
Serious,
Critical,
}
```

  • Depends on: None
  • Blocks: Mobile platform support
  • Related: Performance optimization, Mobile battery life

Assignee: @siennathesane

## User Story **As a** Marathon application user **I want** the app to intelligently manage performance based on power source and thermal state **So that** I can enjoy maximum performance when plugged in while preserving battery life and preventing thermal throttling when on battery power ## Background Currently, the executor runs in unbounded mode (`ControlFlow::Poll`) which provides maximum performance but drains battery quickly and can cause thermal issues on laptops and mobile devices. We need adaptive behavior that balances performance with power efficiency. ## Acceptance Criteria ### Scenario 1: Plugged In Mode - Maximum Performance ```gherkin Given the device is connected to external power When the application is running Then the executor should run in unbounded mode And both the window event loop and ECS should run without frame rate caps And GPU rendering should proceed at maximum rate ``` ### Scenario 2: Battery Mode - Efficient Operation ```gherkin Given the device is running on battery power When the application is running Then the executor should cap the frame rate at 60fps And the ECS tick rate should be reduced to 30-60Hz (configurable) And unnecessary redraws should be skipped ``` ### Scenario 3: Thermal Throttling - Prevent Overheating ```gherkin Given the device temperature exceeds safe thresholds When the application is running Then the executor should reduce frame rate below battery mode caps And the system should log thermal throttling events And performance should gradually restore as temperature normalizes ``` ### Scenario 4: Power Source Change - Seamless Transition ```gherkin Given the application is running in battery mode at 60fps When the user plugs in external power Then the executor should transition to unbounded mode within 1 second And no frames should be dropped during transition And no visible artifacts or stuttering should occur ``` ### Scenario 5: Configuration - User Control ```gherkin Given a user wants custom performance settings When they configure frame rate caps in settings Then the executor should respect user-defined limits And configuration should persist across app restarts And configuration should override default battery/plugged behavior if specified ``` ## Technical Requirements ### Power Detection - [ ] Detect power source on macOS (IOKit) - [ ] Detect power source on iOS (UIDevice batteryState) - [ ] Detect power source on Windows (Windows API) - [ ] Detect power source on Linux (upower/sysfs) - [ ] Subscribe to power source change notifications ### Thermal Monitoring - [ ] Monitor CPU/GPU temperature on macOS (IOKit sensors) - [ ] Monitor thermal state on iOS (ProcessInfo.thermalState) - [ ] Monitor thermal state on Windows (WMI) - [ ] Monitor thermal state on Linux (hwmon/thermal zones) - [ ] Define safe temperature thresholds per platform ### Frame Rate Limiting - [ ] Implement frame pacing with vsync when capped - [ ] Implement ECS tick rate decoupling from render rate - [ ] Add configurable FPS targets (30, 60, 120, 144, unlimited) - [ ] Measure actual frame times and adjust dynamically - [ ] Log performance metrics for debugging ### Configuration - [ ] Add \`ExecutorConfig\` struct with battery/power/thermal settings - [ ] Serialize/deserialize config to TOML - [ ] Add runtime config update without restart - [ ] Add command-line flags for testing (--force-battery-mode, --fps-cap=N) ## Definition of Done - [ ] Power source detection works on all target platforms (macOS, iOS, Windows, Linux) - [ ] Frame rate capping reduces battery drain by at least 40% compared to unbounded - [ ] Thermal throttling prevents sustained temperatures above safe thresholds - [ ] Transition between modes is imperceptible to users (<100ms latency) - [ ] Configuration persists and applies correctly on app restart - [ ] Unit tests cover power detection logic - [ ] Integration tests verify frame rate limiting accuracy (±5fps) - [ ] Documentation updated with battery management guide - [ ] TODO comments at \`crates/app/src/executor.rs:319-322\` are resolved ## Implementation Notes ### Current Code Location The executor unbounded mode is implemented in \`crates/app/src/executor.rs\`: - Line 325: \`event_loop.set_control_flow(ControlFlow::Poll);\` - Lines 319-322: TODO comment for battery detection ### Suggested Architecture \`\`\`rust pub struct ExecutorConfig { /// Frame rate cap when on battery (0 = unlimited) pub battery_fps_cap: u32, /// Frame rate cap when plugged in (0 = unlimited) pub power_fps_cap: u32, /// ECS tick rate independent of render rate pub ecs_tick_rate: u32, /// Enable thermal throttling pub enable_thermal_throttling: bool, /// Temperature threshold for throttling (Celsius) pub thermal_threshold_celsius: f32, } pub struct PowerMonitor { current_source: PowerSource, thermal_state: ThermalState, // Platform-specific fields } enum PowerSource { Battery { percent: f32 }, ExternalPower, Unknown, } enum ThermalState { Nominal, Fair, Serious, Critical, } \`\`\` ### Related Issues - Depends on: None - Blocks: Mobile platform support - Related: Performance optimization, Mobile battery life --- **Assignee:** @siennathesane
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: studio/marathon#1