mirror of
https://github.com/AdnanHodzic/auto-cpufreq.git
synced 2025-07-24 14:15:20 +02:00
Allow for overriding the CPU turbo setting via CLI and GUI. (#859)
* Allow for overriding the CPU turbo setting via CLI and GUI. * Add Turbo mode override info to README --------- Co-authored-by: JuanR4140 <N/A>
This commit is contained in:
parent
fabeee6ed7
commit
36aca759c4
24
README.md
24
README.md
@ -47,13 +47,15 @@ Example of `auto-cpufreq --stats` CLI output
|
||||
- [Configuring auto-cpufreq](#configuring-auto-cpufreq)
|
||||
- [1: power_helper.py script (Snap package install only)](#1-power_helperpy-script-snap-package-install-only)
|
||||
- [2: `--force` governor override](#2---force-governor-override)
|
||||
- [3: auto-cpufreq config file](#3-auto-cpufreq-config-file)
|
||||
- [3: `--turbo` mode override](#3---turbo-mode-override)
|
||||
- [4: auto-cpufreq config file](#4-auto-cpufreq-config-file)
|
||||
- [Example config file contents](#example-config-file-contents)
|
||||
- [How to run auto-cpufreq](#how-to-run-auto-cpufreq)
|
||||
- [auto-cpufreq modes and options](#auto-cpufreq-modes-and-options)
|
||||
- [monitor](#monitor)
|
||||
- [live](#live)
|
||||
- [overriding governor](#overriding-governor)
|
||||
- [overriding turbo mode](#overriding-turbo-mode)
|
||||
- [Install - auto-cpufreq daemon](#install---auto-cpufreq-daemon)
|
||||
- [Update - auto-cpufreq update](#update---auto-cpufreq-update)
|
||||
- [Remove - auto-cpufreq daemon](#remove---auto-cpufreq-daemon)
|
||||
@ -319,7 +321,15 @@ However, you can override this behaviour by switching to `performance` or `power
|
||||
|
||||
See [`--force` flag](#overriding-governor) for more info.
|
||||
|
||||
### 3: auto-cpufreq config file
|
||||
### 3: `--turbo` mode override
|
||||
|
||||
By default, auto-cpufreq handles CPU turbo mode automatically, enabling it under load and disabling it otherwise to balance performance and efficiency.
|
||||
|
||||
However, you can override this behavior by forcing CPU turbo's mode to `always` or `never`. Setting to `always` keeps turbo mode always enabled, allowing the CPU to reach its maximum frequency at the cost of higher energy use (battery consumption). `never`, on the other hand, keeps turbo mode always disabled, limiting the CPU's maximum frequency to extend battery life.
|
||||
|
||||
See [`--turbo` flag](#overriding-turbo-mode) for more info.
|
||||
|
||||
### 4: auto-cpufreq config file
|
||||
|
||||
You can configure separate profiles for the battery and power supply. These profiles will let you pick which governor to use, as well as how and when turbo boost is enabled. The possible values for turbo boost behavior are `always`, `auto`, and `never`. The default behavior is `auto`, which only activates turbo during high load.
|
||||
|
||||
@ -451,6 +461,9 @@ auto-cpufreq should be run with with one of the following options:
|
||||
- [force=TEXT](#overriding-governor)
|
||||
- Force use of either the "powersave" or "performance" governor, or set to "reset" to go back to normal mode
|
||||
|
||||
- [turbo=TEXT](#overriding-turbo-mode)
|
||||
- Force use of CPU turbo mode, if supported, with "never" or "always", or set to "auto" to automatically handle turbo mode
|
||||
|
||||
- config=TEXT
|
||||
- Use config file at designated path
|
||||
|
||||
@ -492,6 +505,13 @@ Necessary changes are temporarily made to the system over time, but this process
|
||||
Force use of either the "powersave" or "performance" governor, or set to "reset" to go back to normal mode.
|
||||
Please note that any set override will persist even after reboot.
|
||||
|
||||
### Overriding Turbo mode
|
||||
|
||||
`sudo auto-cpufreq --turbo=mode`
|
||||
|
||||
Force use of CPU turbo mode, if supported, with "never" or "always", or set to "auto" to automatically handle turbo mode.
|
||||
Please note that any set override will persist even after reboot.
|
||||
|
||||
### Install - auto-cpufreq daemon
|
||||
|
||||
Necessary changes are made to the system over time and this process will continue across reboots. The daemon is deployed and started as a systemd service. Changes are made automatically and live stats are generated for monitoring purposes.
|
||||
|
@ -26,6 +26,7 @@ from threading import Thread
|
||||
@click.option("--update", is_flag=False, help="Update daemon and package for (permanent) automatic CPU optimizations", flag_value="--update")
|
||||
@click.option("--remove", is_flag=True, help="Remove daemon for (permanent) automatic CPU optimizations")
|
||||
@click.option("--force", is_flag=False, help="Force use of either \"powersave\" or \"performance\" governors. Setting to \"reset\" will go back to normal mode")
|
||||
@click.option("--turbo", is_flag=False, help="Force use of CPU turbo mode, if supported, with \"never\" or \"always\". Setting to \"auto\" automatically handles turbo mode")
|
||||
@click.option("--config", is_flag=False, required=False, help="Use config file at defined path",)
|
||||
@click.option("--stats", is_flag=True, help="View live stats of CPU optimizations made by daemon")
|
||||
@click.option("--get-state", is_flag=True, hidden=True)
|
||||
@ -34,7 +35,7 @@ from threading import Thread
|
||||
@click.option("--debug", is_flag=True, help="Show debug info (include when submitting bugs)")
|
||||
@click.option("--version", is_flag=True, help="Show currently installed version")
|
||||
@click.option("--donate", is_flag=True, help="Support the project")
|
||||
def main(monitor, live, daemon, install, update, remove, force, config, stats, get_state,
|
||||
def main(monitor, live, daemon, install, update, remove, force, turbo, config, stats, get_state,
|
||||
bluetooth_boot_off, bluetooth_boot_on, debug, version, donate):
|
||||
# display info if config file is used
|
||||
config_path = find_config_file(config)
|
||||
@ -58,6 +59,11 @@ def main(monitor, live, daemon, install, update, remove, force, config, stats, g
|
||||
not_running_daemon_check()
|
||||
root_check() # Calling root_check before set_override as it will require sudo access
|
||||
set_override(force) # Calling set override, only if force has some values
|
||||
|
||||
if turbo is not None:
|
||||
not_running_daemon_check()
|
||||
root_check()
|
||||
set_turbo_override(turbo)
|
||||
|
||||
if monitor:
|
||||
root_check()
|
||||
|
@ -47,13 +47,15 @@ powersave_load_threshold = (75 * CPUS) / 100
|
||||
auto_cpufreq_stats_file = None
|
||||
auto_cpufreq_stats_path = None
|
||||
|
||||
# track governor override
|
||||
# track governor override and turbo boost override
|
||||
if IS_INSTALLED_WITH_SNAP:
|
||||
auto_cpufreq_stats_path = Path("/var/snap/auto-cpufreq/current/auto-cpufreq.stats")
|
||||
governor_override_state = Path("/var/snap/auto-cpufreq/current/override.pickle")
|
||||
turbo_override_state = Path("/var/snap/auto-cpufreq/current/turbo-override.pickle")
|
||||
else:
|
||||
auto_cpufreq_stats_path = Path("/var/run/auto-cpufreq.stats")
|
||||
governor_override_state = Path("/opt/auto-cpufreq/override.pickle")
|
||||
turbo_override_state = Path("/opt/auto-cpufreq/turbo-override.pickle")
|
||||
|
||||
def file_stats():
|
||||
global auto_cpufreq_stats_file
|
||||
@ -76,6 +78,22 @@ def set_override(override):
|
||||
print("Governor override removed")
|
||||
elif override is not None: print("Invalid option.\nUse force=performance, force=powersave, or force=reset")
|
||||
|
||||
def get_turbo_override():
|
||||
if os.path.isfile(turbo_override_state):
|
||||
with open(turbo_override_state, "rb") as store: return load(store)
|
||||
else: return "auto"
|
||||
|
||||
def set_turbo_override(override):
|
||||
if override in ["never", "always"]:
|
||||
with open(turbo_override_state, "wb") as store:
|
||||
dump(override, store)
|
||||
print(f"Set turbo boost override to {override}")
|
||||
elif override == "auto":
|
||||
if os.path.isfile(turbo_override_state):
|
||||
os.remove(turbo_override_state)
|
||||
print("Turbo override removed")
|
||||
elif override is not None: print("Invalid option.\nUse turbo=always, turbo=never, or turbo=auto")
|
||||
|
||||
# get distro name
|
||||
try: dist_name = distro.id()
|
||||
except PermissionError:
|
||||
@ -202,6 +220,14 @@ def turbo(value: bool = None):
|
||||
else:
|
||||
print("Warning: CPU turbo is not available")
|
||||
return False
|
||||
|
||||
turbo_override = get_turbo_override()
|
||||
if turbo_override != "auto":
|
||||
# Set the value in respect to if turbo override is enabled or not.
|
||||
if turbo_override == "always":
|
||||
value = True
|
||||
elif turbo_override == "never":
|
||||
value = False
|
||||
|
||||
if value is not None:
|
||||
try: f.write_text(f"{int(value ^ inverse)}\n")
|
||||
@ -559,6 +585,7 @@ def set_powersave():
|
||||
cpuload, load1m= get_load()
|
||||
|
||||
auto = conf["battery"]["turbo"] if conf.has_option("battery", "turbo") else "auto"
|
||||
auto = get_turbo_override() if (get_turbo_override() != "auto") else auto # Override turbo if override file is present, otherwise stick to config.
|
||||
|
||||
if auto == "always":
|
||||
print("Configuration file enforces turbo boost")
|
||||
@ -670,6 +697,7 @@ def set_performance():
|
||||
|
||||
cpuload, load1m = get_load()
|
||||
auto = conf["charger"]["turbo"] if conf.has_option("charger", "turbo") else "auto"
|
||||
auto = get_turbo_override() if (get_turbo_override() != "auto") else auto # Override turbo if override file is present, otherwise stick to config.
|
||||
|
||||
if auto == "always":
|
||||
print("Configuration file enforces turbo boost")
|
||||
|
@ -9,7 +9,8 @@ from threading import Thread
|
||||
|
||||
from auto_cpufreq.core import check_for_update, is_running
|
||||
from auto_cpufreq.globals import GITHUB, IS_INSTALLED_WITH_SNAP
|
||||
from auto_cpufreq.gui.objects import CPUFreqStatsLabel, CurrentGovernorBox, DaemonNotRunningView, DropDownMenu, RadioButtonView, SystemStatsLabel, UpdateDialog
|
||||
from auto_cpufreq.gui.objects import CPUFreqStatsLabel, CurrentGovernorBox, DaemonNotRunningView, DropDownMenu, RadioButtonView, CPUTurboOverride, SystemStatsLabel, UpdateDialog
|
||||
from auto_cpufreq.gui.objects import get_stats
|
||||
|
||||
if IS_INSTALLED_WITH_SNAP:
|
||||
CSS_FILE = "/snap/auto-cpufreq/current/style.css"
|
||||
@ -48,6 +49,8 @@ class ToolWindow(Gtk.Window):
|
||||
self.currentgovernor = CurrentGovernorBox()
|
||||
self.vbox_right.pack_start(self.currentgovernor, False, False, 0)
|
||||
self.vbox_right.pack_start(RadioButtonView(), False, False, 0)
|
||||
if "Warning: CPU turbo is not available" not in get_stats():
|
||||
self.vbox_right.pack_start(CPUTurboOverride(), False, False, 0)
|
||||
|
||||
self.cpufreqstats = CPUFreqStatsLabel()
|
||||
self.vbox_right.pack_start(self.cpufreqstats, False, False, 0)
|
||||
|
@ -9,7 +9,7 @@ from os.path import isfile
|
||||
from platform import python_version
|
||||
from subprocess import getoutput, PIPE, run
|
||||
|
||||
from auto_cpufreq.core import distro_info, get_formatted_version, get_override, sysinfo
|
||||
from auto_cpufreq.core import distro_info, get_formatted_version, get_override, get_turbo_override, sysinfo
|
||||
from auto_cpufreq.globals import GITHUB, IS_INSTALLED_WITH_AUR, IS_INSTALLED_WITH_SNAP
|
||||
|
||||
PKEXEC_ERROR = "Error executing command as another user: Not authorized\n\nThis incident has been reported.\n"
|
||||
@ -78,6 +78,50 @@ class RadioButtonView(Gtk.Box):
|
||||
if self.set_by_app: self.set_by_app = False
|
||||
self.default.set_active(True)
|
||||
|
||||
class CPUTurboOverride(Gtk.Box):
|
||||
def __init__(self):
|
||||
super().__init__(orientation=Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
self.set_hexpand(True)
|
||||
self.hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
|
||||
|
||||
self.label = Gtk.Label("CPU Turbo Override", name="bold")
|
||||
|
||||
self.auto = Gtk.RadioButton.new_with_label_from_widget(None, "Auto")
|
||||
self.auto.connect("toggled", self.on_button_toggled, "auto")
|
||||
self.auto.set_halign(Gtk.Align.END)
|
||||
self.never = Gtk.RadioButton.new_with_label_from_widget(self.auto, "Never")
|
||||
self.never.connect("toggled", self.on_button_toggled, "never")
|
||||
self.never.set_halign(Gtk.Align.END)
|
||||
self.always = Gtk.RadioButton.new_with_label_from_widget(self.auto, "Always")
|
||||
self.always.connect("toggled", self.on_button_toggled, "always")
|
||||
self.always.set_halign(Gtk.Align.END)
|
||||
|
||||
self.set_by_app = True
|
||||
self.set_selected()
|
||||
|
||||
self.pack_start(self.label, False, False, 0)
|
||||
self.pack_start(self.auto, True, True, 0)
|
||||
self.pack_start(self.never, True, True, 0)
|
||||
self.pack_start(self.always, True, True, 0)
|
||||
|
||||
def on_button_toggled(self, button, override):
|
||||
if button.get_active():
|
||||
if not self.set_by_app:
|
||||
result = run(f"pkexec auto-cpufreq --turbo={override}", shell=True, stdout=PIPE, stderr=PIPE)
|
||||
if result.stderr.decode() == PKEXEC_ERROR: self.set_selected()
|
||||
else: self.set_by_app = False
|
||||
|
||||
def set_selected(self):
|
||||
override = get_turbo_override()
|
||||
match override:
|
||||
case "never": self.never.set_active(True)
|
||||
case "always": self.always.set_active(True)
|
||||
case "auto":
|
||||
# because this is the default button, it does not trigger the callback when set by the app
|
||||
if self.set_by_app: self.set_by_app = False
|
||||
self.auto.set_active(True)
|
||||
|
||||
class CurrentGovernorBox(Gtk.Box):
|
||||
def __init__(self):
|
||||
super().__init__(spacing=25)
|
||||
|
Loading…
x
Reference in New Issue
Block a user