1111import subprocess
1212import sys
1313import tempfile
14+ from datetime import datetime
15+ from enum import auto , Enum
16+ from pathlib import Path
17+ from typing import Any
1418
1519import pytest
1620
1923from executorch .backends .arm .arm_backend import ArmCompileSpecBuilder
2024from executorch .exir .backend .compile_spec_schema import CompileSpec
2125
22- _enabled_options : list [str ] = []
26+
27+ class arm_test_options (Enum ):
28+ quantize_io = auto ()
29+ corstone300 = auto ()
30+ dump_path = auto ()
31+ date_format = auto ()
32+
33+
34+ _test_options : dict [arm_test_options , Any ] = {}
2335
2436# ==== Pytest hooks ====
2537
2638
2739def pytest_addoption (parser ):
2840 parser .addoption ("--arm_quantize_io" , action = "store_true" )
2941 parser .addoption ("--arm_run_corstone300" , action = "store_true" )
42+ parser .addoption ("--default_dump_path" , default = None )
43+ parser .addoption ("--date_format" , default = "%d-%b-%H:%M:%S" )
3044
3145
3246def pytest_configure (config ):
3347 if config .option .arm_quantize_io :
3448 load_libquantized_ops_aot_lib ()
35- _enabled_options . append ( " quantize_io" )
49+ _test_options [ arm_test_options . quantize_io ] = True
3650 if config .option .arm_run_corstone300 :
3751 corstone300_exists = shutil .which ("FVP_Corstone_SSE-300_Ethos-U55" )
3852 if not corstone300_exists :
3953 raise RuntimeError (
4054 "Tests are run with --arm_run_corstone300 but corstone300 FVP is not installed."
4155 )
42- _enabled_options .append ("corstone300" )
56+ _test_options [arm_test_options .corstone300 ] = True
57+ if config .option .default_dump_path :
58+ dump_path = Path (config .option .default_dump_path ).expanduser ()
59+ if dump_path .exists () and os .path .isdir (dump_path ):
60+ _test_options [arm_test_options .dump_path ] = dump_path
61+ else :
62+ raise RuntimeError (
63+ f"Supplied argument 'default_dump_path={ dump_path } ' that does not exist or is not a directory."
64+ )
65+ _test_options [arm_test_options .date_format ] = config .option .date_format
4366 logging .basicConfig (level = logging .INFO , stream = sys .stdout )
4467
4568
@@ -54,6 +77,18 @@ def pytest_collection_modifyitems(config, items):
5477 item .add_marker (skip_if_aot_lib_not_loaded )
5578
5679
80+ def pytest_sessionstart (session ):
81+ pass
82+
83+
84+ def pytest_sessionfinish (session , exitstatus ):
85+ if get_option (arm_test_options .dump_path ):
86+ _clean_dir (
87+ get_option (arm_test_options .dump_path ),
88+ f"ArmTester_{ get_option (arm_test_options .date_format )} .log" ,
89+ )
90+
91+
5792# ==== End of Pytest hooks =====
5893
5994
@@ -76,7 +111,9 @@ def load_libquantized_ops_aot_lib():
76111 torch .ops .load_library (library_path )
77112
78113
79- def is_option_enabled (option : str , fail_if_not_enabled : bool = False ) -> bool :
114+ def is_option_enabled (
115+ option : str | arm_test_options , fail_if_not_enabled : bool = False
116+ ) -> bool :
80117 """
81118 Returns whether an option is successfully enabled, i.e. if the flag was
82119 given to pytest and the necessary requirements are available.
@@ -87,7 +124,10 @@ def is_option_enabled(option: str, fail_if_not_enabled: bool = False) -> bool:
87124 The optional parameter 'fail_if_not_enabled' makes the function raise
88125 a RuntimeError instead of returning False.
89126 """
90- if option .lower () in _enabled_options :
127+ if isinstance (option , str ):
128+ option = arm_test_options [option .lower ()]
129+
130+ if option in _test_options and _test_options [option ]:
91131 return True
92132 else :
93133 if fail_if_not_enabled :
@@ -96,6 +136,12 @@ def is_option_enabled(option: str, fail_if_not_enabled: bool = False) -> bool:
96136 return False
97137
98138
139+ def get_option (option : arm_test_options ) -> Any | None :
140+ if option in _test_options :
141+ return _test_options [option ]
142+ return None
143+
144+
99145def maybe_get_tosa_collate_path () -> str | None :
100146 """
101147 Checks the environment variable TOSA_TESTCASES_BASE_PATH and returns the
@@ -219,3 +265,32 @@ def get_u85_compile_spec_unbuilt(
219265 .dump_intermediate_artifacts_to (artifact_path )
220266 )
221267 return compile_spec
268+
269+
270+ def current_time_formated () -> str :
271+ """Return current time as a formated string"""
272+ return datetime .now ().strftime (get_option (arm_test_options .date_format ))
273+
274+
275+ def _clean_dir (dir : Path , filter : str , num_save = 10 ):
276+ sorted_files : list [tuple [datetime , Path ]] = []
277+ for file in dir .iterdir ():
278+ try :
279+ creation_time = datetime .strptime (file .name , filter )
280+ insert_index = - 1
281+ for i , to_compare in enumerate (sorted_files ):
282+ compare_time = to_compare [0 ]
283+ if creation_time < compare_time :
284+ insert_index = i
285+ break
286+ if insert_index == - 1 and len (sorted_files ) < num_save :
287+ sorted_files .append ((creation_time , file ))
288+ else :
289+ sorted_files .insert (insert_index , (creation_time , file ))
290+ except ValueError :
291+ continue
292+
293+ if len (sorted_files ) > num_save :
294+ for remove in sorted_files [0 : len (sorted_files ) - num_save ]:
295+ file = remove [1 ]
296+ file .unlink ()
0 commit comments