diff --git a/auto_cpufreq/core.py b/auto_cpufreq/core.py index bda532f9..f2831d12 100755 --- a/auto_cpufreq/core.py +++ b/auto_cpufreq/core.py @@ -4,6 +4,7 @@ import os import platform as pl +import shutil import sys import psutil import distro @@ -15,7 +16,7 @@ import importlib.metadata from math import isclose from pathlib import Path -from shutil import copy +from shutil import which from subprocess import getoutput, call, run, check_output, DEVNULL import requests import re @@ -66,9 +67,12 @@ # track governor override if os.getenv("PKG_MARKER") == "SNAP": governor_override_state = Path("/var/snap/auto-cpufreq/current/override.pickle") - auto_cpufreq_stats_path = Path("/var/snap/auto-cpufreq/current/auto-cpufreq.stats") else: governor_override_state = Path("/opt/auto-cpufreq/override.pickle") + +if os.getenv("PKG_MARKER") == "SNAP": + auto_cpufreq_stats_path = Path("/var/snap/auto-cpufreq/current/auto-cpufreq.stats") +else: auto_cpufreq_stats_path = Path("/var/run/auto-cpufreq.stats") # daemon check @@ -85,7 +89,8 @@ def get_override(): if os.path.isfile(governor_override_state): with open(governor_override_state, "rb") as store: return pickle.load(store) - else: return "default" + else: + return "default" def set_override(override): if override in ["powersave", "performance"]: @@ -102,41 +107,52 @@ def set_override(override): # get distro name -try: dist_name = distro.id() +try: + dist_name = distro.id() except PermissionError: # Current work-around for Pop!_OS where symlink causes permission issues print("[!] Warning: Cannot get distro name") if os.path.exists("/etc/pop-os/os-release"): # Check if using a Snap if os.getenv("PKG_MARKER") == "SNAP": - print("[!] Snap install on PopOS detected, you must manually run the following commands in another terminal:\n") + print("[!] Snap install on PopOS detected, you must manually run the following" + " commands in another terminal:\n") print("[!] Backup the /etc/os-release file:") print("sudo mv /etc/os-release /etc/os-release-backup\n") print("[!] Create hardlink to /etc/os-release:") print("sudo ln /etc/pop-os/os-release /etc/os-release\n") print("[!] Aborting. Restart auto-cpufreq when you created the hardlink") + sys.exit(1) else: # This should not be the case. But better be sure. print("[!] Check /etc/os-release permissions and make sure it is not a symbolic link") print("[!] Aborting...") + sys.exit(1) + else: print("[!] Check /etc/os-release permissions and make sure it is not a symbolic link") print("[!] Aborting...") - sys.exit(1) + sys.exit(1) # display running version of auto-cpufreq def app_version(): + print("auto-cpufreq version: ", end="") # snap package - if os.getenv("PKG_MARKER") == "SNAP": print(getoutput(r"echo \(Snap\) $SNAP_VERSION")) + if os.getenv("PKG_MARKER") == "SNAP": + print(getoutput(r"echo \(Snap\) $SNAP_VERSION")) # aur package elif dist_name in ["arch", "manjaro", "garuda"]: - if call("pacman -Qs auto-cpufreq > /dev/null", shell=True) == 1: print(get_formatted_version()) - else: print(getoutput("pacman -Qi auto-cpufreq | grep Version")) + aur_pkg_check = call("pacman -Qs auto-cpufreq > /dev/null", shell=True) + if aur_pkg_check == 1: + print(get_formatted_version()) + else: + print(getoutput("pacman -Qi auto-cpufreq | grep Version")) else: # source code (auto-cpufreq-installer) - try: print(get_formatted_version()) + try: + print(get_formatted_version()) except Exception as e: print(repr(e)) pass @@ -147,19 +163,21 @@ def check_for_update(): # Specify the repository and package name # IT IS IMPORTANT TO THAT IF THE REPOSITORY STRUCTURE IS CHANGED, THE FOLLOWING FUNCTION NEEDS TO BE UPDATED ACCORDINGLY # Fetch the latest release information from GitHub API - latest_release_url = "https://api.github.com/repos/AdnanHodzic/auto-cpufreq/releases/latest" + latest_release_url = f"https://api.github.com/repos/AdnanHodzic/auto-cpufreq/releases/latest" try: response = requests.get(latest_release_url) - if response.ok: latest_release = response.json() + if response.status_code == 200: + latest_release = response.json() else: message = response.json().get("message") print("Error fetching recent release!") if message is not None and message.startswith("API rate limit exceeded"): print("GitHub Rate limit exceeded. Please try again later within 1 hour or use different network/VPN.") - else: print("Unexpected status code:", response.status_code) + else: + print("Unexpected status code:", response.status_code) return False except (requests.exceptions.ConnectionError, requests.exceptions.Timeout, - requests.exceptions.RequestException, requests.exceptions.HTTPError): + requests.exceptions.RequestException, requests.exceptions.HTTPError) as err: print("Error Connecting to server!") return False @@ -169,18 +187,21 @@ def check_for_update(): # Get the current version of auto-cpufreq # Extract version number from the output string output = check_output(['auto-cpufreq', '--version']).decode('utf-8') - try: version_line = next((re.search(r'\d+\.\d+\.\d+', line).group() for line in output.split('\n') if line.startswith('auto-cpufreq version')), None) + try: + version_line = next((re.search(r'\d+\.\d+\.\d+', line).group() for line in output.split('\n') if line.startswith('auto-cpufreq version')), None) except AttributeError: print("Error Retrieving Current Version!") exit(1) installed_version = "v" + version_line #Check whether the same is installed or not # Compare the latest version with the installed version and perform update if necessary - if latest_version == installed_version: print("auto-cpufreq is up to date") + if latest_version == installed_version: + print("auto-cpufreq is up to date") + return False else: print(f"Updates are available,\nCurrent version: {installed_version}\nLatest version: {latest_version}") print("Note that your previous custom settings might be erased with the following update") - return True + return True else: # Handle the case where "tag_name" key doesn't exist print("Malformed Released data!\nReinstall manually or Open an issue on GitHub for help!") @@ -200,18 +221,26 @@ def get_literal_version(package_name): package_metadata = importlib.metadata.metadata(package_name) package_name = package_metadata['Name'] - numbered_version, _, git_version = package_metadata['Version'].partition("+") + metadata_version = package_metadata['Version'] + + numbered_version, _, git_version = metadata_version.partition("+") # Construct the literal version string - return f"{numbered_version}+{git_version}" + literal_version = f"{numbered_version}+{git_version}" + + return literal_version - except importlib.metadata.PackageNotFoundError: return f"Package '{package_name}' not found" + except importlib.metadata.PackageNotFoundError: + return f"Package '{package_name}' not found" # return formatted version for a better readability def get_formatted_version(): literal_version = get_literal_version("auto-cpufreq") splitted_version = literal_version.split("+") - formatted_version = splitted_version[0] + " (git: " + splitted_version[1] + ")" if len(splitted_version) > 1 else '' + formatted_version = splitted_version[0] + + if len(splitted_version) > 1: + formatted_version += " (git: " + splitted_version[1] + ")" return formatted_version @@ -239,7 +268,8 @@ def turbo(value: bool = None): inverse = False elif amd_pstate.exists(): amd_value = amd_pstate.read_text().strip() - if amd_value == "active": print("CPU turbo is controlled by amd-pstate-epp driver") + if amd_value == "active": + print("CPU turbo is controlled by amd-pstate-epp driver") # Basically, no other value should exist. return False else: @@ -247,24 +277,30 @@ def turbo(value: bool = None): return False if value is not None: - if inverse: value = not value + if inverse: + value = not value - try: f.write_text(str(int(value)) + "\n") + try: + f.write_text(str(int(value)) + "\n") except PermissionError: print("Warning: Changing CPU turbo is not supported. Skipping.") return False value = bool(int(f.read_text().strip())) - if inverse: value = not value + if inverse: + value = not value return value + # display current state of turbo -def get_turbo(): print(f"Currently turbo boost is: {'on' if turbo() else 'off'}") +def get_turbo(): + + if turbo(): + print("Currently turbo boost is: on") + else: + print("Currently turbo boost is: off") -def set_turbo(value:bool): # set turbo state - print(f"setting turbo boost: {'on' if value else 'off'}") - turbo(value) def charging(): """ @@ -277,14 +313,18 @@ def charging(): # check if we found power supplies. on a desktop these are not found # and we assume we are on a powercable. - if len(power_supplies) == 0: return True # nothing found found, so nothing to check + if len(power_supplies) == 0: + # nothing found found, so nothing to check + return True # we found some power supplies, lets check their state else: for supply in power_supplies: # Check if supply is in ignore list ignore_supply = any(item in supply for item in POWER_SUPPLY_IGNORELIST) # If found in ignore list, skip it. - if ignore_supply: continue + if ignore_supply: + continue + try: with open(Path(power_supply_path + supply + "/type")) as f: supply_type = f.read()[:-1] @@ -292,34 +332,55 @@ def charging(): # we found an AC try: with open(Path(power_supply_path + supply + "/online")) as f: - if int(f.read()[:-1]) == 1: return True # we are definitely charging - except FileNotFoundError: continue # we could not find online, check next item + val = int(f.read()[:-1]) + if val == 1: + # we are definitely charging + return True + except FileNotFoundError: + # we could not find online, check next item + continue elif supply_type == "Battery": # we found a battery, check if its being discharged try: with open(Path(power_supply_path + supply + "/status")) as f: - if str(f.read()[:-1]) == "Discharging": return False # we found a discharging battery - except FileNotFoundError: continue # could not find status, check the next item - else: continue # continue to next item because current is not "Mains" or "Battery" - except FileNotFoundError: continue # could not find type, check the next item + val = str(f.read()[:-1]) + if val == "Discharging": + # we found a discharging battery + return False + except FileNotFoundError: + # could not find status, check the next item + continue + else: + # continue to next item because current is not + # "Mains" or "Battery" + continue + except FileNotFoundError: + # could not find type, check the next item + continue # we cannot determine discharging state, assume we are on powercable return True def get_avail_gov(): - return Path("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors").read_text().strip().split() + f = Path("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors") + return f.read_text().strip().split(" ") -def get_avail(reverse:bool): + +def get_avail_powersave(): """ - Iterate over ALL_GOVERNORS: from performance to powersave (invert if reverse=True) + Iterate over ALL_GOVERNORS in reverse order: from powersave to performance :return: """ - gov = ALL_GOVERNORS[::-1] if reverse else ALL_GOVERNORS - for g in gov: - if g in get_avail_gov(): return g + for g in ALL_GOVERNORS[::-1]: + if g in get_avail_gov(): + return g + + +def get_avail_performance(): + for g in ALL_GOVERNORS: + if g in get_avail_gov(): + return g -def get_avail_performance(): get_avail(False) -def get_avail_powersave(): get_avail(True) def get_current_gov(): return print( @@ -328,22 +389,36 @@ def get_current_gov(): "governor", ) + def cpufreqctl(): """ deploy cpufreqctl script """ - if not os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq"): # deploy cpufreqctl.auto-cpufreq script if not running on a SNAP - copy(SCRIPTS_DIR / "cpufreqctl.sh", "/usr/local/bin/cpufreqctl.auto-cpufreq") + + # detect if running on a SNAP + if os.getenv("PKG_MARKER") == "SNAP": + pass + else: + # deploy cpufreqctl.auto-cpufreq script + if not os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq"): + shutil.copy(SCRIPTS_DIR / "cpufreqctl.sh", "/usr/local/bin/cpufreqctl.auto-cpufreq") + def cpufreqctl_restore(): """ remove cpufreqctl.auto-cpufreq script """ # detect if running on a SNAP - if os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq"): # remove cpufreqctl.auto-cpufreq script if not running on a SNAP - os.remove("/usr/local/bin/cpufreqctl.auto-cpufreq") + if os.getenv("PKG_MARKER") == "SNAP": + pass + else: + if os.path.isfile("/usr/local/bin/cpufreqctl.auto-cpufreq"): + os.remove("/usr/local/bin/cpufreqctl.auto-cpufreq") + + +def footer(l=79): + print("\n" + "-" * l + "\n") -def footer(l=79): print("\n" + "-" * l + "\n") def deploy_complete_msg(): print("\n" + "-" * 17 + " auto-cpufreq daemon installed and running " + "-" * 17 + "\n") @@ -351,17 +426,20 @@ def deploy_complete_msg(): print("\nTo disable and remove auto-cpufreq daemon, run:\nsudo auto-cpufreq --remove") footer() + def deprecated_log_msg(): print("\n" + "-" * 24 + " auto-cpufreq log file renamed " + "-" * 24 + "\n") print("The --log flag has been renamed to --stats\n") print("To view live stats, run:\nauto-cpufreq --stats") footer() + def remove_complete_msg(): print("\n" + "-" * 25 + " auto-cpufreq daemon removed " + "-" * 25 + "\n") print("auto-cpufreq successfully removed.") footer() + def deploy_daemon(): print("\n" + "-" * 21 + " Deploying auto-cpufreq as a daemon " + "-" * 22 + "\n") @@ -374,10 +452,10 @@ def deploy_daemon(): auto_cpufreq_stats_path.touch(exist_ok=True) print("\n* Deploy auto-cpufreq install script") - copy(SCRIPTS_DIR / "auto-cpufreq-install.sh", "/usr/local/bin/auto-cpufreq-install") + shutil.copy(SCRIPTS_DIR / "auto-cpufreq-install.sh", "/usr/local/bin/auto-cpufreq-install") print("\n* Deploy auto-cpufreq remove script") - copy(SCRIPTS_DIR / "auto-cpufreq-remove.sh", "/usr/local/bin/auto-cpufreq-remove") + shutil.copy(SCRIPTS_DIR / "auto-cpufreq-remove.sh", "/usr/local/bin/auto-cpufreq-remove") # output warning if gnome power profile is running gnome_power_detect_install() @@ -388,6 +466,7 @@ def deploy_daemon(): call("/usr/local/bin/auto-cpufreq-install", shell=True) + def deploy_daemon_performance(): print("\n" + "-" * 21 + " Deploying auto-cpufreq as a daemon (performance) " + "-" * 22 + "\n") @@ -407,10 +486,10 @@ def deploy_daemon_performance(): auto_cpufreq_stats_path.touch(exist_ok=True) print("\n* Deploy auto-cpufreq install script") - copy(SCRIPTS_DIR / "auto-cpufreq-install.sh", "/usr/local/bin/auto-cpufreq-install") + shutil.copy(SCRIPTS_DIR / "auto-cpufreq-install.sh", "/usr/local/bin/auto-cpufreq-install") print("\n* Deploy auto-cpufreq remove script") - copy(SCRIPTS_DIR / "auto-cpufreq-remove.sh", "/usr/local/bin/auto-cpufreq-remove") + shutil.copy(SCRIPTS_DIR / "auto-cpufreq-remove.sh", "/usr/local/bin/auto-cpufreq-remove") # output warning if gnome power profile is running gnome_power_detect_install() @@ -422,8 +501,10 @@ def deploy_daemon_performance(): call("/usr/local/bin/auto-cpufreq-install", shell=True) + # remove auto-cpufreq daemon def remove_daemon(): + # check if auto-cpufreq is installed if not os.path.exists("/usr/local/bin/auto-cpufreq-remove"): print("\nauto-cpufreq daemon is not installed.\n") @@ -445,23 +526,27 @@ def remove_daemon(): os.remove("/usr/local/bin/auto-cpufreq-remove") # delete override pickle if it exists - if os.path.exists(governor_override_state): os.remove(governor_override_state) + if os.path.exists(governor_override_state): + os.remove(governor_override_state) # delete stats file if auto_cpufreq_stats_path.exists(): - if auto_cpufreq_stats_file is not None: auto_cpufreq_stats_file.close() + if auto_cpufreq_stats_file is not None: + auto_cpufreq_stats_file.close() auto_cpufreq_stats_path.unlink() # restore original cpufrectl script cpufreqctl_restore() + def gov_check(): for gov in get_avail_gov(): if gov not in ALL_GOVERNORS: print("\n" + "-" * 18 + " Checking for necessary scaling governors " + "-" * 19 + "\n") sys.exit("ERROR:\n\nCouldn't find any of the necessary scaling governors.\n") + # root check func def root_check(): if not os.geteuid() == 0: @@ -470,6 +555,7 @@ def root_check(): footer() exit(1) + # refresh countdown def countdown(s): # Fix for wrong stats output and "TERM environment variable not set" @@ -486,27 +572,34 @@ def countdown(s): # auto-refresh counter for remaining in range(s, -1, -1): - if remaining <= 3 and remaining >= 0: print(".", end="", flush=True) + + if remaining <= 3 and remaining >= 0: + print(".", end="", flush=True) time.sleep(0.75) now = datetime.now() current_time = now.strftime("%B %d (%A) - %H:%M:%S") print("\n\t\tExecuted on:", current_time) + # get cpu usage + system load for (last minute) def display_load(): - cpuload = psutil.cpu_percent(interval=1) # get CPU utilization as a percentage - load1m = os.getloadavg()[0] # get system/CPU load + + # get CPU utilization as a percentage + cpuload = psutil.cpu_percent(interval=1) + + # get system/CPU load + load1m, _, _ = os.getloadavg() print("\nTotal CPU usage:", cpuload, "%") print("Total system load: {:.2f}".format(load1m)) print("Average temp. of all cores: {:.2f} °C \n".format(avg_all_core_temp)) - return cpuload, load1m - # get system load average 1m, 5m, 15m (equivalent to uptime) def display_system_load_avg(): + load1m, load5m, load15m = os.getloadavg() + print(f" (load average: {load1m:.2f}, {load5m:.2f}, {load15m:.2f})") # set minimum and maximum CPU frequencies @@ -523,9 +616,10 @@ def set_frequencies(): if ( hasattr(set_frequencies, "prev_power_supply") and power_supply == set_frequencies.prev_power_supply - ): return - - set_frequencies.prev_power_supply = power_supply + ): + return + else: + set_frequencies.prev_power_supply = power_supply frequency = { "scaling_max_freq": { @@ -554,15 +648,23 @@ def set_frequencies(): else: curr_freq = int(getoutput(f"cpufreqctl.auto-cpufreq --frequency-min")) value = set_frequencies.min_limit - if curr_freq == value: continue + if curr_freq == value: + continue - try: frequency[freq_type]["value"] = (value if value else int(conf[power_supply][freq_type].strip())) + try: + frequency[freq_type]["value"] = ( + value if value else int(conf[power_supply][freq_type].strip()) + ) except ValueError: print(f"Invalid value for '{freq_type}': {frequency[freq_type]['value']}") exit(1) - if not (set_frequencies.min_limit <= frequency[freq_type]["value"] <= set_frequencies.max_limit): - print(f"Given value for '{freq_type}' is not within the allowed frequencies {set_frequencies.min_limit}-{set_frequencies.max_limit} kHz") + if not ( + set_frequencies.min_limit <= frequency[freq_type]["value"] <= set_frequencies.max_limit + ): + print( + f"Given value for '{freq_type}' is not within the allowed frequencies {set_frequencies.min_limit}-{set_frequencies.max_limit} kHz" + ) exit(1) args = f"{frequency[freq_type]['cmdargs']} --set={frequency[freq_type]['value']}" @@ -572,27 +674,32 @@ def set_frequencies(): print(message) run(f"cpufreqctl.auto-cpufreq {args}", shell=True) -def display_average_core_temperatures(cpuload): - print(f"Optimal total CPU usage: {cpuload} %, high average core temp: {avg_all_core_temp} °C") # set powersave and enable turbo def set_powersave(): conf = config.get_config() - if conf.has_option("battery", "governor"): gov = conf["battery"]["governor"] - else: gov = get_avail_powersave() + if conf.has_option("battery", "governor"): + gov = conf["battery"]["governor"] + else: + gov = get_avail_powersave() print(f'Setting to use: "{gov}" governor') - if get_override() != "default": print("Warning: governor overwritten using `--force` flag.") + 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() is False: print('Not setting EPP (not supported by system)') else: dynboost_enabled = Path("/sys/devices/system/cpu/intel_pstate/hwp_dynamic_boost").exists() if dynboost_enabled: - dynboost_enabled = bool(int(os.popen("cat /sys/devices/system/cpu/intel_pstate/hwp_dynamic_boost").read())) + dynboost_enabled = bool(int( + os.popen("cat /sys/devices/system/cpu/intel_pstate/hwp_dynamic_boost").read() + )) - if dynboost_enabled: print('Not setting EPP (dynamic boosting is enabled)') + if dynboost_enabled: + print('Not setting EPP (dynamic boosting is enabled)') else: if conf.has_option("battery", "energy_performance_preference"): epp = conf["battery"]["energy_performance_preference"] @@ -605,77 +712,221 @@ def set_powersave(): # set frequencies set_frequencies() - cpuload , load1m = display_load() + # get CPU utilization as a percentage + cpuload = psutil.cpu_percent(interval=1) + + # get system/CPU load + load1m, _, _ = os.getloadavg() + + print("\nTotal CPU usage:", cpuload, "%") + print("Total system load: {:.2f}".format(load1m)) + print("Average temp. of all cores: {:.2f} °C \n".format(avg_all_core_temp)) # conditions for setting turbo in powersave - auto = conf["battery"]["turbo"] if conf.has_option("battery", "turbo") else "auto" + if conf.has_option("battery", "turbo"): + auto = conf["battery"]["turbo"] + else: + auto = "auto" if auto == "always": print("Configuration file enforces turbo boost") - set_turbo(True) + print("setting turbo boost: on") + turbo(True) elif auto == "never": print("Configuration file disables turbo boost") - set_turbo(False) + print("setting turbo boost: off") + turbo(False) else: if psutil.cpu_percent(percpu=False, interval=0.01) >= 30.0 or isclose( max(psutil.cpu_percent(percpu=True, interval=0.01)), 100 - ): print("High CPU load", end=""), display_system_load_avg() - elif load1m > powersave_load_threshold: print("High system load", end="") - else: print("Load optimal", end="") + ): + print("High CPU load", end=""), display_system_load_avg() - display_system_load_avg() + # high cpu usage trigger + if cpuload >= 20: + print("setting turbo boost: on") + turbo(True) + + # set turbo state based on average of all core temperatures + elif cpuload <= 20 and avg_all_core_temp >= 70: + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("setting turbo boost: off") + turbo(False) + else: + print("setting turbo boost: off") + turbo(False) + + elif load1m > powersave_load_threshold: + print("High system load", end=""), display_system_load_avg() + + # high cpu usage trigger + if cpuload >= 20: + print("setting turbo boost: on") + turbo(True) + + # set turbo state based on average of all core temperatures + elif cpuload <= 20 and avg_all_core_temp >= 65: + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("setting turbo boost: off") + turbo(False) + else: + print("setting turbo boost: off") + turbo(False) - # high cpu usage trigger - if cpuload >= 20: set_turbo(True) - # set turbo state based on average of all core temperatures else: - display_average_core_temperatures(cpuload) - set_turbo(False) + print("Load optimal", end=""), display_system_load_avg() + + # high cpu usage trigger + if cpuload >= 20: + print("setting turbo boost: on") + turbo(True) + + # set turbo state based on average of all core temperatures + elif cpuload <= 20 and avg_all_core_temp >= 60: + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("setting turbo boost: off") + turbo(False) + else: + print("setting turbo boost: off") + turbo(False) footer() + # make turbo suggestions in powersave def mon_powersave(): + # get CPU utilization as a percentage - cpuload, load1m = display_load() + cpuload = psutil.cpu_percent(interval=1) + + # get system/CPU load + load1m, _, _ = os.getloadavg() + + print("\nTotal CPU usage:", cpuload, "%") + print("Total system load: {:.2f}".format(load1m)) + print("Average temp. of all cores: {:.2f} °C \n".format(avg_all_core_temp)) if psutil.cpu_percent(percpu=False, interval=0.01) >= 30.0 or isclose( max(psutil.cpu_percent(percpu=True, interval=0.01)), 100 - ): print("High CPU load", end=""), - elif load1m > powersave_load_threshold: print("High system load", end="") - else: print("Load optimal", end="") + ): + print("High CPU load", end=""), display_system_load_avg() - display_system_load_avg() + # high cpu usage trigger + if cpuload >= 20: + print("suggesting to set turbo boost: on") + get_turbo() + + # set turbo state based on average of all core temperatures + elif cpuload <= 20 and avg_all_core_temp >= 70: + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("suggesting to set turbo boost: off") + get_turbo() + else: + print("suggesting to set turbo boost: off") + get_turbo() + + elif load1m > powersave_load_threshold: + print("High system load", end=""), display_system_load_avg() + + # high cpu usage trigger + if cpuload >= 20: + print("suggesting to set turbo boost: on") + get_turbo() + + # set turbo state based on average of all core temperatures + elif cpuload <= 20 and avg_all_core_temp >= 65: + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("suggesting to set turbo boost: off") + get_turbo() + else: + print("suggesting to set turbo boost: off") + get_turbo() - # high cpu usage trigger - if cpuload >= 20: print("suggesting to set turbo boost: on") - # set turbo state based on average of all core temperatures else: - display_average_core_temperatures(cpuload) - print("suggesting to set turbo boost: off") - - get_turbo() + print("Load optimal", end=""), display_system_load_avg() + + # high cpu usage trigger + if cpuload >= 20: + print("suggesting to set turbo boost: on") + get_turbo() + + # set turbo state based on average of all core temperatures + elif cpuload <= 20 and avg_all_core_temp >= 60: + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("suggesting to set turbo boost: off") + get_turbo() + else: + print("suggesting to set turbo boost: off") + get_turbo() footer() + # set performance and enable turbo def set_performance(): conf = config.get_config() - gov = conf["charger"]["governor"] if conf.has_option("charger", "governor") else get_avail_performance() + if conf.has_option("charger", "governor"): + gov = conf["charger"]["governor"] + else: + 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) + if get_override() != "default": + print("Warning: governor overwritten using `--force` flag.") + run( + f"cpufreqctl.auto-cpufreq --governor --set={gov}", + shell=True, + ) - if not Path("/sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference").exists(): + + if Path("/sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference").exists() is False: print('Not setting EPP (not supported by system)') else: dynboost_enabled = Path("/sys/devices/system/cpu/intel_pstate/hwp_dynamic_boost").exists() if dynboost_enabled: - dynboost_enabled = bool(int(os.popen("cat /sys/devices/system/cpu/intel_pstate/hwp_dynamic_boost").read())) + dynboost_enabled = bool(int( + os.popen("cat /sys/devices/system/cpu/intel_pstate/hwp_dynamic_boost").read() + )) - if dynboost_enabled: print('Not setting EPP (dynamic boosting is enabled)') + if dynboost_enabled: + print('Not setting EPP (dynamic boosting is enabled)') else: intel_pstate_status_path = "/sys/devices/system/cpu/intel_pstate/status" @@ -701,16 +952,28 @@ def set_performance(): set_frequencies() # get CPU utilization as a percentage - cpuload, load1m = display_load() + cpuload = psutil.cpu_percent(interval=1) + + # get system/CPU load + load1m, _, _ = os.getloadavg() + + print("\nTotal CPU usage:", cpuload, "%") + print("Total system load: {:.2f}".format(load1m)) + print("Average temp. of all cores: {:.2f} °C \n".format(avg_all_core_temp)) - auto = conf["charger"]["turbo"] if conf.has_option("charger", "turbo") else "auto" + if conf.has_option("charger", "turbo"): + auto = conf["charger"]["turbo"] + else: + auto = "auto" if auto == "always": print("Configuration file enforces turbo boost") - set_turbo(True) + print("setting turbo boost: on") + turbo(True) elif auto == "never": print("Configuration file disables turbo boost") - set_turbo(False) + print("setting turbo boost: off") + turbo(False) else: if ( psutil.cpu_percent(percpu=False, interval=0.01) >= 20.0 @@ -719,61 +982,165 @@ def set_performance(): print("High CPU load", end=""), display_system_load_avg() # high cpu usage trigger - if cpuload >= 20: set_turbo(True) + if cpuload >= 20: + print("setting turbo boost: on") + turbo(True) + # set turbo state based on average of all core temperatures elif avg_all_core_temp >= 70: - display_average_core_temperatures(cpuload) - set_turbo(False) - else: set_turbo(True) + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("setting turbo boost: off") + turbo(False) + else: + print("setting turbo boost: on") + turbo(True) elif load1m >= performance_load_threshold: print("High system load", end=""), display_system_load_avg() # high cpu usage trigger - if cpuload >= 20: set_turbo(True) + if cpuload >= 20: + print("setting turbo boost: on") + turbo(True) + # set turbo state based on average of all core temperatures elif avg_all_core_temp >= 65: - display_average_core_temperatures(cpuload) - set_turbo(False) - else: set_turbo(True) + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("setting turbo boost: off") + turbo(False) + else: + print("setting turbo boost: on") + turbo(True) else: print("Load optimal", end=""), display_system_load_avg() # high cpu usage trigger - if cpuload >= 20: set_turbo(True) + if cpuload >= 20: + print("setting turbo boost: on") + turbo(True) + # set turbo state based on average of all core temperatures + elif avg_all_core_temp >= 60: + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("setting turbo boost: off") + turbo(False) else: - display_average_core_temperatures(cpuload) - set_turbo(False) + print("setting turbo boost: off") + turbo(False) footer() + # make turbo suggestions in performance def mon_performance(): - cpuload, load1m = display_load() + + # get CPU utilization as a percentage + cpuload = psutil.cpu_percent(interval=1) + + # get system/CPU load + load1m, _, _ = os.getloadavg() + + print("\nTotal CPU usage:", cpuload, "%") + print("Total system load: {:.2f}".format(load1m)) + print("Average temp. of all cores: {:.2f} °C \n".format(avg_all_core_temp)) + + # get system/CPU load + load1m, _, _ = os.getloadavg() if ( psutil.cpu_percent(percpu=False, interval=0.01) >= 20.0 or max(psutil.cpu_percent(percpu=True, interval=0.01)) >= 75 - ): print("High CPU load", end="") - elif load1m > performance_load_threshold: print("High system load", end="") - else: print("Load optimal", end="") + ): + print("High CPU load", end=""), display_system_load_avg() + + # high cpu usage trigger + if cpuload >= 20: + print("suggesting to set turbo boost: on") + get_turbo() + + # set turbo state based on average of all core temperatures + elif cpuload <= 25 and avg_all_core_temp >= 70: + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("suggesting to set turbo boost: off") + get_turbo() + else: + print("suggesting to set turbo boost: on") + get_turbo() + + elif load1m > performance_load_threshold: + print("High system load", end=""), display_system_load_avg() - display_system_load_avg() + # high cpu usage trigger + if cpuload >= 20: + print("suggesting to set turbo boost: on") + get_turbo() - # high cpu usage trigger - if cpuload >= 20: print("suggesting to set turbo boost: on") - # set turbo state based on average of all core temperatures - elif cpuload <= 25 and avg_all_core_temp >= 60: - display_average_core_temperatures(cpuload) - print("suggesting to set turbo boost: off") - else: print("suggesting to set turbo boost: on") + # set turbo state based on average of all core temperatures + elif cpuload <= 25 and avg_all_core_temp >= 65: + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("suggesting to set turbo boost: off") + get_turbo() + else: + print("suggesting to set turbo boost: on") + get_turbo() - get_turbo() + else: + print("Load optimal", end=""), display_system_load_avg() + + # high cpu usage trigger + if cpuload >= 20: + print("suggesting to set turbo boost: on") + get_turbo() + + # set turbo state based on average of all core temperatures + elif cpuload <= 25 and avg_all_core_temp >= 60: + print( + "Optimal total CPU usage:", + cpuload, + "%, high average core temp:", + avg_all_core_temp, + "°C", + ) + print("suggesting to set turbo boost: off") + get_turbo() + else: + print("suggesting to set turbo boost: on") + get_turbo() footer() + def set_autofreq(): """ set cpufreq governor based if device is charging @@ -782,8 +1149,10 @@ def set_autofreq(): # determine which governor should be used override = get_override() - if override == "powersave": set_powersave() - elif override == "performance": set_performance() + if override == "powersave": + set_powersave() + elif override == "performance": + set_performance() elif charging(): print("Battery is: charging\n") set_performance() @@ -791,6 +1160,7 @@ def set_autofreq(): print("Battery is: discharging\n") set_powersave() + def mon_autofreq(): """ make cpufreq suggestions @@ -810,6 +1180,7 @@ def mon_autofreq(): print(f'Suggesting use of "{get_avail_powersave()}" governor') mon_powersave() + def python_info(): print("Python:", pl.python_version()) print("psutil package:", psutil.__version__) @@ -817,7 +1188,10 @@ def python_info(): print("click package:", click.__version__) print("distro package:", distro.__version__) -def device_info(): print("Computer type:", getoutput("dmidecode --string chassis-type")) + +def device_info(): + print("Computer type:", getoutput("dmidecode --string chassis-type")) + def distro_info(): dist = "UNKNOWN distro" @@ -839,17 +1213,20 @@ def distro_info(): pass dist = f"{dist} {version}" - else: # get distro information + else: + # get distro information fdist = distro.linux_distribution() dist = " ".join(x for x in fdist) print("Linux distro: " + dist) print("Linux kernel: " + pl.release()) + def sysinfo(): """ get system information """ + # processor_info model_name = getoutput("grep -E 'model name' /proc/cpuinfo -m 1").split(":")[-1] print(f"Processor:{model_name}") @@ -884,14 +1261,19 @@ def sysinfo(): freq_per_cpu = [] for i in range(0, len(coreid_info), 3): # ensure that indices are within the valid range, before accessing the corresponding elements - if i + 1 < len(coreid_info): freq_per_cpu.append(float(coreid_info[i + 1].split(":")[-1])) - else: continue # handle the case where the index is out of range + if i + 1 < len(coreid_info): + freq_per_cpu.append(float(coreid_info[i + 1].split(":")[-1])) + else: + # handle the case where the index is out of range + continue # ensure that indices are within the valid range, before accessing the corresponding elements cpu = int(coreid_info[i].split(":")[-1]) if i + 2 < len(coreid_info): core = int(coreid_info[i + 2].split(":")[-1]) cpu_core[cpu] = core - else: continue # handle the case where the index is out of range + else: + # handle the case where the index is out of range + continue online_cpu_count = len(cpu_core) offline_cpus = [str(cpu) for cpu in range(total_cpu_count) if cpu not in cpu_core] @@ -918,14 +1300,15 @@ def sysinfo(): if temp.current != 0: temp_per_cpu = [temp.current] * online_cpu_count break - else: continue + else: + continue break else: for sensor in ["acpitz", "k10temp", "zenpower"]: if sensor in temp_sensors: if temp_sensors[sensor][0].current != 0: temp_per_cpu = [temp_sensors[sensor][0].current] * online_cpu_count - break + break; except Exception as e: print(repr(e)) pass @@ -934,7 +1317,8 @@ def sysinfo(): for (cpu, usage, freq, temp) in zip(cpu_core, usage_per_cpu, freq_per_cpu, temp_per_cpu): print(f"CPU{cpu} {usage:>5.1f}% {temp:>3.0f} °C {freq:>5.0f} MHz") - if offline_cpus: print(f"\nDisabled CPUs: {','.join(offline_cpus)}") + if offline_cpus: + print(f"\nDisabled CPUs: {','.join(offline_cpus)}") # get average temperature of all cores avg_cores_temp = sum(temp_per_cpu) @@ -943,32 +1327,45 @@ def sysinfo(): # print current fan speed current_fans = list(psutil.sensors_fans()) - for current_fan in current_fans: print("\nCPU fan speed:", psutil.sensors_fans()[current_fan][0].current, "RPM") + for current_fan in current_fans: + print("\nCPU fan speed:", psutil.sensors_fans()[current_fan][0].current, "RPM") + + # 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) + if os.path.isfile(auto_cpufreq_stats_path): + call(["tail", "-n 50", "-f", str(auto_cpufreq_stats_path)], stderr=DEVNULL) footer() + # check if program (argument) is running def is_running(program, argument): # iterate over all processes found by psutil # and find the one with name and args passed to the function for p in psutil.process_iter(): - try: cmd = p.cmdline() - except: continue - for _ in filter(lambda x: program in x, cmd): - if argument in cmd: return True + try: + cmd = p.cmdline(); + except: + continue + for s in filter(lambda x: program in x, cmd): + if argument in cmd: + return True + def daemon_running_msg(): print("\n" + "-" * 24 + " auto-cpufreq running " + "-" * 30 + "\n") - print("ERROR: auto-cpufreq is running in daemon mode.\n\nMake sure to stop the daemon before running with --live or --monitor mode") + print( + "ERROR: auto-cpufreq is running in daemon mode.\n\nMake sure to stop the daemon before running with --live or --monitor mode" + ) 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") + 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 @@ -987,4 +1384,4 @@ def not_running_daemon_check(): exit(1) elif os.getenv("PKG_MARKER") == "SNAP" and dcheck == "disabled": daemon_not_running_msg() - exit(1) + exit(1) \ No newline at end of file