ryzenset/main.py

202 lines
6.0 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import configparser
import os
import sys
import argparse
from ctypes import *
VERSION = "0.1"
CONFIG_FILE = f"/home/{os.getlogin()}/.local/share/ryzen-set/profiles.ini"
lib_path = os.path.dirname(os.path.abspath(__file__))
os.chdir(lib_path)
lib = cdll.LoadLibrary('/usr/lib64/libryzenadj.so')
# define ctype mappings for types which can not be mapped automatically
# ryzenadj tables
lib.init_ryzenadj.restype = c_void_p
lib.refresh_table.argtypes = [c_void_p]
# Stapm value and limit
lib.get_stapm_limit.restype = c_float
lib.get_stapm_limit.argtypes = [c_void_p]
# Slow limit and value
lib.get_slow_limit.restype = c_float
lib.get_slow_limit.argtypes = [c_void_p]
# Fast limit and value
lib.get_fast_limit.restype = c_float
lib.get_fast_limit.argtypes = [c_void_p]
# Slow time and value
lib.get_slow_time.restype = c_float
lib.get_slow_time.argtypes = [c_void_p]
# stapm time and value
lib.get_stapm_time.restype = c_float
lib.get_stapm_time.argtypes = [c_void_p]
# Vrm Max Current and value
lib.get_vrmmax_current.restype = c_float
lib.get_vrmmax_current.argtypes = [c_void_p]
# Tctl cpu temp
lib.get_tctl_temp.restype = c_float
lib.get_tctl_temp.argtypes = [c_void_p]
ry = lib.init_ryzenadj()
if not ry:
sys.exit("RyzenAdj could not get initialized")
error_messages = {
-1: "{:s} is not supported on this family\n",
-3: "{:s} is not supported on this SMU\n",
-4: "{:s} is rejected by SMU\n"
}
def adjust(field, value):
function_name = "set_" + field
adjust_func = lib.__getattr__(function_name)
adjust_func.argtypes = [c_void_p, c_ulong]
res = adjust_func(ry, value)
if res:
error = error_messages.get(res, "{:s} did fail with {:d}\n")
sys.stderr.write(error.format(function_name, res))
else:
print(f"Sucessfully set {field} to {value}")
def enable(field):
function_name = "set_" + field
adjust_func = lib.__getattr__(function_name)
adjust_func.argtypes = [c_void_p]
res = adjust_func(ry)
if res:
error = error_messages.get(res, "{:s} did fail with {:d}\n")
sys.stderr.write(error.format(function_name, res))
else:
print(f"Sucessfully enable {field}")
def list_categories(config):
categories = []
for profile in config.sections():
if config.has_option(profile, "category"):
category = config.get(profile, "category")
if category not in categories:
categories.append(category)
for category in categories:
print(category)
def list_by_category(list, config):
if list == "categories":
list_categories(config)
else:
for profile in config.sections():
if config.has_option(profile, "category"):
if config.get(profile, "category") == list:
print(profile)
sys.exit(0)
def set_from_config(config, profile):
adjust("stapm_limit", config.getint(profile, 'stapm-limit'))
adjust("fast_limit", config.getint(profile, 'fast-limit'))
adjust("slow_limit", config.getint(profile, 'slow-limit'))
adjust("slow_time", config.getint(profile, 'slow-time'))
adjust("stapm_time", config.getint(profile, 'stapm-time'))
adjust("tctl_temp", config.getint(profile, 'tctl-temp'))
adjust("vrmmax_current", config.getint(profile, 'vrmmax-current'))
if config.getboolean(profile, 'max-performance'):
enable("max_performance")
else:
enable("power_saving")
def get_current_profile(config):
profiles = config.sections()
lib.refresh_table(ry)
current = {
'stapm-limit' : f'{round(lib.get_stapm_limit(ry) * 1000)}',
'fast-limit' : f'{round(lib.get_fast_limit(ry) * 1000)}',
'slow-limit' : f'{round(lib.get_slow_limit(ry) * 1000)}',
'slow-time' : f'{round(lib.get_slow_time(ry))}',
'stapm-time' : f'{round(lib.get_stapm_time(ry))}',
'tctl-temp' : f'{round(lib.get_tctl_temp(ry))}',
'vrmmax-current' : f'{round(lib.get_vrmmax_current(ry) * 1000)}',
}
for profile in profiles:
options = dict(config.items(profile))
options.pop('category')
options.pop('max-performance')
if current == options:
print(profile)
sys.exit(0)
print("system-default")
sys.exit(0)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--version', action='store_true',
help='Print program version')
subparser = parser.add_subparsers(dest='command')
list = subparser.add_parser(
'list', help="List profile category's or profiles from a category")
list.add_argument('category', type=str, metavar='CATEGORY', action='store', nargs='?',
help="Category to print profiles from")
set = subparser.add_parser('set', help="Set specified profile")
set.add_argument('profile', type=str, metavar='PROFILE', action='store', nargs='?',
help="Profile name from the config")
subparser.add_parser('get', help="Get current profile")
config = configparser.ConfigParser()
if os.path.isfile((CONFIG_FILE)):
configExists = True
config.read(os.path.expanduser(
CONFIG_FILE))
else:
configExists = False
if len(sys.argv) == 1:
parser.print_help()
sys.exit(0)
args = parser.parse_args()
if args.version:
print(f'Version: {VERSION}')
sys.exit(0)
if not configExists:
print("No config existing, add profiles first")
sys.exit(1)
if args.command == 'list':
if args.category:
list_by_category(args.category, config)
else:
list_categories(config)
sys.exit(0)
if args.command == 'set':
if args.profile:
set_from_config(config, args.profile)
else:
print('Profile must be provided')
sys.exit(1)
if args.command == 'get':
get_current_profile(config)
if __name__ == "__main__":
main()