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
sudo apt-get -y install graphviz libgraphviz-dev pkg-config
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 .
- name: Test
run: |

View File

@@ -13,6 +13,7 @@ from osaca.semantics import MachineModel
from osaca.parser.memory import MemoryOperand
from osaca.parser.register import RegisterOperand
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):
@@ -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,
)
print(report, file=output_file)
return not any([missing_port_pressure, bad_operand])
@@ -147,14 +148,9 @@ def _get_asmbench_output(input_data, isa):
mnemonic = i_form.split("-")[0]
operands = i_form.split("-")[1].split("_")
operands = [_create_db_operand(op, isa) for op in operands]
entry = {
"name": mnemonic,
"operands": operands,
"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"]:
entry = instructionForm(instruction_id=mnemonic,operands_id=operands,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(
"Your measurement for {} looks suspicious".format(i_form)
+ " and was not added. Please inspect your benchmark."
@@ -178,23 +174,17 @@ def _get_ibench_output(input_data, isa):
mnemonic = instruction.split("-")[0]
operands = instruction.split("-")[1].split("_")
operands = [_create_db_operand(op, isa) for op in operands]
entry = {
"name": mnemonic,
"operands": operands,
"throughput": None,
"latency": None,
"port_pressure": None,
}
entry = instructionForm(instruction_id=mnemonic,operands_id=operands,throughput=None,latency=None,port_pressure=None)
if "TP" in instruction:
entry["throughput"] = _validate_measurement(float(line.split()[1]), "tp")
if not entry["throughput"]:
entry.throughput = _validate_measurement(float(line.split()[1]), "tp")
if not entry.throughput:
warnings.warn(
"Your throughput measurement for {} looks suspicious".format(key)
+ " and was not added. Please inspect your benchmark."
)
elif "LT" in instruction:
entry["latency"] = _validate_measurement(float(line.split()[1]), "lt")
if not entry["latency"]:
entry.latency = _validate_measurement(float(line.split()[1]), "lt")
if not entry.latency:
warnings.warn(
"Your latency measurement for {} looks suspicious".format(key)
+ " 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
):
# Missing 'name' key
bad_operand.append(instr_form)
# bad_operand.append(instr_form)
continue
elif isinstance(operand, MemoryOperand) and (
operand.base 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
):
# 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:
# Missing 'imd' key
bad_operand.append(instr_form)

View File

@@ -426,6 +426,8 @@ class ParserAArch64(BaseParser):
if "shift" in memory_address["index"]:
if memory_address["index"]["shift_op"].lower() in valid_shift_ops:
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(
offset_ID=offset,
base_id=RegisterOperand(name=base["name"], prefix_id=base["prefix"]),
@@ -443,9 +445,7 @@ class ParserAArch64(BaseParser):
def process_sp_register(self, register):
"""Post-process stack pointer register"""
# reg = register
new_reg = RegisterOperand(prefix_id="x", name="sp")
# reg["prefix"] = "x"
return new_reg
def process_condition(self, condition):
@@ -631,6 +631,8 @@ class ParserAArch64(BaseParser):
def is_reg_dependend_of(self, reg_a, 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):
reg_a = RegisterOperand(name=reg_a["name"])
prefixes_gpr = "wx"

View File

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

View File

@@ -202,6 +202,8 @@ class MachineModel(object):
elif o["class"] == "memory":
if isinstance(o["base"], dict):
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(
MemoryOperand(
base_id=o["base"],
@@ -261,6 +263,7 @@ class MachineModel(object):
if name is None:
return None
name_matched_iforms = self._data["instruction_forms_dict"].get(name.upper(), [])
try:
return next(
instruction_form
@@ -449,6 +452,7 @@ class MachineModel(object):
def dump(self, stream=None):
"""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
'''
formatted_instruction_forms = deepcopy(self._data["instruction_forms"])
for instruction_form in formatted_instruction_forms:
if instruction_form["port_pressure"] is not None:
@@ -489,7 +493,7 @@ class MachineModel(object):
"""
if isinstance(stream, StringIO):
return stream.getvalue()
'''
def operand_to_dict(self, mem):
return {
"base": mem.base,
@@ -823,6 +827,8 @@ class MachineModel(object):
# check for wildcards
if isinstance(reg, str):
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:
return True
# 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:
for i, o in enumerate(instruction_form.operands):
operand_name = "op{}".format(i + 1)
if isinstance(o, RegisterOperand):
o_reg_name = (o.prefix if o.prefix is not None else "") + o.name
reg_operand_names[o_reg_name] = operand_name

View File

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

View File

@@ -97,15 +97,15 @@ class TestDBInterface(unittest.TestCase):
entries = dbi._get_ibench_output(input_data, "x86")
self.assertEqual(len(entries), 3)
for _, e in entries.items():
self.assertIsNotNone(e["throughput"])
self.assertIsNotNone(e["latency"])
self.assertIsNotNone(e.throughput)
self.assertIsNotNone(e.latency)
with open(self._find_file("ibench_import_aarch64.dat")) as input_file:
input_data = input_file.readlines()
entries = dbi._get_ibench_output(input_data, "aarch64")
self.assertEqual(len(entries), 4)
for _, e in entries.items():
self.assertIsNotNone(e["throughput"])
self.assertIsNotNone(e["latency"])
self.assertIsNotNone(e.throughput)
self.assertIsNotNone(e.latency)
def test_asmbench_import(self):
# 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")
self.assertEqual(len(entries), 3)
for _, e in entries.items():
self.assertIsNotNone(e["throughput"])
self.assertIsNotNone(e["latency"])
self.assertIsNotNone(e.throughput)
self.assertIsNotNone(e.latency)
with open(self._find_file("asmbench_import_aarch64.dat")) as input_file:
input_data = input_file.readlines()
entries = dbi._get_asmbench_output(input_data, "aarch64")
self.assertEqual(len(entries), 4)
for _, e in entries.items():
self.assertIsNotNone(e["throughput"])
self.assertIsNotNone(e["latency"])
self.assertIsNotNone(e.throughput)
self.assertIsNotNone(e.latency)
# remove empty line => no import since broken format
del input_data[3]
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.assertEqual(parsed_4.operands[1].base.name, "sp")
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["prefix"], "x")
self.assertEqual(parsed_4.operands[1].index.name, "1")
self.assertEqual(parsed_4.operands[1].index.prefix, "x")
self.assertEqual(parsed_4.operands[1].scale, 16)
self.assertEqual(parsed_4.operands[0].name, "28")
self.assertEqual(parsed_4.operands[0].prefix, "x")