mirror of
https://github.com/RRZE-HPC/OSACA.git
synced 2025-12-16 00:50:06 +01:00
sanity check validity of operand entries
This commit is contained in:
@@ -575,7 +575,7 @@ instruction_forms:
|
||||
- name: XOR
|
||||
operands:
|
||||
- class: register
|
||||
imd: gpr
|
||||
name: gpr
|
||||
- class: register
|
||||
name: gpr
|
||||
latency: 1
|
||||
|
||||
@@ -4552,7 +4552,7 @@ instruction_forms:
|
||||
- name: xor # assumed from SKX
|
||||
operands:
|
||||
- class: register
|
||||
imd: gpr
|
||||
name: gpr
|
||||
- class: register
|
||||
name: gpr
|
||||
latency: 1
|
||||
|
||||
@@ -44078,7 +44078,7 @@ instruction_forms:
|
||||
scale: '*' # model_importer.py SKX
|
||||
- class: register # model_importer.py SKX
|
||||
name: xmm # model_importer.py SKX
|
||||
latency: ~ # model_importer.py SKX
|
||||
latency: 19
|
||||
port_pressure: [[1, '0'], [1, '23'], [6, [0DV]], [1, [2D, 3D]]] # model_importer.py SKX
|
||||
throughput: 6.0 # model_importer.py SKX
|
||||
uops: 2 # model_importer.py SKX
|
||||
|
||||
@@ -26,6 +26,7 @@ def sanity_check(arch: str, verbose=False, internet_check=False, output_file=sys
|
||||
:param output_file: output stream specifying where to write output, defaults to :class:`sys.stdout`
|
||||
:type output_file: stream, optional
|
||||
|
||||
:return: True if everything checked out
|
||||
"""
|
||||
# load arch machine model
|
||||
arch_mm = MachineModel(arch=arch)
|
||||
@@ -42,6 +43,7 @@ def sanity_check(arch: str, verbose=False, internet_check=False, output_file=sys
|
||||
missing_port_pressure,
|
||||
suspicious_instructions,
|
||||
duplicate_instr_arch,
|
||||
bad_operand,
|
||||
) = _check_sanity_arch_db(arch_mm, isa_mm, internet_check=internet_check)
|
||||
# check ISA DB entries
|
||||
duplicate_instr_isa, only_in_isa = _check_sanity_isa_db(arch_mm, isa_mm)
|
||||
@@ -55,11 +57,14 @@ def sanity_check(arch: str, verbose=False, internet_check=False, output_file=sys
|
||||
duplicate_instr_arch,
|
||||
duplicate_instr_isa,
|
||||
only_in_isa,
|
||||
bad_operand,
|
||||
verbose=verbose,
|
||||
colors=True if output_file == sys.stdout else False,
|
||||
)
|
||||
print(report, file=output_file)
|
||||
|
||||
return not any([missing_port_pressure, bad_operand])
|
||||
|
||||
|
||||
def import_benchmark_output(arch, bench_type, filepath, output=sys.stdout):
|
||||
"""
|
||||
@@ -384,6 +389,7 @@ def _check_sanity_arch_db(arch_mm, isa_mm, internet_check=True):
|
||||
suspicious_instructions = []
|
||||
duplicate_instr_arch = []
|
||||
duplicate_strings = []
|
||||
bad_operand = []
|
||||
|
||||
for instr_form in arch_mm['instruction_forms']:
|
||||
# check value in DB entry
|
||||
@@ -420,6 +426,24 @@ def _check_sanity_arch_db(arch_mm, isa_mm, internet_check=True):
|
||||
# check for duplicates in DB
|
||||
if arch_mm._check_for_duplicate(instr_form['name'], instr_form['operands']):
|
||||
duplicate_instr_arch.append(instr_form)
|
||||
|
||||
# Check operands
|
||||
for operand in instr_form['operands']:
|
||||
if operand['class'] == 'register' and not (
|
||||
'name' in operand or
|
||||
'prefix' in operand):
|
||||
# Missing 'name' key
|
||||
bad_operand.append(instr_form)
|
||||
elif operand['class'] == 'memory' and (
|
||||
'base' not in operand or
|
||||
'offset' not in operand or
|
||||
'index' not in operand or
|
||||
'scale' not in operand):
|
||||
# Missing at least one key necessary for memory operands
|
||||
bad_operand.append(instr_form)
|
||||
elif operand['class'] == 'immediate' and 'imd' not in operand:
|
||||
# Missing 'imd' key
|
||||
bad_operand.append(instr_form)
|
||||
# every entry exists twice --> uniquify
|
||||
tmp_list = []
|
||||
for _ in range(0, len(duplicate_instr_arch)):
|
||||
@@ -434,6 +458,7 @@ def _check_sanity_arch_db(arch_mm, isa_mm, internet_check=True):
|
||||
missing_port_pressure,
|
||||
suspicious_instructions,
|
||||
duplicate_instr_arch,
|
||||
bad_operand,
|
||||
)
|
||||
|
||||
|
||||
@@ -461,9 +486,8 @@ def _check_sanity_isa_db(arch_mm, isa_mm):
|
||||
return duplicate_instr_isa, only_in_isa
|
||||
|
||||
|
||||
def _get_sanity_report(
|
||||
total, m_tp, m_l, m_pp, suspic_instr, dup_arch, dup_isa, only_isa, verbose=False, colors=False
|
||||
):
|
||||
def _get_sanity_report(total, m_tp, m_l, m_pp, suspic_instr, dup_arch, dup_isa, only_isa,
|
||||
bad_operands, verbose=False, colors=False):
|
||||
"""Get sanity summary report."""
|
||||
s = ''
|
||||
# non-verbose summary
|
||||
@@ -486,18 +510,19 @@ def _get_sanity_report(
|
||||
'{} instruction forms in ISA DB are not referenced by instruction '.format(len(only_isa))
|
||||
+ 'forms in uarch DB.\n'
|
||||
)
|
||||
s += '{} bad operands found in uarch DB\n'.format(len(bad_operands))
|
||||
s += '----------------------\n'
|
||||
# verbose version
|
||||
if verbose:
|
||||
s += _get_sanity_report_verbose(
|
||||
total, m_tp, m_l, m_pp, suspic_instr, dup_arch, dup_isa, only_isa, colors=colors
|
||||
total, m_tp, m_l, m_pp, suspic_instr, dup_arch, dup_isa, only_isa, bad_operands,
|
||||
colors=colors
|
||||
)
|
||||
return s
|
||||
|
||||
|
||||
def _get_sanity_report_verbose(
|
||||
total, m_tp, m_l, m_pp, suspic_instr, dup_arch, dup_isa, only_isa, colors=False
|
||||
):
|
||||
def _get_sanity_report_verbose(total, m_tp, m_l, m_pp, suspic_instr, dup_arch, dup_isa, only_isa,
|
||||
bad_operands, colors=False):
|
||||
"""Get the verbose part of the sanity report with all missing instruction forms."""
|
||||
BRIGHT_CYAN = '\033[1;36;1m' if colors else ''
|
||||
BRIGHT_BLUE = '\033[1;34;1m' if colors else ''
|
||||
@@ -508,17 +533,16 @@ def _get_sanity_report_verbose(
|
||||
YELLOW = '\033[33m' if colors else ''
|
||||
WHITE = '\033[0m' if colors else ''
|
||||
|
||||
s = ''
|
||||
s += 'Instruction forms without throughput value:\n' if len(m_tp) != 0 else ''
|
||||
s = 'Instruction forms without throughput value:\n' if m_tp else ''
|
||||
for instr_form in sorted(m_tp, key=lambda i: i['name']):
|
||||
s += '{}{}{}\n'.format(BRIGHT_BLUE, _get_full_instruction_name(instr_form), WHITE)
|
||||
s += 'Instruction forms without latency value:\n' if len(m_l) != 0 else ''
|
||||
s += 'Instruction forms without latency value:\n' if m_l else ''
|
||||
for instr_form in sorted(m_l, key=lambda i: i['name']):
|
||||
s += '{}{}{}\n'.format(BRIGHT_RED, _get_full_instruction_name(instr_form), WHITE)
|
||||
s += 'Instruction forms without port pressure assignment:\n' if len(m_pp) != 0 else ''
|
||||
s += 'Instruction forms without port pressure assignment:\n' if m_pp else ''
|
||||
for instr_form in sorted(m_pp, key=lambda i: i['name']):
|
||||
s += '{}{}{}\n'.format(BRIGHT_MAGENTA, _get_full_instruction_name(instr_form), WHITE)
|
||||
s += 'Instruction forms which might miss an ISA DB entry:\n' if len(suspic_instr) != 0 else ''
|
||||
s += 'Instruction forms which might miss an ISA DB entry:\n' if suspic_instr else ''
|
||||
for instr_form in sorted(suspic_instr, key=lambda i: i['name']):
|
||||
s += '{}{}{}{}\n'.format(
|
||||
BRIGHT_CYAN,
|
||||
@@ -526,17 +550,18 @@ def _get_sanity_report_verbose(
|
||||
' -- ' + instr_form['note'] if 'note' in instr_form else '',
|
||||
WHITE,
|
||||
)
|
||||
s += 'Duplicate instruction forms in uarch DB:\n' if len(dup_arch) != 0 else ''
|
||||
s += 'Duplicate instruction forms in uarch DB:\n' if dup_arch else ''
|
||||
for instr_form in sorted(dup_arch, key=lambda i: i['name']):
|
||||
s += '{}{}{}\n'.format(YELLOW, _get_full_instruction_name(instr_form), WHITE)
|
||||
s += 'Duplicate instruction forms in ISA DB:\n' if len(dup_isa) != 0 else ''
|
||||
s += 'Duplicate instruction forms in ISA DB:\n' if dup_isa else ''
|
||||
for instr_form in sorted(dup_isa, key=lambda i: i['name']):
|
||||
s += '{}{}{}\n'.format(BRIGHT_YELLOW, _get_full_instruction_name(instr_form), WHITE)
|
||||
s += (
|
||||
'Instruction forms existing in ISA DB but not in uarch DB:\n' if len(only_isa) != 0 else ''
|
||||
)
|
||||
s += 'Instruction forms existing in ISA DB but not in uarch DB:\n' if only_isa else ''
|
||||
for instr_form in sorted(only_isa, key=lambda i: i['name']):
|
||||
s += '{}{}{}\n'.format(CYAN, _get_full_instruction_name(instr_form), WHITE)
|
||||
s += '{} bad operands found in uarch DB:\n'.format(len(bad_operands)) if bad_operands else ''
|
||||
for instr_form in sorted(bad_operands, key=lambda i: i['name']):
|
||||
s += '{}{}{}\n'.format(BRIGHT_RED, _get_full_instruction_name(instr_form), WHITE)
|
||||
return s
|
||||
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ class MachineModel(object):
|
||||
for b, i, o, s in product(['gpr'], ['gpr', None], ['imd', None], [1, 8])
|
||||
],
|
||||
'load_throughput_default': [],
|
||||
'store_throughput': [],
|
||||
'store_throughput_default': [],
|
||||
'ports': [],
|
||||
'port_model_scheme': None,
|
||||
'instruction_forms': []
|
||||
|
||||
@@ -18,5 +18,5 @@ suite = unittest.TestLoader().loadTestsFromNames(
|
||||
]
|
||||
)
|
||||
|
||||
testresult = unittest.TextTestRunner(verbosity=2).run(suite)
|
||||
testresult = unittest.TextTestRunner(verbosity=2, buffer=True).run(suite)
|
||||
sys.exit(0 if testresult.wasSuccessful() else 1)
|
||||
|
||||
@@ -11,6 +11,7 @@ from shutil import copyfile
|
||||
from unittest.mock import patch
|
||||
|
||||
import osaca.osaca as osaca
|
||||
from osaca.db_interface import sanity_check
|
||||
from osaca.parser import ParserAArch64, ParserX86ATT
|
||||
from osaca.semantics import MachineModel
|
||||
|
||||
@@ -153,6 +154,16 @@ class TestCLI(unittest.TestCase):
|
||||
output = StringIO()
|
||||
osaca.run(args, output_file=output)
|
||||
|
||||
def test_architectures_sanity(self):
|
||||
parser = osaca.create_parser()
|
||||
# Run sanity check for all architectures
|
||||
archs = osaca.SUPPORTED_ARCHS
|
||||
for arch in archs:
|
||||
with self.subTest(micro_arch=arch):
|
||||
out = io.StringIO()
|
||||
sanity = sanity_check(arch, verbose=2, output=out)
|
||||
self.assertTrue(sanity, msg=output)
|
||||
|
||||
def test_without_arch(self):
|
||||
# Run test kernels without --arch flag
|
||||
parser = osaca.create_parser()
|
||||
@@ -239,4 +250,4 @@ class TestCLI(unittest.TestCase):
|
||||
|
||||
if __name__ == '__main__':
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestCLI)
|
||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
||||
unittest.TextTestRunner(verbosity=2, buffer=True).run(suite)
|
||||
|
||||
@@ -149,4 +149,4 @@ class TestDBInterface(unittest.TestCase):
|
||||
|
||||
if __name__ == '__main__':
|
||||
suite = unittest.TestLoader().loadTestsFromTestCase(TestDBInterface)
|
||||
unittest.TextTestRunner(verbosity=2).run(suite)
|
||||
unittest.TextTestRunner(verbosity=2, buffer=True).run(suite)
|
||||
|
||||
Reference in New Issue
Block a user