diff --git a/.gitignore b/.gitignore index b6e4761..e21e8a4 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ share/python-wheels/ .installed.cfg *.egg MANIFEST +files.txt # PyInstaller # Usually these files are written by a python script from a template @@ -127,3 +128,7 @@ dmypy.json # Pyre type checker .pyre/ + +# vim +*.swp +*.swo diff --git a/README.md b/README.md index 2b33969..f2013de 100644 --- a/README.md +++ b/README.md @@ -33,74 +33,60 @@ Please note: this tool doesn't conflict and [works great in tandem with TLP](htt * System load * Automatic CPU & power optimization (temporary and persistent) -## How to run auto-cpufreq? +## Installing auto-cpufreq -#### Arch Linux +### From Snap store + +auto-cpufreq snap package is created and is ready in [snap store](https://snapcraft.io/store). However it's still unreleased to public due to changes which first need to be [made as part of snapd 2.4.4](https://github.com/snapcore/snapd/pull/8127). + +Hence, please stay tuned for auto-cpufreq snap package release. + +### From source code + +Get source code, run installer and follow on screen instructions: + +``` +git clone https://github.com/AdnanHodzic/auto-cpufreq.git +cd auto-cpufreq && sudo sudo ./auto-cpufreq-installer +``` + +In case you encounter any problems with `auto-cpufreq-installer`, please [submit a bug report](https://github.com/AdnanHodzic/auto-cpufreq/issues/new). + +### Arch Linux [AUR package is available](https://aur.archlinux.org/packages/auto-cpufreq-git/) for install. After which `auto-cpufreq` will be available as a binary and you can skip to [auto-cpufreq: modes and options](https://github.com/AdnanHodzic/auto-cpufreq#auto-cpufreq-modes-and-options) for further reference. -#### Get auto-cpufreq source code +## How to run auto-cpufreq -`git clone https://github.com/AdnanHodzic/auto-cpufreq.git` +auto-cpufreq can be run by simply running the `auto-cpufreq` and following on screen instructions, i.e: -#### Install requirements +`sudo auto-cpufreq` -##### Requirements installation for Debian/Ubuntu and their derivatives - -All requirements can be installed by running: - -`sudo apt install python3-dev python3-pip python3-distro python3-psutil python3-click python3-power -y` - -Since APT packages may contain older version of necessary Python packages, please make sure to have latest version by running: -`sudo pip3 install --upgrade psutil click distro power` - -##### Requirements installation for Redhat/Fedora and its derivatives - -Necessary pre-requisites can be installed by running: - -`sudo yum install python-devel` - -After which you need to[ need to install rest of the requirements](https://github.com/AdnanHodzic/auto-cpufreq#requirements-installation-for-all-other-linux-distributions) as stated below. - -##### Requirements installation for all other Linux distributions - -If you have python3 and pip3 installed simply run: - -`sudo pip3 install psutil click distro power` - -Note: libraries must be installed using root user as tool will be run as root. - -##### Running auto-cpufreq on AMD CPU and/or desktop/servers's +#### Running auto-cpufreq on AMD CPU and/or desktop/servers's Please note when this tool was made it was solely targeting Intel CPU's running on laptops. Support for both AMD CPU is [currently being worked on](https://github.com/AdnanHodzic/auto-cpufreq/issues/17). While there are plans to [extend support for desktop/servers](https://www.reddit.com/r/linux/comments/ejxx9f/github_autocpufreq_automatic_cpu_speed_power/fd5nodm/) in near future. -#### Run auto-cpufreq - -auto-cpufreq can be run by simply running the `auto-cpufreq.py` and following on screen instructions, i.e: - -`sudo python3 auto-cpufreq.py` - ## auto-cpufreq modes and options -#### Monitor +### Monitor -`sudo python3 auto-cpufreq.py --monitor` +`sudo auto-cpufreq --monitor` No changes are made to the system, and is solely made for demonstration purposes what auto-cpufreq could do differently for your system. -#### Live +### Live -`sudo python3 auto-cpufreq.py --live` +`sudo auto-cpufreq --live` 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. -#### Install - auto-cpufreq daemon +### Install - auto-cpufreq daemon Necessary changes are made to the system for auto-cpufreq CPU optimizaton to persist across reboots. Daemon is deployed and then started as a systemd service. Changes are made automatically and live log is made for monitoring purposes. -`sudo python3 auto-cpufreq.py --install` +`sudo auto-cpufreq --install` After daemon is installed, `auto-cpufreq` is available as a binary and is running in the background. Its logs can be viewed by running: `auto-cpufreq --log` @@ -108,20 +94,17 @@ Since daemon is running as a systemd service, its status can be seen by running: `systemctl status auto-cpufreq` -#### Remove - auto-cpufreq daemon +### Remove - auto-cpufreq daemon auto-cpufreq daemon and its systemd service, along with all its persistent changes can be removed by running: `sudo auto-cpufreq --remove` -or -`sudo python3 auto-cpufreq.py --remove` -#### Log +### Log If daemon has been instaled, live log of CPU/system load monitoring and optimizaiton can be seen by running: `auto-cpufreq --log` -or `sudo python3 auto-cpufreq.py --log` ## Discussion: diff --git a/auto-cpufreq-installer b/auto-cpufreq-installer new file mode 100755 index 0000000..1b993f9 --- /dev/null +++ b/auto-cpufreq-installer @@ -0,0 +1,192 @@ +#!/bin/bash +# +# auto-cpufreq-installer: +# auto-cpufreq source code based installer + +distro="$(lsb_release -is)" +release="$(lsb_release -rs)" +codename="$(lsb_release -cs)" + +separator(){ +sep="\n-------------------------------------------------------------------------------" +echo -e $sep +} + +# root check +root_check(){ +if (( $EUID != 0 )); +then + separator + echo -e "\nMust be run as root (i.e: 'sudo $0')." + separator + exit 1 +fi +} + +# python packages install +pip_pkg_install(){ +pip3 install psutil click distro power +} + +complete_msg(){ +echo -e "\nauto-cpufreq tool successfully installed.\n" +echo -e "For list of options, run:\nauto-cpufreq" +} + +# tool install +install(){ +python3 setup.py install --record files.txt +mkdir -p /usr/local/share/auto-cpufreq/ +cp -r scripts/ /usr/local/share/auto-cpufreq/ +} + +tool_install(){ +# Debian +if [ -f /etc/debian_version ]; +then + separator + echo -e "\nDetected Debian based distribution" + separator + echo -e "\nSetting up Python environment\n" + apt install python3-dev python3-pip -y + separator + echo -e "\nInstalling necessary Python packages\n" + pip_pkg_install + separator + echo -e "\ninstalling auto-cpufreq tool\n" + install + separator + complete_msg + separator +# RedHat +elif [ -f /etc/redhat-release ]; +then + separator + echo -e "\nDetected RedHat based distribution\n" + echo -e "\nSetting up Python environment\n" + # CentOS exception + if [ -f /etc/centos-release ]; + then + yum install platform-python-devel + else + yum install python-devel + fi + echo -e "\nInstalling necessary Python packages\n" + pip_pkg_install + separator + echo -e "\ninstalling auto-cpufreq tool\n" + install + separator + complete_msg + separator +# Other +else + separator + echo -e "\nDidn't detect Debian or RedHat based distro.\n" + echo -e "To complete installation, you need to:" + echo -e "Install: python3 and pip3\n" + echo -e "Install necessary Python packages:" + echo -e "pip3 install psutil click distro power" + echo -e "\nRun following sequence of lines:" + echo -e "\n-----" + echo -e "\npython3 setup.py install --record files.txt" + echo -e "mkdir -p /usr/local/share/auto-cpufreq/" + echo -e "cp -r scripts/ /usr/local/share/auto-cpufreq/" + echo -e "\n-----" + echo -e "\nAfter which tool is installed, for full list of options run:" + echo -e "auto-cpufreq" + separator + echo -e "\nConsider creating a feature request to add support for your distro:" + echo -e "https://github.com/AdnanHodzic/auto-cpufreq/issues/new" + echo -e "\nMake sure to include following information:\n" + echo -e "Distribution: $distro" + echo -e "Release: $release" + echo -e "Codename: $codename" + separator +fi +} + +tool_remove(){ + +files="files.txt" +share_dir="/usr/local/share/auto-cpufreq/" +srv_install="/usr/bin/auto-cpufreq-install" +srv_remove="/usr/bin/auto-cpufreq-remove" +log_file="/var/log/auto-cpufreq.log" +tool_proc_rm="auto-cpufreq --remove" + +# stop any running auto-cpufreq argument (daemon/live/monitor) +tool_arg_pids=( $(pgrep -f "auto-cpufreq --") ) +for pid in "${tool_arg_pids[@]}"; do + if [[ $tool_arg_pids != $$ ]]; then + kill "$tool_arg_pids" + fi +done + +# run uninstall in case of installed daemon +if [ -f $srv_remove ] +then + eval $tool_proc_rm +fi + +# remove auto-cpufreq and all its supporting files +[ -f $files ] && cat $files | xargs sudo rm -rf && rm -f $files +[ -f $share_dir ] && rm -rf $share_dir + +# files cleanup +[ -f $srv_install ] && rm $srv_install +[ -f $srv_remove ] && rm $srv_remove +[ -f $log_file ] && rm $log_file + +separator +echo -e "\nauto-cpufreq tool and all its supporting files successfully removed.\n" +} + +ask_operation(){ +echo -e "\n-------------------------- auto-cpufreq installer -----------------------------" +echo -e "\nWelcome to auto-cpufreq tool installer." +echo -e "\nOptions:\n" +read -p "[I]nstall +[R]emove +[Q]uit + +Select a key: [i/r/q]: " answer +} + +root_check + +if [[ -z "${1}" ]]; +then + ask_operation +else + case "${1}" in + "--install") + answer="i" + ;; + "--remove") + answer="r" + ;; + *) + answer="n" + ;; + esac +fi + +if [[ $answer == [Ii] ]]; +then + root_check + tool_install +elif [[ $answer == [Rr] ]]; +then + root_check + tool_remove +elif [[ $answer == [Qq] ]]; +then + separator + echo "" + exit 0 +else + separator + echo -e "\nUnknown key, aborting ...\n" + exit 1 +fi \ No newline at end of file diff --git a/bin/auto-cpufreq b/bin/auto-cpufreq new file mode 100755 index 0000000..aa5cb02 --- /dev/null +++ b/bin/auto-cpufreq @@ -0,0 +1,108 @@ +#!/usr/bin/env python3 +# +# auto-cpufreq - Automatic CPU speed & power optimizer for Linux +# +# Blog post: http://foolcontrol.org/?p=3124 + +# core import +import sys +sys.path.append('../') +from source.core import * + +# ToD: replace every s.call with s.run + +# cli +@click.command() +@click.option("--monitor", is_flag=True, help="Monitor and suggest CPU optimizations") +@click.option("--live", is_flag=True, help="Monitor and make suggested CPU optimizations") +@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: + print("\n" + "-" * 32 + " auto-cpufreq " + "-" * 33 + "\n") + print("Automatic CPU speed & power optimizer for Linux") + print("\nExample usage:\nauto-cpufreq --monitor") + print("\n-----\n") + + s.call(["auto-cpufreq", "--help"]) + footer(79) + else: + if daemon: + if os.getenv("PKG_MARKER") == "SNAP" and dcheck == "enabled": + while True: + root_check() + gov_check() + cpufreqctl() + sysinfo() + set_autofreq() + countdown(5) + subprocess.call("clear") + elif os.getenv("PKG_MARKER") != "SNAP": + while True: + root_check() + gov_check() + cpufreqctl() + sysinfo() + set_autofreq() + countdown(5) + subprocess.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") + footer(79) + exit(1) + elif monitor: + while True: + root_check() + running_daemon() + gov_check() + cpufreqctl() + sysinfo() + mon_autofreq() + countdown(5) + subprocess.call("clear") + elif live: + while True: + root_check() + running_daemon() + gov_check() + cpufreqctl() + sysinfo() + set_autofreq() + countdown(5) + subprocess.call("clear") + elif log: + # ToDo: fail if log is missing or empty (on) + read_log() + elif install: + if os.getenv('PKG_MARKER') == "SNAP": + root_check() + running_daemon() + gov_check() + s.run("snapctl set daemon=enabled", shell=True) + s.run("snapctl start --enable auto-cpufreq", shell=True) + deploy_complete_msg() + else: + root_check() + running_daemon() + gov_check() + deploy() + deploy_complete_msg() + elif remove: + if os.getenv('PKG_MARKER') == "SNAP": + root_check() + s.run("snapctl set daemon=disabled", shell=True) + s.run("snapctl stop --disable auto-cpufreq", shell=True) + delete_file(auto_cpufreq_log_file) + remove_complete_msg() + else: + root_check() + remove() + remove_complete_msg() + +if __name__ == '__main__': + # while True: + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5984983 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +psutil +click +distro +power \ No newline at end of file diff --git a/scripts/auto-cpufreq-install.sh b/scripts/auto-cpufreq-install.sh index bb586fa..c800e60 100755 --- a/scripts/auto-cpufreq-install.sh +++ b/scripts/auto-cpufreq-install.sh @@ -11,11 +11,8 @@ then exit 1 fi -# this is needed on SELinux enabled systems (see also ConditionPathExists in .service) -touch /var/log/auto-cpufreq.log - echo -e "\n* Deploy auto-cpufreq systemd unit file" -cp scripts/auto-cpufreq.service /etc/systemd/system/auto-cpufreq.service +cp /usr/local/share/auto-cpufreq/scripts/auto-cpufreq.service /etc/systemd/system/auto-cpufreq.service echo -e "\n* Reloading systemd manager configuration" systemctl daemon-reload @@ -27,11 +24,4 @@ echo -e "\n* Starting auto-cpufreq daemon (systemd) service" systemctl start auto-cpufreq echo -e "\n* Enabling auto-cpufreq daemon (systemd) service at boot" -systemctl enable auto-cpufreq - -echo -e "\n------------------ auto-cpufreq daemon installed and running -----------------\n" - -echo -e "To view live log, run:\nauto-cpufreq --log" -echo -e "\nTo disable and remove auto-cpufreq daemon, run:\nsudo auto-cpufreq --remove" - -echo -e "\n-------------------------------------------------------------------------------\n" +systemctl enable auto-cpufreq \ No newline at end of file diff --git a/scripts/auto-cpufreq-remove.sh b/scripts/auto-cpufreq-remove.sh index 2a248fd..a387c33 100755 --- a/scripts/auto-cpufreq-remove.sh +++ b/scripts/auto-cpufreq-remove.sh @@ -24,15 +24,4 @@ echo -e "\n* Reloading systemd manager configuration" systemctl daemon-reload echo -e "reset failed" -systemctl reset-failed - -echo -e "\n* Removing auto-cpufreq daemon install script" -rm /usr/bin/auto-cpufreq-install - -echo -e "\n* Removing auto-cpufreq binary" -rm /usr/bin/auto-cpufreq - -echo -e "\n* Removing auto-cpufreq log file" -rm /var/log/auto-cpufreq.log - -echo -e "\n-------------------------------------------------------------------------------\n" +systemctl reset-failed \ No newline at end of file diff --git a/scripts/auto-cpufreq.service b/scripts/auto-cpufreq.service index e47dbd3..e0f1fc3 100644 --- a/scripts/auto-cpufreq.service +++ b/scripts/auto-cpufreq.service @@ -6,7 +6,7 @@ ConditionPathExists=/var/log/auto-cpufreq.log [Service] Type=simple User=root -ExecStart=/usr/bin/python3 /usr/bin/auto-cpufreq --daemon -StandardOutput=file:/var/log/auto-cpufreq.log +ExecStart=auto-cpufreq --daemon +StandardOutput=append:/var/log/auto-cpufreq.log [Install] WantedBy=multi-user.target diff --git a/scripts/cpufreqctl.sh b/scripts/cpufreqctl.sh index 008f0da..81c5453 100755 --- a/scripts/cpufreqctl.sh +++ b/scripts/cpufreqctl.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash VERSION='20' -cpucount=`nproc` +cpucount=`cat /proc/cpuinfo|grep processor|wc -l` FLROOT=/sys/devices/system/cpu DRIVER=auto VERBOSE=0 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b32d50f --- /dev/null +++ b/setup.py @@ -0,0 +1,35 @@ +import os + +from setuptools import setup + +with open('README.md') as readme_file: + readme = readme_file.read() + +this = os.path.dirname(os.path.realpath(__file__)) + +def read(name): + with open(os.path.join(this, name)) as f: + return f.read() +setup( + name='auto-cpufreq', + version='1.0', + description='Automatic CPU speed & power optimizer for Linux', + long_description=readme, + author='Adnan Hodzic', + author_email='adnan@hodzic.org', + url='https://github.com/AdnanHodzic/auto-cpufreq', + packages=['source'], + install_requires=read('requirements.txt'), + include_package_data=True, + zip_safe=True, + licence='GPLv3', + keywords='linux cpu speed power frequency turbo optimzier auto cpufreq', + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Operating System :: POSIX :: Linux' + 'Environment :: Console' + 'Natural Language :: English' + ], + scripts=['bin/auto-cpufreq'] +) \ No newline at end of file diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml new file mode 100644 index 0000000..ac89f99 --- /dev/null +++ b/snap/snapcraft.yaml @@ -0,0 +1,48 @@ +name: auto-cpufreq +base: core18 +version: '1.0' +summary: Automatic CPU speed & power optimizer for Linux +description: | + Automatic CPU speed & power optimizer for Linux based on active + monitoring of laptop's battery state, CPU usage and system load. + Ultimately allowing you to improve battery life without making + any compromises. + +grade: stable +confinement: strict + +parts: + auto-cpufreq: + plugin: python + python-version: python3 + source: . + + deploy-cpufrectl: + plugin: dump + source: scripts + organize: + cpufreqctl.sh: usr/bin/cpufreqctl + +apps: + auto-cpufreq: + command: bin/auto-cpufreq + plugs: + - cpu-control + - system-observe + - hardware-observe + environment: + LC_ALL: C.UTF-8 + LANG: C.UTF-8 + PKG_MARKER: SNAP + + service: + command: bin/auto-cpufreq --daemon 2>&1 | tee -a $SNAP_DATA/auto-cpufreq.log + plugs: + - cpu-control + - system-observe + - hardware-observe + environment: + LC_ALL: C.UTF-8 + LANG: C.UTF-8 + PKG_MARKER: SNAP + daemon: simple \ No newline at end of file diff --git a/source/__init__.py b/source/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/auto-cpufreq.py b/source/core.py old mode 100755 new mode 100644 similarity index 64% rename from auto-cpufreq.py rename to source/core.py index d935b09..bf03cb8 --- a/auto-cpufreq.py +++ b/source/core.py @@ -1,9 +1,8 @@ #!/usr/bin/env python3 # -# auto-cpufreq - Automatic CPU speed & power optimizer for Linux -# -# Blog post: http://foolcontrol.org/?p=3124 +# auto-cpufreq - core functionality +# ToDo: re-order in a single line? import subprocess import os import sys @@ -12,6 +11,7 @@ import psutil import platform import click import power +import signal # ToDo: # - re-enable CPU fan speed display and make more generic and not only for thinkpad @@ -21,33 +21,58 @@ import power p = psutil pl = platform s = subprocess -tool_run = sys.argv[0] cpus = os.cpu_count() +pw = power # get turbo boost state -cur_turbo = s.getoutput("cat /sys/devices/system/cpu/intel_pstate/no_turbo") +turbo_loc = "/sys/devices/system/cpu/intel_pstate/no_turbo" +cur_turbo = s.getoutput("cat " + turbo_loc) + + # govs/script loc +avail_gov_loc = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors" +scripts_dir = "/usr/local/share/auto-cpufreq/scripts/" # get current scaling governor get_cur_gov = s.getoutput("cpufreqctl --governor") gov_state = get_cur_gov.split()[0] # get battery state -bat_state = power.PowerManagement().get_providing_power_source_type() +bat_state = pw.PowerManagement().get_providing_power_source_type() # auto-cpufreq log file auto_cpufreq_log_file = "/var/log/auto-cpufreq.log" +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(): - # deploy cpufreqctl script (if missing) - if os.path.isfile("/usr/bin/cpufreqctl"): + # detect if running on a SNAP + if os.getenv('PKG_MARKER') == "SNAP": pass else: - os.system("cp scripts/cpufreqctl.sh /usr/bin/cpufreqctl") + # deploy cpufreqctl script (if missing) + if os.path.isfile("/usr/bin/cpufreqctl"): + pass + else: + os.system("cp " + scripts_dir + "cpufreqctl.sh /usr/bin/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(): @@ -69,14 +94,14 @@ def deploy(): except: print("\nERROR:\nWas unable to turn off bluetooth on boot") - print("\n* Deploy auto-cpufreq as system wide accessible binary") - os.system("cp auto-cpufreq.py /usr/bin/auto-cpufreq") + # create log file + create_file(auto_cpufreq_log_file) print("\n* Deploy auto-cpufreq install script") - os.system("cp scripts/auto-cpufreq-install.sh /usr/bin/auto-cpufreq-install") + os.system("cp " + scripts_dir + "/auto-cpufreq-install.sh /usr/bin/auto-cpufreq-install") print("\n* Deploy auto-cpufreq remove script") - os.system("cp scripts/auto-cpufreq-remove.sh /usr/bin/auto-cpufreq-remove") + os.system("cp " + scripts_dir + "/auto-cpufreq-remove.sh /usr/bin/auto-cpufreq-remove") # run auto-cpufreq daemon deploy script s.call("/usr/bin/auto-cpufreq-install", shell=True) @@ -102,9 +127,15 @@ def remove(): # run auto-cpufreq daemon install script s.call("/usr/bin/auto-cpufreq-remove", shell=True) + # remove auto-cpufreq-remove + os.remove("/usr/bin/auto-cpufreq-remove") + + # delete log file + delete_file(auto_cpufreq_log_file) + # check for necessary scaling governors def gov_check(): - avail_gov = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors" + avail_gov = avail_gov_loc governors=["performance","powersave"] @@ -120,7 +151,8 @@ def gov_check(): def root_check(): if not os.geteuid() == 0: print("\n" + "-" * 33 + " Root check " + "-" * 34 + "\n") - sys.exit("ERROR:\n\nMust be run root for this functionality to work, i.e: \nsudo " + tool_run + "\n") + print("ERROR:\n\nMust be run root for this functionality to work, i.e: \nsudo auto-cpufreq") + footer(79) exit(1) # refresh countdown @@ -148,19 +180,17 @@ def set_powersave(): print("Total system load:", load1m, "\n") # conditions for setting turbo in powersave - if load1m > cpus: + if load1m > cpus / 7: print("High load, setting turbo boost: on") - s.run("echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo", shell=True) + s.run("echo 0 > " + turbo_loc, shell=True) footer(79) - elif cpuload > 50: + elif cpuload > 25: print("High CPU load, setting turbo boost: on") - s.run("echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo", shell=True) - #print("\n" + "-" * 60 + "\n") + s.run("echo 0 > " + turbo_loc, shell=True) footer(79) else: print("Load optimal, setting turbo boost: off") - s.run("echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo", shell=True) - #print("\n" + "-" * 60 + "\n") + s.run("echo 1 > " + turbo_loc, shell=True) footer(79) # make turbo suggestions in powersave @@ -174,7 +204,7 @@ def mon_powersave(): print("\nTotal CPU usage:", cpuload, "%") print("Total system load:", load1m, "\n") - if load1m > 2: + if load1m > cpus / 7: print("High load, suggesting to set turbo boost: on") if cur_turbo == "0": print("Currently turbo boost is: on") @@ -211,19 +241,17 @@ def set_performance(): print("Total system load:", load1m, "\n") # conditions for setting turbo in performance - if load1m > 1: + if load1m >= cpus / 5: print("High load, setting turbo boost: on") - s.run("echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo", shell=True) + s.run("echo 0 > " + turbo_loc, shell=True) footer(79) elif cpuload > 20: print("High CPU load, setting turbo boost: on") - s.run("echo 0 > /sys/devices/system/cpu/intel_pstate/no_turbo", shell=True) - #print("\n" + "-" * 60 + "\n") + s.run("echo 0 > " + turbo_loc, shell=True) footer(79) else: print("Load optimal, setting turbo boost: off") - s.run("echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo", shell=True) - #print("\n" + "-" * 60 + "\n") + s.run("echo 1 > " + turbo_loc, shell=True) footer(79) # make turbo suggestions in performance @@ -251,36 +279,36 @@ def set_autofreq(): print("\n" + "-" * 28 + " CPU frequency scaling " + "-" * 28 + "\n") # get battery state - bat_state = power.PowerManagement().get_providing_power_source_type() + bat_state = pw.PowerManagement().get_providing_power_source_type() # determine which governor should be used - if bat_state == power.POWER_TYPE_AC: + if bat_state == pw.POWER_TYPE_AC: print("Battery is: charging") set_performance() - elif bat_state == power.POWER_TYPE_BATTERY: + elif bat_state == pw.POWER_TYPE_BATTERY: print("Battery is: discharging") set_powersave() else: - print("Couldn't determine battery status. Please report this issue.") + 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") # get battery state - bat_state = power.PowerManagement().get_providing_power_source_type() + bat_state = pw.PowerManagement().get_providing_power_source_type() # determine which governor should be used - if bat_state == power.POWER_TYPE_AC: + if bat_state == pw.POWER_TYPE_AC: print("Battery is: charging") print("Suggesting use of \"performance\" governor\nCurrently using:", gov_state) mon_performance() - elif bat_state == power.POWER_TYPE_BATTERY: + elif bat_state == pw.POWER_TYPE_BATTERY: print("Battery is: discharging") print("Suggesting use of \"powersave\" governor\nCurrently using:", gov_state) mon_powersave() else: - print("Couldn't determine battery status. Please report this issue.") + print("Couldn't determine the battery status. Please report this issue.") # get system information def sysinfo(): @@ -292,9 +320,25 @@ def sysinfo(): print("\n" + "-" * 29 + " System information " + "-" * 30 + "\n") import distro - # get info about linux distro - fdist = distro.linux_distribution() - dist = " ".join(x for x in fdist) + + # get distro information in snap env. + if os.getenv("PKG_MARKER") == "SNAP": + searchfile = open("/var/lib/snapd/hostfs/etc/os-release", "r") + for line in searchfile: + if line.startswith('NAME='): + distro = line[5:line.find('$')].strip("\"") + continue + elif line.startswith('VERSION='): + version = line[8:line.find('$')].strip("\"") + continue + + dist = distro + " " + version + searchfile.close() + else: + # get distro information + fdist = distro.linux_distribution() + dist = " ".join(x for x in fdist) + print("Linux distro: " + dist) print("Linux kernel: " + pl.release()) @@ -353,96 +397,52 @@ def sysinfo(): #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.path.isfile(auto_cpufreq_log_file): - # read /var/log/auto-cpufreq.log + if os.getenv("PKG_MARKER") == "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: print("\n" + "-" * 30 + " auto-cpufreq log " + "-" * 31 + "\n") - print("ERROR: auto-cpufreq log is missing.\n\nMake sure to run: \"python3 auto-cpufreq.py --install\" first") + print("ERROR: auto-cpufreq log is missing.\n\nMake sure to run: \"auto-cpufreq --install\" first") footer(79) -def running_check(): - daemon_marker = False - for proc in p.process_iter(): +# 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(): try: - pinfo = proc.as_dict(attrs=['pid', 'name', 'cmdline']) - except p.NoSuchProcess: - pass - else: - if pinfo['name'] == 'python3' and \ - '/usr/bin/auto-cpufreq' in pinfo['cmdline'] and '--daemon' in pinfo['cmdline']: - daemon_marker = True + # requests the process information corresponding to each process id + p = psutil.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(): + # 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): + return True + else: + pass + else: + pass + except: + continue - if daemon_marker: - print("\n" + "-" * 25 + " detected auto-cpufreq daemon" + "-" * 25 + "\n") - print("ERROR: prevention from running multiple instances") - print("\nIt seems like auto-cpufreq daemon is already running.\n") - print("----") - print("\nTo view live log run:\n\tauto-cpufreq --log") - footer(79) - sys.exit() - -# cli -@click.command() -@click.option("--monitor", is_flag=True, help="Monitor and suggest CPU optimizations") -@click.option("--live", is_flag=True, help="Monitor and make suggested CPU optimizations") -@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 cli(monitor, live, daemon, install, log): - # print --help by default if no argument is provided when auto-cpufreq is run - if len(sys.argv) == 1: - print("\n" + "-" * 22 + " auto-cpufreq " + "-" * 23 + "\n") - print("Automatic CPU speed & power optimizer for Linux") - print("\nExample usage:\npython3 " + tool_run + " --monitor") - print("\n-----\n") - - s.call(["python3", "auto-cpufreq.py", "--help"]) - print("\n" + "-" * 59 + "\n") - else: - if daemon: - while True: - root_check() - gov_check() - cpufreqctl() - sysinfo() - set_autofreq() - countdown(5) - subprocess.call("clear") - elif monitor: - while True: - running_check() - root_check() - gov_check() - cpufreqctl() - sysinfo() - mon_autofreq() - countdown(5) - subprocess.call("clear") - elif live: - while True: - running_check() - root_check() - gov_check() - cpufreqctl() - sysinfo() - set_autofreq() - countdown(5) - subprocess.call("clear") - elif log: - read_log() - elif install: - running_check() - root_check() - gov_check() - deploy() - elif remove: - root_check() - remove() - -if __name__ == '__main__': - # while True: - cli() +# check if auto-cpufreq --daemon is running +def running_daemon(): + if is_running('auto-cpufreq', '--daemon'): + deploy_complete_msg() + exit(1) + elif os.getenv("PKG_MARKER") == "SNAP" and dcheck == "enabled": + deploy_complete_msg() + exit(1) \ No newline at end of file