Workflow file includes new kenrcraft branch. Also changed checks for 'bad_operands' since they don't fit class style attributes

This commit is contained in:
stefandesouza
2023-12-10 17:25:53 +01:00
parent cac4a0ebf2
commit 8a6ae8c701
9 changed files with 47 additions and 41 deletions

View File

@@ -22,7 +22,8 @@ jobs:
python -m pip install bs4 python -m pip install bs4
sudo apt-get -y install graphviz libgraphviz-dev pkg-config sudo apt-get -y install graphviz libgraphviz-dev pkg-config
python -m pip install pygraphviz python -m pip install pygraphviz
python -m pip install kerncraft #python -m pip install kerncraft
python -m pip install git+https://github.com/RRZE-HPC/kerncraft.git@InstrucForm
python -m pip install -e . python -m pip install -e .
- name: Test - name: Test
run: | run: |

View File

@@ -13,6 +13,7 @@ from osaca.semantics import MachineModel
from osaca.parser.memory import MemoryOperand from osaca.parser.memory import MemoryOperand
from osaca.parser.register import RegisterOperand from osaca.parser.register import RegisterOperand
from osaca.parser.immediate import ImmediateOperand from osaca.parser.immediate import ImmediateOperand
from osaca.parser.instruction_form import instructionForm
def sanity_check(arch: str, verbose=False, internet_check=False, output_file=sys.stdout): def sanity_check(arch: str, verbose=False, internet_check=False, output_file=sys.stdout):
@@ -67,7 +68,7 @@ def sanity_check(arch: str, verbose=False, internet_check=False, output_file=sys
colors=True if output_file == sys.stdout else False, colors=True if output_file == sys.stdout else False,
) )
print(report, file=output_file) print(report, file=output_file)
return not any([missing_port_pressure, bad_operand]) return not any([missing_port_pressure, bad_operand])
@@ -147,14 +148,9 @@ def _get_asmbench_output(input_data, isa):
mnemonic = i_form.split("-")[0] mnemonic = i_form.split("-")[0]
operands = i_form.split("-")[1].split("_") operands = i_form.split("-")[1].split("_")
operands = [_create_db_operand(op, isa) for op in operands] operands = [_create_db_operand(op, isa) for op in operands]
entry = { entry = instructionForm(instruction_id=mnemonic,operands_id=operands,throughput=_validate_measurement(float(input_data[i + 2].split()[1]), "tp"),
"name": mnemonic, latency=_validate_measurement(float(input_data[i + 1].split()[1]), "lt"),port_pressure=None)
"operands": operands, if not entry.throughput or not entry.latency:
"throughput": _validate_measurement(float(input_data[i + 2].split()[1]), "tp"),
"latency": _validate_measurement(float(input_data[i + 1].split()[1]), "lt"),
"port_pressure": None,
}
if not entry["throughput"] or not entry["latency"]:
warnings.warn( warnings.warn(
"Your measurement for {} looks suspicious".format(i_form) "Your measurement for {} looks suspicious".format(i_form)
+ " and was not added. Please inspect your benchmark." + " and was not added. Please inspect your benchmark."
@@ -178,23 +174,17 @@ def _get_ibench_output(input_data, isa):
mnemonic = instruction.split("-")[0] mnemonic = instruction.split("-")[0]
operands = instruction.split("-")[1].split("_") operands = instruction.split("-")[1].split("_")
operands = [_create_db_operand(op, isa) for op in operands] operands = [_create_db_operand(op, isa) for op in operands]
entry = { entry = instructionForm(instruction_id=mnemonic,operands_id=operands,throughput=None,latency=None,port_pressure=None)
"name": mnemonic,
"operands": operands,
"throughput": None,
"latency": None,
"port_pressure": None,
}
if "TP" in instruction: if "TP" in instruction:
entry["throughput"] = _validate_measurement(float(line.split()[1]), "tp") entry.throughput = _validate_measurement(float(line.split()[1]), "tp")
if not entry["throughput"]: if not entry.throughput:
warnings.warn( warnings.warn(
"Your throughput measurement for {} looks suspicious".format(key) "Your throughput measurement for {} looks suspicious".format(key)
+ " and was not added. Please inspect your benchmark." + " and was not added. Please inspect your benchmark."
) )
elif "LT" in instruction: elif "LT" in instruction:
entry["latency"] = _validate_measurement(float(line.split()[1]), "lt") entry.latency = _validate_measurement(float(line.split()[1]), "lt")
if not entry["latency"]: if not entry.latency:
warnings.warn( warnings.warn(
"Your latency measurement for {} looks suspicious".format(key) "Your latency measurement for {} looks suspicious".format(key)
+ " and was not added. Please inspect your benchmark." + " and was not added. Please inspect your benchmark."
@@ -439,7 +429,8 @@ def _check_sanity_arch_db(arch_mm, isa_mm, internet_check=True):
operand.name is not None or operand.prefix is not None operand.name is not None or operand.prefix is not None
): ):
# Missing 'name' key # Missing 'name' key
bad_operand.append(instr_form) # bad_operand.append(instr_form)
continue
elif isinstance(operand, MemoryOperand) and ( elif isinstance(operand, MemoryOperand) and (
operand.base is None operand.base is None
or operand.offset is None or operand.offset is None
@@ -447,7 +438,9 @@ def _check_sanity_arch_db(arch_mm, isa_mm, internet_check=True):
or operand.scale is None or operand.scale is None
): ):
# Missing at least one key necessary for memory operands # Missing at least one key necessary for memory operands
bad_operand.append(instr_form) # Since we're using classes with default 'None' values for these attributes, this check doesn't make sense anymore
# bad_operand.append(instr_form)
continue
elif isinstance(operand, ImmediateOperand) and operand.type is None: elif isinstance(operand, ImmediateOperand) and operand.type is None:
# Missing 'imd' key # Missing 'imd' key
bad_operand.append(instr_form) bad_operand.append(instr_form)

View File

@@ -426,6 +426,8 @@ class ParserAArch64(BaseParser):
if "shift" in memory_address["index"]: if "shift" in memory_address["index"]:
if memory_address["index"]["shift_op"].lower() in valid_shift_ops: if memory_address["index"]["shift_op"].lower() in valid_shift_ops:
scale = 2 ** int(memory_address["index"]["shift"][0]["value"]) scale = 2 ** int(memory_address["index"]["shift"][0]["value"])
if index is not None:
index = RegisterOperand(name=index["name"], prefix_id=index["prefix"] if "prefix" in index else None)
new_dict = MemoryOperand( new_dict = MemoryOperand(
offset_ID=offset, offset_ID=offset,
base_id=RegisterOperand(name=base["name"], prefix_id=base["prefix"]), base_id=RegisterOperand(name=base["name"], prefix_id=base["prefix"]),
@@ -443,9 +445,7 @@ class ParserAArch64(BaseParser):
def process_sp_register(self, register): def process_sp_register(self, register):
"""Post-process stack pointer register""" """Post-process stack pointer register"""
# reg = register
new_reg = RegisterOperand(prefix_id="x", name="sp") new_reg = RegisterOperand(prefix_id="x", name="sp")
# reg["prefix"] = "x"
return new_reg return new_reg
def process_condition(self, condition): def process_condition(self, condition):
@@ -631,6 +631,8 @@ class ParserAArch64(BaseParser):
def is_reg_dependend_of(self, reg_a, reg_b): def is_reg_dependend_of(self, reg_a, reg_b):
"""Check if ``reg_a`` is dependent on ``reg_b``""" """Check if ``reg_a`` is dependent on ``reg_b``"""
#if not isinstance(reg_b, Operand):
# print(reg_b)
if not isinstance(reg_a, Operand): if not isinstance(reg_a, Operand):
reg_a = RegisterOperand(name=reg_a["name"]) reg_a = RegisterOperand(name=reg_a["name"])
prefixes_gpr = "wx" prefixes_gpr = "wx"

View File

@@ -254,7 +254,6 @@ class ParserX86ATT(BaseParser):
instruction_form.instruction = result.instruction instruction_form.instruction = result.instruction
instruction_form.operands = result.operands instruction_form.operands = result.operands
instruction_form.comment = result.comment instruction_form.comment = result.comment
return instruction_form return instruction_form
def parse_instruction(self, instruction): def parse_instruction(self, instruction):
@@ -312,7 +311,7 @@ class ParserX86ATT(BaseParser):
else None, else None,
) )
if self.IDENTIFIER_ID in operand: if self.IDENTIFIER_ID in operand:
return IdentifierOperand(name=operand[self.IDENTIFIER_ID]["name"]) return self.process_identifier(operand[self.IDENTIFIER_ID])
return operand return operand
def process_directive(self, directive): def process_directive(self, directive):
@@ -370,11 +369,14 @@ class ParserX86ATT(BaseParser):
"""Post-process immediate operand""" """Post-process immediate operand"""
if "identifier" in immediate: if "identifier" in immediate:
# actually an identifier, change declaration # actually an identifier, change declaration
return immediate return self.process_identifier(immediate["identifier"])
# otherwise just make sure the immediate is a decimal # otherwise just make sure the immediate is a decimal
# immediate["value"] = int(immediate["value"], 0) # immediate["value"] = int(immediate["value"], 0)
new_immediate = ImmediateOperand(value_id=int(immediate["value"], 0)) new_immediate = ImmediateOperand(value_id=int(immediate["value"], 0))
return new_immediate return new_immediate
def process_identifier(self, identifier):
return IdentifierOperand(name=identifier["name"])
def get_full_reg_name(self, register): def get_full_reg_name(self, register):
"""Return one register name string including all attributes""" """Return one register name string including all attributes"""
@@ -466,7 +468,7 @@ class ParserX86ATT(BaseParser):
def is_vector_register(self, register): def is_vector_register(self, register):
"""Check if register is a vector register""" """Check if register is a vector register"""
if register is None: if register is None or register.name is None:
return False return False
if register.name.rstrip(string.digits).lower() in [ if register.name.rstrip(string.digits).lower() in [
"mm", "mm",

View File

@@ -202,6 +202,8 @@ class MachineModel(object):
elif o["class"] == "memory": elif o["class"] == "memory":
if isinstance(o["base"], dict): if isinstance(o["base"], dict):
o["base"] = RegisterOperand(name=o["base"]["name"]) o["base"] = RegisterOperand(name=o["base"]["name"])
if isinstance(o["index"], dict):
o["index"] = RegisterOperand(name=o["index"]["name"],prefix_id=o["index"]["prefix"] if "prefix" in o["index"] else None)
new_operands.append( new_operands.append(
MemoryOperand( MemoryOperand(
base_id=o["base"], base_id=o["base"],
@@ -261,6 +263,7 @@ class MachineModel(object):
if name is None: if name is None:
return None return None
name_matched_iforms = self._data["instruction_forms_dict"].get(name.upper(), []) name_matched_iforms = self._data["instruction_forms_dict"].get(name.upper(), [])
try: try:
return next( return next(
instruction_form instruction_form
@@ -449,6 +452,7 @@ class MachineModel(object):
def dump(self, stream=None): def dump(self, stream=None):
"""Dump machine model to stream or return it as a ``str`` if no stream is given.""" """Dump machine model to stream or return it as a ``str`` if no stream is given."""
# Replace instruction form's port_pressure with styled version for RoundtripDumper # Replace instruction form's port_pressure with styled version for RoundtripDumper
'''
formatted_instruction_forms = deepcopy(self._data["instruction_forms"]) formatted_instruction_forms = deepcopy(self._data["instruction_forms"])
for instruction_form in formatted_instruction_forms: for instruction_form in formatted_instruction_forms:
if instruction_form["port_pressure"] is not None: if instruction_form["port_pressure"] is not None:
@@ -489,7 +493,7 @@ class MachineModel(object):
""" """
if isinstance(stream, StringIO): if isinstance(stream, StringIO):
return stream.getvalue() return stream.getvalue()
'''
def operand_to_dict(self, mem): def operand_to_dict(self, mem):
return { return {
"base": mem.base, "base": mem.base,
@@ -823,6 +827,8 @@ class MachineModel(object):
# check for wildcards # check for wildcards
if isinstance(reg, str): if isinstance(reg, str):
return False return False
if i_reg_name is None and reg.name is None:
return True
if i_reg_name == self.WILDCARD or reg.name == self.WILDCARD: if i_reg_name == self.WILDCARD or reg.name == self.WILDCARD:
return True return True
# differentiate between vector registers (mm, xmm, ymm, zmm) and others (gpr) # differentiate between vector registers (mm, xmm, ymm, zmm) and others (gpr)

View File

@@ -225,7 +225,7 @@ class ISASemantics(object):
if isa_data is not None and isa_data.operation is not None: if isa_data is not None and isa_data.operation is not None:
for i, o in enumerate(instruction_form.operands): for i, o in enumerate(instruction_form.operands):
operand_name = "op{}".format(i + 1) operand_name = "op{}".format(i + 1)
if isinstance(o, RegisterOperand): if isinstance(o, RegisterOperand):
o_reg_name = (o.prefix if o.prefix is not None else "") + o.name o_reg_name = (o.prefix if o.prefix is not None else "") + o.name
reg_operand_names[o_reg_name] = operand_name reg_operand_names[o_reg_name] = operand_name

View File

@@ -199,6 +199,7 @@ class TestCLI(unittest.TestCase):
) )
output = StringIO() output = StringIO()
osaca.run(args, output_file=output) osaca.run(args, output_file=output)
# WARNING for length # WARNING for length
self.assertTrue( self.assertTrue(
output.getvalue().count( output.getvalue().count(
@@ -229,6 +230,7 @@ class TestCLI(unittest.TestCase):
osaca.run(args, output_file=output) osaca.run(args, output_file=output)
self.assertTrue(output.getvalue().count("WARNING: LCD analysis timed out") == 0) self.assertTrue(output.getvalue().count("WARNING: LCD analysis timed out") == 0)
def test_lines_arg(self): def test_lines_arg(self):
# Run tests with --lines option # Run tests with --lines option
parser = osaca.create_parser() parser = osaca.create_parser()

View File

@@ -97,15 +97,15 @@ class TestDBInterface(unittest.TestCase):
entries = dbi._get_ibench_output(input_data, "x86") entries = dbi._get_ibench_output(input_data, "x86")
self.assertEqual(len(entries), 3) self.assertEqual(len(entries), 3)
for _, e in entries.items(): for _, e in entries.items():
self.assertIsNotNone(e["throughput"]) self.assertIsNotNone(e.throughput)
self.assertIsNotNone(e["latency"]) self.assertIsNotNone(e.latency)
with open(self._find_file("ibench_import_aarch64.dat")) as input_file: with open(self._find_file("ibench_import_aarch64.dat")) as input_file:
input_data = input_file.readlines() input_data = input_file.readlines()
entries = dbi._get_ibench_output(input_data, "aarch64") entries = dbi._get_ibench_output(input_data, "aarch64")
self.assertEqual(len(entries), 4) self.assertEqual(len(entries), 4)
for _, e in entries.items(): for _, e in entries.items():
self.assertIsNotNone(e["throughput"]) self.assertIsNotNone(e.throughput)
self.assertIsNotNone(e["latency"]) self.assertIsNotNone(e.latency)
def test_asmbench_import(self): def test_asmbench_import(self):
# only check import without dumping the DB file (takes too much time) # only check import without dumping the DB file (takes too much time)
@@ -114,15 +114,15 @@ class TestDBInterface(unittest.TestCase):
entries = dbi._get_asmbench_output(input_data, "x86") entries = dbi._get_asmbench_output(input_data, "x86")
self.assertEqual(len(entries), 3) self.assertEqual(len(entries), 3)
for _, e in entries.items(): for _, e in entries.items():
self.assertIsNotNone(e["throughput"]) self.assertIsNotNone(e.throughput)
self.assertIsNotNone(e["latency"]) self.assertIsNotNone(e.latency)
with open(self._find_file("asmbench_import_aarch64.dat")) as input_file: with open(self._find_file("asmbench_import_aarch64.dat")) as input_file:
input_data = input_file.readlines() input_data = input_file.readlines()
entries = dbi._get_asmbench_output(input_data, "aarch64") entries = dbi._get_asmbench_output(input_data, "aarch64")
self.assertEqual(len(entries), 4) self.assertEqual(len(entries), 4)
for _, e in entries.items(): for _, e in entries.items():
self.assertIsNotNone(e["throughput"]) self.assertIsNotNone(e.throughput)
self.assertIsNotNone(e["latency"]) self.assertIsNotNone(e.latency)
# remove empty line => no import since broken format # remove empty line => no import since broken format
del input_data[3] del input_data[3]
entries = dbi._get_asmbench_output(input_data, "aarch64") entries = dbi._get_asmbench_output(input_data, "aarch64")

View File

@@ -127,8 +127,8 @@ class TestParserAArch64(unittest.TestCase):
self.assertIsNone(parsed_4.operands[1].offset) self.assertIsNone(parsed_4.operands[1].offset)
self.assertEqual(parsed_4.operands[1].base.name, "sp") self.assertEqual(parsed_4.operands[1].base.name, "sp")
self.assertEqual(parsed_4.operands[1].base.prefix, "x") self.assertEqual(parsed_4.operands[1].base.prefix, "x")
self.assertEqual(parsed_4.operands[1].index["name"], "1") self.assertEqual(parsed_4.operands[1].index.name, "1")
self.assertEqual(parsed_4.operands[1].index["prefix"], "x") self.assertEqual(parsed_4.operands[1].index.prefix, "x")
self.assertEqual(parsed_4.operands[1].scale, 16) self.assertEqual(parsed_4.operands[1].scale, 16)
self.assertEqual(parsed_4.operands[0].name, "28") self.assertEqual(parsed_4.operands[0].name, "28")
self.assertEqual(parsed_4.operands[0].prefix, "x") self.assertEqual(parsed_4.operands[0].prefix, "x")