ekalda commented on a change in pull request #8849:
URL: https://github.com/apache/tvm/pull/8849#discussion_r717701148
##########
File path: tests/python/contrib/test_ethosu/infra.py
##########
@@ -42,6 +58,218 @@ class AttachType(IntEnum):
kScanUpdate = 5
+class VelaArtifacts:
+ def __init__(self):
+ self.cs = dict()
+ self.flash = dict()
+ self.sram = dict()
+ self.npu_ops = set()
+
+
+def parse_relay_tflite_model(tflite_model, input_tensor, input_shape,
input_dtype):
+ mod_, params_ = relay.frontend.from_tflite(
+ tflite_model,
+ shape_dict={input_tensor: input_shape},
+ dtype_dict={input_tensor: input_dtype},
+ )
+ return mod_, params_
+
+
+def parse_tflite_model(model_file):
+ try:
+ import tflite
+
+ return tflite.Model.GetRootAsModel(model_file, 0)
+ except AttributeError:
+ import tflite.Model
+
+ return tflite.Model.Model.GetRootAsModel(model_file, 0)
+
+
+def print_payload(payload):
+ cmds = deserialize_command_stream(payload)
+ for cmd_val in cmds:
+ cmd, val = parse_cmd(cmd_val)
+ s = str(cmd)
+ s = s.ljust(40)
+ s += str(val)
+ print(s)
+
+
+def parse_cmd(binary_cmd):
+ code = binary_cmd[0] & 0x0000FFFF # lower 16 bits
+ param = binary_cmd[0] >> 16 # higher 16 bits
+ payload_mode = CmdMode(code & CmdMode.Mask)
+ if payload_mode == CmdMode.Payload32:
+ command = cmd1(code & CmdMode.CmdOpMask)
+ value = binary_cmd[1]
+ else:
+ command = cmd0(code & CmdMode.CmdOpMask)
+ value = param
+ return command, value
+
+
+def check_cmms_equivalency(vela_cmd, vela_value, tvm_value, ignore_cmds=None):
+ if ignore_cmds is None:
+ ignore_cmds = []
+ if vela_value != tvm_value and vela_cmd not in ignore_cmds:
+ raise RuntimeError(
+ "ValueMismatch :: vela={}, tvm={} for command:{}".format(
+ vela_value, tvm_value, vela_cmd
+ )
+ )
+
+
+def verify_cmms(cmms_tvm_blob, cmms_vela_blob):
+ vela_cmm = deserialize_command_stream(cmms_vela_blob)
+ tvm_cmm = deserialize_command_stream(cmms_tvm_blob)
+ cmms_zip = zip(vela_cmm, tvm_cmm)
+
+ first_ifm_found = False
+ last_ofm_found = False
+
+ ignore_commands = (
+ cmd1.NPU_SET_DMA0_SRC,
+ cmd1.NPU_SET_DMA0_DST,
+ cmd1.NPU_SET_WEIGHT_BASE,
+ cmd1.NPU_SET_OFM_BASE0,
+ cmd1.NPU_SET_IFM_BASE0,
+ cmd1.NPU_SET_SCALE_BASE,
+ )
+
+ ofm_region_params = []
+ ofm_bases = []
+ for vela_cmm, tvm_cmm in cmms_zip:
+ vela_cmd, vela_value = parse_cmd(vela_cmm)
+ tvm_cmd, tvm_value = parse_cmd(tvm_cmm)
+
+ assert vela_cmd == tvm_cmd
+
+ # The first IFM region could be different, but it needs to be 1 and 3.
+ if vela_cmd == cmd0.NPU_SET_IFM_REGION and not first_ifm_found:
+ if vela_value == 1 and tvm_value == 3:
+ first_ifm_found = True
+ continue
+
+ if vela_cmd == cmd1.NPU_SET_IFM_BASE0 and not first_ifm_found:
+ if tvm_value != 0:
+ raise RuntimeError("ValueError :: tvm primary ifm base should
be zero")
+ continue
+
+ # OFM regions should be cached to be checked later
+ if vela_cmd == cmd0.NPU_SET_OFM_REGION:
+ ofm_region_params.append((vela_value, tvm_value))
+ continue
+
+ # OFM bases should be cached to be checked later
+ if vela_cmd == cmd1.NPU_SET_OFM_BASE0:
+ ofm_bases.append((vela_value, tvm_value))
+ continue
+
+ check_cmms_equivalency(vela_cmd, vela_value, tvm_value,
ignore_commands)
+
+ # The last OFM region could be different but it should be 1 and 4.
+ last_vela_ofm_region, last_tvm_ofm_region = ofm_region_params.pop(-1)
+ if not (last_vela_ofm_region == 1 and last_tvm_ofm_region == 4):
+ raise RuntimeError(
+ "ValueMismatch :: vela={}, tvm={} for last ofm region it should be
1 and 4 respectively".format(
+ last_vela_ofm_region, last_tvm_ofm_region
+ )
+ )
+
+ # The rest of the OFM regions should be the same.
+ for vela_value, tvm_value in ofm_region_params:
+ check_cmms_equivalency(vela_cmd, vela_value, tvm_value,
ignore_commands)
+
+ # The last OFM base should be zero for tvm
+ _, last_tvm_ofm_base = ofm_bases.pop(-1)
+ if not last_tvm_ofm_base == 0:
+ raise RuntimeError("ValueError :: tvm primary ofm base should be zero")
+
+
+def deserialize_command_stream(blob):
+ assert isinstance(blob, bytes)
+ payload_bytes = struct.unpack("<{0}I".format(len(blob) // 4), blob)
+ cmms = []
+ # remove_header
+ payload_bytes = payload_bytes[8:]
+ idx = 0
+ while idx < len(payload_bytes):
+ cmd = []
+ code = payload_bytes[idx]
+ idx += 1
+ cmd.append(code)
+ payload_mode = CmdMode(code & CmdMode.Mask)
+ if payload_mode == CmdMode.Payload32:
+ value = payload_bytes[idx]
+ idx += 1
+ cmd.append(value)
+ cmms.append(cmd)
+ return cmms
+
+
+def _create_test_runner(accel):
+ file_dir = os.path.dirname(os.path.abspath(__file__))
+ test_root = os.path.join(file_dir, "reference_system")
+ ethosu_macs = accel[accel.rfind("-") + 1 :]
+ return AOTTestRunner(
+ makefile="corstone300",
+ prologue="""
+ uart_init();
+ EthosuInit();
+ """,
+ includes=["uart.h", "ethosu_55.h", "ethosu_mod.h", "hard_fault.h"],
+ parameters={"ETHOSU_TEST_ROOT": test_root, "NPU_VARIANT": ethosu_macs},
+ pass_config={
+ "relay.ext.ethosu.options": {
+ "accelerator_config": accel,
+ }
+ },
+ )
+
+
+def build_source(module, inputs, outputs, accel="ethos-u55-256"):
+ test_runner = _create_test_runner(accel)
+ return compile_models(
+ models=AOTTestModel(
+ module=module,
+ inputs=inputs,
+ outputs=outputs,
+ output_tolerance=10,
Review comment:
I think the default value of output_tolerance should be 0 and
build_source should have an optional parameter to set it to something else, if
necessary
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]