mirror of
https://github.com/RRZE-HPC/OSACA.git
synced 2026-01-05 10:40:06 +01:00
Validation (#71)
Validating of OSACA predictions for IVB, SKX, ZEN1, ZEN2, A64FX and TX2 with different kernels. build_and_run.py contains the configuration used at RRZE's testcluster and UR's qpace4, Analysis.ipynb contains the analysis script and results. Raw data from measurements (122MB) will be attached to next OSACA release. For now, find the raw data here: https://hawo.net/~sijuhamm/d/UPIhBOtz/validation-data.tar.gz The analysis report can be viewed at https://nbviewer.jupyter.org/github/RRZE-HPC/OSACA/blob/validation/validation/Analysis.ipynb Quite a few changes on OSACA included: Feature: register change tracking via semantic understanding of operations Feature: recording LCD latency along path and exposing this to frontend Feature: support for memory reference aliases Feature: store throughput scaling (similar to load throughput scaling) Fix: model importer works with latest uops.info export Fix: immediate type tracking on ARM now preserves type in internal representaion Removed unused KerncraftAPI
This commit is contained in:
@@ -99,18 +99,28 @@ class ISASemantics(object):
|
||||
# post-process pre- and post-indexing for aarch64 memory operands
|
||||
if self._isa == "aarch64":
|
||||
for operand in [op for op in op_dict["source"] if "memory" in op]:
|
||||
if ("post_indexed" in operand["memory"] and operand["memory"]["post_indexed"]) or (
|
||||
"pre_indexed" in operand["memory"] and operand["memory"]["pre_indexed"]
|
||||
):
|
||||
post_indexed = ("post_indexed" in operand["memory"] and
|
||||
operand["memory"]["post_indexed"])
|
||||
pre_indexed = ("pre_indexed" in operand["memory"] and
|
||||
operand["memory"]["pre_indexed"])
|
||||
if post_indexed or pre_indexed:
|
||||
op_dict["src_dst"].append(
|
||||
AttrDict.convert_dict({"register": operand["memory"]["base"]})
|
||||
AttrDict.convert_dict({
|
||||
"register": operand["memory"]["base"],
|
||||
"pre_indexed": pre_indexed,
|
||||
"post_indexed": post_indexed})
|
||||
)
|
||||
for operand in [op for op in op_dict["destination"] if "memory" in op]:
|
||||
if ("post_indexed" in operand["memory"] and operand["memory"]["post_indexed"]) or (
|
||||
"pre_indexed" in operand["memory"] and operand["memory"]["pre_indexed"]
|
||||
):
|
||||
post_indexed = ("post_indexed" in operand["memory"] and
|
||||
operand["memory"]["post_indexed"])
|
||||
pre_indexed = ("pre_indexed" in operand["memory"] and
|
||||
operand["memory"]["pre_indexed"])
|
||||
if post_indexed or pre_indexed:
|
||||
op_dict["src_dst"].append(
|
||||
AttrDict.convert_dict({"register": operand["memory"]["base"]})
|
||||
AttrDict.convert_dict({
|
||||
"register": operand["memory"]["base"],
|
||||
"pre_indexed": pre_indexed,
|
||||
"post_indexed": post_indexed})
|
||||
)
|
||||
# store operand list in dict and reassign operand key/value pair
|
||||
instruction_form["semantic_operands"] = AttrDict.convert_dict(op_dict)
|
||||
@@ -121,10 +131,87 @@ class ISASemantics(object):
|
||||
if self._has_store(instruction_form):
|
||||
instruction_form["flags"] += [INSTR_FLAGS.HAS_ST]
|
||||
|
||||
def get_reg_changes(self, instruction_form, only_postindexed=False):
|
||||
"""
|
||||
Returns register changes, as dict, for insruction_form, based on operation defined in isa.
|
||||
|
||||
Empty dict if no changes of registers occured. None for registers with unknown changes.
|
||||
If only_postindexed is True, only considers changes due to post_indexed memory references.
|
||||
"""
|
||||
if instruction_form.get('instruction') is None:
|
||||
return {}
|
||||
dest_reg_names = [op.register.get('prefix', '') + op.register.name
|
||||
for op in chain(instruction_form.semantic_operands.destination,
|
||||
instruction_form.semantic_operands.src_dst)
|
||||
if 'register' in op]
|
||||
isa_data = self._isa_model.get_instruction(
|
||||
instruction_form["instruction"], instruction_form["operands"]
|
||||
)
|
||||
if (
|
||||
isa_data is None
|
||||
and self._isa == "x86"
|
||||
and instruction_form["instruction"][-1] in self.GAS_SUFFIXES
|
||||
):
|
||||
# Check for instruction without GAS suffix
|
||||
isa_data = self._isa_model.get_instruction(
|
||||
instruction_form["instruction"][:-1], instruction_form["operands"]
|
||||
)
|
||||
|
||||
if only_postindexed:
|
||||
for o in instruction_form.operands:
|
||||
if 'post_indexed' in o.get('memory', {}):
|
||||
base_name = o.memory.base.get('prefix', '')+o.memory.base.name
|
||||
return {base_name: {
|
||||
'name': o.memory.base.get('prefix', '')+o.memory.base.name,
|
||||
'value': int(o.memory.post_indexed.value)
|
||||
}}
|
||||
return {}
|
||||
|
||||
reg_operand_names = {} # e.g., {'rax': 'op1'}
|
||||
operand_state = {} # e.g., {'op1': {'name': 'rax', 'value': 0}} 0 means unchanged
|
||||
|
||||
for o in instruction_form.operands:
|
||||
if 'pre_indexed' in o.get('memory', {}):
|
||||
# Assuming no isa_data.operation
|
||||
if isa_data.get("operation", None) is not None:
|
||||
raise ValueError(
|
||||
"ISA information for pre-indexed instruction {!r} has operation set."
|
||||
"This is currently not supprted.".format(instruction_form.line))
|
||||
base_name = o.memory.base.get('prefix', '')+o.memory.base.name
|
||||
reg_operand_names = {base_name: 'op1'}
|
||||
operand_state = {'op1': {
|
||||
'name': base_name,
|
||||
'value': int(o.memory.offset.value)
|
||||
}}
|
||||
|
||||
if isa_data is not None and 'operation' in isa_data:
|
||||
for i, o in enumerate(instruction_form.operands):
|
||||
operand_name = "op{}".format(i+1)
|
||||
if "register" in o:
|
||||
o_reg_name = o["register"].get('prefix', '')+o["register"]["name"]
|
||||
reg_operand_names[o_reg_name] = operand_name
|
||||
operand_state[operand_name] = {
|
||||
'name': o_reg_name,
|
||||
'value': 0}
|
||||
elif "immediate" in o:
|
||||
operand_state[operand_name] = {'value': int(o["immediate"]["value"])}
|
||||
elif "memory" in o:
|
||||
# TODO lea needs some thinking about
|
||||
pass
|
||||
|
||||
operand_changes = exec(isa_data['operation'], {}, operand_state)
|
||||
|
||||
change_dict = {reg_name: operand_state.get(reg_operand_names.get(reg_name))
|
||||
for reg_name in dest_reg_names}
|
||||
return change_dict
|
||||
|
||||
def _apply_found_ISA_data(self, isa_data, operands):
|
||||
"""
|
||||
Create operand dictionary containing src/dst operands out of the ISA data entry and
|
||||
the oeprands of an instruction form
|
||||
|
||||
If breaks_pedendency_on_equal_operands is True (configuted per instruction in ISA db)
|
||||
and all operands are equal, place operand into destination only.
|
||||
|
||||
:param dict isa_data: ISA DB entry
|
||||
:param list operands: operands of the instruction form
|
||||
@@ -134,6 +221,17 @@ class ISASemantics(object):
|
||||
op_dict["source"] = []
|
||||
op_dict["destination"] = []
|
||||
op_dict["src_dst"] = []
|
||||
|
||||
# handle dependency breaking instructions
|
||||
if "breaks_pedendency_on_equal_operands" in isa_data and operands[1:] == operands[:-1]:
|
||||
op_dict["destination"] += operands
|
||||
if "hidden_operands" in isa_data:
|
||||
op_dict["destination"] += [
|
||||
AttrDict.convert_dict(
|
||||
{hop["class"]: {k: hop[k] for k in ["class", "source", "destination"]}})
|
||||
for hop in isa_data["hidden_operands"]]
|
||||
return op_dict
|
||||
|
||||
for i, op in enumerate(isa_data["operands"]):
|
||||
if op["source"] and op["destination"]:
|
||||
op_dict["src_dst"].append(operands[i])
|
||||
|
||||
Reference in New Issue
Block a user