Merge branch 'project-overhaul' into dev
This commit is contained in:
commit
2b5e2244c1
5 changed files with 132 additions and 22 deletions
|
|
@ -63,27 +63,27 @@ SMC_IDS = {
|
||||||
# Sources: https://github.com/beltex/SMCKit/blob/master/SMCKit/SMC.swift
|
# Sources: https://github.com/beltex/SMCKit/blob/master/SMCKit/SMC.swift
|
||||||
# http://www.opensource.apple.com/source/net_snmp/
|
# http://www.opensource.apple.com/source/net_snmp/
|
||||||
# https://github.com/jedda/OSX-Monitoring-Tools
|
# https://github.com/jedda/OSX-Monitoring-Tools
|
||||||
'TA0P': {'CPU Temp': False, 'Source': 'Ambient temp'},
|
'TA0P': {'CPU Temp': False, 'Source': 'Ambient'},
|
||||||
'TA0S': {'CPU Temp': False, 'Source': 'PCIE Slot 1 Ambient'},
|
'TA0S': {'CPU Temp': False, 'Source': 'PCIE Slot 1 Ambient'},
|
||||||
'TA1P': {'CPU Temp': False, 'Source': 'Ambient temp'},
|
'TA1P': {'CPU Temp': False, 'Source': 'Ambient'},
|
||||||
'TA1S': {'CPU Temp': False, 'Source': 'PCIE Slot 1 PCB'},
|
'TA1S': {'CPU Temp': False, 'Source': 'PCIE Slot 1 PCB'},
|
||||||
'TA2S': {'CPU Temp': False, 'Source': 'PCIE Slot 2 Ambient'},
|
'TA2S': {'CPU Temp': False, 'Source': 'PCIE Slot 2 Ambient'},
|
||||||
'TA3S': {'CPU Temp': False, 'Source': 'PCIE Slot 2 PCB'},
|
'TA3S': {'CPU Temp': False, 'Source': 'PCIE Slot 2 PCB'},
|
||||||
'TC0C': {'CPU Temp': True, 'Source': 'CPU Core 0'},
|
'TC0C': {'CPU Temp': True, 'Source': 'CPU Core 1'},
|
||||||
'TC0D': {'CPU Temp': True, 'Source': 'CPU die temp'},
|
'TC0D': {'CPU Temp': True, 'Source': 'CPU Diode'},
|
||||||
'TC0H': {'CPU Temp': True, 'Source': 'CPU heatsink temp'},
|
'TC0H': {'CPU Temp': True, 'Source': 'CPU Heatsink'},
|
||||||
'TC0P': {'CPU Temp': True, 'Source': 'CPU Ambient 1'},
|
'TC0P': {'CPU Temp': True, 'Source': 'CPU Proximity'},
|
||||||
'TC1C': {'CPU Temp': True, 'Source': 'CPU Core 1'},
|
'TC1C': {'CPU Temp': True, 'Source': 'CPU Core 2'},
|
||||||
'TC1P': {'CPU Temp': True, 'Source': 'CPU Ambient 2'},
|
'TC1P': {'CPU Temp': True, 'Source': 'CPU Proximity 2'},
|
||||||
'TC2C': {'CPU Temp': True, 'Source': 'CPU B Core 0'},
|
'TC2C': {'CPU Temp': True, 'Source': 'CPU Core 3'},
|
||||||
'TC2P': {'CPU Temp': True, 'Source': 'CPU B Ambient 1'},
|
'TC2P': {'CPU Temp': True, 'Source': 'CPU Proximity 3'},
|
||||||
'TC3C': {'CPU Temp': True, 'Source': 'CPU B Core 1'},
|
'TC3C': {'CPU Temp': True, 'Source': 'CPU Core 4'},
|
||||||
'TC3P': {'CPU Temp': True, 'Source': 'CPU B Ambient 2'},
|
'TC3P': {'CPU Temp': True, 'Source': 'CPU Proximity 4'},
|
||||||
'TCAC': {'CPU Temp': True, 'Source': 'CPU core from PCECI'},
|
'TCAC': {'CPU Temp': True, 'Source': 'CPU core from PCECI'},
|
||||||
'TCAH': {'CPU Temp': True, 'Source': 'CPU HeatSink'},
|
'TCAH': {'CPU Temp': True, 'Source': 'CPU HeatSink'},
|
||||||
'TCBC': {'CPU Temp': True, 'Source': 'CPU B core from PCECI'},
|
'TCBC': {'CPU Temp': True, 'Source': 'CPU B core from PCECI'},
|
||||||
'TCBH': {'CPU Temp': True, 'Source': 'CPU HeatSink'},
|
'TCBH': {'CPU Temp': True, 'Source': 'CPU HeatSink'},
|
||||||
'Te1P': {'CPU Temp': False, 'Source': 'PCIE ambient temp'},
|
'Te1P': {'CPU Temp': False, 'Source': 'PCIE Ambient'},
|
||||||
'Te1S': {'CPU Temp': False, 'Source': 'PCIE slot 1'},
|
'Te1S': {'CPU Temp': False, 'Source': 'PCIE slot 1'},
|
||||||
'Te2S': {'CPU Temp': False, 'Source': 'PCIE slot 2'},
|
'Te2S': {'CPU Temp': False, 'Source': 'PCIE slot 2'},
|
||||||
'Te3S': {'CPU Temp': False, 'Source': 'PCIE slot 3'},
|
'Te3S': {'CPU Temp': False, 'Source': 'PCIE slot 3'},
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ from collections import OrderedDict
|
||||||
from docopt import docopt
|
from docopt import docopt
|
||||||
|
|
||||||
from wk import cfg, debug, exe, graph, log, net, std, tmux
|
from wk import cfg, debug, exe, graph, log, net, std, tmux
|
||||||
|
from wk import os as wk_os
|
||||||
from wk.hw import obj as hw_obj
|
from wk.hw import obj as hw_obj
|
||||||
from wk.hw import sensors as hw_sensors
|
from wk.hw import sensors as hw_sensors
|
||||||
|
|
||||||
|
|
@ -761,6 +762,7 @@ def disk_io_benchmark(state, test_objects, skip_usb=True):
|
||||||
if PLATFORM == 'Darwin':
|
if PLATFORM == 'Darwin':
|
||||||
# Use "RAW" disks under macOS
|
# Use "RAW" disks under macOS
|
||||||
dev_path = dev_path.with_name(f'r{dev_path.name}')
|
dev_path = dev_path.with_name(f'r{dev_path.name}')
|
||||||
|
LOG.info('Using %s for better performance', dev_path)
|
||||||
offset = 0
|
offset = 0
|
||||||
read_rates = []
|
read_rates = []
|
||||||
test_obj.report.append(std.color_string('I/O Benchmark', 'BLUE'))
|
test_obj.report.append(std.color_string('I/O Benchmark', 'BLUE'))
|
||||||
|
|
@ -978,6 +980,11 @@ def disk_surface_scan(state, test_objects):
|
||||||
"""Run surface scan and handle exceptions."""
|
"""Run surface scan and handle exceptions."""
|
||||||
block_size = '1024'
|
block_size = '1024'
|
||||||
dev = test_obj.dev
|
dev = test_obj.dev
|
||||||
|
dev_path = test_obj.dev.path
|
||||||
|
if PLATFORM == 'Darwin':
|
||||||
|
# Use "RAW" disks under macOS
|
||||||
|
dev_path = dev_path.with_name(f'r{dev_path.name}')
|
||||||
|
LOG.info('Using %s for better performance', dev_path)
|
||||||
test_obj.report.append(std.color_string('badblocks', 'BLUE'))
|
test_obj.report.append(std.color_string('badblocks', 'BLUE'))
|
||||||
test_obj.set_status('Working')
|
test_obj.set_status('Working')
|
||||||
|
|
||||||
|
|
@ -987,7 +994,7 @@ def disk_surface_scan(state, test_objects):
|
||||||
block_size = '4096'
|
block_size = '4096'
|
||||||
|
|
||||||
# Start scan
|
# Start scan
|
||||||
cmd = ['sudo', 'badblocks', '-sv', '-b', block_size, '-e', '1', dev.path]
|
cmd = ['sudo', 'badblocks', '-sv', '-b', block_size, '-e', '1', dev_path]
|
||||||
with open(log_path, 'a') as _f:
|
with open(log_path, 'a') as _f:
|
||||||
size_str = std.bytes_to_string(dev.details["size"], use_binary=False)
|
size_str = std.bytes_to_string(dev.details["size"], use_binary=False)
|
||||||
_f.write(
|
_f.write(
|
||||||
|
|
@ -1304,12 +1311,17 @@ def set_apple_fan_speed(speed):
|
||||||
raise RuntimeError(f'Invalid speed {speed}')
|
raise RuntimeError(f'Invalid speed {speed}')
|
||||||
|
|
||||||
# Set cmd
|
# Set cmd
|
||||||
if PLATFORM == 'Linux':
|
if PLATFORM == 'Darwin':
|
||||||
|
try:
|
||||||
|
wk_os.mac.set_fans(speed)
|
||||||
|
except (RuntimeError, ValueError, subprocess.CalledProcessError) as err:
|
||||||
|
LOG.error('Failed to set fans to %s', speed)
|
||||||
|
LOG.error('Error: %s', err)
|
||||||
|
std.print_error(f'Failed to set fans to {speed}')
|
||||||
|
for line in str(err).splitlines():
|
||||||
|
std.print_warning(f' {line.strip()}')
|
||||||
|
elif PLATFORM == 'Linux':
|
||||||
cmd = ['apple-fans', speed]
|
cmd = ['apple-fans', speed]
|
||||||
#TODO: Add method for use under macOS
|
|
||||||
|
|
||||||
# Run cmd
|
|
||||||
if cmd:
|
|
||||||
exe.run_program(cmd, check=False)
|
exe.run_program(cmd, check=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -368,9 +368,13 @@ class Disk(BaseObj):
|
||||||
try:
|
try:
|
||||||
details = self.smartctl['ata_smart_data']['self_test']
|
details = self.smartctl['ata_smart_data']['self_test']
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
# Assuming disk lacks SMART support, ignore and return empty dict.
|
# Assuming disk lacks SMART support, ignore and return nearly empty dict.
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Ensure status is present even if empty
|
||||||
|
if 'status' not in details:
|
||||||
|
details['status'] = {}
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
return details
|
return details
|
||||||
|
|
||||||
|
|
@ -723,7 +727,13 @@ def get_disks_macos():
|
||||||
disks = []
|
disks = []
|
||||||
|
|
||||||
# Get info from diskutil
|
# Get info from diskutil
|
||||||
proc = run_program(cmd, encoding=None, errors=None)
|
proc = run_program(cmd, encoding=None, errors=None, check=False)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
# Assuming we're running on an older macOS version
|
||||||
|
cmd.pop(-1)
|
||||||
|
proc = run_program(cmd, encoding=None, errors=None, check=False)
|
||||||
|
|
||||||
|
# Parse plist data
|
||||||
try:
|
try:
|
||||||
plist_data = plistlib.loads(proc.stdout)
|
plist_data = plistlib.loads(proc.stdout)
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
|
|
@ -735,6 +745,11 @@ def get_disks_macos():
|
||||||
for disk in plist_data['WholeDisks']:
|
for disk in plist_data['WholeDisks']:
|
||||||
disks.append(Disk(f'/dev/{disk}'))
|
disks.append(Disk(f'/dev/{disk}'))
|
||||||
|
|
||||||
|
# Remove virtual disks
|
||||||
|
disks = [
|
||||||
|
d for d in disks if d.details.get('VirtualOrPhysical') == 'Physical'
|
||||||
|
]
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
return disks
|
return disks
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
#if platform.system() == 'Darwin':
|
if platform.system() == 'Darwin':
|
||||||
|
from wk.os import mac
|
||||||
if platform.system() == 'Linux':
|
if platform.system() == 'Linux':
|
||||||
from wk.os import linux
|
from wk.os import linux
|
||||||
if platform.system() == 'Windows':
|
if platform.system() == 'Windows':
|
||||||
|
|
|
||||||
82
scripts/wk/os/mac.py
Normal file
82
scripts/wk/os/mac.py
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
"""WizardKit: macOS Functions"""
|
||||||
|
# vim: sts=2 sw=2 ts=2
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
|
||||||
|
from wk.exe import run_program
|
||||||
|
|
||||||
|
|
||||||
|
# STATIC VARIABLES
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
REGEX_FANS = re.compile(r'^.*\(bytes (?P<bytes>.*)\)$')
|
||||||
|
|
||||||
|
|
||||||
|
# Functions
|
||||||
|
def decode_smc_bytes(text):
|
||||||
|
"""Decode SMC bytes, returns int."""
|
||||||
|
result = None
|
||||||
|
|
||||||
|
# Get bytes
|
||||||
|
match = REGEX_FANS.match(text)
|
||||||
|
if not match:
|
||||||
|
LOG.error('Failed to decode smc output: %s', text)
|
||||||
|
raise ValueError(f'Failed to decocde smc output: {text}')
|
||||||
|
|
||||||
|
# Convert to text
|
||||||
|
result = match.group('bytes')
|
||||||
|
result = result.replace(' ', '')
|
||||||
|
result = int(result, 16)
|
||||||
|
|
||||||
|
# Done
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def set_fans(mode):
|
||||||
|
"""Set fans to auto or max."""
|
||||||
|
if mode == 'auto':
|
||||||
|
set_fans_auto()
|
||||||
|
elif mode == 'max':
|
||||||
|
set_fans_max()
|
||||||
|
else:
|
||||||
|
raise RuntimeError(f'Invalid fan mode: {mode}')
|
||||||
|
|
||||||
|
|
||||||
|
def set_fans_auto():
|
||||||
|
"""Set fans to auto."""
|
||||||
|
LOG.info('Setting fans to auto')
|
||||||
|
cmd = ['sudo', 'smc', '-k', 'FS! ', '-w', '0000']
|
||||||
|
run_program(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def set_fans_max():
|
||||||
|
"""Set fans to their max speeds."""
|
||||||
|
LOG.info('Setting fans to max')
|
||||||
|
num_fans = 0
|
||||||
|
|
||||||
|
# Get number of fans
|
||||||
|
cmd = ['smc', '-k', 'FNum', '-r']
|
||||||
|
proc = run_program(cmd)
|
||||||
|
num_fans = decode_smc_bytes(proc.stdout)
|
||||||
|
LOG.info('Found %s fans', num_fans)
|
||||||
|
|
||||||
|
# Set all fans to forced speed
|
||||||
|
## NOTE: mask is bit mask from right to left enabling fans
|
||||||
|
## e.g. bit 1 is fan 0, bit 2 is fan 1, etc
|
||||||
|
## So the mask for two fans is 0b11 or 0x3, four would be 0b111 or 0x7
|
||||||
|
mask = f'{hex(2**num_fans - 1)[2:]:0>4}'
|
||||||
|
cmd = ['sudo', 'smc', '-k', 'FS! ', '-w', mask]
|
||||||
|
run_program(cmd)
|
||||||
|
|
||||||
|
# Set all fans to their max speed
|
||||||
|
for fan in range(num_fans):
|
||||||
|
cmd = ['smc', '-k', f'F{fan}Mx', '-r']
|
||||||
|
proc = run_program(cmd)
|
||||||
|
max_temp = decode_smc_bytes(proc.stdout)
|
||||||
|
LOG.info('Setting fan #%s to %s RPM', fan, str(max_temp >> 2))
|
||||||
|
cmd = ['sudo', 'smc', '-k', f'F{fan}Tg', '-w', hex(max_temp)[2:]]
|
||||||
|
run_program(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print("This file is not meant to be called directly.")
|
||||||
Loading…
Reference in a new issue