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:
2Shirt 2018-04-16 02:53:48 -06:00
parent a7079d4eae
commit e55dbeeb23
2 changed files with 124 additions and 8 deletions

View file

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

View 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}"