From eb1658949dae99b0592734cc38b5c8a2c447fdbc Mon Sep 17 00:00:00 2001 From: Martin Lutonsky Date: Wed, 27 May 2026 12:41:36 +0200 Subject: [PATCH] idle-power-manager: restore profile active before idle, not a fixed one Capture the active tuned profile right before each switch to the idle profile and restore exactly that on wake, instead of locking in a single profile auto-detected once at startup. This restores whatever mode the user was on (e.g. balanced) and survives mid-session profile changes. PERFORMANCE_PROFILE now forces a fixed profile on wake rather than being the storage slot; unset (default) it remembers and restores. Co-Authored-By: Claude Opus 4.7 --- README.md | 9 +++---- idle-power-manager.sh | 56 ++++++++++++++++++++++++++++--------------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 122007c..46efd52 100644 --- a/README.md +++ b/README.md @@ -182,9 +182,10 @@ ln -s "$PWD/git-commit-msg" ~/.local/bin/git-commit-msg Monitors user activity via GNOME Mutter DBus (Wayland-native, no sudo needed). Switches to a powersave [tuned](https://tuned-project.org/) profile after a -configurable idle timeout and restores the performance profile as soon as -activity is detected. The performance profile is auto-detected from the active -tuned profile at startup. +configurable idle timeout. The profile that was active right before going idle +is remembered and restored as soon as activity is detected — so whatever mode +you were using (e.g. `balanced`) comes back on wake. Set `PERFORMANCE_PROFILE` +to force a fixed profile instead. **Requirements:** `gdbus` (glib2), `tuned` + `tuned-adm`, GNOME session (Wayland), `wheel` group membership @@ -202,7 +203,7 @@ All settings are controlled via environment variables: | Variable | Default | Description | |----------------------|------------------------------------------------|-------------------------------------------------| | `IDLE_THRESHOLD_MINS`| `15` | Minutes of inactivity before switching profiles | -| `PERFORMANCE_PROFILE`| auto-detected from current tuned profile | Profile to restore when activity is detected | +| `PERFORMANCE_PROFILE`| remembered profile from before idle | Force a fixed profile on wake instead of restoring | | `IDLE_PROFILE` | `powersave` | Profile to apply when idle | | `CHECK_INTERVAL` | `30` | Seconds between idle checks | | `WAKE_THRESHOLD_SECS`| `3` | Idle must drop below this to count as "woke up" | diff --git a/idle-power-manager.sh b/idle-power-manager.sh index 1d693d2..88409dc 100755 --- a/idle-power-manager.sh +++ b/idle-power-manager.sh @@ -2,9 +2,10 @@ # idle-power-manager.sh — automatic CPU power profile manager based on idle detection # # Monitors user activity via GNOME Mutter DBus (Wayland-native, no sudo needed). -# Switches to a powersave tuned profile after a configurable idle timeout and -# restores the performance profile as soon as activity is detected. -# Performance profile is auto-detected at startup from the current tuned profile. +# Switches to a powersave tuned profile after a configurable idle timeout. The +# profile that was active right before going idle is remembered and restored as +# soon as activity is detected, so whatever mode you were on (e.g. balanced) +# comes back on wake. Setting PERFORMANCE_PROFILE forces a fixed profile instead. # # Requirements: # gdbus - DBus CLI tool (glib2 package, usually pre-installed on GNOME) @@ -20,7 +21,8 @@ # # Configuration (environment variables): # IDLE_THRESHOLD_MINS - minutes of inactivity before switching to idle profile (default: 15) -# PERFORMANCE_PROFILE - tuned profile to restore on activity (default: auto-detected) +# PERFORMANCE_PROFILE - force this tuned profile on activity instead of restoring +# the one active before idle (default: remember & restore) # IDLE_PROFILE - tuned profile to use when idle (default: powersave) # CHECK_INTERVAL - seconds between idle checks (default: 30) # WAKE_THRESHOLD_SECS - idle must drop below this to count as "woke up" (default: 3) @@ -129,19 +131,26 @@ mkdir -p "$(dirname "$LOG_FILE")" log "INFO" "Starting idle-power-manager (threshold: ${IDLE_THRESHOLD_MINS}m, check every: ${CHECK_INTERVAL}s)" -# Auto-detect performance profile: use current profile at startup (unless it's already powersave) +# PERFORMANCE_PROFILE (if set) forces a fixed profile on wake. Otherwise the +# profile active right before each idle switch is remembered and restored. PERFORMANCE_PROFILE="${PERFORMANCE_PROFILE:-}" -if [[ -z "$PERFORMANCE_PROFILE" ]]; then - startup_profile=$(get_current_profile) - if [[ "$startup_profile" == "$IDLE_PROFILE" ]]; then - # Was left in powersave from a previous run, use a sane default - PERFORMANCE_PROFILE="throughput-performance" - log "WARN" "System was already in idle profile at startup, defaulting performance profile to: $PERFORMANCE_PROFILE" - else - PERFORMANCE_PROFILE="$startup_profile" - fi + +# Fallback used only when the active profile can't be read, or is already the idle +# profile at the moment we switch (e.g. left in powersave by a crashed run). +RESTORE_FALLBACK="throughput-performance" + +# Seed the restore target from the current profile at startup; it is refreshed +# right before each switch to the idle profile. +restore_profile=$(get_current_profile) +if [[ -z "$restore_profile" || "$restore_profile" == "$IDLE_PROFILE" ]]; then + restore_profile="$RESTORE_FALLBACK" +fi + +if [[ -n "$PERFORMANCE_PROFILE" ]]; then + log "INFO" "Performance profile (forced): $PERFORMANCE_PROFILE | Idle profile: $IDLE_PROFILE" +else + log "INFO" "Restore profile (remembered): $restore_profile | Idle profile: $IDLE_PROFILE" fi -log "INFO" "Performance profile: $PERFORMANCE_PROFILE | Idle profile: $IDLE_PROFILE" wait_for_session_bus || exit 1 @@ -162,16 +171,25 @@ while true; do if [[ "$state" == "active" ]] && (( idle_ms >= IDLE_THRESHOLD_MS )); then idle_mins=$(( idle_secs / 60 )) - log "INFO" "Idle for ${idle_mins}m ${idle_secs}s — switching to $IDLE_PROFILE" + # Remember the profile active right now so we can restore it on wake + # (unless an explicit PERFORMANCE_PROFILE override is in effect). + if [[ -z "$PERFORMANCE_PROFILE" ]]; then + current_profile=$(get_current_profile) + if [[ -n "$current_profile" && "$current_profile" != "$IDLE_PROFILE" ]]; then + restore_profile="$current_profile" + fi + fi + log "INFO" "Idle for ${idle_mins}m ${idle_secs}s — switching to $IDLE_PROFILE (restore on wake: ${PERFORMANCE_PROFILE:-$restore_profile})" if switch_profile "$IDLE_PROFILE"; then log "INFO" "Switched to $IDLE_PROFILE" state="idle" fi elif [[ "$state" == "idle" ]] && (( idle_ms < WAKE_THRESHOLD_MS )); then - log "INFO" "User activity detected (idle dropped to ${idle_secs}s) — restoring $PERFORMANCE_PROFILE" - if switch_profile "$PERFORMANCE_PROFILE"; then - log "INFO" "Restored to $PERFORMANCE_PROFILE" + target_profile="${PERFORMANCE_PROFILE:-$restore_profile}" + log "INFO" "User activity detected (idle dropped to ${idle_secs}s) — restoring $target_profile" + if switch_profile "$target_profile"; then + log "INFO" "Restored to $target_profile" state="active" fi fi