blob: f4d1c140f852f9737d8b364686470997ac1f7018 [file] [log] [blame]
Jeremy Johnson0ecfa372022-06-30 14:27:56 +01001#!/usr/bin/env python3
Jeremy Johnson14087952024-02-29 16:13:10 +00002# Copyright (c) 2021-2024, ARM Limited.
Jeremy Johnson0ecfa372022-06-30 14:27:56 +01003# SPDX-License-Identifier: Apache-2.0
4"""Build conformance tests.
5
6Steps:
7- Specific input shapes (or tests) are specified and produced by using the
8 settings in the .json files.
9- Tests are selected to produce a good coverage.
10- Tests are run on the reference model to produce the correct output files.
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010011- Tests are converted to JSON and/or copied and saved to desired output directory.
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010012"""
13import argparse
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +000014import copy
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010015import json
16import logging
17import multiprocessing as mp
18import os
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +010019import re
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010020import shlex
21import shutil
22import subprocess
23from functools import partial
24from itertools import tee
25from pathlib import Path
26
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +010027import conformance.model_files as cmf
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010028from conformance.test_select import Operator
Won Jeon3eec59b2024-03-11 22:17:13 +000029from conformance.tosa_profiles import TosaProfiles
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010030from convert2conformance.convert2conformance import main as c2c_main
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010031from convert2conformance.convert2conformance import OUTPUT_TYPE_DEFAULT
32from convert2conformance.convert2conformance import OUTPUT_TYPES
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010033from distutils.dir_util import copy_tree
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +010034from serializer.tosa_serializer import TOSA_VERSION
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010035
36logging.basicConfig()
37logger = logging.getLogger("tosa_verif_conformance_generator")
38
Jeremy Johnsonbf9ee052024-05-01 17:26:24 +010039# Configuration
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010040PROFILE_OPS_INFO = {
Jeremy Johnsonbf9ee052024-05-01 17:26:24 +010041 "operator_test_params": "tosa_ext_profile_ops_info.json",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010042}
Won Jeon3eec59b2024-03-11 22:17:13 +000043PROFILES_EXTENSIONS_ALL = "all"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010044
Jeremy Johnson93d43902022-09-27 12:26:14 +010045DEFAULT_SEED = 42
46
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +000047# When there is a dictionary of generator argument lists (groups) only the
48# standard group will have negative tests generated for it
49STANDARD_GENERATOR_GROUP = "standard"
50
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010051TEST_VERSION_LATEST = "latest"
52TEST_VERSION_V0_60_0 = "v0.60.0"
53TEST_VERSIONS = (TEST_VERSION_LATEST, TEST_VERSION_V0_60_0)
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +010054REGEX_VERSION = re.compile(r"v([0-9]+)\.([0-9]+)\.([0-9]+)")
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010055
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010056
57class GenConformanceError(Exception):
58 """Generation error reporting exception."""
59
60 pass
61
62
63def _run_sh_command(args, cwd, full_cmd):
64 """Run an external command and capture stdout/stderr."""
65 # Quote the command line for printing
Jeremy Johnsonaf090182024-02-13 18:25:39 +000066 try:
67 full_cmd_esc = [shlex.quote(x) for x in full_cmd]
68 except Exception as e:
69 raise Exception(f"Error quoting command: {e}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010070 if args.capture_output:
Jeremy Johnsonaf090182024-02-13 18:25:39 +000071 logger.info(f"Command: {full_cmd_esc}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010072
73 rc = subprocess.run(
74 full_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
75 )
76
77 if args.capture_output:
Jeremy Johnsondd975b82024-02-28 17:29:13 +000078 stderr = rc.stderr.decode("utf-8")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010079 stdout = rc.stdout.decode("utf-8")
Jeremy Johnsondd975b82024-02-28 17:29:13 +000080 logger.info(f"stderr: \n{stderr}")
Jeremy Johnsonaf090182024-02-13 18:25:39 +000081 logger.info(f"stdout: \n{stdout}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010082 if rc.returncode != 0:
83
84 raise Exception(
85 "Error running command: {}.\n{}".format(
86 " ".join(full_cmd_esc), rc.stderr.decode("utf-8")
87 )
88 )
89 return (rc.stdout, rc.stderr)
90
91
Won Jeon3eec59b2024-03-11 22:17:13 +000092def _supports_for_enabled(profile_ext):
93 # The "supports_for" part of the config only works for MI and related extensions
94 # TODO - Update with TosaBI etc in future
95 return profile_ext in (
96 TosaProfiles.TosaMI,
97 TosaProfiles.TosaExtFP8E4M3,
98 TosaProfiles.TosaExtFP8E5M2,
99 TosaProfiles.TosaExtBF16,
100 TosaProfiles.TosaExtFFT,
101 )
102
103
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000104def build_op_tests(
Jeremy Johnson1271c442023-09-05 11:39:26 +0100105 args,
106 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +0000107 profile_ext,
Jeremy Johnson1271c442023-09-05 11:39:26 +0100108 operator,
109 group,
110 gen_args_list,
111 gen_neg_dim_range,
112 supports=[],
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000113 gen_filter=None,
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000114 selector_info=None,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000115):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100116 """Build tests for a given operator.
117
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000118 Builds a set of tests based on the given generator arguments list
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100119
120 Returns operator output directory
121 """
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100122 build_tests_cmd = "tosa_verif_build_tests"
Won Jeon3eec59b2024-03-11 22:17:13 +0000123 op_build_dir = args.build_dir / profile_ext / group
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100124
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000125 if gen_filter is None:
126 gen_filter = f"^{operator}$"
127
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000128 build_cmd_base = [
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100129 build_tests_cmd,
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100130 "--generate-lib-path",
131 str(args.generate_lib_path),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100132 "--filter",
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000133 gen_filter,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100134 "-o",
135 str(op_build_dir),
136 "--seed",
Jeremy Johnson93d43902022-09-27 12:26:14 +0100137 str(args.random_seed),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100138 ]
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000139 if args.verbosity:
140 build_cmd_base.append("-" + ("v" * args.verbosity))
141
142 if args.tests_list_file is not None:
143 build_cmd_base.append("--list-tests")
144
Won Jeon3eec59b2024-03-11 22:17:13 +0000145 if _supports_for_enabled(profile_ext):
146 if "lazy_data_gen" in supports and args.lazy_data_generation:
147 build_cmd_base.append("--lazy-data-generation")
148 if "stable_random_gen" in supports and not args.global_random_generation:
149 build_cmd_base.append("--stable-random-generation")
150 if "random_const_inputs" in supports:
151 build_cmd_base.append("--random-const-inputs")
Jeremy Johnson1271c442023-09-05 11:39:26 +0100152
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000153 if "generator_select" in supports:
154 if selector_info is None:
155 logger.error(
156 "build_op_tests error: generator_select mode without selector information"
157 )
158 raise (GenConformanceError())
159 selector_config, selector_name = selector_info
160 build_cmd_base.extend(
161 [
162 "--test-selection-config",
163 str(selector_config),
164 "--test-selection-criteria",
165 selector_name,
166 ]
167 )
168
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000169 build_cmds_list = []
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100170
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000171 if test_type in ["positive", "both"]:
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100172 # Append extra parameters and run test generator for each set of parameters.
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000173 for arglist in gen_args_list:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000174 build_cmd_pos_test = build_cmd_base.copy()
175 build_cmd_pos_test.extend(["--test-type", "positive"])
176 build_cmd_pos_test.extend(arglist)
177 build_cmds_list.append(build_cmd_pos_test)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100178
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000179 if test_type in ["negative", "both"]:
Jeremy Johnson35396f22023-01-04 17:05:25 +0000180 # Get target-dtypes options and any filter string to limit tests
Jeremy Johnson93d43902022-09-27 12:26:14 +0100181 target_dtypes_args = []
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000182 for arglist in gen_args_list:
Jeremy Johnson93d43902022-09-27 12:26:14 +0100183 idx = 0
184 while idx < len(arglist):
185 if arglist[idx] == "--target-dtype":
Jeremy Johnsonda84df92024-06-05 16:29:15 +0100186 idx += 1
187 # Support single or multiple args after --target-dtype
188 while idx < len(arglist) and (not arglist[idx].startswith("--")):
189 if arglist[idx] not in target_dtypes_args:
190 target_dtypes_args.append(arglist[idx])
191 idx += 1
192 else:
193 idx += 1
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000194 build_cmd_neg_test = build_cmd_base.copy()
195 build_cmd_neg_test.extend(["--test-type", "negative"])
Jeremy Johnson93d43902022-09-27 12:26:14 +0100196 # Limit sizes of negative tests
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000197 dim_range = gen_neg_dim_range if gen_neg_dim_range is not None else "1,16"
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000198 build_cmd_neg_test.extend(["--tensor-dim-range", dim_range])
Jeremy Johnsonda84df92024-06-05 16:29:15 +0100199 for arg in target_dtypes_args:
200 build_cmd_neg_test.extend(["--target-dtype", arg])
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000201 build_cmds_list.append(build_cmd_neg_test)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100202
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000203 logger.info(f"Creating {operator} tests in {len(build_cmds_list)} batch(es)")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100204 error = False
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000205 for i, cmd in enumerate(build_cmds_list):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100206 try:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000207 raw_stdout, _ = _run_sh_command(args, args.ref_model_path.parent, cmd)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100208 logger.info(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000209 f"{operator} test batch {(i+1)}/{len(build_cmds_list)} created successfully"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100210 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000211
212 if args.tests_list_file is not None:
213 with args.tests_list_file.open("a") as fd:
214 fd.write(raw_stdout.decode("utf-8"))
215
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100216 except Exception as e:
217 logger.error(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000218 f"{operator} test batch {(i+1)}/{len(build_cmds_list)} unsuccessful, skipping"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100219 )
220 logger.error(f" build_op_tests error: {e} ")
221 error = True
222 if error:
223 raise (GenConformanceError())
224
225 return op_build_dir
226
227
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000228def _check_to_include_test(test_type, test_name):
229 """Check test name for inclusion based on test_type, returns True to include."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100230
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000231 if test_type == "both":
232 return True
233 else:
234 error_test = "_ERRORIF_" in test_name
235 return (error_test and test_type == "negative") or (
236 not error_test and test_type == "positive"
237 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100238
239
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000240def _get_all_tests_list(test_type, test_root_dir, operator):
241 """Create test list from tests in the test_dir based on chosen type."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100242 test_dir = test_root_dir / operator
243 if not test_dir.is_dir():
244 # Tests are split into multiple dirs, for example: conv2d_1x1, conv2d_3x3
245 test_dir = test_root_dir
246 directories = [
247 tdir for tdir in test_dir.glob("*") if tdir.name.startswith(operator)
248 ]
249 else:
250 directories = [test_dir]
251
252 tests = []
253 for tdir in directories:
254 tests.extend(
255 [
256 test
257 for test in tdir.glob("*")
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000258 if _check_to_include_test(test_type, test.name)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100259 ]
260 )
261 return tests
262
263
Won Jeon3eec59b2024-03-11 22:17:13 +0000264def generate_results(
265 args, profile_ext, operator, op_build_dir, supports=[], tests=None
266):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100267 """Run tests on reference model and save result to the test directory."""
Won Jeon3eec59b2024-03-11 22:17:13 +0000268 if _supports_for_enabled(profile_ext):
269 if "lazy_data_gen" in supports and args.lazy_data_generation:
270 logger.info("Skipping running tests due to lazy data gen")
271 return
Jeremy Johnson1271c442023-09-05 11:39:26 +0100272
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100273 num_cores = args.num_cores
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100274
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100275 # Use the test runner
276 ref_cmd_base = [
277 "tosa_verif_run_tests",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100278 "--ref-model-path",
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100279 str(args.ref_model_path),
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100280 "--schema-path",
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100281 str(args.schema_path),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100282 "-j",
283 str(num_cores),
284 "-v",
285 "-t",
286 ]
287 ref_cmds = []
288
289 if not tests:
290 # Do not need to run ERRORIF tests as they don't have result files
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000291 tests = _get_all_tests_list("positive", op_build_dir, operator)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100292
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000293 skipped = 0
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100294 for test in tests:
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100295 desc = test / "desc.json"
296 with desc.open("r") as fd:
297 test_desc = json.load(fd)
298 if "meta" in test_desc and "compliance" in test_desc["meta"]:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000299 skipped += 1
300 logger.debug(
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100301 f"Skipping generating results for new compliance test - {str(test)}"
302 )
303 continue
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100304 ref_cmd = ref_cmd_base.copy()
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100305 ref_cmd.append(str(test.absolute()))
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100306 ref_cmds.append(ref_cmd)
307
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000308 if skipped:
309 logger.info(f"{skipped} new compliance tests skipped for results generation")
310
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100311 fail_string = "UNEXPECTED_FAILURE"
312 failed_counter = 0
313
314 job_pool = mp.Pool(args.num_cores)
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100315 sh_partial = partial(_run_sh_command, args, args.ref_model_path.parent)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100316 pool_results = job_pool.map(sh_partial, ref_cmds)
317 job_pool.close()
318 job_pool.join()
319
320 # Use captured output for run_sh_command to work out if test passed.
321 for i, rc in enumerate(pool_results):
322 if fail_string in str(rc[0]):
323 logger.error(f"Test {i+1}/{len(ref_cmds)}: {ref_cmds[i][-1]} failed.")
324 failed_counter += 1
325 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000326 logger.debug(f"Test {i+1}/{len(ref_cmds)}: {ref_cmds[i][-1]} passed.")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100327
328 logger.info(f"{len(ref_cmds)-failed_counter}/{len(ref_cmds)} tests passed")
329 logger.info("Ran tests on model and saved results of passing tests")
330
331
332def convert_tests(
333 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000334 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +0000335 profile_ext,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100336 operator,
337 op_build_dir,
338 output_dir,
Won Jeon3eec59b2024-03-11 22:17:13 +0000339 op_profiles_extensions_list,
Jeremy Johnson1271c442023-09-05 11:39:26 +0100340 supports=[],
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100341 tests=None,
342 group=None,
343 trim_op_subdir=False,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000344 tags=None,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100345):
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100346 """Convert/copy tests to output directory."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100347 if group:
348 output_dir = output_dir / group
349
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100350 c2c_args_base = ["--strict"]
351 c2c_args_base.extend(["--schema-path", str(args.schema_path)])
352 c2c_args_base.extend(["--flatc-path", str(args.flatc_path)])
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100353 c2c_args_base.extend(["--output-type", args.output_type])
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100354 # This op maybe in more than one profile - e.g. tosa_bi and tosa_mi
355 # even if we are only producing tests for tosa_mi
Won Jeon3eec59b2024-03-11 22:17:13 +0000356 for op_profile in op_profiles_extensions_list:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000357 c2c_args_base.extend(["--profile", op_profile])
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000358 if tags is not None:
359 for tag in tags:
360 c2c_args_base.extend(["--tag", tag])
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100361 if args.framework_schema:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000362 c2c_args_base.extend(["--framework-schema", str(args.framework_schema)])
Won Jeon3eec59b2024-03-11 22:17:13 +0000363 if _supports_for_enabled(profile_ext):
364 if "lazy_data_gen" in supports and args.lazy_data_generation:
365 c2c_args_base.append("--lazy-data-generation")
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000366 c2c_args_base.append("--output-directory")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100367
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000368 c2c_args_list = []
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100369
370 if not tests:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000371 tests = _get_all_tests_list(test_type, op_build_dir, operator)
Won Jeon3eec59b2024-03-11 22:17:13 +0000372 logger.info(f"Converting all {profile_ext} profile tests of type {test_type}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100373
374 # Controls if we copy the tests in their operator sub-directory or not
375 output_dir_relative_pos = -1 if trim_op_subdir else -2
376 for test in tests:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000377 logger.debug(f"Test chosen: {test}")
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000378 c2c_args = c2c_args_base.copy()
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100379 full_output_directory = output_dir / test.relative_to(
380 *test.parts[:output_dir_relative_pos]
381 )
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000382 c2c_args.append(str(full_output_directory))
383 c2c_args.append(str(test))
384 c2c_args_list.append(c2c_args)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100385
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000386 if len(c2c_args_list) == 0:
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000387 logger.error(
388 f"No tests found for {operator}. Nothing to convert in {op_build_dir}"
389 )
390 raise (GenConformanceError())
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100391
392 job_pool = mp.Pool(args.num_cores)
393
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000394 pool_results = job_pool.map(c2c_main, c2c_args_list)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100395 job_pool.close()
396 job_pool.join()
397
398 failed_counter = 0
399 for i, result in enumerate(pool_results):
400 if result != 0:
401 logger.error(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000402 f"test {i+1}/{len(c2c_args_list)}: {c2c_args_list[i][-1]} failed to convert."
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100403 )
404 failed_counter += 1
405 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000406 logger.debug(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000407 f"test {i+1}/{len(c2c_args_list)}: {c2c_args_list[i][-1]} converted"
408 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100409 logger.info(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000410 f"{len(c2c_args_list)-failed_counter}/{len(c2c_args_list)} tests successfully converted"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100411 )
412
413 if failed_counter > 0:
414 logger.error(f"Stopping due to {failed_counter} test conversion errors")
415 raise (GenConformanceError())
416
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100417 logger.info("Converted/copied tests and saved to output directory")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100418
419 return output_dir
420
421
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100422def get_op_tests_selection(
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000423 args,
Won Jeon3eec59b2024-03-11 22:17:13 +0000424 profile_ext,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000425 operator,
426 op_build_dir,
427 selection_config,
428 negative=False,
429 ignore_missing=False,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100430):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100431 """Use test picker to get subsection of tests generated."""
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000432 # Need a full copy of the config as the selector updates it
433 config = copy.deepcopy(selection_config)
Won Jeon3eec59b2024-03-11 22:17:13 +0000434 logger.info(
435 "Choosing {} tests for {}".format(
436 ("negative" if negative else "positive"), profile_ext
437 )
438 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100439 try:
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100440 op = Operator.registry[operator](
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000441 op_build_dir, config, negative=negative, ignore_missing=ignore_missing
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100442 )
443 except KeyError:
444 logger.error(f"{operator} operator is not supported by test_select")
445 raise (GenConformanceError())
446
447 return op.select_tests()
448
449
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100450def check_op_tests(args, profile, operator, output_dir):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100451 """Move test folders than contain files larger than 30MB to new directory."""
452 destination_dir = str(args.output_dir) + "_large_files"
453
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000454 # Include all tests - both positive and negative
455 tests = _get_all_tests_list("both", output_dir, operator)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100456 if not tests:
457 logger.error(
458 f"Couldn't find any tests to size check for {operator} in {output_dir}"
459 )
460 raise (GenConformanceError())
461
462 for tdir in tests:
463 move_dir = False
464 test_files = [file for file in tdir.glob("*")]
465 for file in test_files:
466 file_size = os.stat(file).st_size / 1024**2
467 if file_size > 30:
468 move_dir = True
469
470 if move_dir:
471 move_destination = destination_dir / tdir.relative_to(output_dir)
472 logger.warning(
473 f"{tdir.relative_to(output_dir)} contains files that are too large (>30MB), test moved to new folder: {destination_dir}"
474 )
475
476 if move_destination.is_dir():
477 logger.warning(
478 f"{move_destination} directory already exists, deleting existing."
479 )
480 shutil.rmtree(str(move_destination))
481 shutil.move(str(tdir), move_destination)
482
483
484def copy_rename_framework_tests(args, operator, test_picks):
485 """Copy framework tests into new folder and rename them if needed.
486
487 The tests are renamed to match the framework operator names if an
488 alternate name has been used instead.
489 """
490 framework_tests_dir = args.framework_tests_dir
491 new_tests_dir = args.build_dir / "frameworks" / operator
492 os.makedirs(new_tests_dir, exist_ok=True)
493
494 # Get the framework tests operator name
495 if "alternate_names" in test_picks[operator]:
496 alternate_names = test_picks[operator]["alternate_names"]
497 else:
498 alternate_names = [operator]
499
500 # Get the alternate named test directories for the operator
501 for alt_name in alternate_names:
502 test_prefix = f"test_{alt_name}"
503 test_dirs = list(framework_tests_dir.glob(f"{test_prefix}_*"))
504
505 # Copy tests to new directory and rename to match framework operator names
506 # - if there is just 1 alternate name, replace the full test prefix
507 # test_add_... -> add_...
508 # - if there are multiple alternate names, just replace the "test"
509 # test_concatv2_... -> concatenation_concatv2_...
510 old_prefix = test_prefix if len(alternate_names) == 1 else "test"
511
512 for tdir in test_dirs:
513 new_test_name = tdir.name.replace(old_prefix, operator)
514 copy_destination = new_tests_dir / new_test_name
515 logger.debug(f"copying test folder {tdir} to {copy_destination}")
516 copy_tree(str(tdir), str(copy_destination))
517
518 logger.info(f"Copied and renamed {len(test_dirs)} framework test folders")
519 return new_tests_dir.parent
520
521
522def get_framework_tests_selection(args, operator, test_picks, op_build_dir):
523 """Get the list of pre-chosen tests with relative paths."""
524 try:
525 tests = test_picks[operator]["tests"]
526 except KeyError:
527 logger.error(f"Framework test selection not defined for {operator} operator")
528 raise (GenConformanceError())
529
530 test_paths = [op_build_dir / operator / test for test in tests]
531 return test_paths
532
533
534def parse_args(argv=None):
535 """Parse the arguments."""
536 parser = argparse.ArgumentParser()
Won Jeon3eec59b2024-03-11 22:17:13 +0000537 profiles = TosaProfiles.profiles()
538 profiles.append(PROFILES_EXTENSIONS_ALL)
Jeremy Johnson88588622022-07-12 16:42:29 +0100539 parser.add_argument(
540 "--profile",
541 dest="profile",
542 choices=profiles,
Won Jeon3eec59b2024-03-11 22:17:13 +0000543 default=[TosaProfiles.TosaBI],
Jeremy Johnson88588622022-07-12 16:42:29 +0100544 type=str,
Won Jeon3eec59b2024-03-11 22:17:13 +0000545 nargs="*",
546 help=f"TOSA profile (default is {TosaProfiles.TosaBI})",
Jeremy Johnson88588622022-07-12 16:42:29 +0100547 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100548 parser.add_argument(
549 "--operators",
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100550 "--op",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100551 type=str,
552 nargs="*",
553 help="The operator(s) to create tests for, if not supplied all tests will be created",
554 )
555 parser.add_argument(
Won Jeon3eec59b2024-03-11 22:17:13 +0000556 "--extension",
557 dest="extension",
558 choices=TosaProfiles.extensions() + [PROFILES_EXTENSIONS_ALL],
559 default=[],
560 type=str,
561 nargs="*",
562 help="TOSA extension(s) to create tests for, if not supplied all tests will be created",
563 )
564 parser.add_argument(
Jeremy Johnson88588622022-07-12 16:42:29 +0100565 "--unit-tests",
566 dest="unit_tests",
567 choices=["operator", "framework", "both"],
568 default="operator",
569 type=str,
570 help="Which unit tests are produced (default is operator)",
571 )
572 parser.add_argument(
573 "--test-type",
574 dest="test_type",
575 choices=["positive", "negative", "both"],
576 default="both",
577 type=str,
578 help="Type of tests produced (default is both)",
579 )
580 parser.add_argument(
Jeremy Johnson0a6d1de2023-09-27 14:59:43 +0100581 "--global-random-generation",
582 action="store_true",
583 help="Disable stable random generation of tests that support this mode",
584 )
585 parser.add_argument(
Jeremy Johnson1271c442023-09-05 11:39:26 +0100586 "--lazy-data-generation",
587 action="store_true",
588 help="Enable lazy data generation (only for tosa-mi)",
589 )
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100590 rm_group = parser.add_mutually_exclusive_group(required=True)
591 rm_group.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100592 "--ref-model-directory",
593 dest="ref_model_dir",
594 type=Path,
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100595 help="(DEPRECATED - use ref-model-path) Reference Model directory - with build directory",
596 )
597 rm_group.add_argument(
598 "--ref-model-path",
599 dest="ref_model_path",
600 type=Path,
601 help="Path to TOSA reference model executable",
602 )
603 parser.add_argument(
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100604 "--generate-lib-path",
605 dest="generate_lib_path",
606 type=Path,
607 help=(
608 "Path to TOSA generate library. Defaults to "
609 "the library in the directory of `ref-model-path`"
610 ),
611 )
612 parser.add_argument(
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100613 "--schema-path",
614 "--operator-fbs",
615 dest="schema_path",
616 type=Path,
617 help=(
618 "Path to TOSA reference model flat buffer schema. Defaults to "
619 f"`{cmf.DEFAULT_REF_MODEL_SCHEMA_PATH}` in parents parent directory of `ref-model-path`"
620 ),
621 )
622 parser.add_argument(
623 "--flatc-path",
624 dest="flatc_path",
625 type=Path,
626 help=(
627 "Path to flatc executable. Defaults to "
628 f"`{cmf.DEFAULT_REF_MODEL_BUILD_FLATC_PATH}` in parent directory of `ref-model-path`"
629 ),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100630 )
Jeremy Johnson88588622022-07-12 16:42:29 +0100631 parser.add_argument(
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100632 "--test-version",
633 dest="test_version",
634 choices=TEST_VERSIONS,
635 default=TEST_VERSION_LATEST,
636 help=f"Version of the tests to produce (default is {TEST_VERSION_LATEST})",
637 )
638 parser.add_argument(
639 "--output-type",
640 dest="output_type",
641 choices=OUTPUT_TYPES,
642 default=OUTPUT_TYPE_DEFAULT,
643 help=f"Output file type produced (default is {OUTPUT_TYPE_DEFAULT})",
644 )
645 parser.add_argument(
Jeremy Johnson93d43902022-09-27 12:26:14 +0100646 "--seed",
647 dest="random_seed",
648 default=DEFAULT_SEED,
649 type=int,
650 help="Random test seed",
651 )
652 parser.add_argument(
Jeremy Johnson88588622022-07-12 16:42:29 +0100653 "--framework-tests-directory",
654 dest="framework_tests_dir",
655 type=Path,
656 default=Path.cwd() / "tests",
657 help="The pre-built framework tests directory (default is tests)",
658 )
659 parser.add_argument(
660 "--framework-schema",
661 dest="framework_schema",
662 type=Path,
663 help="Framework flatbuffers schema needed to convert framework models",
664 )
665 parser.add_argument(
666 "--build-directory",
667 dest="build_dir",
668 type=Path,
669 default=Path.cwd() / "conformance_build",
670 help="Temporary build directory for files created during this process (default is conformance_build)",
671 )
672 parser.add_argument(
673 "--output-directory",
674 dest="output_dir",
675 type=Path,
676 default=Path.cwd() / "conformance",
677 help="Output directory (default is conformance)",
678 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100679 script_dir = Path(__file__).parent.absolute()
680 parser.add_argument(
681 "--test-param-json-directory",
682 dest="param_json_dir",
683 type=Path,
684 default=script_dir,
Jeremy Johnson88588622022-07-12 16:42:29 +0100685 help=f"Test parameters (ops info) JSON file directory (default is {script_dir})",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100686 )
687 parser.add_argument(
Won Jeon3eec59b2024-03-11 22:17:13 +0000688 "--test-params-json-config",
689 "--config",
690 dest="param_config",
691 type=Path,
692 help="Test parameters (ops info) JSON file (overrides --test-param-json-directory)",
693 )
694 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100695 "--convert-all-tests",
696 action="store_true",
697 help="Converts all tests instead of those picked by test_select",
698 )
699 parser.add_argument(
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000700 "--list-tests-to-file",
701 dest="tests_list_file",
702 type=Path,
703 help="Lists out the tests to be generated to a file instead of generating them",
704 )
705 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100706 "--keep-large-files",
707 action="store_true",
708 help="Keeps tests that contain files larger than 30MB in output directory",
709 )
710 parser.add_argument(
711 "--capture-output",
712 action="store_true",
713 help="Prints output of running sh commands",
714 )
715 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100716 "-j",
717 dest="num_cores",
718 type=int,
719 default=6,
720 help="Number of simultaneous jobs to split the tasks into for multiprocessing",
721 )
722 parser.add_argument(
723 "-v",
724 dest="verbosity",
725 action="count",
726 default=0,
727 help="Verbosity (can be used multiple times for more details)",
728 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100729 args = parser.parse_args(argv)
730
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000731 if args.ref_model_dir is not None:
732 # Assume the ref model exe path based on the ref model directory
733 args.ref_model_path = cmf.find_tosa_file(
734 cmf.TosaFileType.REF_MODEL, args.ref_model_dir, False
735 )
736 if not args.ref_model_path.is_file():
737 logger.error(
738 f"Missing reference model binary (--ref-model-path): {args.ref_model_path}"
739 )
740 return None
741 args.ref_model_path = args.ref_model_path.absolute()
742
743 if args.generate_lib_path is None:
744 args.generate_lib_path = cmf.find_tosa_file(
745 cmf.TosaFileType.GENERATE_LIBRARY, args.ref_model_path
746 )
747 if not args.generate_lib_path.is_file():
748 logger.error(
749 f"Missing TOSA generate data library (--generate-lib-path): {args.generate_lib_path}"
750 )
751 return None
752 args.generate_lib_path = args.generate_lib_path.absolute()
753
754 if args.schema_path is None:
755 args.schema_path = cmf.find_tosa_file(
756 cmf.TosaFileType.SCHEMA, args.ref_model_path
757 )
758 if not args.schema_path.is_file():
759 logger.error(
760 f"Missing reference model schema (--schema-path): {args.schema_path}"
761 )
762 return None
763 args.schema_path = args.schema_path.absolute()
764
765 if args.flatc_path is None:
766 args.flatc_path = cmf.find_tosa_file(
767 cmf.TosaFileType.FLATC, args.ref_model_path
768 )
769 if not args.flatc_path.is_file():
770 logger.error(f"Missing flatc binary (--flatc-path): {args.flatc_path}")
771 return None
772 args.flatc_path = args.flatc_path.absolute()
773
774 args.param_json_dir = args.param_json_dir.absolute()
775
Won Jeon3eec59b2024-03-11 22:17:13 +0000776 if args.param_config is not None:
777 args.param_config = args.param_config.absolute()
778
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000779 if args.unit_tests in ["framework", "both"]:
780 logger.warning(
781 "DEPRECATION - Framework tests are not part of TOSA conformance testing"
782 )
783 if not args.framework_schema:
784 logger.error(
785 "Need to supply location of Framework flatbuffers schema via --framework-schema"
786 )
787 return None
788 if not args.framework_tests_dir.is_dir():
789 logger.error(
790 f"Missing or invalid framework tests directory: {args.framework_tests_dir}"
791 )
792 return None
793
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100794 return args
795
796
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +0100797def in_version(test_version, gen_dict):
798 """Check if the selected test_version is compatible with the tests."""
799
800 def version_string_to_numbers(verstr):
801 # Turn the "vM.mm.pp" string into Major, Minor, Patch versions
802 if verstr == TEST_VERSION_LATEST:
803 return (TOSA_VERSION[0], TOSA_VERSION[1], TOSA_VERSION[2])
804 else:
805 match = re.match(REGEX_VERSION, verstr)
806 if match is None:
807 raise KeyError(f"Invalid version string {verstr}")
808 return (int(v) for v in match.groups())
809
810 if "from_version" in gen_dict:
811 selected_version = version_string_to_numbers(test_version)
812 from_version = version_string_to_numbers(gen_dict["from_version"])
813
814 # Check the Major version is compatible, then Minor, and lastly Patch
815 # Unless the versions match, we can exit early due to obvious precedence
816 for sel, fro in zip(selected_version, from_version):
817 if sel < fro:
818 # From version is later than selected version
819 return False
820 elif sel > fro:
821 # From version is earlier than selected version
822 return True
823 # If we get here, the version numbers match exactly
824 return True
825 else:
826 # No specific version info
827 return True
828
829
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000830def _get_log_level(verbosity):
831 loglevels = (logging.WARNING, logging.INFO, logging.DEBUG)
832 verbosity = max(verbosity, 0)
833 return loglevels[min(verbosity, len(loglevels) - 1)]
834
835
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100836def main():
837 args = parse_args()
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000838 if args is None:
839 # Argument processing error
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100840 return 2
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100841
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000842 loglevel = _get_log_level(args.verbosity)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100843 logger.setLevel(loglevel)
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000844 # Set other loggers to a quieter level
845 loglevel = _get_log_level(args.verbosity - 1)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100846 logging.getLogger("test_select").setLevel(loglevel)
847 logging.getLogger("convert2conformance").setLevel(loglevel)
848
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100849 print(f"Output directory: {args.output_dir}")
850
Jeremy Johnson93d43902022-09-27 12:26:14 +0100851 if args.random_seed != DEFAULT_SEED:
852 logger.warning(
853 "Random test seed changed from default, tests will not match official conformance"
854 )
855
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100856 args.build_dir = args.build_dir.resolve()
857 logger.debug(f"Creating build directory: {args.build_dir}")
858 args.build_dir.mkdir(parents=True, exist_ok=True)
859
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000860 if args.tests_list_file is not None:
861 # Try creating tests list file
862 with args.tests_list_file.open("w") as fd:
863 fd.write("")
864
Won Jeon3eec59b2024-03-11 22:17:13 +0000865 if PROFILES_EXTENSIONS_ALL in args.profile:
866 profiles = TosaProfiles.profiles()
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100867 else:
Won Jeon3eec59b2024-03-11 22:17:13 +0000868 profiles = args.profile
869
870 if PROFILES_EXTENSIONS_ALL in args.extension:
871 extensions = TosaProfiles.extensions()
872 else:
873 extensions = args.extension
Jeremy Johnsonbf9ee052024-05-01 17:26:24 +0100874
Won Jeon3eec59b2024-03-11 22:17:13 +0000875 profileExtList = profiles + extensions
876 profileExtDone = []
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100877
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100878 try:
Won Jeon3eec59b2024-03-11 22:17:13 +0000879 for profile_ext in profileExtList:
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100880 # Framework unit tests
881 if args.unit_tests in ["framework", "both"]:
Won Jeon3eec59b2024-03-11 22:17:13 +0000882 logger.error("Framework test support has been removed")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100883
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100884 # Operator unit tests
885 if args.unit_tests in ["operator", "both"]:
886 logger.debug("Creating OPERATOR unit tests")
Won Jeon3eec59b2024-03-11 22:17:13 +0000887 if args.param_config is None:
Jeremy Johnsonbf9ee052024-05-01 17:26:24 +0100888 # Use default config
889 config = PROFILE_OPS_INFO["operator_test_params"]
890 test_params_file = args.param_json_dir / config
Won Jeon3eec59b2024-03-11 22:17:13 +0000891 else:
892 test_params_file = args.param_config
893
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100894 try:
895 with open(test_params_file, "r") as fd:
896 test_params = json.load(fd)
897 except Exception as e:
898 logger.error(
899 f"Couldn't load operator test params - {test_params_file}: {e}"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100900 )
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100901 return 1
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000902 logger.debug(f"Using config file: {str(test_params_file)}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100903
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100904 operators = args.operators
905 if not operators:
906 # Create tests for all the operators
907 operators = list(test_params.keys())
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100908
Won Jeon3eec59b2024-03-11 22:17:13 +0000909 print(
910 f"Creating conformance tests for TOSA {profile_ext} profile/extension"
911 )
912
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100913 for op in operators:
914 logger.info(f"OPERATOR: {op}")
915 if op not in test_params:
916 logger.warning(
917 f"{op} operator parameters not found in {test_params_file} - skipping"
918 )
919 continue
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100920
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100921 operator_group = test_params[op]["group"]
922 root_output_dir = args.output_dir / "operators"
Won Jeon3eec59b2024-03-11 22:17:13 +0000923 supports = test_params[op].get("support_for", [])
924 gen_filter = test_params[op].get("gen_filter", None)
925 old_profile_info = test_params[op].get("profile", [])
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000926
927 # Iterate through the generation groups selecting tests from each
928 for gen_name, gen_dict in test_params[op]["generation"].items():
Won Jeon3eec59b2024-03-11 22:17:13 +0000929 supports_any = gen_dict.get("supports_any", [])
930 supports_all = gen_dict.get("supports_all", [])
931
932 # Fall back for old configs
933 if not supports_all and not supports_any:
934 if not old_profile_info:
935 logger.error(
936 f"generator {gen_name} for {op} is missing supports_all/supports_any"
937 )
938 raise (GenConformanceError())
939 else:
940 supports_any = old_profile_info
941
942 supported = supports_any + supports_all
943
944 if profile_ext not in supported:
945 logger.info(
946 f"No match for profile/extension {profile_ext} for generation group {gen_name} - skipping"
947 )
948 continue
949
950 if any(p in supported for p in profileExtDone):
951 logger.info(
952 f"Already used this generator {gen_name} before - skipping"
953 )
954 continue
955
956 if profile_ext not in supports_any and not (
957 len(supports_all) > 0
958 and all(p in profileExtList for p in supports_all)
959 ):
960 logger.info(
961 f"Profile/extension {profile_ext} is not in {supports_any} or the profiles/extensions chosen do not meet all the requirements of {supports_all} - skipping"
962 )
963 continue
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +0100964
965 if not in_version(args.test_version, gen_dict):
966 logger.warning(
967 f"{op} [{gen_name}] is not in {args.test_version} - skipping"
968 )
969 continue
970
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000971 no_neg_tests = (
972 "no_negative_tests" in gen_dict
973 and gen_dict["no_negative_tests"] == "true"
974 )
975
976 if no_neg_tests:
977 if args.test_type == "negative":
978 logger.info(
979 f"No negative tests for {op} / generation group {gen_name}"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100980 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000981 continue
982 # Only produce positive tests
983 test_type = "positive"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100984 else:
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000985 test_type = args.test_type
986
987 gen_neg_dim_range = (
988 gen_dict["negative_dim_range"]
989 if "negative_dim_range" in gen_dict
990 else None
991 )
992
Jeremy Johnson0c716862023-04-13 17:18:19 +0100993 # Work out which selection criteria we are using
994 if "selector" in gen_dict:
995 selector_name = gen_dict["selector"]
996 if selector_name not in test_params[op]["selection"]:
997 logger.warn(
998 f"Could not find {selector_name} in selection dict for {op} - using default"
999 )
1000 selector_name = "default"
1001 else:
1002 selector_name = "default"
Won Jeon3eec59b2024-03-11 22:17:13 +00001003
Jeremy Johnson0c716862023-04-13 17:18:19 +01001004 if selector_name not in test_params[op]["selection"]:
1005 logger.error(
1006 f"Could not find {selector_name} in selection dict for {op}"
1007 )
1008 raise (GenConformanceError())
1009
Won Jeon3eec59b2024-03-11 22:17:13 +00001010 if test_params[op]["selection"][selector_name].get(
1011 "generator_select", False
1012 ):
1013 # Extend the support to include the new test selection in the generator
1014 supports = supports + ["generator_select"]
1015
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001016 op_build_dir = build_op_tests(
1017 args,
1018 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +00001019 profile_ext,
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001020 op,
1021 gen_name,
1022 gen_dict["generator_args"],
1023 gen_neg_dim_range,
1024 supports=supports,
1025 gen_filter=gen_filter,
1026 selector_info=(test_params_file, selector_name),
1027 )
Jeremy Johnson0c716862023-04-13 17:18:19 +01001028
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001029 if args.tests_list_file is not None:
1030 logger.info("Tests list file extended")
1031 continue
1032
1033 if args.convert_all_tests or "generator_select" in supports:
1034 if test_type in ["positive", "both"]:
1035 logger.info(f"Running and converting all {op} tests")
1036 generate_results(
Won Jeon3eec59b2024-03-11 22:17:13 +00001037 args,
1038 profile_ext,
1039 op,
1040 op_build_dir,
1041 supports=supports,
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001042 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001043 operator_test_list = None
1044 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001045 logger.info(
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001046 f"Running and converting selection of {op} tests"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +01001047 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001048 # Selection criteria
1049 selection_config = test_params[op]["selection"][
1050 selector_name
1051 ]
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001052 if test_type in ["positive", "both"]:
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001053 if (
1054 "all" in selection_config
1055 and selection_config["all"] == "true"
1056 ):
1057 # Just get all the positive tests
1058 tests_gen, tests_gen2 = tee(
1059 _get_all_tests_list(
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001060 "positive",
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001061 op_build_dir,
1062 op,
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001063 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001064 )
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001065 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001066 ignore_missing = (
1067 gen_name != STANDARD_GENERATOR_GROUP
1068 )
1069
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001070 # Get a selection of positive tests
1071 tests_gen, tests_gen2 = tee(
1072 get_op_tests_selection(
1073 args,
Won Jeon3eec59b2024-03-11 22:17:13 +00001074 profile_ext,
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001075 op,
1076 op_build_dir,
1077 selection_config,
1078 ignore_missing=ignore_missing,
1079 )
1080 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001081 generate_results(
Jeremy Johnson1271c442023-09-05 11:39:26 +01001082 args,
Won Jeon3eec59b2024-03-11 22:17:13 +00001083 profile_ext,
Jeremy Johnson1271c442023-09-05 11:39:26 +01001084 op,
1085 op_build_dir,
1086 supports=supports,
1087 tests=tests_gen,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001088 )
1089 operator_test_list = list(tests_gen2)
1090 else:
1091 operator_test_list = []
1092 if test_type in ["negative", "both"]:
1093 operator_test_list.extend(
1094 get_op_tests_selection(
1095 args,
Won Jeon3eec59b2024-03-11 22:17:13 +00001096 profile_ext,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001097 op,
1098 op_build_dir,
1099 selection_config,
1100 negative=True,
1101 )
1102 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001103
1104 tags = (
1105 [gen_name] if gen_name != STANDARD_GENERATOR_GROUP else None
1106 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001107 output_dir = convert_tests(
1108 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001109 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +00001110 profile_ext,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001111 op,
1112 op_build_dir,
1113 root_output_dir,
Won Jeon3eec59b2024-03-11 22:17:13 +00001114 supported,
Jeremy Johnson1271c442023-09-05 11:39:26 +01001115 supports=supports,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001116 tests=operator_test_list,
1117 group=operator_group,
1118 tags=tags,
1119 )
1120 if not args.keep_large_files:
Won Jeon3eec59b2024-03-11 22:17:13 +00001121 check_op_tests(args, profile_ext, op, output_dir)
1122
1123 profileExtDone.append(profile_ext)
1124
Jeremy Johnson0ecfa372022-06-30 14:27:56 +01001125 except GenConformanceError:
1126 return 1
1127
1128 return 0
1129
1130
1131if __name__ == "__main__":
1132 exit(main())