已合并
feat: 新增 --append/-a 选项支持追加结果到已有CSV #131
FishPotatoChen创建于 13 天前
feat: 新增 --append/-a 选项支持追加结果到已有CSV #131
已合并
FishPotatoChen创建于 13 天前
6 个文件变更+220-118
M.claude/skills/ttk-how-run-test/SKILL.md+2-1
@@ -121,7 +121,8 @@ E2E 默认自动探测 NPU;`--cpu` 强制 CPU 执行。详见 `references/e2e-
121 121 
122| 参数 | 缩写 | 说明 |122| 参数 | 缩写 | 说明 |
123|------|------|------|123|------|------|------|
124-| `--output` | `-o` | 输出结果 CSV |124+| `--output` | `-o` | 输出结果 CSV(覆盖已有文件) |
125+| `--append` | `-a` | 追加结果到已有 CSV;表头不匹配时覆盖;与 `-o` 互斥 |
125 126 
126## 快速示例127## 快速示例
127 128 
Mdocs/Task_Execution.md+2-1
@@ -116,7 +116,8 @@ python3 -m ttk list -i cases.csv --op add
116 116 
117| 参数 | 缩写 | 默认值 | 说明 | 示例 |117| 参数 | 缩写 | 默认值 | 说明 | 示例 |
118|------|------|--------|------|------|118|------|------|--------|------|------|
119-| `--output` | `-o` | 无 | 输出结果CSV路径 | `-o results.csv` |119+| `--output` | `-o` | 无 | 输出结果CSV路径(覆盖已有文件),与 `-a` 互斥 | `-o results.csv` |
120+| `--append` | `-a` | 无 | 追加结果到已有CSV(表头不匹配则覆盖),与 `-o` 互斥 | `-a results.csv` |
120| `--title` | | 无 | 自定义输出列 | `--title testcase_name,precision_status` |121| `--title` | | 无 | 自定义输出列 | `--title testcase_name,precision_status` |
121| `--csv-preserve` | | 关闭 | 保留原始CSV表头 | `--csv-preserve` |122| `--csv-preserve` | | 关闭 | 保留原始CSV表头 | `--csv-preserve` |
122| `--print` | | 开启 | 打印摘要信息 | `--print=false` |123| `--print` | | 开启 | 打印摘要信息 | `--print=false` |
Mttk/cli/bridge.py+47-17
@@ -7,23 +7,17 @@ _INTEGER_CLEAN_VALUE = re.compile(r"[+-]?(?:0[xX][0-9a-fA-F]+|0[oO][0-7]+|0[bB][
7_FLOAT_CLEAN_VALUE = re.compile(r"[+-]?(?:(?:[0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)(?:[eE][+-]?[0-9]+)?)$")7_FLOAT_CLEAN_VALUE = re.compile(r"[+-]?(?:(?:[0-9]+\.[0-9]*|\.[0-9]+|[0-9]+)(?:[eE][+-]?[0-9]+)?)$")
8 8 
9 9 
10-def args_to_switches(args):10+def _apply_io_args(sw, args):
11- from ttk.utilities.classes import SWITCHES
12- 
13- sw = SWITCHES()
14- sw.logging_to_file = True
15- sw.config_path = getattr(args, "config", None) # NEW: 经 SWITCHES pickle 传 worker
16- sw.provider_filter = getattr(args, "provider", None) # NEW: --provider CLI 过滤器
17- 
18- # 无条件加载配置(config_path=None 时走标准路径:default.yaml + ~/.config/ttk + ./ttk.conf.yaml)。
19- # 删 get_config lazy fallback 后,这是 parent 侧唯一的 load 入口。
20- from ttk.config.loader import load_config
21- 
22- load_config(sw.config_path)
23- 
24 sw.input_files = [args.input]11 sw.input_files = [args.input]
25- sw.output_file_name = args.output12+ if hasattr(args, "append_file") and args.append_file:
13+ sw.output_file_name = args.append_file
14+ sw.append_mode = True
15+ else:
16+ sw.output_file_name = args.output
17+ sw.append_mode = False
26 18 
19+ 
20+def _apply_case_selection_args(sw, args):
27 if hasattr(args, "testcase") and args.testcase:21 if hasattr(args, "testcase") and args.testcase:
28 sw.selected_testcases = args.testcase.split(",")22 sw.selected_testcases = args.testcase.split(",")
29 if hasattr(args, "testcase_index") and args.testcase_index:23 if hasattr(args, "testcase_index") and args.testcase_index:
@@ -31,6 +25,8 @@ def args_to_switches(args):
31 if hasattr(args, "testcase_count") and args.testcase_count is not None:25 if hasattr(args, "testcase_count") and args.testcase_count is not None:
32 sw.selected_testcase_count = args.testcase_count26 sw.selected_testcase_count = args.testcase_count
33 27 
28+ 
29+def _apply_filter_args(sw, args):
34 if hasattr(args, "priority") and args.priority:30 if hasattr(args, "priority") and args.priority:
35 sw.priorities = _parse_priorities(args.priority)31 sw.priorities = _parse_priorities(args.priority)
36 if hasattr(args, "operator") and args.operator:32 if hasattr(args, "operator") and args.operator:
@@ -38,6 +34,8 @@ def args_to_switches(args):
38 if hasattr(args, "exclude_operator") and args.exclude_operator:34 if hasattr(args, "exclude_operator") and args.exclude_operator:
39 sw.excluded_operators = tuple(args.exclude_operator.split(","))35 sw.excluded_operators = tuple(args.exclude_operator.split(","))
40 36 
37+ 
38+def _apply_compare_dump_args(sw, args):
41 if hasattr(args, "random_seed") and args.random_seed is not None:39 if hasattr(args, "random_seed") and args.random_seed is not None:
42 sw.random_seed = args.random_seed40 sw.random_seed = args.random_seed
43 if hasattr(args, "input_dist"):41 if hasattr(args, "input_dist"):
@@ -46,7 +44,6 @@ def args_to_switches(args):
46 sw.compare_method = args.compare44 sw.compare_method = args.compare
47 if hasattr(args, "golden_mode"):45 if hasattr(args, "golden_mode"):
48 sw.golden_mode = args.golden_mode46 sw.golden_mode = args.golden_mode
49- 
50 if hasattr(args, "dump") and args.dump is not None:47 if hasattr(args, "dump") and args.dump is not None:
51 _apply_dump_config(sw.dump_config, args.dump)48 _apply_dump_config(sw.dump_config, args.dump)
52 if hasattr(args, "dump_format"):49 if hasattr(args, "dump_format"):
@@ -56,12 +53,15 @@ def args_to_switches(args):
56 if hasattr(args, "xpu_perf") and args.xpu_perf:53 if hasattr(args, "xpu_perf") and args.xpu_perf:
57 sw.xpu_perf = True54 sw.xpu_perf = True
58 55 
56+ 
57+def _apply_plugin_rerun_args(sw, args):
59 if hasattr(args, "plugin") and args.plugin:58 if hasattr(args, "plugin") and args.plugin:
60 sw.plugin_path = tuple(pathlib.Path(p.strip()).resolve() for p in args.plugin.split(",") if p.strip())59 sw.plugin_path = tuple(pathlib.Path(p.strip()).resolve() for p in args.plugin.split(",") if p.strip())
61- 
62 if hasattr(args, "rerun") and args.rerun:60 if hasattr(args, "rerun") and args.rerun:
63 sw.rerun_targets = args.rerun.lower().split(",")61 sw.rerun_targets = args.rerun.lower().split(",")
64 62 
63+ 
64+def _apply_output_log_args(sw, args):
65 if hasattr(args, "title") and args.title:65 if hasattr(args, "title") and args.title:
66 sw.custom_columns = args.title.split(",")66 sw.custom_columns = args.title.split(",")
67 if hasattr(args, "csv_preserve") and args.csv_preserve:67 if hasattr(args, "csv_preserve") and args.csv_preserve:
@@ -78,6 +78,9 @@ def args_to_switches(args):
78 sw.TASK_PROFILING = False78 sw.TASK_PROFILING = False
79 if hasattr(args, "progress_output") and args.progress_output:79 if hasattr(args, "progress_output") and args.progress_output:
80 sw.progress_output = args.progress_output80 sw.progress_output = args.progress_output
81+ 
82+ 
83+def _apply_device_args(sw, args):
81 if hasattr(args, "device") and args.device is not None:84 if hasattr(args, "device") and args.device is not None:
82 sw.device_count = args.device85 sw.device_count = args.device
83 if hasattr(args, "device_blacklist") and args.device_blacklist:86 if hasattr(args, "device_blacklist") and args.device_blacklist:
@@ -90,6 +93,9 @@ def args_to_switches(args):
90 sw.dev_plat = args.platform93 sw.dev_plat = args.platform
91 if hasattr(args, "proc_timeout") and args.proc_timeout:94 if hasattr(args, "proc_timeout") and args.proc_timeout:
92 sw.proc_timeout = args.proc_timeout95 sw.proc_timeout = args.proc_timeout
96+ 
97+ 
98+def _apply_run_args(sw, args):
93 if hasattr(args, "validate_only") and args.validate_only:99 if hasattr(args, "validate_only") and args.validate_only:
94 sw.validate_only = True100 sw.validate_only = True
95 if hasattr(args, "warmup") and not args.warmup:101 if hasattr(args, "warmup") and not args.warmup:
@@ -101,6 +107,30 @@ def args_to_switches(args):
101 if hasattr(args, "deterministic_level") and args.deterministic_level:107 if hasattr(args, "deterministic_level") and args.deterministic_level:
102 sw.deterministic_level = args.deterministic_level108 sw.deterministic_level = args.deterministic_level
103 109 
110+ 
111+def args_to_switches(args):
112+ from ttk.utilities.classes import SWITCHES
113+ 
114+ sw = SWITCHES()
115+ sw.logging_to_file = True
116+ sw.config_path = getattr(args, "config", None) # NEW: 经 SWITCHES pickle 传 worker
117+ sw.provider_filter = getattr(args, "provider", None) # NEW: --provider CLI 过滤器
118+ 
119+ # 无条件加载配置(config_path=None 时走标准路径:default.yaml + ~/.config/ttk + ./ttk.conf.yaml)。
120+ # 删 get_config lazy fallback 后,这是 parent 侧唯一的 load 入口。
121+ from ttk.config.loader import load_config
122+ 
123+ load_config(sw.config_path)
124+ 
125+ _apply_io_args(sw, args)
126+ _apply_case_selection_args(sw, args)
127+ _apply_filter_args(sw, args)
128+ _apply_compare_dump_args(sw, args)
129+ _apply_plugin_rerun_args(sw, args)
130+ _apply_output_log_args(sw, args)
131+ _apply_device_args(sw, args)
132+ _apply_run_args(sw, args)
133+ 
104 return sw134 return sw
105 135 
106 136 
Mttk/cli/common.py+38-15
@@ -3,12 +3,18 @@ import argparse
3from ttk.remote import is_remote_configured3from ttk.remote import is_remote_configured
4 4 
5 5 
6-def add_common_args(parser):6+def _add_io_args(parser):
7 parser.add_argument("-i", "--input", required=True, help="CSV test case file")7 parser.add_argument("-i", "--input", required=True, help="CSV test case file")
8 parser.add_argument(8 parser.add_argument(
9 "--config", default=None, help="Path to ttk config YAML (overrides ~/.config/ttk/ and ./ttk.conf.yaml)"9 "--config", default=None, help="Path to ttk config YAML (overrides ~/.config/ttk/ and ./ttk.conf.yaml)"
10 )10 )
11- parser.add_argument("-o", "--output", help="Output CSV file")11+ output_group = parser.add_mutually_exclusive_group()
12+ output_group.add_argument("-o", "--output", help="Output CSV file (overwrite existing)")
13+ output_group.add_argument("-a", "--append", dest="append_file", help="Append results to existing CSV file; "
14+ "overwrites if file header does not match")
15+ 
16+ 
17+def _add_case_filter_args(parser):
12 parser.add_argument("-t", "--testcase", help="Specify testcase name(s), comma-separated")18 parser.add_argument("-t", "--testcase", help="Specify testcase name(s), comma-separated")
13 parser.add_argument(19 parser.add_argument(
14 "--ti", "--testcase-index", dest="testcase_index", help="Specify testcase indexes, e.g. --ti=1,3,6 or --ti=1-5"20 "--ti", "--testcase-index", dest="testcase_index", help="Specify testcase indexes, e.g. --ti=1,3,6 or --ti=1-5"
@@ -25,6 +31,9 @@ def add_common_args(parser):
25 default="uniform",31 default="uniform",
26 help="Input data distribution (default: uniform)",32 help="Input data distribution (default: uniform)",
27 )33 )
34+ 
35+ 
36+def _add_precision_args(parser):
28 parser.add_argument(37 parser.add_argument(
29 "--compare",38 "--compare",
30 default=None,39 default=None,
@@ -57,8 +66,27 @@ def add_common_args(parser):
57 help="Prepared input/golden data directories. Without --no-prof, "66 help="Prepared input/golden data directories. Without --no-prof, "
58 "load matching testcase data and run device comparison",67 "load matching testcase data and run device comparison",
59 )68 )
69+ 
70+ 
71+def _add_run_args(parser):
60 parser.add_argument("--plugin", help="External plugin path for customized golden/inputs")72 parser.add_argument("--plugin", help="External plugin path for customized golden/inputs")
61 parser.add_argument("--rerun", help="Rerun failed cases, e.g. --rerun=precision_status")73 parser.add_argument("--rerun", help="Rerun failed cases, e.g. --rerun=precision_status")
74+ parser.add_argument(
75+ "--validate", dest="validate_only", action="store_true", help="Validate CSV cases only, skip device execution"
76+ )
77+ parser.add_argument(
78+ "--proc-no-reuse", dest="proc_no_reuse", action="store_true", help="Create new process for each case"
79+ )
80+ parser.add_argument(
81+ "--provider",
82+ default=None,
83+ help="Which providers to TEST (e.g. torch,tf). "
84+ "Test filter — narrows dispatch, does NOT override remote config. "
85+ "If not set, uses the first available key from spec's third_party.",
86+ )
87+ 
88+ 
89+def _add_output_args(parser):
62 parser.add_argument(90 parser.add_argument(
63 "--title", "--titles", dest="title", help="Custom output columns, e.g. --title=testcase_name,dyn_perf_us"91 "--title", "--titles", dest="title", help="Custom output columns, e.g. --title=testcase_name,dyn_perf_us"
64 )92 )
@@ -75,12 +103,6 @@ def add_common_args(parser):
75 type=lambda x: x.lower() != "false",103 type=lambda x: x.lower() != "false",
76 help="Print summary info periodically (default: true)",104 help="Print summary info periodically (default: true)",
77 )105 )
78- parser.add_argument(
79- "--validate", dest="validate_only", action="store_true", help="Validate CSV cases only, skip device execution"
80- )
81- parser.add_argument(
82- "--proc-no-reuse", dest="proc_no_reuse", action="store_true", help="Create new process for each case"
83- )
84 parser.add_argument("--no-memory-check", dest="no_memory_check", action="store_true", help="Skip host memory check")106 parser.add_argument("--no-memory-check", dest="no_memory_check", action="store_true", help="Skip host memory check")
85 parser.add_argument(107 parser.add_argument(
86 "--task-prof",108 "--task-prof",
@@ -90,13 +112,14 @@ def add_common_args(parser):
90 help="Task-level profiling (msprof) switch (default: true)",112 help="Task-level profiling (msprof) switch (default: true)",
91 )113 )
92 parser.add_argument("--po", "--progress-output", dest="progress_output", help="Progress output file")114 parser.add_argument("--po", "--progress-output", dest="progress_output", help="Progress output file")
93- parser.add_argument(115+ 
94- "--provider",116+ 
95- default=None,117+def add_common_args(parser):
96- help="Which providers to TEST (e.g. torch,tf). "118+ _add_io_args(parser)
97- "Test filter — narrows dispatch, does NOT override remote config. "119+ _add_case_filter_args(parser)
98- "If not set, uses the first available key from spec's third_party.",120+ _add_precision_args(parser)
99- )121+ _add_run_args(parser)
122+ _add_output_args(parser)
100 123 
101 124 
102def validate_xpu_perf_precondition(sw):125def validate_xpu_perf_precondition(sw):
Mttk/core_modules/infra/instance_base.py+38-4
@@ -84,6 +84,15 @@ class InstanceBase(metaclass=ABCMeta):
84 self.heartbeat_manager = None # HeartbeatManager or None84 self.heartbeat_manager = None # HeartbeatManager or None
85 self.collected_results: list = []85 self.collected_results: list = []
86 86 
87+ @staticmethod
88+ def _read_existing_header(path: str):
89+ try:
90+ with open(path, newline='', encoding='utf-8') as f:
91+ reader = csv.reader(f)
92+ return next(reader, None)
93+ except (UnicodeDecodeError, csv.Error, OSError):
94+ return None
95+ 
87 @abstractmethod96 @abstractmethod
88 def env_prepare(self):97 def env_prepare(self):
89 pass98 pass
@@ -436,10 +445,35 @@ class InstanceBase(metaclass=ABCMeta):
436 f"It will be set as {self.result_path}")445 f"It will be set as {self.result_path}")
437 if not self.result_path.endswith('.csv'):446 if not self.result_path.endswith('.csv'):
438 self.result_path += '.csv'447 self.result_path += '.csv'
439- self.result_csv_file = open(self.result_path, newline='', mode='w+')448+ parent_dir = os.path.dirname(self.result_path)
440- self.result_csv_writer = csv.writer(self.result_csv_file)449+ if parent_dir and not os.path.isdir(parent_dir):
441- self._prepare_output_titles()450+ os.makedirs(parent_dir, exist_ok=True)
442- self._flush(self.case_result_titles)451+ logging.info(f"Created output directory: {parent_dir}")
452+ append_mode = self.switches.append_mode
453+ file_exists = os.path.exists(self.result_path) and os.path.getsize(self.result_path) > 0
454+ if append_mode and file_exists:
455+ self._prepare_output_titles()
456+ existing_header = self._read_existing_header(self.result_path)
457+ header_match = existing_header is not None and tuple(existing_header) == self.case_result_titles
458+ if header_match:
459+ self.result_csv_file = open(self.result_path, newline='', mode='a+')
460+ self.result_csv_writer = csv.writer(self.result_csv_file)
461+ self._header_flushed = True
462+ self._precision_status_idx = self._resolve_precision_status_idx(self.case_result_titles)
463+ logging.info(f"Append mode: appending to existing {self.result_path}")
464+ else:
465+ logging.warning(f"Append mode: existing file header does not match "
466+ f"(file has {len(existing_header) if existing_header else 0} columns, "
467+ f"current expects {len(self.case_result_titles)}). "
468+ f"Overwriting {self.result_path}")
469+ self.result_csv_file = open(self.result_path, newline='', mode='w+')
470+ self.result_csv_writer = csv.writer(self.result_csv_file)
471+ self._flush(self.case_result_titles)
472+ else:
473+ self.result_csv_file = open(self.result_path, newline='', mode='w+')
474+ self.result_csv_writer = csv.writer(self.result_csv_file)
475+ self._prepare_output_titles()
476+ self._flush(self.case_result_titles)
443 477 
444 def _prepare_output_titles(self):478 def _prepare_output_titles(self):
445 first_testcase = next(iter(self.flatten_testcases))479 first_testcase = next(iter(self.flatten_testcases))
Mttk/utilities/classes.py+93-80
@@ -105,6 +105,7 @@ class SWITCHES:
105 "mode",105 "mode",
106 "input_files",106 "input_files",
107 "output_file_name",107 "output_file_name",
108+ "append_mode",
108 "logging_to_file",109 "logging_to_file",
109 "single_testcase_log_mode",110 "single_testcase_log_mode",
110 "dev_plat",111 "dev_plat",
@@ -181,86 +182,10 @@ class SWITCHES:
181 ]182 ]
182 183 
183 def __init__(self):184 def __init__(self):
184- self.root_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))185+ self._init_paths_and_mode()
185- self.mode: MODE = MODE.ASCEND_ONBOARD186+ self._init_device_and_run()
186- self.input_files: Optional[List[str]] = None187+ self._init_testcases_and_filters()
187- self.output_file_name: Optional[str] = None188+ self._init_modes_and_backend()
188- self.logging_to_file: bool = False
189- self.single_testcase_log_mode = False
190- self.dev_plat: str = "AUTO"
191- self.short_soc_version: Optional[str] = None # None in non-NPU mode
192- self.custom_columns = None
193- self.print_help: bool = False
194- self.process_per_device = None
195- self.dyn_switches: OPTestSwitch = OPTestSwitch("Dynamic Shape", True, True, True)
196- self.cst_switches: OPTestSwitch = OPTestSwitch("Const Shape", False, True, True)
197- self.bin_switches: OPTestSwitch = OPTestSwitch("Binary Release", False, True, True)
198- self.rerun_targets = None
199- self.TASK_PROFILING = True
200- self.dump_config = DumpConfig()
201- self.device_count = -1
202- self.device_blacklist = []
203- self.device_whitelist = []
204- self.run_timeout = 0
205- self.proc_timeout = 0
206- self.tiling_run_time = 3
207- self.no_memory_check = False
208- self.force_clear_atomic = [None, None, None]
209- self.force_block_dim = [None, None, None]
210- self.force_clear_ub = None
211- self.force_clear_l1 = None
212- self.force_simt_ub_size = [None, None, None] # dynamic/const/binary
213- self.proc_no_reuse = False
214- # Hidden switches
215- self.kernel_meta = os.path.join(self.root_path, "kernel_meta")
216- self.warmup = True
217- self.summary_print = True
218- # Constants
219- self.DAVINCI_HBM_SIZE_LIMIT = 30 # GB
220- # Testcases
221- self.selected_testcases = []
222- self.selected_testcase_indexes = []
223- self.selected_testcase_count = -1
224- self.selected_operators = None
225- self.excluded_operators = None
226- self.preserve_original_csv = False
227- self.random_seed = None
228- self.progress_output = None
229- self.op_impl_mode: Optional[str] = None
230- self.simt_cfg: SoCSimtCfg = SoCSimtCfg()
231- self.input_distribution: str = "uniform"
232- self.golden_mode: str = "Enable"
233- self.compare_method = None
234- self.xpu_perf: bool = False
235- self.precision_report: Optional[str] = None
236- self.reuse_hbm: bool = False
237- self.reserve_hbm: int = 0
238- self.priorities: Optional[tuple] = None
239- self.compile_options: dict = {}
240- self.plugin_path: Optional[Tuple[pathlib.Path]] = None
241- self.test_mode: str = "op"
242- self.force_cpu: bool = False
243- self.fullgraph: int = 0
244- self.aclgraph_enabled: bool = False
245- self.validate_only: bool = False
246- self.manual_data_mode: Optional[str] = None
247- self.manual_data_dirs: Tuple[str, ...] = ()
248- # private properties below
249- self._run_time: Optional[int] = None
250- self._compile_only: bool = False
251- self.config_path: Optional[str] = None
252- self.provider_filter: Optional[str] = None
253- # GEIR mode
254- self.geir_binary: bool = False
255- self.deterministic_level: int = 0
256- # NPUSim simulator backend
257- self.backend: str = "npu" # "npu" | "npusim"
258- self.sim_soc_version: str = "Ascend950"
259- self.sim_output_dir: str = "" # 空 -> root_path/sim_output
260- self.sim_report: bool = False
261- self.sim_cores: str = ""
262- self.sim_object_file: str = ""
263- self.framework: str = "torch"
264 189 
265 def __getstate__(self):190 def __getstate__(self):
266 """Pickle 支持:仅导出 __slots__ 中已赋值的属性(跳过 property/私有)。"""191 """Pickle 支持:仅导出 __slots__ 中已赋值的属性(跳过 property/私有)。"""
@@ -314,6 +239,94 @@ class SWITCHES:
314 def oom_enabled(self) -> bool:239 def oom_enabled(self) -> bool:
315 return "oom" in self.compile_options.get("op_debug_config", "")240 return "oom" in self.compile_options.get("op_debug_config", "")
316 241 
242+ def _init_paths_and_mode(self):
243+ self.root_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
244+ self.mode: MODE = MODE.ASCEND_ONBOARD
245+ self.input_files: Optional[List[str]] = None
246+ self.output_file_name: Optional[str] = None
247+ self.append_mode: bool = False
248+ self.logging_to_file: bool = False
249+ self.single_testcase_log_mode = False
250+ self.dev_plat: str = "AUTO"
251+ self.short_soc_version: Optional[str] = None # None in non-NPU mode
252+ self.custom_columns = None
253+ self.print_help: bool = False
254+ self.process_per_device = None
255+ self.dyn_switches: OPTestSwitch = OPTestSwitch("Dynamic Shape", True, True, True)
256+ self.cst_switches: OPTestSwitch = OPTestSwitch("Const Shape", False, True, True)
257+ self.bin_switches: OPTestSwitch = OPTestSwitch("Binary Release", False, True, True)
258+ self.rerun_targets = None
259+ self.TASK_PROFILING = True
260+ self.dump_config = DumpConfig()
261+ 
262+ def _init_device_and_run(self):
263+ self.device_count = -1
264+ self.device_blacklist = []
265+ self.device_whitelist = []
266+ self.run_timeout = 0
267+ self.proc_timeout = 0
268+ self.tiling_run_time = 3
269+ self.no_memory_check = False
270+ self.force_clear_atomic = [None, None, None]
271+ self.force_block_dim = [None, None, None]
272+ self.force_clear_ub = None
273+ self.force_clear_l1 = None
274+ self.force_simt_ub_size = [None, None, None] # dynamic/const/binary
275+ self.proc_no_reuse = False
276+ # Hidden switches
277+ self.kernel_meta = os.path.join(self.root_path, "kernel_meta")
278+ self.warmup = True
279+ self.summary_print = True
280+ # Constants
281+ self.DAVINCI_HBM_SIZE_LIMIT = 30 # GB
282+ 
283+ def _init_testcases_and_filters(self):
284+ self.selected_testcases = []
285+ self.selected_testcase_indexes = []
286+ self.selected_testcase_count = -1
287+ self.selected_operators = None
288+ self.excluded_operators = None
289+ self.preserve_original_csv = False
290+ self.random_seed = None
291+ self.progress_output = None
292+ self.op_impl_mode: Optional[str] = None
293+ self.simt_cfg: SoCSimtCfg = SoCSimtCfg()
294+ self.input_distribution: str = "uniform"
295+ self.golden_mode: str = "Enable"
296+ self.compare_method = None
297+ self.xpu_perf: bool = False
298+ self.precision_report: Optional[str] = None
299+ self.reuse_hbm: bool = False
300+ self.reserve_hbm: int = 0
301+ self.priorities: Optional[tuple] = None
302+ self.compile_options: dict = {}
303+ self.plugin_path: Optional[Tuple[pathlib.Path]] = None
304+ 
305+ def _init_modes_and_backend(self):
306+ self.test_mode: str = "op"
307+ self.force_cpu: bool = False
308+ self.fullgraph: int = 0
309+ self.aclgraph_enabled: bool = False
310+ self.validate_only: bool = False
311+ self.manual_data_mode: Optional[str] = None
312+ self.manual_data_dirs: Tuple[str, ...] = ()
313+ # private properties below
314+ self._run_time: Optional[int] = None
315+ self._compile_only: bool = False
316+ self.config_path: Optional[str] = None
317+ self.provider_filter: Optional[str] = None
318+ # GEIR mode
319+ self.geir_binary: bool = False
320+ self.deterministic_level: int = 0
321+ # NPUSim simulator backend
322+ self.backend: str = "npu" # "npu" | "npusim"
323+ self.sim_soc_version: str = "Ascend950"
324+ self.sim_output_dir: str = "" # 空 -> root_path/sim_output
325+ self.sim_report: bool = False
326+ self.sim_cores: str = ""
327+ self.sim_object_file: str = ""
328+ self.framework: str = "torch"
329+ 
317 330 
318class OPTestSwitch:331class OPTestSwitch:
319 """332 """