1818import numpy as np
1919import torch
2020
21- from executorch .backends .arm .arm_backend import is_tosa
21+ from executorch .backends .arm .arm_backend import is_tosa , is_vgf
2222from executorch .backends .arm .test .conftest import is_option_enabled
2323from executorch .backends .arm .tosa_specification import (
2424 get_tosa_spec ,
5757 torch .complex128 : np .complex128 ,
5858}
5959
60+ VALID_TARGET = {"corstone-300" , "corstone-320" , "vkml_emulation_layer" }
61+
6062
6163class QuantizationParams :
6264 __slots__ = ["node_name" , "zp" , "scale" , "qmin" , "qmax" , "dtype" ]
@@ -218,6 +220,69 @@ def __torch_function__(self, func, types, args=..., kwargs=None):
218220 return func (* args , ** kwargs )
219221
220222
223+ def run_target (
224+ executorch_program_manager : ExecutorchProgramManager ,
225+ inputs : Tuple [torch .Tensor ],
226+ intermediate_path : str | Path ,
227+ target_board : Literal ["corestone-300" , "corestone-320" , "vkml_emulation_layer" ],
228+ elf_path : str | Path ,
229+ timeout : int = 120 , # s
230+ ):
231+ if target_board not in VALID_TARGET :
232+ raise ValueError (f"Unsupported target: { target_board } " )
233+
234+ if target_board in ("corstone-300" , "corstone-320" ):
235+ return run_corstone (
236+ executorch_program_manager ,
237+ inputs ,
238+ intermediate_path ,
239+ target_board ,
240+ elf_path ,
241+ timeout ,
242+ )
243+ elif target_board == "vkml_emulation_layer" :
244+ return run_vkml_emulation_layer (
245+ executorch_program_manager ,
246+ intermediate_path ,
247+ elf_path ,
248+ )
249+
250+
251+ def run_vkml_emulation_layer (
252+ executorch_program_manager : ExecutorchProgramManager ,
253+ intermediate_path : str | Path ,
254+ elf_path : str | Path ,
255+ ):
256+ """Executes an inference of the exported_program on ML Emulation Layer for Vulkan
257+ Args:
258+ `executorch_program_manager`: The executorch program to run.
259+ `intermediate_path`: Directory to save the .pte and capture outputs.
260+ `elf_path`: Path to the Vulkan-capable executor_runner binary.
261+ """
262+
263+ intermediate_path = Path (intermediate_path )
264+ intermediate_path .mkdir (exist_ok = True )
265+ elf_path = Path (elf_path )
266+ if not elf_path .exists ():
267+ raise FileNotFoundError (f"Did not find elf file { elf_path } " )
268+
269+ # Save pte to file
270+ pte_path = os .path .join (intermediate_path , "program.pte" )
271+ with open (pte_path , "wb" ) as f :
272+ f .write (executorch_program_manager .buffer )
273+
274+ cmd_line = [elf_path , "-model_path" , pte_path ]
275+ result = _run_cmd (cmd_line )
276+
277+ result_stdout = result .stdout .decode () # noqa: F841
278+ # TODO: MLETORCH-1234: Support VGF e2e tests in VgfPipeline
279+ # TODO: Add regex to check for error or fault messages in stdout from Emulation Layer
280+ # TODO: Retrieve and return the output tensors once VGF runtime is able to dump them.
281+ raise NotImplementedError (
282+ "Output parsing from VKML Emulation Layer is not yet implemented. "
283+ )
284+
285+
221286def run_corstone (
222287 executorch_program_manager : ExecutorchProgramManager ,
223288 inputs : Tuple [torch .Tensor ],
@@ -229,7 +294,7 @@ def run_corstone(
229294 """Executes an inference of the exported_program on FVP.
230295 Returns a list of tensors with the output.
231296 Args:
232- `executorch_program_manager`: the executorch program to run.
297+ `executorch_program_manager`: The executorch program to run.
233298 The output of a EdgeProgramManager.to_executorch() call.
234299 `inputs`: A list of tensors with the inputs of the inference.
235300 `dump_path`: A directory where the .pte and inputs are saved to file.
@@ -558,18 +623,52 @@ def model_converter_installed() -> bool:
558623 return True
559624
560625
561- def get_elf_path (target_board ):
562- elf_path = os .path .join (
563- "arm_test" ,
564- f"arm_semihosting_executor_runner_{ target_board } " ,
565- "arm_executor_runner" ,
566- )
626+ def vkml_emulation_layer_installed () -> bool :
627+ # Check VK_INSTANCE_LAYERS
628+ vk_instance_layers = os .environ .get ("VK_INSTANCE_LAYERS" , "" )
629+ required_layers = {
630+ "VK_LAYER_ML_Graph_Emulation" ,
631+ "VK_LAYER_ML_Tensor_Emulation" ,
632+ }
633+ existing_layers = set (vk_instance_layers .split (":" ))
634+ layers_exists = required_layers .issubset (existing_layers )
635+
636+ # Check LD_LIBRARY_PATH for "emulation-layer/deploy"
637+ ld_library_path = os .environ .get ("LD_LIBRARY_PATH" , "" )
638+ deploy_exists = False
639+ for path in ld_library_path .split (os .path .pathsep ):
640+ if "emulation-layer/deploy" in path and os .path .isdir (path ):
641+ deploy_exists = True
642+
643+ return layers_exists and deploy_exists
644+
645+
646+ def assert_elf_path_exists (elf_path ):
567647 if not os .path .exists (elf_path ):
568648 raise FileNotFoundError (
569- f"Did not find build arm_executor_runner in path { elf_path } , run setup_testing.sh?"
649+ f"Did not find build arm_executor_runner or executor_runner in path { elf_path } , run setup_testing.sh?"
570650 )
571- else :
572- return elf_path
651+
652+
653+ def get_elf_path (target_board ):
654+ if target_board not in VALID_TARGET :
655+ raise ValueError (f"Unsupported target: { target_board } " )
656+
657+ if target_board in ("corstone-300" , "corstone-320" ):
658+ elf_path = os .path .join (
659+ "arm_test" ,
660+ f"arm_semihosting_executor_runner_{ target_board } " ,
661+ "arm_executor_runner" ,
662+ )
663+ assert_elf_path_exists (elf_path )
664+ elif target_board == "vkml_emulation_layer" :
665+ elf_path = os .path .join (
666+ "cmake-out" ,
667+ "executor_runner" ,
668+ )
669+ assert_elf_path_exists (elf_path )
670+
671+ return elf_path
573672
574673
575674def arm_executor_runner_exists (target_board ):
@@ -629,6 +728,8 @@ def transpose_data_format(data: list[np.ndarray], to: Literal["NHWC", "NCHW"]):
629728
630729
631730def get_target_board (compile_spec : list [CompileSpec ]) -> str | None :
731+ if is_vgf (compile_spec ):
732+ return "vkml_emulation_layer"
632733 for spec in compile_spec :
633734 if spec .key == "compile_flags" :
634735 flags = spec .value .decode ()
0 commit comments