mirror of
https://github.com/RRZE-HPC/OSACA.git
synced 2025-12-16 09:00:05 +01:00
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:
3
.github/workflows/test-n-publish.yml
vendored
3
.github/workflows/test-n-publish.yml
vendored
@@ -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: |
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user