diff --git a/System cost comparison.ods b/System cost comparison.ods new file mode 100644 index 0000000..0c5523d Binary files /dev/null and b/System cost comparison.ods differ diff --git a/autoaspm.py b/autoaspm.py new file mode 100644 index 0000000..d461dec --- /dev/null +++ b/autoaspm.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 + +# Original bash script by Luis R. Rodriguez +# Re-written in Python by z8 +# Re-re-written to patch supported devices automatically by notthebee + +import re +import subprocess +import os +import platform +from enum import Enum + +class ASPM(Enum): + DISABLED = 0b00 + L0s = 0b01 + L1 = 0b10 + L0sL1 = 0b11 + + +def run_prerequisites(): + if platform.system() != "Linux": + raise OSError("This script only runs on Linux-based systems") + if not os.environ.get("SUDO_UID") and os.geteuid() != 0: + raise PermissionError("This script needs root privileges to run") + lspci_detected = subprocess.run(["which", "lspci"], stdout = subprocess.DEVNULL, stderr = subprocess.DEVNULL) + if lspci_detected.returncode > 0: + raise Exception("lspci not detected. Please install pciutils") + lspci_detected = subprocess.run(["which", "setpci"], stdout = subprocess.DEVNULL, stderr = subprocess.DEVNULL) + if lspci_detected.returncode > 0: + raise Exception("setpci not detected. Please install pciutils") + + +def get_device_name(addr): + p = subprocess.Popen([ + "lspci", + "-s", + addr, + ], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + return p.communicate()[0].splitlines()[0].decode() + +def read_all_bytes(device): + all_bytes = bytearray() + device_name = get_device_name(device) + p = subprocess.Popen([ + "lspci", + "-s", + device, + "-xxx" + ], stdout= subprocess.PIPE, stderr=subprocess.PIPE) + ret = p.communicate() + ret = ret[0].decode() + for line in ret.splitlines(): + if not device_name in line and ": " in line: + all_bytes.extend(bytearray.fromhex(line.split(": ")[1])) + if len(all_bytes) < 256: + exit() + return all_bytes + +def find_byte_to_patch(bytes, pos): + pos = bytes[pos] + if bytes[pos] != 0x10: + pos += 0x1 + return find_byte_to_patch(bytes, pos) + else: + pos += 0x10 + return pos + +def patch_byte(device, position, value): + subprocess.Popen([ + "setpci", + "-s", + device, + f"{hex(position)}.B={hex(value)}" + ]).communicate() + +def patch_device(addr, aspm_value): + endpoint_bytes = read_all_bytes(addr) + byte_position_to_patch = find_byte_to_patch(endpoint_bytes, 0x34) + if int(endpoint_bytes[byte_position_to_patch]) & 0b11 != aspm_value.value: + patched_byte = int(endpoint_bytes[byte_position_to_patch]) + patched_byte = patched_byte >> 2 + patched_byte = patched_byte << 2 + patched_byte = patched_byte | aspm_value.value + + patch_byte(addr, byte_position_to_patch, patched_byte) + print(f"{addr}: Enabled ASPM {aspm_value.name}") + else: + print(f"{addr}: Already has ASPM {aspm_value.name} enabled") + + +def list_supported_devices(): + pcie_addr_regex = r"([0-9a-f]{2}:[0-9a-f]{2}\.[0-9a-f])" + lspci = subprocess.run("lspci -vv", shell=True, capture_output=True).stdout + lspci_arr = re.split(pcie_addr_regex, str(lspci))[1:] + lspci_arr = [ x+y for x,y in zip(lspci_arr[0::2], lspci_arr[1::2]) ] + + aspm_devices = {} + for dev in lspci_arr: + device_addr = re.findall(pcie_addr_regex, dev)[0] + if "ASPM" not in dev or "ASPM not supported" in dev: + continue + aspm_support = re.findall(r"ASPM (L[L0-1s ]*),", dev) + if aspm_support: + aspm_devices.update({device_addr: ASPM[aspm_support[0].replace(" ", "")]}) + return aspm_devices + + +def main(): + run_prerequisites() + for device, aspm_mode in list_supported_devices().items(): + patch_device(device, aspm_mode) + +if __name__ == "__main__": + main() diff --git a/check_aspm.sh b/check_aspm.sh new file mode 100644 index 0000000..f571608 --- /dev/null +++ b/check_aspm.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +lspci -vv | awk '/ASPM/{print $0}' RS= | grep --color -P '(^[a-z0-9:.]+|ASPM )' + + diff --git a/init.sh b/init.sh new file mode 100644 index 0000000..b2418e1 --- /dev/null +++ b/init.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +apt install -y powertop linux-cpupower +./autoaspm.py +./check_aspm.sh +powertop --auto-tune diff --git a/turbostat.sh b/turbostat.sh new file mode 100644 index 0000000..62b404a --- /dev/null +++ b/turbostat.sh @@ -0,0 +1,5 @@ +#!/binsh + +turbostat --Summary -quiet --show PkgWatt --interval 1 + +