Merge branch 'snap'

This commit is contained in:
Adnan Hodzic 2020-03-16 16:37:06 +01:00
commit 1b796b4323
13 changed files with 553 additions and 199 deletions

5
.gitignore vendored
View File

@ -26,6 +26,7 @@ share/python-wheels/
.installed.cfg .installed.cfg
*.egg *.egg
MANIFEST MANIFEST
files.txt
# PyInstaller # PyInstaller
# Usually these files are written by a python script from a template # Usually these files are written by a python script from a template
@ -127,3 +128,7 @@ dmypy.json
# Pyre type checker # Pyre type checker
.pyre/ .pyre/
# vim
*.swp
*.swo

View File

@ -33,74 +33,60 @@ Please note: this tool doesn't conflict and [works great in tandem with TLP](htt
* System load * System load
* Automatic CPU & power optimization (temporary and persistent) * 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. [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 #### Running auto-cpufreq on AMD CPU and/or desktop/servers's
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
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). 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. 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 ## 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. 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. 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. 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` 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` `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: auto-cpufreq daemon and its systemd service, along with all its persistent changes can be removed by running:
`sudo auto-cpufreq --remove` `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: If daemon has been instaled, live log of CPU/system load monitoring and optimizaiton can be seen by running:
`auto-cpufreq --log` `auto-cpufreq --log`
or `sudo python3 auto-cpufreq.py --log`
## Discussion: ## Discussion:

192
auto-cpufreq-installer Executable file
View File

@ -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

108
bin/auto-cpufreq Executable file
View File

@ -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()

4
requirements.txt Normal file
View File

@ -0,0 +1,4 @@
psutil
click
distro
power

View File

@ -11,11 +11,8 @@ then
exit 1 exit 1
fi 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" 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" echo -e "\n* Reloading systemd manager configuration"
systemctl daemon-reload systemctl daemon-reload
@ -28,10 +25,3 @@ systemctl start auto-cpufreq
echo -e "\n* Enabling auto-cpufreq daemon (systemd) service at boot" echo -e "\n* Enabling auto-cpufreq daemon (systemd) service at boot"
systemctl enable auto-cpufreq 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"

View File

@ -25,14 +25,3 @@ systemctl daemon-reload
echo -e "reset failed" echo -e "reset failed"
systemctl 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"

View File

@ -6,7 +6,7 @@ ConditionPathExists=/var/log/auto-cpufreq.log
[Service] [Service]
Type=simple Type=simple
User=root User=root
ExecStart=/usr/bin/python3 /usr/bin/auto-cpufreq --daemon ExecStart=auto-cpufreq --daemon
StandardOutput=file:/var/log/auto-cpufreq.log StandardOutput=append:/var/log/auto-cpufreq.log
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
VERSION='20' VERSION='20'
cpucount=`nproc` cpucount=`cat /proc/cpuinfo|grep processor|wc -l`
FLROOT=/sys/devices/system/cpu FLROOT=/sys/devices/system/cpu
DRIVER=auto DRIVER=auto
VERBOSE=0 VERBOSE=0

35
setup.py Normal file
View File

@ -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']
)

48
snap/snapcraft.yaml Normal file
View File

@ -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

0
source/__init__.py Normal file
View File

248
auto-cpufreq.py → source/core.py Executable file → Normal file
View File

@ -1,9 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# #
# auto-cpufreq - Automatic CPU speed & power optimizer for Linux # auto-cpufreq - core functionality
#
# Blog post: http://foolcontrol.org/?p=3124
# ToDo: re-order in a single line?
import subprocess import subprocess
import os import os
import sys import sys
@ -12,6 +11,7 @@ import psutil
import platform import platform
import click import click
import power import power
import signal
# ToDo: # ToDo:
# - re-enable CPU fan speed display and make more generic and not only for thinkpad # - re-enable CPU fan speed display and make more generic and not only for thinkpad
@ -21,33 +21,58 @@ import power
p = psutil p = psutil
pl = platform pl = platform
s = subprocess s = subprocess
tool_run = sys.argv[0]
cpus = os.cpu_count() cpus = os.cpu_count()
pw = power
# get turbo boost state # 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 current scaling governor
get_cur_gov = s.getoutput("cpufreqctl --governor") get_cur_gov = s.getoutput("cpufreqctl --governor")
gov_state = get_cur_gov.split()[0] gov_state = get_cur_gov.split()[0]
# get battery state # 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
auto_cpufreq_log_file = "/var/log/auto-cpufreq.log" 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 # deploy cpufreqctl script
def cpufreqctl(): def cpufreqctl():
# deploy cpufreqctl script (if missing) # detect if running on a SNAP
if os.path.isfile("/usr/bin/cpufreqctl"): if os.getenv('PKG_MARKER') == "SNAP":
pass pass
else: 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): def footer(l):
print("\n" + "-" * l + "\n") 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 # deploy auto-cpufreq daemon
def deploy(): def deploy():
@ -69,14 +94,14 @@ def deploy():
except: except:
print("\nERROR:\nWas unable to turn off bluetooth on boot") print("\nERROR:\nWas unable to turn off bluetooth on boot")
print("\n* Deploy auto-cpufreq as system wide accessible binary") # create log file
os.system("cp auto-cpufreq.py /usr/bin/auto-cpufreq") create_file(auto_cpufreq_log_file)
print("\n* Deploy auto-cpufreq install script") 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") 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 # run auto-cpufreq daemon deploy script
s.call("/usr/bin/auto-cpufreq-install", shell=True) s.call("/usr/bin/auto-cpufreq-install", shell=True)
@ -102,9 +127,15 @@ def remove():
# run auto-cpufreq daemon install script # run auto-cpufreq daemon install script
s.call("/usr/bin/auto-cpufreq-remove", shell=True) 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 # check for necessary scaling governors
def gov_check(): def gov_check():
avail_gov = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors" avail_gov = avail_gov_loc
governors=["performance","powersave"] governors=["performance","powersave"]
@ -120,7 +151,8 @@ def gov_check():
def root_check(): def root_check():
if not os.geteuid() == 0: if not os.geteuid() == 0:
print("\n" + "-" * 33 + " Root check " + "-" * 34 + "\n") 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) exit(1)
# refresh countdown # refresh countdown
@ -148,19 +180,17 @@ def set_powersave():
print("Total system load:", load1m, "\n") print("Total system load:", load1m, "\n")
# conditions for setting turbo in powersave # conditions for setting turbo in powersave
if load1m > cpus: if load1m > cpus / 7:
print("High load, setting turbo boost: on") 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) footer(79)
elif cpuload > 50: elif cpuload > 25:
print("High CPU load, setting turbo boost: on") print("High CPU 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)
#print("\n" + "-" * 60 + "\n")
footer(79) footer(79)
else: else:
print("Load optimal, setting turbo boost: off") print("Load optimal, setting turbo boost: off")
s.run("echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo", shell=True) s.run("echo 1 > " + turbo_loc, shell=True)
#print("\n" + "-" * 60 + "\n")
footer(79) footer(79)
# make turbo suggestions in powersave # make turbo suggestions in powersave
@ -174,7 +204,7 @@ def mon_powersave():
print("\nTotal CPU usage:", cpuload, "%") print("\nTotal CPU usage:", cpuload, "%")
print("Total system load:", load1m, "\n") print("Total system load:", load1m, "\n")
if load1m > 2: if load1m > cpus / 7:
print("High load, suggesting to set turbo boost: on") print("High load, suggesting to set turbo boost: on")
if cur_turbo == "0": if cur_turbo == "0":
print("Currently turbo boost is: on") print("Currently turbo boost is: on")
@ -211,19 +241,17 @@ def set_performance():
print("Total system load:", load1m, "\n") print("Total system load:", load1m, "\n")
# conditions for setting turbo in performance # conditions for setting turbo in performance
if load1m > 1: if load1m >= cpus / 5:
print("High load, setting turbo boost: on") 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) footer(79)
elif cpuload > 20: elif cpuload > 20:
print("High CPU load, setting turbo boost: on") print("High CPU 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)
#print("\n" + "-" * 60 + "\n")
footer(79) footer(79)
else: else:
print("Load optimal, setting turbo boost: off") print("Load optimal, setting turbo boost: off")
s.run("echo 1 > /sys/devices/system/cpu/intel_pstate/no_turbo", shell=True) s.run("echo 1 > " + turbo_loc, shell=True)
#print("\n" + "-" * 60 + "\n")
footer(79) footer(79)
# make turbo suggestions in performance # make turbo suggestions in performance
@ -251,36 +279,36 @@ def set_autofreq():
print("\n" + "-" * 28 + " CPU frequency scaling " + "-" * 28 + "\n") print("\n" + "-" * 28 + " CPU frequency scaling " + "-" * 28 + "\n")
# get battery state # 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 # 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("Battery is: charging")
set_performance() set_performance()
elif bat_state == power.POWER_TYPE_BATTERY: elif bat_state == pw.POWER_TYPE_BATTERY:
print("Battery is: discharging") print("Battery is: discharging")
set_powersave() set_powersave()
else: 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 # make cpufreq suggestions
def mon_autofreq(): def mon_autofreq():
print("\n" + "-" * 28 + " CPU frequency scaling " + "-" * 28 + "\n") print("\n" + "-" * 28 + " CPU frequency scaling " + "-" * 28 + "\n")
# get battery state # 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 # 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("Battery is: charging")
print("Suggesting use of \"performance\" governor\nCurrently using:", gov_state) print("Suggesting use of \"performance\" governor\nCurrently using:", gov_state)
mon_performance() mon_performance()
elif bat_state == power.POWER_TYPE_BATTERY: elif bat_state == pw.POWER_TYPE_BATTERY:
print("Battery is: discharging") print("Battery is: discharging")
print("Suggesting use of \"powersave\" governor\nCurrently using:", gov_state) print("Suggesting use of \"powersave\" governor\nCurrently using:", gov_state)
mon_powersave() mon_powersave()
else: 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 # get system information
def sysinfo(): def sysinfo():
@ -292,9 +320,25 @@ def sysinfo():
print("\n" + "-" * 29 + " System information " + "-" * 30 + "\n") print("\n" + "-" * 29 + " System information " + "-" * 30 + "\n")
import distro import distro
# get info about linux distro
fdist = distro.linux_distribution() # get distro information in snap env.
dist = " ".join(x for x in fdist) 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 distro: " + dist)
print("Linux kernel: " + pl.release()) print("Linux kernel: " + pl.release())
@ -353,96 +397,52 @@ def sysinfo():
#current_fans = p.sensors_fans()['thinkpad'][0].current #current_fans = p.sensors_fans()['thinkpad'][0].current
#print("\nCPU fan speed:", current_fans, "RPM") #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 # read log func
def read_log(): def read_log():
if os.path.isfile(auto_cpufreq_log_file): if os.getenv("PKG_MARKER") == "SNAP":
# read /var/log/auto-cpufreq.log 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]) s.call(["tail", "-n 50", "-f", auto_cpufreq_log_file])
else: else:
print("\n" + "-" * 30 + " auto-cpufreq log " + "-" * 31 + "\n") 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) footer(79)
def running_check(): # check if program (argument) is running
daemon_marker = False def is_running(program, argument):
for proc in p.process_iter(): # iterate over all process id's found by psutil
for pid in psutil.pids():
try: try:
pinfo = proc.as_dict(attrs=['pid', 'name', 'cmdline']) # requests the process information corresponding to each process id
except p.NoSuchProcess: p = psutil.Process(pid)
pass # check if value of program-variable that was used to call the function matches the name field of the plutil.Process(pid) output
else: if program in p.name():
if pinfo['name'] == 'python3' and \ # check output of p.name(), output name of program
'/usr/bin/auto-cpufreq' in pinfo['cmdline'] and '--daemon' in pinfo['cmdline']: # p.cmdline() - echo the exact command line via which p was called.
daemon_marker = True for arg in p.cmdline():
if argument in str(arg):
return True
else:
pass
else:
pass
except:
continue
if daemon_marker: # check if auto-cpufreq --daemon is running
print("\n" + "-" * 25 + " detected auto-cpufreq daemon" + "-" * 25 + "\n") def running_daemon():
print("ERROR: prevention from running multiple instances") if is_running('auto-cpufreq', '--daemon'):
print("\nIt seems like auto-cpufreq daemon is already running.\n") deploy_complete_msg()
print("----") exit(1)
print("\nTo view live log run:\n\tauto-cpufreq --log") elif os.getenv("PKG_MARKER") == "SNAP" and dcheck == "enabled":
footer(79) deploy_complete_msg()
sys.exit() exit(1)
# 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()