diff --git a/bin/auto-cpufreq b/bin/auto-cpufreq index aa5cb02..3921538 100755 --- a/bin/auto-cpufreq +++ b/bin/auto-cpufreq @@ -6,8 +6,12 @@ # core import import sys +from subprocess import call + sys.path.append('../') -from source.core import * +from source.core import * +import click + # ToD: replace every s.call with s.run @@ -18,7 +22,6 @@ from source.core import * @click.option("--install/--remove", default=True, help="Install/remove daemon for automatic CPU optimizations") @click.option("--log", is_flag=True, help="View live CPU optimization log made by daemon") @click.option("--daemon", is_flag=True, hidden=True) - def main(monitor, live, daemon, install, log): # print --help by default if no argument is provided when auto-cpufreq is run if len(sys.argv) == 1: @@ -39,7 +42,7 @@ def main(monitor, live, daemon, install, log): sysinfo() set_autofreq() countdown(5) - subprocess.call("clear") + call("clear") elif os.getenv("PKG_MARKER") != "SNAP": while True: root_check() @@ -48,7 +51,7 @@ def main(monitor, live, daemon, install, log): sysinfo() set_autofreq() countdown(5) - subprocess.call("clear") + call("clear") else: print("\n" + "-" * 32 + " Daemon check " + "-" * 33 + "\n") print("ERROR:\n\nDaemon not enabled, must run install first, i.e: \nsudo auto-cpufreq --install") @@ -63,7 +66,7 @@ def main(monitor, live, daemon, install, log): sysinfo() mon_autofreq() countdown(5) - subprocess.call("clear") + call("clear") elif live: while True: root_check() @@ -73,7 +76,7 @@ def main(monitor, live, daemon, install, log): sysinfo() set_autofreq() countdown(5) - subprocess.call("clear") + call("clear") elif log: # ToDo: fail if log is missing or empty (on) read_log() diff --git a/source/core.py b/source/core.py index 61c6db8..08e8435 100644 --- a/source/core.py +++ b/source/core.py @@ -2,33 +2,26 @@ # # auto-cpufreq - core functionality -# ToDo: re-order in a single line? -import subprocess import os +import platform as pl +import subprocess as s import sys import time -import psutil -import platform -import click -import power -import signal + +import power as pw +import psutil as p # ToDo: # - re-enable CPU fan speed display and make more generic and not only for thinkpad # - replace get system/CPU load from: psutil.getloadavg() | available in 5.6.2) -# global vars -p = psutil -pl = platform -s = subprocess cpus = os.cpu_count() -pw = power # get turbo boost state turbo_loc = "/sys/devices/system/cpu/intel_pstate/no_turbo" cur_turbo = s.getoutput("cat " + turbo_loc) - - # govs/script loc + +# govs/script loc avail_gov_loc = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors" scripts_dir = "/usr/local/share/auto-cpufreq/scripts/" @@ -46,6 +39,7 @@ auto_cpufreq_log_file_snap = "/var/snap/auto-cpufreq/current/auto-cpufreq.log" # daemon check dcheck = s.getoutput("snapctl get daemon") + # deploy cpufreqctl script def cpufreqctl(): # detect if running on a SNAP @@ -59,6 +53,7 @@ def cpufreqctl(): else: os.system("cp " + scripts_dir + "cpufreqctl.sh /usr/bin/cpufreqctl") + # restore original cpufreqctl script def cpufreqctl_restore(): # detect if running on a SNAP @@ -73,31 +68,34 @@ def cpufreqctl_restore(): # restored if overwritten by system. But during tool removal to also remove it # in def cpufreqctl + # print footer func def footer(l): print("\n" + "-" * l + "\n") + def deploy_complete_msg(): print("\n" + "-" * 17 + " auto-cpufreq daemon installed and running " + "-" * 17 + "\n") print("To view live log, run:\nauto-cpufreq --log") print("\nTo disable and remove auto-cpufreq daemon, run:\nsudo auto-cpufreq --remove") footer(79) + def remove_complete_msg(): print("\n" + "-" * 25 + " auto-cpufreq daemon removed " + "-" * 25 + "\n") print("auto-cpufreq successfully removed.") footer(79) + # deploy auto-cpufreq daemon def deploy(): - print("\n" + "-" * 21 + " Deploying auto-cpufreq as a daemon " + "-" * 22 + "\n") # deploy cpufreqctl script func call cpufreqctl() print("* Turn off bluetooth on boot") - btconf="/etc/bluetooth/main.conf" + btconf = "/etc/bluetooth/main.conf" try: orig_set = "AutoEnable=true" change_set = "AutoEnable=false" @@ -121,13 +119,13 @@ def deploy(): # run auto-cpufreq daemon deploy script s.call("/usr/bin/auto-cpufreq-install", shell=True) + # remove auto-cpufreq daemon def remove(): - print("\n" + "-" * 21 + " Removing auto-cpufreq daemon " + "-" * 22 + "\n") print("* Turn on bluetooth on boot") - btconf="/etc/bluetooth/main.conf" + btconf = "/etc/bluetooth/main.conf" try: orig_set = "AutoEnable=true" change_set = "AutoEnable=false" @@ -151,11 +149,12 @@ def remove(): # restore original cpufrectl script cpufreqctl_restore() + # check for necessary scaling governors def gov_check(): avail_gov = avail_gov_loc - governors=["performance","powersave"] + governors = ["performance", "powersave"] for line in open(avail_gov): for keyword in governors: @@ -165,6 +164,7 @@ def gov_check(): 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: @@ -173,26 +173,28 @@ def root_check(): footer(79) exit(1) + # refresh countdown def countdown(s): # Fix for wrong log output and "TERM environment variable not set" os.environ['TERM'] = 'xterm' - + for remaining in range(s, 0, -1): sys.stdout.write("\r") sys.stdout.write("\t\t\t\"auto-cpufreq\" refresh in:{:2d}".format(remaining)) sys.stdout.flush() time.sleep(1) + # set powersave and enable turbo def set_powersave(): print("Setting to use: \"powersave\" governor") s.run("cpufreqctl --governor --set=powersave", shell=True) - if (os.path.exists("/sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference")): + if os.path.exists("/sys/devices/system/cpu/cpu0/cpufreq/energy_performance_preference"): s.run("cpufreqctl --epp --set=balance_power", shell=True) - print("Setting to use: \"balance_power\" EPP") + print("Setting to use: \"balance_power\" EPP") - # get system/CPU load + # get system/CPU load load1m, _, _ = os.getloadavg() # get CPU utilization as a percentage cpuload = p.cpu_percent(interval=1) @@ -214,9 +216,9 @@ def set_powersave(): s.run("echo 1 > " + turbo_loc, shell=True) footer(79) + # make turbo suggestions in powersave def mon_powersave(): - # get system/CPU load load1m, _, _ = os.getloadavg() # get CPU utilization as a percentage @@ -232,7 +234,7 @@ def mon_powersave(): else: print("Currently turbo boost is: off") footer(79) - + elif cpuload > 25: print("High CPU load, suggesting to set turbo boost: on") if cur_turbo == "0": @@ -248,6 +250,7 @@ def mon_powersave(): print("Currently turbo boost is: off") footer(79) + # set performance and enable turbo def set_performance(): print("Setting to use \"performance\" governor") @@ -256,7 +259,6 @@ def set_performance(): s.run("cpufreqctl --epp --set=balance_performance", shell=True) print("Setting to use: \"balance_performance\" EPP") - # get system/CPU load load1m, _, _ = os.getloadavg() # get CPU utilization as a percentage @@ -276,12 +278,12 @@ def set_performance(): footer(79) else: print("Load optimal, setting turbo boost: off") - s.run("echo 1 > " + turbo_loc, shell=True) + s.run("echo 1 > " + turbo_loc, shell=True) footer(79) + # make turbo suggestions in performance def mon_performance(): - # get system/CPU load load1m, _, _ = os.getloadavg() # get CPU utilization as a percentage @@ -299,6 +301,7 @@ def mon_performance(): footer(79) + # set cpufreq based if device is charging def set_autofreq(): print("\n" + "-" * 28 + " CPU frequency scaling " + "-" * 28 + "\n") @@ -313,9 +316,10 @@ def set_autofreq(): elif bat_state == pw.POWER_TYPE_BATTERY: print("Battery is: discharging") set_powersave() - else: + else: print("Couldn't determine the battery status. Please report this issue.") + # make cpufreq suggestions def mon_autofreq(): print("\n" + "-" * 28 + " CPU frequency scaling " + "-" * 28 + "\n") @@ -334,10 +338,10 @@ def mon_autofreq(): mon_powersave() else: print("Couldn't determine the battery status. Please report this issue.") - + + # get system information def sysinfo(): - # added as a temp fix for issue: https://github.com/giampaolo/psutil/issues/1650 import warnings warnings.filterwarnings("ignore") @@ -346,9 +350,11 @@ def sysinfo(): import distro + dist = "UNKNOWN" # get distro information in snap env. if os.getenv("PKG_MARKER") == "SNAP": searchfile = open("/var/lib/snapd/hostfs/etc/os-release", "r") + version = "" for line in searchfile: if line.startswith('NAME='): distro = line[5:line.find('$')].strip("\"") @@ -391,10 +397,8 @@ def sysinfo(): print("Cores:", cpu_count) print("\n" + "-" * 30 + " Current CPU states " + "-" * 30 + "\n") - - # print cpu max frequency - max_cpu_freq = p.cpu_freq().max - print("CPU max frequency: " + "\n{:.0f}".format(max_cpu_freq) + " MHz\n") + print(f"CPU max frequency: {p.cpu_freq().max:.0f}MHz") + print(f"CPU min frequency: {p.cpu_freq().min:.0f}MHz") # get current cpu frequency per core core_usage = p.cpu_freq(percpu=True) @@ -403,7 +407,7 @@ def sysinfo(): print("CPU frequency for each core:\n") core_num = 0 while core_num < cpu_count: - print("CPU" + str(core_num) + ": {:.0f}".format(core_usage[core_num].current) + " MHz") + print(f"CPU{core_num}: {core_usage[core_num].current:.0f} MHz") core_num += 1 # get number of core temp sensors @@ -415,26 +419,34 @@ def sysinfo(): print("\nTemperature for each physical core:\n") core_num = 0 while core_num < core_temp_num: - print("CPU" + str(core_num) + " temp: {:.0f}".format(core_temp['coretemp'][core_num].current) + "°C") + if "coretemp" in core_temp: + temp = core_temp['coretemp'][core_num].current + else: + temp = core_temp['acpitz'][0].current + + print(f"CPU{core_num} temp: {temp:.0f}°C") core_num += 1 # print current fan speed | temporarily commented - #current_fans = p.sensors_fans()['thinkpad'][0].current - #print("\nCPU fan speed:", current_fans, "RPM") + # current_fans = p.sensors_fans()['thinkpad'][0].current + # print("\nCPU fan speed:", current_fans, "RPM") + # create file func def create_file(file): open(file, 'a').close() + # delete file func def delete_file(file): if os.path.exists(file): os.remove(file) + # read log func def read_log(): if os.getenv("PKG_MARKER") == "SNAP": - s.call(["tail", "-n 50", "-f", auto_cpufreq_log_file_snap]) + s.call(["tail", "-n 50", "-f", auto_cpufreq_log_file_snap]) elif os.path.isfile(auto_cpufreq_log_file): s.call(["tail", "-n 50", "-f", auto_cpufreq_log_file]) else: @@ -442,19 +454,20 @@ def read_log(): print("ERROR: auto-cpufreq log is missing.\n\nMake sure to run: \"auto-cpufreq --install\" first") footer(79) + # check if program (argument) is running def is_running(program, argument): # iterate over all process id's found by psutil - for pid in psutil.pids(): + for pid in p.pids(): try: # requests the process information corresponding to each process id - p = psutil.Process(pid) + proc = p.Process(pid) # check if value of program-variable that was used to call the function matches the name field of the plutil.Process(pid) output - if program in p.name(): + if program in proc.name(): # check output of p.name(), output name of program # p.cmdline() - echo the exact command line via which p was called. - for arg in p.cmdline(): - if argument in str(arg): + for arg in proc.cmdline(): + if argument in str(arg): return True else: pass @@ -463,6 +476,7 @@ def is_running(program, argument): except: continue + # check if auto-cpufreq --daemon is running def running_daemon(): if is_running('auto-cpufreq', '--daemon'):