Merge branch 'project-overhaul' into dev

This commit is contained in:
2Shirt 2020-01-28 18:21:59 -07:00
commit 2b5e2244c1
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C
5 changed files with 132 additions and 22 deletions

View file

@ -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'},

View file

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

View file

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

View file

@ -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
View 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.")