blob: 59e88bbae2d2275f6552d54b1d7851ca532cb2d3 [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
39# Configuration for each TOSA profile
40PROFILE_OPS_INFO = {
Jeremy Johnson88588622022-07-12 16:42:29 +010041 "tosa-bi": {
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010042 "operator_test_params": "tosa_base_profile_ops_info.json",
43 "framework_tests": "tosa_base_profile_framework_ops_info.json",
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010044 },
45 "tosa-mi": {
46 # Note: This is just the extra tests not in the base profile!
47 "operator_test_params": "tosa_main_profile_ops_info.json",
48 "framework_tests": "tosa_main_profile_framework_ops_info.json",
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010049 },
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010050}
Won Jeon3eec59b2024-03-11 22:17:13 +000051PROFILES_EXTENSIONS_ALL = "all"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010052
Jeremy Johnson93d43902022-09-27 12:26:14 +010053DEFAULT_SEED = 42
54
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +000055# When there is a dictionary of generator argument lists (groups) only the
56# standard group will have negative tests generated for it
57STANDARD_GENERATOR_GROUP = "standard"
58
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010059TEST_VERSION_LATEST = "latest"
60TEST_VERSION_V0_60_0 = "v0.60.0"
61TEST_VERSIONS = (TEST_VERSION_LATEST, TEST_VERSION_V0_60_0)
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +010062REGEX_VERSION = re.compile(r"v([0-9]+)\.([0-9]+)\.([0-9]+)")
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010063
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010064
65class GenConformanceError(Exception):
66 """Generation error reporting exception."""
67
68 pass
69
70
71def _run_sh_command(args, cwd, full_cmd):
72 """Run an external command and capture stdout/stderr."""
73 # Quote the command line for printing
Jeremy Johnsonaf090182024-02-13 18:25:39 +000074 try:
75 full_cmd_esc = [shlex.quote(x) for x in full_cmd]
76 except Exception as e:
77 raise Exception(f"Error quoting command: {e}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010078 if args.capture_output:
Jeremy Johnsonaf090182024-02-13 18:25:39 +000079 logger.info(f"Command: {full_cmd_esc}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010080
81 rc = subprocess.run(
82 full_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
83 )
84
85 if args.capture_output:
Jeremy Johnsondd975b82024-02-28 17:29:13 +000086 stderr = rc.stderr.decode("utf-8")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010087 stdout = rc.stdout.decode("utf-8")
Jeremy Johnsondd975b82024-02-28 17:29:13 +000088 logger.info(f"stderr: \n{stderr}")
Jeremy Johnsonaf090182024-02-13 18:25:39 +000089 logger.info(f"stdout: \n{stdout}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010090 if rc.returncode != 0:
91
92 raise Exception(
93 "Error running command: {}.\n{}".format(
94 " ".join(full_cmd_esc), rc.stderr.decode("utf-8")
95 )
96 )
97 return (rc.stdout, rc.stderr)
98
99
Won Jeon3eec59b2024-03-11 22:17:13 +0000100def _supports_for_enabled(profile_ext):
101 # The "supports_for" part of the config only works for MI and related extensions
102 # TODO - Update with TosaBI etc in future
103 return profile_ext in (
104 TosaProfiles.TosaMI,
105 TosaProfiles.TosaExtFP8E4M3,
106 TosaProfiles.TosaExtFP8E5M2,
107 TosaProfiles.TosaExtBF16,
108 TosaProfiles.TosaExtFFT,
109 )
110
111
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000112def build_op_tests(
Jeremy Johnson1271c442023-09-05 11:39:26 +0100113 args,
114 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +0000115 profile_ext,
Jeremy Johnson1271c442023-09-05 11:39:26 +0100116 operator,
117 group,
118 gen_args_list,
119 gen_neg_dim_range,
120 supports=[],
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000121 gen_filter=None,
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000122 selector_info=None,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000123):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100124 """Build tests for a given operator.
125
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000126 Builds a set of tests based on the given generator arguments list
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100127
128 Returns operator output directory
129 """
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100130 build_tests_cmd = "tosa_verif_build_tests"
Won Jeon3eec59b2024-03-11 22:17:13 +0000131 op_build_dir = args.build_dir / profile_ext / group
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100132
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000133 if gen_filter is None:
134 gen_filter = f"^{operator}$"
135
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000136 build_cmd_base = [
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100137 build_tests_cmd,
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100138 "--generate-lib-path",
139 str(args.generate_lib_path),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100140 "--filter",
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000141 gen_filter,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100142 "-o",
143 str(op_build_dir),
144 "--seed",
Jeremy Johnson93d43902022-09-27 12:26:14 +0100145 str(args.random_seed),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100146 ]
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000147 if args.verbosity:
148 build_cmd_base.append("-" + ("v" * args.verbosity))
149
150 if args.tests_list_file is not None:
151 build_cmd_base.append("--list-tests")
152
Won Jeon3eec59b2024-03-11 22:17:13 +0000153 if _supports_for_enabled(profile_ext):
154 if "lazy_data_gen" in supports and args.lazy_data_generation:
155 build_cmd_base.append("--lazy-data-generation")
156 if "stable_random_gen" in supports and not args.global_random_generation:
157 build_cmd_base.append("--stable-random-generation")
158 if "random_const_inputs" in supports:
159 build_cmd_base.append("--random-const-inputs")
Jeremy Johnson1271c442023-09-05 11:39:26 +0100160
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000161 if "generator_select" in supports:
162 if selector_info is None:
163 logger.error(
164 "build_op_tests error: generator_select mode without selector information"
165 )
166 raise (GenConformanceError())
167 selector_config, selector_name = selector_info
168 build_cmd_base.extend(
169 [
170 "--test-selection-config",
171 str(selector_config),
172 "--test-selection-criteria",
173 selector_name,
174 ]
175 )
176
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000177 build_cmds_list = []
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100178
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000179 if test_type in ["positive", "both"]:
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100180 # Append extra parameters and run test generator for each set of parameters.
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000181 for arglist in gen_args_list:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000182 build_cmd_pos_test = build_cmd_base.copy()
183 build_cmd_pos_test.extend(["--test-type", "positive"])
184 build_cmd_pos_test.extend(arglist)
185 build_cmds_list.append(build_cmd_pos_test)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100186
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000187 if test_type in ["negative", "both"]:
Jeremy Johnson35396f22023-01-04 17:05:25 +0000188 # Get target-dtypes options and any filter string to limit tests
Jeremy Johnson93d43902022-09-27 12:26:14 +0100189 target_dtypes_args = []
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000190 for arglist in gen_args_list:
Jeremy Johnson93d43902022-09-27 12:26:14 +0100191 idx = 0
192 while idx < len(arglist):
193 if arglist[idx] == "--target-dtype":
194 if arglist[idx + 1] not in target_dtypes_args:
195 target_dtypes_args.extend(arglist[idx : idx + 2])
196 idx += 1 # skip over option (and then argument below)
197 idx += 1
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000198 build_cmd_neg_test = build_cmd_base.copy()
199 build_cmd_neg_test.extend(["--test-type", "negative"])
Jeremy Johnson93d43902022-09-27 12:26:14 +0100200 # Limit sizes of negative tests
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000201 dim_range = gen_neg_dim_range if gen_neg_dim_range is not None else "1,16"
202
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000203 build_cmd_neg_test.extend(["--tensor-dim-range", dim_range])
204 build_cmd_neg_test.extend(target_dtypes_args)
205 build_cmds_list.append(build_cmd_neg_test)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100206
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000207 logger.info(f"Creating {operator} tests in {len(build_cmds_list)} batch(es)")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100208 error = False
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000209 for i, cmd in enumerate(build_cmds_list):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100210 try:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000211 raw_stdout, _ = _run_sh_command(args, args.ref_model_path.parent, cmd)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100212 logger.info(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000213 f"{operator} test batch {(i+1)}/{len(build_cmds_list)} created successfully"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100214 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000215
216 if args.tests_list_file is not None:
217 with args.tests_list_file.open("a") as fd:
218 fd.write(raw_stdout.decode("utf-8"))
219
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100220 except Exception as e:
221 logger.error(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000222 f"{operator} test batch {(i+1)}/{len(build_cmds_list)} unsuccessful, skipping"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100223 )
224 logger.error(f" build_op_tests error: {e} ")
225 error = True
226 if error:
227 raise (GenConformanceError())
228
229 return op_build_dir
230
231
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000232def _check_to_include_test(test_type, test_name):
233 """Check test name for inclusion based on test_type, returns True to include."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100234
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000235 if test_type == "both":
236 return True
237 else:
238 error_test = "_ERRORIF_" in test_name
239 return (error_test and test_type == "negative") or (
240 not error_test and test_type == "positive"
241 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100242
243
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000244def _get_all_tests_list(test_type, test_root_dir, operator):
245 """Create test list from tests in the test_dir based on chosen type."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100246 test_dir = test_root_dir / operator
247 if not test_dir.is_dir():
248 # Tests are split into multiple dirs, for example: conv2d_1x1, conv2d_3x3
249 test_dir = test_root_dir
250 directories = [
251 tdir for tdir in test_dir.glob("*") if tdir.name.startswith(operator)
252 ]
253 else:
254 directories = [test_dir]
255
256 tests = []
257 for tdir in directories:
258 tests.extend(
259 [
260 test
261 for test in tdir.glob("*")
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000262 if _check_to_include_test(test_type, test.name)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100263 ]
264 )
265 return tests
266
267
Won Jeon3eec59b2024-03-11 22:17:13 +0000268def generate_results(
269 args, profile_ext, operator, op_build_dir, supports=[], tests=None
270):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100271 """Run tests on reference model and save result to the test directory."""
Won Jeon3eec59b2024-03-11 22:17:13 +0000272 if _supports_for_enabled(profile_ext):
273 if "lazy_data_gen" in supports and args.lazy_data_generation:
274 logger.info("Skipping running tests due to lazy data gen")
275 return
Jeremy Johnson1271c442023-09-05 11:39:26 +0100276
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100277 num_cores = args.num_cores
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100278
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100279 # Use the test runner
280 ref_cmd_base = [
281 "tosa_verif_run_tests",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100282 "--ref-model-path",
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100283 str(args.ref_model_path),
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100284 "--schema-path",
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100285 str(args.schema_path),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100286 "-j",
287 str(num_cores),
288 "-v",
289 "-t",
290 ]
291 ref_cmds = []
292
293 if not tests:
294 # Do not need to run ERRORIF tests as they don't have result files
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000295 tests = _get_all_tests_list("positive", op_build_dir, operator)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100296
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000297 skipped = 0
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100298 for test in tests:
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100299 desc = test / "desc.json"
300 with desc.open("r") as fd:
301 test_desc = json.load(fd)
302 if "meta" in test_desc and "compliance" in test_desc["meta"]:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000303 skipped += 1
304 logger.debug(
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100305 f"Skipping generating results for new compliance test - {str(test)}"
306 )
307 continue
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100308 ref_cmd = ref_cmd_base.copy()
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100309 ref_cmd.append(str(test.absolute()))
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100310 ref_cmds.append(ref_cmd)
311
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000312 if skipped:
313 logger.info(f"{skipped} new compliance tests skipped for results generation")
314
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100315 fail_string = "UNEXPECTED_FAILURE"
316 failed_counter = 0
317
318 job_pool = mp.Pool(args.num_cores)
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100319 sh_partial = partial(_run_sh_command, args, args.ref_model_path.parent)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100320 pool_results = job_pool.map(sh_partial, ref_cmds)
321 job_pool.close()
322 job_pool.join()
323
324 # Use captured output for run_sh_command to work out if test passed.
325 for i, rc in enumerate(pool_results):
326 if fail_string in str(rc[0]):
327 logger.error(f"Test {i+1}/{len(ref_cmds)}: {ref_cmds[i][-1]} failed.")
328 failed_counter += 1
329 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000330 logger.debug(f"Test {i+1}/{len(ref_cmds)}: {ref_cmds[i][-1]} passed.")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100331
332 logger.info(f"{len(ref_cmds)-failed_counter}/{len(ref_cmds)} tests passed")
333 logger.info("Ran tests on model and saved results of passing tests")
334
335
336def convert_tests(
337 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000338 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +0000339 profile_ext,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100340 operator,
341 op_build_dir,
342 output_dir,
Won Jeon3eec59b2024-03-11 22:17:13 +0000343 op_profiles_extensions_list,
Jeremy Johnson1271c442023-09-05 11:39:26 +0100344 supports=[],
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100345 tests=None,
346 group=None,
347 trim_op_subdir=False,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000348 tags=None,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100349):
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100350 """Convert/copy tests to output directory."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100351 if group:
352 output_dir = output_dir / group
353
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100354 c2c_args_base = ["--strict"]
355 c2c_args_base.extend(["--schema-path", str(args.schema_path)])
356 c2c_args_base.extend(["--flatc-path", str(args.flatc_path)])
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100357 c2c_args_base.extend(["--output-type", args.output_type])
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100358 # This op maybe in more than one profile - e.g. tosa_bi and tosa_mi
359 # even if we are only producing tests for tosa_mi
Won Jeon3eec59b2024-03-11 22:17:13 +0000360 for op_profile in op_profiles_extensions_list:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000361 c2c_args_base.extend(["--profile", op_profile])
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000362 if tags is not None:
363 for tag in tags:
364 c2c_args_base.extend(["--tag", tag])
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100365 if args.framework_schema:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000366 c2c_args_base.extend(["--framework-schema", str(args.framework_schema)])
Won Jeon3eec59b2024-03-11 22:17:13 +0000367 if _supports_for_enabled(profile_ext):
368 if "lazy_data_gen" in supports and args.lazy_data_generation:
369 c2c_args_base.append("--lazy-data-generation")
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000370 c2c_args_base.append("--output-directory")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100371
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000372 c2c_args_list = []
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100373
374 if not tests:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000375 tests = _get_all_tests_list(test_type, op_build_dir, operator)
Won Jeon3eec59b2024-03-11 22:17:13 +0000376 logger.info(f"Converting all {profile_ext} profile tests of type {test_type}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100377
378 # Controls if we copy the tests in their operator sub-directory or not
379 output_dir_relative_pos = -1 if trim_op_subdir else -2
380 for test in tests:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000381 logger.debug(f"Test chosen: {test}")
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000382 c2c_args = c2c_args_base.copy()
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100383 full_output_directory = output_dir / test.relative_to(
384 *test.parts[:output_dir_relative_pos]
385 )
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000386 c2c_args.append(str(full_output_directory))
387 c2c_args.append(str(test))
388 c2c_args_list.append(c2c_args)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100389
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000390 if len(c2c_args_list) == 0:
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000391 logger.error(
392 f"No tests found for {operator}. Nothing to convert in {op_build_dir}"
393 )
394 raise (GenConformanceError())
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100395
396 job_pool = mp.Pool(args.num_cores)
397
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000398 pool_results = job_pool.map(c2c_main, c2c_args_list)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100399 job_pool.close()
400 job_pool.join()
401
402 failed_counter = 0
403 for i, result in enumerate(pool_results):
404 if result != 0:
405 logger.error(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000406 f"test {i+1}/{len(c2c_args_list)}: {c2c_args_list[i][-1]} failed to convert."
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100407 )
408 failed_counter += 1
409 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000410 logger.debug(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000411 f"test {i+1}/{len(c2c_args_list)}: {c2c_args_list[i][-1]} converted"
412 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100413 logger.info(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000414 f"{len(c2c_args_list)-failed_counter}/{len(c2c_args_list)} tests successfully converted"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100415 )
416
417 if failed_counter > 0:
418 logger.error(f"Stopping due to {failed_counter} test conversion errors")
419 raise (GenConformanceError())
420
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100421 logger.info("Converted/copied tests and saved to output directory")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100422
423 return output_dir
424
425
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100426def get_op_tests_selection(
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000427 args,
Won Jeon3eec59b2024-03-11 22:17:13 +0000428 profile_ext,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000429 operator,
430 op_build_dir,
431 selection_config,
432 negative=False,
433 ignore_missing=False,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100434):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100435 """Use test picker to get subsection of tests generated."""
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000436 # Need a full copy of the config as the selector updates it
437 config = copy.deepcopy(selection_config)
Won Jeon3eec59b2024-03-11 22:17:13 +0000438 logger.info(
439 "Choosing {} tests for {}".format(
440 ("negative" if negative else "positive"), profile_ext
441 )
442 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100443 try:
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100444 op = Operator.registry[operator](
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000445 op_build_dir, config, negative=negative, ignore_missing=ignore_missing
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100446 )
447 except KeyError:
448 logger.error(f"{operator} operator is not supported by test_select")
449 raise (GenConformanceError())
450
451 return op.select_tests()
452
453
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100454def check_op_tests(args, profile, operator, output_dir):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100455 """Move test folders than contain files larger than 30MB to new directory."""
456 destination_dir = str(args.output_dir) + "_large_files"
457
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000458 # Include all tests - both positive and negative
459 tests = _get_all_tests_list("both", output_dir, operator)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100460 if not tests:
461 logger.error(
462 f"Couldn't find any tests to size check for {operator} in {output_dir}"
463 )
464 raise (GenConformanceError())
465
466 for tdir in tests:
467 move_dir = False
468 test_files = [file for file in tdir.glob("*")]
469 for file in test_files:
470 file_size = os.stat(file).st_size / 1024**2
471 if file_size > 30:
472 move_dir = True
473
474 if move_dir:
475 move_destination = destination_dir / tdir.relative_to(output_dir)
476 logger.warning(
477 f"{tdir.relative_to(output_dir)} contains files that are too large (>30MB), test moved to new folder: {destination_dir}"
478 )
479
480 if move_destination.is_dir():
481 logger.warning(
482 f"{move_destination} directory already exists, deleting existing."
483 )
484 shutil.rmtree(str(move_destination))
485 shutil.move(str(tdir), move_destination)
486
487
488def copy_rename_framework_tests(args, operator, test_picks):
489 """Copy framework tests into new folder and rename them if needed.
490
491 The tests are renamed to match the framework operator names if an
492 alternate name has been used instead.
493 """
494 framework_tests_dir = args.framework_tests_dir
495 new_tests_dir = args.build_dir / "frameworks" / operator
496 os.makedirs(new_tests_dir, exist_ok=True)
497
498 # Get the framework tests operator name
499 if "alternate_names" in test_picks[operator]:
500 alternate_names = test_picks[operator]["alternate_names"]
501 else:
502 alternate_names = [operator]
503
504 # Get the alternate named test directories for the operator
505 for alt_name in alternate_names:
506 test_prefix = f"test_{alt_name}"
507 test_dirs = list(framework_tests_dir.glob(f"{test_prefix}_*"))
508
509 # Copy tests to new directory and rename to match framework operator names
510 # - if there is just 1 alternate name, replace the full test prefix
511 # test_add_... -> add_...
512 # - if there are multiple alternate names, just replace the "test"
513 # test_concatv2_... -> concatenation_concatv2_...
514 old_prefix = test_prefix if len(alternate_names) == 1 else "test"
515
516 for tdir in test_dirs:
517 new_test_name = tdir.name.replace(old_prefix, operator)
518 copy_destination = new_tests_dir / new_test_name
519 logger.debug(f"copying test folder {tdir} to {copy_destination}")
520 copy_tree(str(tdir), str(copy_destination))
521
522 logger.info(f"Copied and renamed {len(test_dirs)} framework test folders")
523 return new_tests_dir.parent
524
525
526def get_framework_tests_selection(args, operator, test_picks, op_build_dir):
527 """Get the list of pre-chosen tests with relative paths."""
528 try:
529 tests = test_picks[operator]["tests"]
530 except KeyError:
531 logger.error(f"Framework test selection not defined for {operator} operator")
532 raise (GenConformanceError())
533
534 test_paths = [op_build_dir / operator / test for test in tests]
535 return test_paths
536
537
538def parse_args(argv=None):
539 """Parse the arguments."""
540 parser = argparse.ArgumentParser()
Won Jeon3eec59b2024-03-11 22:17:13 +0000541 profiles = TosaProfiles.profiles()
542 profiles.append(PROFILES_EXTENSIONS_ALL)
Jeremy Johnson88588622022-07-12 16:42:29 +0100543 parser.add_argument(
544 "--profile",
545 dest="profile",
546 choices=profiles,
Won Jeon3eec59b2024-03-11 22:17:13 +0000547 default=[TosaProfiles.TosaBI],
Jeremy Johnson88588622022-07-12 16:42:29 +0100548 type=str,
Won Jeon3eec59b2024-03-11 22:17:13 +0000549 nargs="*",
550 help=f"TOSA profile (default is {TosaProfiles.TosaBI})",
Jeremy Johnson88588622022-07-12 16:42:29 +0100551 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100552 parser.add_argument(
553 "--operators",
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100554 "--op",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100555 type=str,
556 nargs="*",
557 help="The operator(s) to create tests for, if not supplied all tests will be created",
558 )
559 parser.add_argument(
Won Jeon3eec59b2024-03-11 22:17:13 +0000560 "--extension",
561 dest="extension",
562 choices=TosaProfiles.extensions() + [PROFILES_EXTENSIONS_ALL],
563 default=[],
564 type=str,
565 nargs="*",
566 help="TOSA extension(s) to create tests for, if not supplied all tests will be created",
567 )
568 parser.add_argument(
Jeremy Johnson88588622022-07-12 16:42:29 +0100569 "--unit-tests",
570 dest="unit_tests",
571 choices=["operator", "framework", "both"],
572 default="operator",
573 type=str,
574 help="Which unit tests are produced (default is operator)",
575 )
576 parser.add_argument(
577 "--test-type",
578 dest="test_type",
579 choices=["positive", "negative", "both"],
580 default="both",
581 type=str,
582 help="Type of tests produced (default is both)",
583 )
584 parser.add_argument(
Jeremy Johnson0a6d1de2023-09-27 14:59:43 +0100585 "--global-random-generation",
586 action="store_true",
587 help="Disable stable random generation of tests that support this mode",
588 )
589 parser.add_argument(
Jeremy Johnson1271c442023-09-05 11:39:26 +0100590 "--lazy-data-generation",
591 action="store_true",
592 help="Enable lazy data generation (only for tosa-mi)",
593 )
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100594 rm_group = parser.add_mutually_exclusive_group(required=True)
595 rm_group.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100596 "--ref-model-directory",
597 dest="ref_model_dir",
598 type=Path,
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100599 help="(DEPRECATED - use ref-model-path) Reference Model directory - with build directory",
600 )
601 rm_group.add_argument(
602 "--ref-model-path",
603 dest="ref_model_path",
604 type=Path,
605 help="Path to TOSA reference model executable",
606 )
607 parser.add_argument(
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100608 "--generate-lib-path",
609 dest="generate_lib_path",
610 type=Path,
611 help=(
612 "Path to TOSA generate library. Defaults to "
613 "the library in the directory of `ref-model-path`"
614 ),
615 )
616 parser.add_argument(
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100617 "--schema-path",
618 "--operator-fbs",
619 dest="schema_path",
620 type=Path,
621 help=(
622 "Path to TOSA reference model flat buffer schema. Defaults to "
623 f"`{cmf.DEFAULT_REF_MODEL_SCHEMA_PATH}` in parents parent directory of `ref-model-path`"
624 ),
625 )
626 parser.add_argument(
627 "--flatc-path",
628 dest="flatc_path",
629 type=Path,
630 help=(
631 "Path to flatc executable. Defaults to "
632 f"`{cmf.DEFAULT_REF_MODEL_BUILD_FLATC_PATH}` in parent directory of `ref-model-path`"
633 ),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100634 )
Jeremy Johnson88588622022-07-12 16:42:29 +0100635 parser.add_argument(
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100636 "--test-version",
637 dest="test_version",
638 choices=TEST_VERSIONS,
639 default=TEST_VERSION_LATEST,
640 help=f"Version of the tests to produce (default is {TEST_VERSION_LATEST})",
641 )
642 parser.add_argument(
643 "--output-type",
644 dest="output_type",
645 choices=OUTPUT_TYPES,
646 default=OUTPUT_TYPE_DEFAULT,
647 help=f"Output file type produced (default is {OUTPUT_TYPE_DEFAULT})",
648 )
649 parser.add_argument(
Jeremy Johnson93d43902022-09-27 12:26:14 +0100650 "--seed",
651 dest="random_seed",
652 default=DEFAULT_SEED,
653 type=int,
654 help="Random test seed",
655 )
656 parser.add_argument(
Jeremy Johnson88588622022-07-12 16:42:29 +0100657 "--framework-tests-directory",
658 dest="framework_tests_dir",
659 type=Path,
660 default=Path.cwd() / "tests",
661 help="The pre-built framework tests directory (default is tests)",
662 )
663 parser.add_argument(
664 "--framework-schema",
665 dest="framework_schema",
666 type=Path,
667 help="Framework flatbuffers schema needed to convert framework models",
668 )
669 parser.add_argument(
670 "--build-directory",
671 dest="build_dir",
672 type=Path,
673 default=Path.cwd() / "conformance_build",
674 help="Temporary build directory for files created during this process (default is conformance_build)",
675 )
676 parser.add_argument(
677 "--output-directory",
678 dest="output_dir",
679 type=Path,
680 default=Path.cwd() / "conformance",
681 help="Output directory (default is conformance)",
682 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100683 script_dir = Path(__file__).parent.absolute()
684 parser.add_argument(
685 "--test-param-json-directory",
686 dest="param_json_dir",
687 type=Path,
688 default=script_dir,
Jeremy Johnson88588622022-07-12 16:42:29 +0100689 help=f"Test parameters (ops info) JSON file directory (default is {script_dir})",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100690 )
691 parser.add_argument(
Won Jeon3eec59b2024-03-11 22:17:13 +0000692 "--test-params-json-config",
693 "--config",
694 dest="param_config",
695 type=Path,
696 help="Test parameters (ops info) JSON file (overrides --test-param-json-directory)",
697 )
698 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100699 "--convert-all-tests",
700 action="store_true",
701 help="Converts all tests instead of those picked by test_select",
702 )
703 parser.add_argument(
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000704 "--list-tests-to-file",
705 dest="tests_list_file",
706 type=Path,
707 help="Lists out the tests to be generated to a file instead of generating them",
708 )
709 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100710 "--keep-large-files",
711 action="store_true",
712 help="Keeps tests that contain files larger than 30MB in output directory",
713 )
714 parser.add_argument(
715 "--capture-output",
716 action="store_true",
717 help="Prints output of running sh commands",
718 )
719 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100720 "-j",
721 dest="num_cores",
722 type=int,
723 default=6,
724 help="Number of simultaneous jobs to split the tasks into for multiprocessing",
725 )
726 parser.add_argument(
727 "-v",
728 dest="verbosity",
729 action="count",
730 default=0,
731 help="Verbosity (can be used multiple times for more details)",
732 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100733 args = parser.parse_args(argv)
734
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000735 if args.ref_model_dir is not None:
736 # Assume the ref model exe path based on the ref model directory
737 args.ref_model_path = cmf.find_tosa_file(
738 cmf.TosaFileType.REF_MODEL, args.ref_model_dir, False
739 )
740 if not args.ref_model_path.is_file():
741 logger.error(
742 f"Missing reference model binary (--ref-model-path): {args.ref_model_path}"
743 )
744 return None
745 args.ref_model_path = args.ref_model_path.absolute()
746
747 if args.generate_lib_path is None:
748 args.generate_lib_path = cmf.find_tosa_file(
749 cmf.TosaFileType.GENERATE_LIBRARY, args.ref_model_path
750 )
751 if not args.generate_lib_path.is_file():
752 logger.error(
753 f"Missing TOSA generate data library (--generate-lib-path): {args.generate_lib_path}"
754 )
755 return None
756 args.generate_lib_path = args.generate_lib_path.absolute()
757
758 if args.schema_path is None:
759 args.schema_path = cmf.find_tosa_file(
760 cmf.TosaFileType.SCHEMA, args.ref_model_path
761 )
762 if not args.schema_path.is_file():
763 logger.error(
764 f"Missing reference model schema (--schema-path): {args.schema_path}"
765 )
766 return None
767 args.schema_path = args.schema_path.absolute()
768
769 if args.flatc_path is None:
770 args.flatc_path = cmf.find_tosa_file(
771 cmf.TosaFileType.FLATC, args.ref_model_path
772 )
773 if not args.flatc_path.is_file():
774 logger.error(f"Missing flatc binary (--flatc-path): {args.flatc_path}")
775 return None
776 args.flatc_path = args.flatc_path.absolute()
777
778 args.param_json_dir = args.param_json_dir.absolute()
779
Won Jeon3eec59b2024-03-11 22:17:13 +0000780 if args.param_config is not None:
781 args.param_config = args.param_config.absolute()
782
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000783 if args.unit_tests in ["framework", "both"]:
784 logger.warning(
785 "DEPRECATION - Framework tests are not part of TOSA conformance testing"
786 )
787 if not args.framework_schema:
788 logger.error(
789 "Need to supply location of Framework flatbuffers schema via --framework-schema"
790 )
791 return None
792 if not args.framework_tests_dir.is_dir():
793 logger.error(
794 f"Missing or invalid framework tests directory: {args.framework_tests_dir}"
795 )
796 return None
797
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100798 return args
799
800
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +0100801def in_version(test_version, gen_dict):
802 """Check if the selected test_version is compatible with the tests."""
803
804 def version_string_to_numbers(verstr):
805 # Turn the "vM.mm.pp" string into Major, Minor, Patch versions
806 if verstr == TEST_VERSION_LATEST:
807 return (TOSA_VERSION[0], TOSA_VERSION[1], TOSA_VERSION[2])
808 else:
809 match = re.match(REGEX_VERSION, verstr)
810 if match is None:
811 raise KeyError(f"Invalid version string {verstr}")
812 return (int(v) for v in match.groups())
813
814 if "from_version" in gen_dict:
815 selected_version = version_string_to_numbers(test_version)
816 from_version = version_string_to_numbers(gen_dict["from_version"])
817
818 # Check the Major version is compatible, then Minor, and lastly Patch
819 # Unless the versions match, we can exit early due to obvious precedence
820 for sel, fro in zip(selected_version, from_version):
821 if sel < fro:
822 # From version is later than selected version
823 return False
824 elif sel > fro:
825 # From version is earlier than selected version
826 return True
827 # If we get here, the version numbers match exactly
828 return True
829 else:
830 # No specific version info
831 return True
832
833
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000834def _get_log_level(verbosity):
835 loglevels = (logging.WARNING, logging.INFO, logging.DEBUG)
836 verbosity = max(verbosity, 0)
837 return loglevels[min(verbosity, len(loglevels) - 1)]
838
839
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100840def main():
841 args = parse_args()
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000842 if args is None:
843 # Argument processing error
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100844 return 2
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100845
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000846 loglevel = _get_log_level(args.verbosity)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100847 logger.setLevel(loglevel)
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000848 # Set other loggers to a quieter level
849 loglevel = _get_log_level(args.verbosity - 1)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100850 logging.getLogger("test_select").setLevel(loglevel)
851 logging.getLogger("convert2conformance").setLevel(loglevel)
852
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100853 print(f"Output directory: {args.output_dir}")
854
Jeremy Johnson93d43902022-09-27 12:26:14 +0100855 if args.random_seed != DEFAULT_SEED:
856 logger.warning(
857 "Random test seed changed from default, tests will not match official conformance"
858 )
859
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100860 args.build_dir = args.build_dir.resolve()
861 logger.debug(f"Creating build directory: {args.build_dir}")
862 args.build_dir.mkdir(parents=True, exist_ok=True)
863
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000864 if args.tests_list_file is not None:
865 # Try creating tests list file
866 with args.tests_list_file.open("w") as fd:
867 fd.write("")
868
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100869 # TODO: For tosa-mi should really generate tosa-bi profile as well
870 # - for now leave it as subset instead of as superset (for testing)
Won Jeon3eec59b2024-03-11 22:17:13 +0000871 if PROFILES_EXTENSIONS_ALL in args.profile:
872 profiles = TosaProfiles.profiles()
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100873 else:
Won Jeon3eec59b2024-03-11 22:17:13 +0000874 profiles = args.profile
875
876 if PROFILES_EXTENSIONS_ALL in args.extension:
877 extensions = TosaProfiles.extensions()
878 else:
879 extensions = args.extension
880 profileExtList = profiles + extensions
881 profileExtDone = []
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100882
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100883 try:
Won Jeon3eec59b2024-03-11 22:17:13 +0000884 for profile_ext in profileExtList:
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100885 # Framework unit tests
886 if args.unit_tests in ["framework", "both"]:
Won Jeon3eec59b2024-03-11 22:17:13 +0000887 logger.error("Framework test support has been removed")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100888
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100889 # Operator unit tests
890 if args.unit_tests in ["operator", "both"]:
891 logger.debug("Creating OPERATOR unit tests")
Won Jeon3eec59b2024-03-11 22:17:13 +0000892 if args.param_config is None:
893 # Fall back to old method
894 if profile_ext in PROFILE_OPS_INFO:
895 config = PROFILE_OPS_INFO[profile_ext]["operator_test_params"]
896 test_params_file = args.param_json_dir / config
897 else:
898 logger.error(
899 "Extensions not supported in old conformance configs - skipping"
900 )
901 continue
902 else:
903 test_params_file = args.param_config
904
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100905 try:
906 with open(test_params_file, "r") as fd:
907 test_params = json.load(fd)
908 except Exception as e:
909 logger.error(
910 f"Couldn't load operator test params - {test_params_file}: {e}"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100911 )
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100912 return 1
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000913 logger.debug(f"Using config file: {str(test_params_file)}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100914
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100915 operators = args.operators
916 if not operators:
917 # Create tests for all the operators
918 operators = list(test_params.keys())
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100919
Won Jeon3eec59b2024-03-11 22:17:13 +0000920 print(
921 f"Creating conformance tests for TOSA {profile_ext} profile/extension"
922 )
923
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100924 for op in operators:
925 logger.info(f"OPERATOR: {op}")
926 if op not in test_params:
927 logger.warning(
928 f"{op} operator parameters not found in {test_params_file} - skipping"
929 )
930 continue
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100931
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100932 operator_group = test_params[op]["group"]
933 root_output_dir = args.output_dir / "operators"
Won Jeon3eec59b2024-03-11 22:17:13 +0000934 supports = test_params[op].get("support_for", [])
935 gen_filter = test_params[op].get("gen_filter", None)
936 old_profile_info = test_params[op].get("profile", [])
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000937
938 # Iterate through the generation groups selecting tests from each
939 for gen_name, gen_dict in test_params[op]["generation"].items():
Won Jeon3eec59b2024-03-11 22:17:13 +0000940 supports_any = gen_dict.get("supports_any", [])
941 supports_all = gen_dict.get("supports_all", [])
942
943 # Fall back for old configs
944 if not supports_all and not supports_any:
945 if not old_profile_info:
946 logger.error(
947 f"generator {gen_name} for {op} is missing supports_all/supports_any"
948 )
949 raise (GenConformanceError())
950 else:
951 supports_any = old_profile_info
952
953 supported = supports_any + supports_all
954
955 if profile_ext not in supported:
956 logger.info(
957 f"No match for profile/extension {profile_ext} for generation group {gen_name} - skipping"
958 )
959 continue
960
961 if any(p in supported for p in profileExtDone):
962 logger.info(
963 f"Already used this generator {gen_name} before - skipping"
964 )
965 continue
966
967 if profile_ext not in supports_any and not (
968 len(supports_all) > 0
969 and all(p in profileExtList for p in supports_all)
970 ):
971 logger.info(
972 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"
973 )
974 continue
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +0100975
976 if not in_version(args.test_version, gen_dict):
977 logger.warning(
978 f"{op} [{gen_name}] is not in {args.test_version} - skipping"
979 )
980 continue
981
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000982 no_neg_tests = (
983 "no_negative_tests" in gen_dict
984 and gen_dict["no_negative_tests"] == "true"
985 )
986
987 if no_neg_tests:
988 if args.test_type == "negative":
989 logger.info(
990 f"No negative tests for {op} / generation group {gen_name}"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100991 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000992 continue
993 # Only produce positive tests
994 test_type = "positive"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100995 else:
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000996 test_type = args.test_type
997
998 gen_neg_dim_range = (
999 gen_dict["negative_dim_range"]
1000 if "negative_dim_range" in gen_dict
1001 else None
1002 )
1003
Jeremy Johnson0c716862023-04-13 17:18:19 +01001004 # Work out which selection criteria we are using
1005 if "selector" in gen_dict:
1006 selector_name = gen_dict["selector"]
1007 if selector_name not in test_params[op]["selection"]:
1008 logger.warn(
1009 f"Could not find {selector_name} in selection dict for {op} - using default"
1010 )
1011 selector_name = "default"
1012 else:
1013 selector_name = "default"
Won Jeon3eec59b2024-03-11 22:17:13 +00001014
Jeremy Johnson0c716862023-04-13 17:18:19 +01001015 if selector_name not in test_params[op]["selection"]:
1016 logger.error(
1017 f"Could not find {selector_name} in selection dict for {op}"
1018 )
1019 raise (GenConformanceError())
1020
Won Jeon3eec59b2024-03-11 22:17:13 +00001021 if test_params[op]["selection"][selector_name].get(
1022 "generator_select", False
1023 ):
1024 # Extend the support to include the new test selection in the generator
1025 supports = supports + ["generator_select"]
1026
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001027 op_build_dir = build_op_tests(
1028 args,
1029 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +00001030 profile_ext,
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001031 op,
1032 gen_name,
1033 gen_dict["generator_args"],
1034 gen_neg_dim_range,
1035 supports=supports,
1036 gen_filter=gen_filter,
1037 selector_info=(test_params_file, selector_name),
1038 )
Jeremy Johnson0c716862023-04-13 17:18:19 +01001039
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001040 if args.tests_list_file is not None:
1041 logger.info("Tests list file extended")
1042 continue
1043
1044 if args.convert_all_tests or "generator_select" in supports:
1045 if test_type in ["positive", "both"]:
1046 logger.info(f"Running and converting all {op} tests")
1047 generate_results(
Won Jeon3eec59b2024-03-11 22:17:13 +00001048 args,
1049 profile_ext,
1050 op,
1051 op_build_dir,
1052 supports=supports,
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001053 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001054 operator_test_list = None
1055 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001056 logger.info(
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001057 f"Running and converting selection of {op} tests"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +01001058 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001059 # Selection criteria
1060 selection_config = test_params[op]["selection"][
1061 selector_name
1062 ]
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001063 if test_type in ["positive", "both"]:
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001064 if (
1065 "all" in selection_config
1066 and selection_config["all"] == "true"
1067 ):
1068 # Just get all the positive tests
1069 tests_gen, tests_gen2 = tee(
1070 _get_all_tests_list(
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001071 "positive",
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001072 op_build_dir,
1073 op,
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001074 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001075 )
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001076 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001077 ignore_missing = (
1078 gen_name != STANDARD_GENERATOR_GROUP
1079 )
1080
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001081 # Get a selection of positive tests
1082 tests_gen, tests_gen2 = tee(
1083 get_op_tests_selection(
1084 args,
Won Jeon3eec59b2024-03-11 22:17:13 +00001085 profile_ext,
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001086 op,
1087 op_build_dir,
1088 selection_config,
1089 ignore_missing=ignore_missing,
1090 )
1091 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001092 generate_results(
Jeremy Johnson1271c442023-09-05 11:39:26 +01001093 args,
Won Jeon3eec59b2024-03-11 22:17:13 +00001094 profile_ext,
Jeremy Johnson1271c442023-09-05 11:39:26 +01001095 op,
1096 op_build_dir,
1097 supports=supports,
1098 tests=tests_gen,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001099 )
1100 operator_test_list = list(tests_gen2)
1101 else:
1102 operator_test_list = []
1103 if test_type in ["negative", "both"]:
1104 operator_test_list.extend(
1105 get_op_tests_selection(
1106 args,
Won Jeon3eec59b2024-03-11 22:17:13 +00001107 profile_ext,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001108 op,
1109 op_build_dir,
1110 selection_config,
1111 negative=True,
1112 )
1113 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001114
1115 tags = (
1116 [gen_name] if gen_name != STANDARD_GENERATOR_GROUP else None
1117 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001118 output_dir = convert_tests(
1119 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001120 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +00001121 profile_ext,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001122 op,
1123 op_build_dir,
1124 root_output_dir,
Won Jeon3eec59b2024-03-11 22:17:13 +00001125 supported,
Jeremy Johnson1271c442023-09-05 11:39:26 +01001126 supports=supports,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001127 tests=operator_test_list,
1128 group=operator_group,
1129 tags=tags,
1130 )
1131 if not args.keep_large_files:
Won Jeon3eec59b2024-03-11 22:17:13 +00001132 check_op_tests(args, profile_ext, op, output_dir)
1133
1134 profileExtDone.append(profile_ext)
1135
Jeremy Johnson0ecfa372022-06-30 14:27:56 +01001136 except GenConformanceError:
1137 return 1
1138
1139 return 0
1140
1141
1142if __name__ == "__main__":
1143 exit(main())