Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Force use of powersave or performance governors #476

Merged
merged 15 commits into from
Feb 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ auto-cpufreq is looking for [co-maintainers & open source developers to help sha
* [auto-cpufreq modes and options](https://github.com/AdnanHodzic/auto-cpufreq/#auto-cpufreq-modes-and-options)
* [monitor](https://github.com/AdnanHodzic/auto-cpufreq/#monitor)
* [live](https://github.com/AdnanHodzic/auto-cpufreq/#live)
* [overriding governor](https://github.com/AdnanHodzic/auto-cpufreq/#overriding-governor)
* [Install - auto-cpufreq daemon](https://github.com/AdnanHodzic/auto-cpufreq/#install---auto-cpufreq-daemon)
* [Remove - auto-cpufreq daemon](https://github.com/AdnanHodzic/auto-cpufreq/#remove---auto-cpufreq-daemon)
* [stats](https://github.com/AdnanHodzic/auto-cpufreq/#stats)
Expand Down Expand Up @@ -207,7 +208,10 @@ auto-cpufreq should be run with with one of the following options:
* [stats](https://github.com/AdnanHodzic/auto-cpufreq/#stats)
- View live stats of CPU optimizations made by daemon

* config TEXT
* [force=TEXT](https://github.com/AdnanHodzic/auto-cpufreq/#overriding-governor)
- Force use of either the "powersave" or "performance" governor. Setting to "reset" goes back to normal mode

* config=TEXT
- Use config file at defined path

* debug
Expand Down Expand Up @@ -238,6 +242,13 @@ No changes are made to the system, and is solely made for demonstration purposes

Necessary changes are temporarily made to the system which are lost with system reboot. This mode is made to evaluate what the system would behave with auto-cpufreq permanently running on the system.

### Overriding governor

`sudo auto-cpufreq --force=governor`

Force use of either "powersave" or "performance" governors. Setting to "reset" will go back to normal mode
Please note that any set override will persist even after reboot.

### Install - auto-cpufreq daemon

Necessary changes are made to the system for auto-cpufreq CPU optimization to persist across reboots. The daemon is deployed and then started as a systemd service. Changes are made automatically and live stats are generated for monitoring purposes.
Expand Down
75 changes: 55 additions & 20 deletions auto_cpufreq/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import distro
import time
import click
import pickle
import warnings
import configparser
import pkg_resources
Expand Down Expand Up @@ -57,6 +58,9 @@
auto_cpufreq_stats_path = None
auto_cpufreq_stats_file = None

# track governor override
STORE = "/opt/auto-cpufreq/venv/override.pickle"

if os.getenv("PKG_MARKER") == "SNAP":
auto_cpufreq_stats_path = Path("/var/snap/auto-cpufreq/current/auto-cpufreq.stats")
else:
Expand All @@ -71,7 +75,6 @@ def file_stats():
auto_cpufreq_stats_file = open(auto_cpufreq_stats_path, "w")
sys.stdout = auto_cpufreq_stats_file


def get_config(config_file=""):
if not hasattr(get_config, "config"):
get_config.config = configparser.ConfigParser()
Expand All @@ -82,6 +85,26 @@ def get_config(config_file=""):

return get_config.config

def get_override():
if os.path.isfile(STORE):
with open(STORE, "rb") as store:
return pickle.load(store)
else:
return "default"

def set_override(override):
if override in ["powersave", "performance"]:
with open(STORE, "wb") as store:
pickle.dump(override, store)
print(f"Set governor override to {override}")
elif override == "reset":
if os.path.isfile(STORE):
os.remove(STORE)
print("Governor override removed")
elif override is not None:
print("Invalid option.\nUse force=performance, force=powersave, or force=reset")



# get distro name
try:
Expand Down Expand Up @@ -314,14 +337,6 @@ def footer(l=79):
print("\n" + "-" * l + "\n")


def daemon_not_found():
print("\n" + "-" * 32 + " Daemon check " + "-" * 33 + "\n")
print(
"ERROR:\n\nDaemon not enabled, must run install first, i.e: \nsudo auto-cpufreq --install"
)
footer()


def deploy_complete_msg():
print("\n" + "-" * 17 + " auto-cpufreq daemon installed and running " + "-" * 17 + "\n")
print("To view live stats, run:\nauto-cpufreq --stats")
Expand Down Expand Up @@ -404,7 +419,7 @@ def deploy_daemon_performance():


# remove auto-cpufreq daemon
def remove():
def remove_daemon():

# check if auto-cpufreq is installed
if not os.path.exists("/usr/local/bin/auto-cpufreq-remove"):
Expand All @@ -426,6 +441,10 @@ def remove():
# remove auto-cpufreq-remove
os.remove("/usr/local/bin/auto-cpufreq-remove")

# delete override pickle if it exists
if os.path.exists(STORE):
os.remove(STORE)

# delete stats file
if auto_cpufreq_stats_path.exists():
if auto_cpufreq_stats_file is not None:
Expand Down Expand Up @@ -580,6 +599,8 @@ def set_powersave():
else:
gov = get_avail_powersave()
print(f'Setting to use: "{gov}" governor')
if get_override() != "default":
print("Warning: governor overwritten using `--force` flag.")
run(f"cpufreqctl.auto-cpufreq --governor --set={gov}", shell=True)
if (
Path("/sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference").exists()
Expand Down Expand Up @@ -786,6 +807,8 @@ def set_performance():
gov = get_avail_performance()

print(f'Setting to use: "{gov}" governor')
if get_override() != "default":
print("Warning: governor overwritten using `--force` flag.")
run(
f"cpufreqctl.auto-cpufreq --governor --set={gov}",
shell=True,
Expand Down Expand Up @@ -997,7 +1020,12 @@ def set_autofreq():
print("\n" + "-" * 28 + " CPU frequency scaling " + "-" * 28 + "\n")

# determine which governor should be used
if charging():
override = get_override()
if override == "powersave":
set_powersave()
elif override == "performance":
set_performance()
elif charging():
print("Battery is: charging\n")
set_performance()
else:
Expand Down Expand Up @@ -1149,20 +1177,12 @@ def sysinfo():
print("\nCPU fan speed:", psutil.sensors_fans()[current_fan][0].current, "RPM")


def no_stats_msg():
print("\n" + "-" * 29 + " auto-cpufreq stats " + "-" * 30 + "\n")
print(
'ERROR: auto-cpufreq stats are missing.\n\nMake sure to run: "auto-cpufreq --install" first'
)


# read stats func
def read_stats():
# read stats
if os.path.isfile(auto_cpufreq_stats_path):
call(["tail", "-n 50", "-f", str(auto_cpufreq_stats_path)], stderr=DEVNULL)
else:
no_stats_msg()
footer()


Expand All @@ -1187,12 +1207,27 @@ def daemon_running_msg():
)
footer()

def daemon_not_running_msg():
print("\n" + "-" * 24 + " auto-cpufreq not running " + "-" * 30 + "\n")
print(
"ERROR: auto-cpufreq is not running in daemon mode.\n\nMake sure to run \"sudo auto-cpufreq --install\" first"
)
footer()

# check if auto-cpufreq --daemon is running
def running_daemon():
def running_daemon_check():
if is_running("auto-cpufreq", "--daemon"):
daemon_running_msg()
exit(1)
elif os.getenv("PKG_MARKER") == "SNAP" and dcheck == "enabled":
daemon_running_msg()
exit(1)

# check if auto-cpufreq --daemon is not running
def not_running_daemon_check():
if not is_running("auto-cpufreq", "--daemon"):
daemon_not_running_msg()
exit(1)
elif os.getenv("PKG_MARKER") == "SNAP" and dcheck == "disabled":
daemon_not_running_msg()
exit(1)
36 changes: 24 additions & 12 deletions bin/auto-cpufreq
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ from auto_cpufreq.power_helper import *
@click.command()
@click.option("--monitor", is_flag=True, help="Monitor and see suggestions for CPU optimizations")
@click.option("--live", is_flag=True, help="Monitor and make (temp.) suggested CPU optimizations")
@click.option(
"--install/--remove",
default=True,
help="Install/remove daemon for (permanent) automatic CPU optimizations",
)
@click.option("--install", is_flag=True, help="Install daemon for (permanent) automatic CPU optimizations")
@click.option("--remove", is_flag=True, help="Remove daemon for (permanent) automatic CPU optimizations")

@click.option("--install_performance", is_flag=True, help="Install daemon in \"performance\" mode, reference:\n https://bit.ly/3bjVZW1")
@click.option("--stats", is_flag=True, help="View live stats of CPU optimizations made by daemon")
@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("--get-state", is_flag=True, hidden=True)
@click.option(
"--config",
is_flag=False,
Expand All @@ -36,16 +36,23 @@ from auto_cpufreq.power_helper import *
@click.option("--donate", is_flag=True, help="Support the project")
@click.option("--log", is_flag=True, hidden=True)
@click.option("--daemon", is_flag=True, hidden=True)
def main(config, daemon, debug, install, install_performance, live, log, monitor, stats, version, donate):
def main(config, daemon, debug, install, remove, install_performance, live, log, monitor, stats, version, donate, force, get_state):

# display info if config file is used
def config_info_dialog():
if get_config(config) and hasattr(get_config, "using_cfg_file"):
print("\nUsing settings defined in " + config + " file")

# set governor override unless None or invalid
if force is not None:
not_running_daemon_check()
set_override(force)

if len(sys.argv) == 1:

print("\n" + "-" * 32 + " auto-cpufreq " + "-" * 33 + "\n")
print("Automatic CPU speed & power optimizer for Linux")

print("\nExample usage:\nauto-cpufreq --monitor")
print("\n-----\n")

Expand Down Expand Up @@ -92,7 +99,7 @@ def main(config, daemon, debug, install, install_performance, live, log, monitor
tlp_service_detect()
while True:
time.sleep(1)
running_daemon()
running_daemon_check()
footer()
gov_check()
cpufreqctl()
Expand All @@ -114,7 +121,7 @@ def main(config, daemon, debug, install, install_performance, live, log, monitor
tlp_service_detect()
while True:
try:
running_daemon()
running_daemon_check()
footer()
gov_check()
cpufreqctl()
Expand All @@ -127,6 +134,7 @@ def main(config, daemon, debug, install, install_performance, live, log, monitor
print("")
sys.exit()
elif stats:
not_running_daemon_check()
config_info_dialog()
print('\nNote: You can quit stats mode by pressing "ctrl+c"')
if os.getenv("PKG_MARKER") == "SNAP":
Expand All @@ -138,6 +146,10 @@ def main(config, daemon, debug, install, install_performance, live, log, monitor
read_stats()
elif log:
deprecated_log_msg()
elif get_state:
not_running_daemon_check()
override = get_override()
print(override)
elif debug:
# ToDo: add status of GNOME Power Profile service status
config_info_dialog()
Expand Down Expand Up @@ -181,14 +193,14 @@ def main(config, daemon, debug, install, install_performance, live, log, monitor
"Reference: https://github.com/AdnanHodzic/auto-cpufreq#configuring-auto-cpufreq\n")
else:
root_check()
running_daemon()
running_daemon_check()
gov_check()
deploy_daemon_performance()
deploy_complete_msg()
elif install:
if os.getenv("PKG_MARKER") == "SNAP":
root_check()
running_daemon()
running_daemon_check()
gnome_power_detect_snap()
tlp_service_detect_snap()
bluetooth_notif_snap()
Expand All @@ -198,7 +210,7 @@ def main(config, daemon, debug, install, install_performance, live, log, monitor
deploy_complete_msg()
else:
root_check()
running_daemon()
running_daemon_check()
gov_check()
deploy_daemon()
deploy_complete_msg()
Expand All @@ -218,7 +230,7 @@ def main(config, daemon, debug, install, install_performance, live, log, monitor
remove_complete_msg()
else:
root_check()
remove()
remove_daemon()
remove_complete_msg()


Expand Down