Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .ci/docker/ci_commit_pins/pytorch.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
aec9b2ab77389967ef39bb9c10662fd0fe3e185a
21a304b17ffa9288b0357633d00804a646bb8a15
9 changes: 7 additions & 2 deletions backends/arm/test/models/test_mobilenet_v2_arm.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ def test_mv2_u55_BI(self):
)
if common.is_option_enabled("corstone300"):
tester.run_method_and_compare_outputs(
atol=1.0, qtol=1, inputs=self.model_inputs
atol=1.0, qtol=1, inputs=self.model_inputs, target_board="corstone-300"
)

def test_mv2_u85_BI(self):
(
tester = (
ArmTester(
self.mv2,
example_inputs=self.model_inputs,
Expand All @@ -116,4 +116,9 @@ def test_mv2_u85_BI(self):
.check(list(self.operators_after_quantization))
.partition()
.to_executorch()
.serialize()
)
if common.is_option_enabled("corstone300"):
tester.run_method_and_compare_outputs(
atol=1.0, qtol=1, inputs=self.model_inputs, target_board="corstone-320"
)
20 changes: 16 additions & 4 deletions backends/arm/test/ops/test_add.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,22 @@ def test_add_u55_BI(self, test_data: torch.Tensor):
test_data,
)
if common.is_option_enabled("corstone300"):
tester.run_method_and_compare_outputs(qtol=1, inputs=test_data)
tester.run_method_and_compare_outputs(
qtol=1, inputs=test_data, target_board="corstone-300"
)

@parameterized.expand(Add.test_parameters)
def test_add_u85_BI(self, test_data: torch.Tensor):
test_data = (test_data,)
self._test_add_ethos_BI_pipeline(
tester = self._test_add_ethos_BI_pipeline(
self.Add(),
common.get_u85_compile_spec(permute_memory_to_nhwc=True),
test_data,
)
if common.is_option_enabled("corstone300"):
tester.run_method_and_compare_outputs(
qtol=1, inputs=test_data, target_board="corstone-320"
)

@parameterized.expand(Add2.test_parameters)
def test_add2_tosa_MI(self, operand1: torch.Tensor, operand2: torch.Tensor):
Expand All @@ -165,11 +171,17 @@ def test_add2_u55_BI(self, operand1: torch.Tensor, operand2: torch.Tensor):
self.Add2(), common.get_u55_compile_spec(), test_data
)
if common.is_option_enabled("corstone300"):
tester.run_method_and_compare_outputs(qtol=1, inputs=test_data)
tester.run_method_and_compare_outputs(
qtol=1, inputs=test_data, target_board="corstone-300"
)

@parameterized.expand(Add2.test_parameters)
def test_add2_u85_BI(self, operand1: torch.Tensor, operand2: torch.Tensor):
test_data = (operand1, operand2)
self._test_add_ethos_BI_pipeline(
tester = self._test_add_ethos_BI_pipeline(
self.Add2(), common.get_u85_compile_spec(), test_data
)
if common.is_option_enabled("corstone300"):
tester.run_method_and_compare_outputs(
qtol=1, inputs=test_data, target_board="corstone-320"
)
101 changes: 70 additions & 31 deletions backends/arm/test/runner_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ def __init__(
self.qp_input: list[QuantizationParams] = None
self.qp_output: QuantizationParams = None
self.timeout = 120
self.target_board: str = None

self._has_init_run = False

Expand All @@ -185,11 +186,17 @@ def init_run(
exported_program: ExportedProgram,
edge_program: ExportedProgram,
is_quantized: bool,
target_board: str,
):

if target_board not in ["corstone-300", "corstone-320"]:
raise RuntimeError(f"Unknown target board: {target_board}")

self.input_names = _get_input_names(edge_program)
self.output_node = _get_output_node(exported_program)
self.output_name = self.output_node.name
self.is_quantized = is_quantized
self.target_board = target_board

if is_quantized:
self.qp_input = _get_input_quantization_params(exported_program)
Expand All @@ -205,7 +212,7 @@ def init_run(
def set_timeout(self, timeout: int):
self.timeout = timeout

def run_corstone300(
def run_corstone(
self,
inputs: Tuple[torch.Tensor],
) -> list[torch.Tensor]:
Expand All @@ -231,7 +238,7 @@ def run_corstone300(
)
elf_path = os.path.join(
"cmake-out",
"arm_semihosting_executor_runner_corstone-300",
f"arm_semihosting_executor_runner_{self.target_board}",
"arm_executor_runner",
)
assert os.path.exists(
Expand All @@ -242,32 +249,66 @@ def run_corstone300(
for input_path in input_paths:
cmd_line += f" -i {input_path}"

command_args = [
"FVP_Corstone_SSE-300_Ethos-U55",
"-C",
"ethosu.num_macs=128",
"-C",
"mps3_board.visualisation.disable-visualisation=1",
"-C",
"mps3_board.telnetterminal0.start_telnet=0",
"-C",
"mps3_board.uart0.out_file='-'",
"-C",
"cpu0.CFGITCMSZ=11",
"-C",
"cpu0.semihosting-enable=1",
"-C",
"cpu0.semihosting-stack_base=0",
"-C",
"cpu0.semihosting-heap_limit=0",
"-C",
f"cpu0.semihosting-cmd_line='{cmd_line}'",
"-a",
elf_path,
"--timelimit",
f"{self.timeout}",
]
result = _run_cmd(command_args, check=False)
command_args = {
"corstone-300": [
"FVP_Corstone_SSE-300_Ethos-U55",
"-C",
"ethosu.num_macs=128",
"-C",
"mps3_board.visualisation.disable-visualisation=1",
"-C",
"mps3_board.telnetterminal0.start_telnet=0",
"-C",
"mps3_board.uart0.out_file='-'",
"-C",
"cpu0.CFGITCMSZ=11",
"-C",
"cpu0.semihosting-enable=1",
"-C",
"cpu0.semihosting-stack_base=0",
"-C",
"cpu0.semihosting-heap_limit=0",
"-C",
f"cpu0.semihosting-cmd_line='{cmd_line}'",
"-a",
elf_path,
"--timelimit",
f"{self.timeout}",
],
"corstone-320": [
"FVP_Corstone_SSE-320",
"-C",
"mps4_board.subsystem.ethosu.num_macs=128",
"-C",
"mps4_board.visualisation.disable-visualisation=1",
"-C",
"mps4_board.telnetterminal0.start_telnet=0",
"-C",
"mps4_board.uart0.out_file='-'",
"-C",
"mps4_board.uart0.unbuffered_output=1",
"-C",
"mps4_board.uart0.shutdown_on_eot=1",
"-C",
"mps4_board.subsystem.cpu0.semihosting-enable=1",
"-C",
"mps4_board.subsystem.cpu0.semihosting-stack_base=0",
"-C",
"mps4_board.subsystem.cpu0.semihosting-heap_limit=0",
"-C",
f"mps4_board.subsystem.cpu0.semihosting-cmd_line='{cmd_line}'",
"-a",
elf_path,
"--timelimit",
f"{self.timeout}",
],
}

result = _run_cmd(command_args[self.target_board], check=False)
if result.returncode != 0:
raise RuntimeError(
f"Failed to run {command_args[self.target_board]}\nError: {result.stderr.decode()}"
)
result_stdout = result.stdout.decode()

error_regex = r"(^[EF][: ].*$)|(^.*Hard fault.*$)|(^.*Assertion.*$)"
Expand All @@ -276,10 +317,8 @@ def run_corstone300(
# regex to check for error or fault messages in stdout from FVP
if re.compile(error_regex, re.MULTILINE).search(result_stdout):
raise RuntimeError(
f"Corstone simulation failed, log: \n {result_stdout}\n{result.stderr.decode()}"
f"Corstone simulation failed:\ncmd: {command_args[self.target_board]}\n, log: \n {result_stdout}\n{result.stderr.decode()}"
)
elif "E [" in result_stdout:
logger.error(result_stdout)

tosa_ref_output = np.fromfile(out_path_with_suffix, dtype=np.float32)
output_shape = self.output_node.args[0][0].meta["val"].shape
Expand Down
10 changes: 8 additions & 2 deletions backends/arm/test/tester/arm_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def __init__(self, runner_util: RunnerUtil, timeout: int = 1):
self.runner.set_timeout(timeout)

def run_artifact(self, inputs):
return self.runner.run_corstone300(inputs)
return self.runner.run_corstone(inputs)

def dump_artifact(self, path_to_dump: Optional[str]):
if not path_to_dump:
Expand Down Expand Up @@ -226,6 +226,7 @@ def run_method_and_compare_outputs(
self,
inputs: Optional[Tuple[torch.Tensor]] = None,
stage: Optional[str] = None,
target_board: Optional[str] = "corstone-300",
num_runs=1,
atol=1e-03,
rtol=1e-03,
Expand Down Expand Up @@ -260,7 +261,12 @@ def run_method_and_compare_outputs(
edge_program = self.stages[
self.stage_name(tester.ToEdge)
].artifact.exported_program()
self.runner_util.init_run(exported_program, edge_program, is_quantized)
self.runner_util.init_run(
exported_program,
edge_program,
is_quantized,
target_board,
)

if is_quantized:
reference_stage = self.stages[self.stage_name(tester.Quantize)]
Expand Down
13 changes: 10 additions & 3 deletions devtools/inspector/_inspector.py
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,7 @@ class Inspector:
def __init__(
self,
etdump_path: Optional[str] = None,
etdump_data: Optional[bytes] = None,
etrecord: Optional[Union[ETRecord, str]] = None,
source_time_scale: TimeScale = TimeScale.NS,
target_time_scale: TimeScale = TimeScale.MS,
Expand All @@ -980,11 +981,12 @@ def __init__(
enable_module_hierarchy: bool = False,
) -> None:
r"""
Initialize an `Inspector` instance with the underlying `EventBlock`\ s populated with data from the provided ETDump path
Initialize an `Inspector` instance with the underlying `EventBlock`\ s populated with data from the provided ETDump path or binary,
and optional ETRecord path.

Args:
etdump_path: Path to the ETDump file.
etdump_path: Path to the ETDump file. Either this parameter or etdump_data should be provided.
etdump_data: ETDump binary. Either this parameter or etdump_path should be provided.
etrecord: Optional ETRecord object or path to the ETRecord file.
source_time_scale: The time scale of the performance data retrieved from the runtime. The default time hook implentation in the runtime returns NS.
target_time_scale: The target time scale to which the users want their performance data converted to. Defaults to MS.
Expand Down Expand Up @@ -1025,8 +1027,13 @@ def __init__(
else:
raise TypeError("Unsupported ETRecord type")

if (etdump_path is None) == (etdump_data is None):
raise ValueError(
"Expecting exactly one of etdump_path or etdump_data to be specified."
)

# Create EventBlocks from ETDump
etdump = gen_etdump_object(etdump_path=etdump_path)
etdump = gen_etdump_object(etdump_path=etdump_path, etdump_data=etdump_data)
if debug_buffer_path is not None:
with open(debug_buffer_path, "rb") as f:
output_buffer = f.read()
Expand Down
19 changes: 13 additions & 6 deletions devtools/inspector/_inspector_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,20 @@ def _extract_debug_handles(graph: OperatorGraph):
return debug_handle_to_op_node_map


def gen_etdump_object(etdump_path: Optional[str] = None) -> ETDumpFlatCC:
def gen_etdump_object(
etdump_path: Optional[str] = None, etdump_data: Optional[bytes] = None
) -> ETDumpFlatCC:
# Gen event blocks from etdump
if etdump_path is None:
raise ValueError("Etdump_path must be specified.")
with open(etdump_path, "rb") as buff:
etdump = deserialize_from_etdump_flatcc(buff.read())
return etdump
if etdump_data is None and etdump_path is not None:
with open(etdump_path, "rb") as buff:
etdump_data = buff.read()

if etdump_data is None:
raise ValueError(
"Unable to get ETDump data. One and only one of etdump_path and etdump_data must be specified."
)

return deserialize_from_etdump_flatcc(etdump_data)


def plot_metric(result: List[float], metric_name: str):
Expand Down
4 changes: 3 additions & 1 deletion devtools/inspector/tests/inspector_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ def test_inspector_constructor(self):

# Assert that expected functions are called
mock_parse_etrecord.assert_called_once_with(etrecord_path=ETRECORD_PATH)
mock_gen_etdump.assert_called_once_with(etdump_path=ETDUMP_PATH)
mock_gen_etdump.assert_called_once_with(
etdump_path=ETDUMP_PATH, etdump_data=None
)
mock_gen_from_etdump.assert_called_once()
# Because we mocked parse_etrecord() to return None, this method shouldn't be called
mock_gen_graphs_from_etrecord.assert_not_called()
Expand Down
Loading
Loading