Add dd drive I/O Benchmark test
* All tests: runs if SMART=CS/OVERRIDE & BADBLOCKS=CS * All drive tests: runs if SMART=CS/OVERRIDE & BADBLOCKS=CS * I/O tests are readonly, blocksize=4M, and limited to 16 Gb * Fix issue #23
This commit is contained in:
parent
a7079d4eae
commit
e55dbeeb23
2 changed files with 124 additions and 8 deletions
|
|
@ -39,6 +39,11 @@ TESTS = {
|
|||
'Results': {},
|
||||
'Status': {},
|
||||
},
|
||||
'iobenchmark': {
|
||||
'Enabled': False,
|
||||
'Results': {},
|
||||
'Status': {},
|
||||
},
|
||||
}
|
||||
|
||||
def get_smart_details(dev):
|
||||
|
|
@ -66,15 +71,17 @@ def menu_diags(*args):
|
|||
"""Main HW-Diagnostic menu."""
|
||||
diag_modes = [
|
||||
{'Name': 'All tests',
|
||||
'Tests': ['Prime95', 'NVMe/SMART', 'badblocks']},
|
||||
'Tests': ['Prime95', 'NVMe/SMART', 'badblocks', 'iobenchmark']},
|
||||
{'Name': 'Prime95',
|
||||
'Tests': ['Prime95']},
|
||||
{'Name': 'NVMe/SMART & badblocks',
|
||||
'Tests': ['NVMe/SMART', 'badblocks']},
|
||||
{'Name': 'All drive tests',
|
||||
'Tests': ['NVMe/SMART', 'badblocks', 'iobenchmark']},
|
||||
{'Name': 'NVMe/SMART',
|
||||
'Tests': ['NVMe/SMART']},
|
||||
{'Name': 'badblocks',
|
||||
'Tests': ['badblocks']},
|
||||
{'Name': 'I/O Benchmark',
|
||||
'Tests': ['iobenchmark']},
|
||||
{'Name': 'Quick drive test',
|
||||
'Tests': ['Quick', 'NVMe/SMART']},
|
||||
]
|
||||
|
|
@ -197,6 +204,75 @@ def run_badblocks():
|
|||
run_program('tmux kill-pane -a'.split(), check=False)
|
||||
pass
|
||||
|
||||
def run_iobenchmark():
|
||||
"""Run a read-only test for all detected disks."""
|
||||
aborted = False
|
||||
clear_screen()
|
||||
print_log('\nStart I/O Benchmark test(s)\n')
|
||||
progress_file = '{}/iobenchmark_progress.out'.format(global_vars['LogDir'])
|
||||
update_progress()
|
||||
|
||||
# Set Window layout and start test
|
||||
run_program('tmux split-window -dhl 15 watch -c -n1 -t cat {}'.format(
|
||||
TESTS['Progress Out']).split())
|
||||
|
||||
# Show disk details
|
||||
for name, dev in sorted(TESTS['iobenchmark']['Devices'].items()):
|
||||
show_disk_details(dev)
|
||||
print_standard(' ')
|
||||
update_progress()
|
||||
|
||||
# Run
|
||||
print_standard('Running benchmark test(s):')
|
||||
for name, dev in sorted(TESTS['iobenchmark']['Devices'].items()):
|
||||
cur_status = TESTS['iobenchmark']['Status'][name]
|
||||
nvme_smart_status = TESTS['NVMe/SMART']['Status'].get(name, None)
|
||||
bb_status = TESTS['badblocks']['Status'].get(name, None)
|
||||
if cur_status == 'Denied':
|
||||
# Skip denied disks
|
||||
continue
|
||||
if nvme_smart_status == 'NS':
|
||||
TESTS['iobenchmark']['Status'][name] = 'Skipped'
|
||||
elif bb_status in ['NS', 'Skipped']:
|
||||
TESTS['iobenchmark']['Status'][name] = 'Skipped'
|
||||
else:
|
||||
# (SMART tests not run or CS/OVERRIDE)
|
||||
# AND (BADBLOCKS tests not run or CS)
|
||||
TESTS['iobenchmark']['Status'][name] = 'Working'
|
||||
update_progress()
|
||||
print_standard(' /dev/{:11} '.format(name+'...'), end='', flush=True)
|
||||
run_program('tmux split-window -dl 5 {} {} {}'.format(
|
||||
'hw-diags-iobenchmark',
|
||||
'/dev/{}'.format(name),
|
||||
progress_file).split())
|
||||
wait_for_process('dd')
|
||||
print_standard('Done', timestamp=False)
|
||||
|
||||
# Check results
|
||||
with open(progress_file, 'r') as f:
|
||||
text = f.read()
|
||||
io_stats = text.replace('\r', '\n').split('\n')
|
||||
try:
|
||||
io_stats = [re.sub(r'.*\s+(\d+) MB/s\s*$', r'\1', stat)
|
||||
for stat in io_stats if 'MB/s' in stat]
|
||||
io_stats = [int(x) for x in io_stats]
|
||||
TESTS['iobenchmark']['Results'][name] = 'Read speed: {:0.0f} MB/s (Min: {}, Max: {})'.format(
|
||||
sum(io_stats) / len(io_stats),
|
||||
min(io_stats),
|
||||
max(io_stats))
|
||||
TESTS['iobenchmark']['Status'][name] = 'CS'
|
||||
except:
|
||||
TESTS['iobenchmark']['Status'][name] = 'NS'
|
||||
|
||||
# Move temp file
|
||||
shutil.move(progress_file, '{}/iobenchmark-{}.log'.format(
|
||||
global_vars['LogDir'], name))
|
||||
update_progress()
|
||||
|
||||
# Done
|
||||
run_program('tmux kill-pane -a'.split(), check=False)
|
||||
pass
|
||||
|
||||
def run_mprime():
|
||||
"""Run Prime95 for MPRIME_LIMIT minutes while showing the temps."""
|
||||
aborted = False
|
||||
|
|
@ -389,12 +465,12 @@ def run_tests(tests):
|
|||
print_log('Starting Hardware Diagnostics')
|
||||
print_log('\nRunning tests: {}'.format(', '.join(tests)))
|
||||
# Enable selected tests
|
||||
for t in ['Prime95', 'NVMe/SMART', 'badblocks']:
|
||||
for t in ['Prime95', 'NVMe/SMART', 'badblocks', 'iobenchmark']:
|
||||
TESTS[t]['Enabled'] = t in tests
|
||||
TESTS['NVMe/SMART']['Quick'] = 'Quick' in tests
|
||||
|
||||
# Initialize
|
||||
if TESTS['NVMe/SMART']['Enabled'] or TESTS['badblocks']['Enabled']:
|
||||
if TESTS['NVMe/SMART']['Enabled'] or TESTS['badblocks']['Enabled'] or TESTS['iobenchmark']['Enabled']:
|
||||
scan_disks()
|
||||
update_progress()
|
||||
|
||||
|
|
@ -410,6 +486,8 @@ def run_tests(tests):
|
|||
run_nvme_smart()
|
||||
if TESTS['badblocks']['Enabled']:
|
||||
run_badblocks()
|
||||
if TESTS['iobenchmark']['Enabled']:
|
||||
run_iobenchmark()
|
||||
|
||||
# Show results
|
||||
show_results()
|
||||
|
|
@ -437,6 +515,7 @@ def scan_disks():
|
|||
devs[d['name']] = {'lsblk': d}
|
||||
TESTS['NVMe/SMART']['Status'][d['name']] = 'Pending'
|
||||
TESTS['badblocks']['Status'][d['name']] = 'Pending'
|
||||
TESTS['iobenchmark']['Status'][d['name']] = 'Pending'
|
||||
else:
|
||||
# Skip WizardKit devices
|
||||
wk_label = '{}_LINUX'.format(KIT_NAME_SHORT)
|
||||
|
|
@ -444,6 +523,7 @@ def scan_disks():
|
|||
devs[d['name']] = {'lsblk': d}
|
||||
TESTS['NVMe/SMART']['Status'][d['name']] = 'Pending'
|
||||
TESTS['badblocks']['Status'][d['name']] = 'Pending'
|
||||
TESTS['iobenchmark']['Status'][d['name']] = 'Pending'
|
||||
|
||||
for dev, data in devs.items():
|
||||
# Get SMART attributes
|
||||
|
|
@ -483,7 +563,7 @@ def scan_disks():
|
|||
data['SMART Support'] = False
|
||||
|
||||
# Ask for manual overrides if necessary
|
||||
if not data['Quick Health OK'] and TESTS['badblocks']['Enabled']:
|
||||
if not data['Quick Health OK'] and (TESTS['badblocks']['Enabled'] or TESTS['iobenchmark']['Enabled']):
|
||||
show_disk_details(data)
|
||||
print_warning("WARNING: Health can't be confirmed for: {}".format(
|
||||
'/dev/{}'.format(dev)))
|
||||
|
|
@ -494,10 +574,12 @@ def scan_disks():
|
|||
else:
|
||||
TESTS['NVMe/SMART']['Status'][dev_name] = 'NS'
|
||||
TESTS['badblocks']['Status'][dev_name] = 'Denied'
|
||||
TESTS['iobenchmark']['Status'][dev_name] = 'Denied'
|
||||
print_standard(' ') # In case there's more than one "OVERRIDE" disk
|
||||
|
||||
TESTS['NVMe/SMART']['Devices'] = devs
|
||||
TESTS['badblocks']['Devices'] = devs
|
||||
TESTS['iobenchmark']['Devices'] = devs
|
||||
|
||||
def show_disk_details(dev):
|
||||
"""Display disk details."""
|
||||
|
|
@ -616,8 +698,8 @@ def show_results():
|
|||
print(' {}'.format(line.strip()))
|
||||
print_standard(' ')
|
||||
|
||||
# NVMe/SMART / badblocks
|
||||
if TESTS['NVMe/SMART']['Enabled'] or TESTS['badblocks']['Enabled']:
|
||||
# NVMe/SMART / badblocks / iobenchmark
|
||||
if TESTS['NVMe/SMART']['Enabled'] or TESTS['badblocks']['Enabled'] or TESTS['iobenchmark']['Enabled']:
|
||||
print_success('Disks:')
|
||||
for name, dev in sorted(TESTS['NVMe/SMART']['Devices'].items()):
|
||||
show_disk_details(dev)
|
||||
|
|
@ -635,6 +717,12 @@ def show_results():
|
|||
print_standard(' {}'.format(line))
|
||||
else:
|
||||
print_error(' {}'.format(line))
|
||||
io_status = TESTS['iobenchmark']['Status'].get(name, None)
|
||||
if (TESTS['iobenchmark']['Enabled']
|
||||
and io_status not in ['Denied', 'OVERRIDE', 'Skipped']):
|
||||
print_info('Benchmark:')
|
||||
result = TESTS['iobenchmark']['Results'].get(name, '')
|
||||
print_standard(' {}'.format(result))
|
||||
print_standard(' ')
|
||||
|
||||
# Done
|
||||
|
|
@ -676,6 +764,16 @@ def update_progress():
|
|||
s_color = get_status_color(status),
|
||||
status = status,
|
||||
**COLORS))
|
||||
if TESTS['iobenchmark']['Enabled']:
|
||||
output.append(' ')
|
||||
output.append('{BLUE}I/O Benchmark{CLEAR}'.format(**COLORS))
|
||||
for dev, status in sorted(TESTS['iobenchmark']['Status'].items()):
|
||||
output.append('{dev}{s_color}{status:>{pad}}{CLEAR}'.format(
|
||||
dev = dev,
|
||||
pad = 15-len(dev),
|
||||
s_color = get_status_color(status),
|
||||
status = status,
|
||||
**COLORS))
|
||||
|
||||
# Add line-endings
|
||||
output = ['{}\n'.format(line) for line in output]
|
||||
|
|
|
|||
18
.bin/Scripts/hw-diags-iobenchmark
Normal file
18
.bin/Scripts/hw-diags-iobenchmark
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
## Wizard Kit: HW Diagnostics - Benchmarks
|
||||
|
||||
function usage {
|
||||
echo "Usage: ${0} device log-file"
|
||||
echo " e.g. ${0} /dev/sda /tmp/tmp.XXXXXXX/benchmarks.log"
|
||||
}
|
||||
|
||||
# Bail early
|
||||
if [ ! -b "${1}" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run Benchmarks
|
||||
echo 3 | sudo tee -a /proc/sys/vm/drop_caches >/dev/null 2>&1
|
||||
sudo dd bs=4M count=4096 if="${1}" of=/dev/null status=progress 2>&1 | tee -a "${2}"
|
||||
Loading…
Reference in a new issue