blob: 433a33fc1f2ec3888562a320c924ff7fe4e9ae1d [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
29from convert2conformance.convert2conformance import main as c2c_main
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010030from convert2conformance.convert2conformance import OUTPUT_TYPE_DEFAULT
31from convert2conformance.convert2conformance import OUTPUT_TYPES
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010032from distutils.dir_util import copy_tree
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +010033from serializer.tosa_serializer import TOSA_VERSION
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010034
35logging.basicConfig()
36logger = logging.getLogger("tosa_verif_conformance_generator")
37
38# Configuration for each TOSA profile
39PROFILE_OPS_INFO = {
Jeremy Johnson88588622022-07-12 16:42:29 +010040 "tosa-bi": {
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010041 "operator_test_params": "tosa_base_profile_ops_info.json",
42 "framework_tests": "tosa_base_profile_framework_ops_info.json",
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010043 },
44 "tosa-mi": {
45 # Note: This is just the extra tests not in the base profile!
46 "operator_test_params": "tosa_main_profile_ops_info.json",
47 "framework_tests": "tosa_main_profile_framework_ops_info.json",
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010048 },
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010049}
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010050PROFILES_ALL = "all"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010051
Jeremy Johnson93d43902022-09-27 12:26:14 +010052DEFAULT_SEED = 42
53
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +000054# When there is a dictionary of generator argument lists (groups) only the
55# standard group will have negative tests generated for it
56STANDARD_GENERATOR_GROUP = "standard"
57
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010058TEST_VERSION_LATEST = "latest"
59TEST_VERSION_V0_60_0 = "v0.60.0"
60TEST_VERSIONS = (TEST_VERSION_LATEST, TEST_VERSION_V0_60_0)
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +010061REGEX_VERSION = re.compile(r"v([0-9]+)\.([0-9]+)\.([0-9]+)")
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010062
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010063
64class GenConformanceError(Exception):
65 """Generation error reporting exception."""
66
67 pass
68
69
70def _run_sh_command(args, cwd, full_cmd):
71 """Run an external command and capture stdout/stderr."""
72 # Quote the command line for printing
Jeremy Johnsonaf090182024-02-13 18:25:39 +000073 try:
74 full_cmd_esc = [shlex.quote(x) for x in full_cmd]
75 except Exception as e:
76 raise Exception(f"Error quoting command: {e}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010077 if args.capture_output:
Jeremy Johnsonaf090182024-02-13 18:25:39 +000078 logger.info(f"Command: {full_cmd_esc}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010079
80 rc = subprocess.run(
81 full_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
82 )
83
84 if args.capture_output:
Jeremy Johnsondd975b82024-02-28 17:29:13 +000085 stderr = rc.stderr.decode("utf-8")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010086 stdout = rc.stdout.decode("utf-8")
Jeremy Johnsondd975b82024-02-28 17:29:13 +000087 logger.info(f"stderr: \n{stderr}")
Jeremy Johnsonaf090182024-02-13 18:25:39 +000088 logger.info(f"stdout: \n{stdout}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010089 if rc.returncode != 0:
90
91 raise Exception(
92 "Error running command: {}.\n{}".format(
93 " ".join(full_cmd_esc), rc.stderr.decode("utf-8")
94 )
95 )
96 return (rc.stdout, rc.stderr)
97
98
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +000099def build_op_tests(
Jeremy Johnson1271c442023-09-05 11:39:26 +0100100 args,
101 test_type,
102 profile,
103 operator,
104 group,
105 gen_args_list,
106 gen_neg_dim_range,
107 supports=[],
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000108 gen_filter=None,
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000109 selector_info=None,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000110):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100111 """Build tests for a given operator.
112
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000113 Builds a set of tests based on the given generator arguments list
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100114
115 Returns operator output directory
116 """
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100117 build_tests_cmd = "tosa_verif_build_tests"
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000118 op_build_dir = args.build_dir / profile / group
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100119
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000120 if gen_filter is None:
121 gen_filter = f"^{operator}$"
122
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000123 build_cmd_base = [
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100124 build_tests_cmd,
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100125 "--generate-lib-path",
126 str(args.generate_lib_path),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100127 "--filter",
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000128 gen_filter,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100129 "-o",
130 str(op_build_dir),
131 "--seed",
Jeremy Johnson93d43902022-09-27 12:26:14 +0100132 str(args.random_seed),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100133 ]
134
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000135 if args.verbosity:
136 build_cmd_base.append("-" + ("v" * args.verbosity))
137
138 if args.tests_list_file is not None:
139 build_cmd_base.append("--list-tests")
140
Jeremy Johnson1271c442023-09-05 11:39:26 +0100141 if "lazy_data_gen" in supports and args.lazy_data_generation:
142 build_cmd_base.append("--lazy-data-generation")
Jeremy Johnson0a6d1de2023-09-27 14:59:43 +0100143 if "stable_random_gen" in supports and not args.global_random_generation:
144 build_cmd_base.append("--stable-random-generation")
Jeremy Johnson962e27d2024-04-09 16:12:35 +0100145 if "random_const_inputs" in supports:
146 build_cmd_base.append("--random-const-inputs")
Jeremy Johnson1271c442023-09-05 11:39:26 +0100147
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000148 if "generator_select" in supports:
149 if selector_info is None:
150 logger.error(
151 "build_op_tests error: generator_select mode without selector information"
152 )
153 raise (GenConformanceError())
154 selector_config, selector_name = selector_info
155 build_cmd_base.extend(
156 [
157 "--test-selection-config",
158 str(selector_config),
159 "--test-selection-criteria",
160 selector_name,
161 ]
162 )
163
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000164 build_cmds_list = []
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100165
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000166 if test_type in ["positive", "both"]:
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100167 # Append extra parameters and run test generator for each set of parameters.
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000168 for arglist in gen_args_list:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000169 build_cmd_pos_test = build_cmd_base.copy()
170 build_cmd_pos_test.extend(["--test-type", "positive"])
171 build_cmd_pos_test.extend(arglist)
172 build_cmds_list.append(build_cmd_pos_test)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100173
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000174 if test_type in ["negative", "both"]:
Jeremy Johnson35396f22023-01-04 17:05:25 +0000175 # Get target-dtypes options and any filter string to limit tests
Jeremy Johnson93d43902022-09-27 12:26:14 +0100176 target_dtypes_args = []
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000177 for arglist in gen_args_list:
Jeremy Johnson93d43902022-09-27 12:26:14 +0100178 idx = 0
179 while idx < len(arglist):
180 if arglist[idx] == "--target-dtype":
181 if arglist[idx + 1] not in target_dtypes_args:
182 target_dtypes_args.extend(arglist[idx : idx + 2])
183 idx += 1 # skip over option (and then argument below)
184 idx += 1
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000185 build_cmd_neg_test = build_cmd_base.copy()
186 build_cmd_neg_test.extend(["--test-type", "negative"])
Jeremy Johnson93d43902022-09-27 12:26:14 +0100187 # Limit sizes of negative tests
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000188 dim_range = gen_neg_dim_range if gen_neg_dim_range is not None else "1,16"
189
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000190 build_cmd_neg_test.extend(["--tensor-dim-range", dim_range])
191 build_cmd_neg_test.extend(target_dtypes_args)
192 build_cmds_list.append(build_cmd_neg_test)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100193
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000194 logger.info(f"Creating {operator} tests in {len(build_cmds_list)} batch(es)")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100195 error = False
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000196 for i, cmd in enumerate(build_cmds_list):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100197 try:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000198 raw_stdout, _ = _run_sh_command(args, args.ref_model_path.parent, cmd)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100199 logger.info(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000200 f"{operator} test batch {(i+1)}/{len(build_cmds_list)} created successfully"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100201 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000202
203 if args.tests_list_file is not None:
204 with args.tests_list_file.open("a") as fd:
205 fd.write(raw_stdout.decode("utf-8"))
206
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100207 except Exception as e:
208 logger.error(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000209 f"{operator} test batch {(i+1)}/{len(build_cmds_list)} unsuccessful, skipping"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100210 )
211 logger.error(f" build_op_tests error: {e} ")
212 error = True
213 if error:
214 raise (GenConformanceError())
215
216 return op_build_dir
217
218
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000219def _check_to_include_test(test_type, test_name):
220 """Check test name for inclusion based on test_type, returns True to include."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100221
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000222 if test_type == "both":
223 return True
224 else:
225 error_test = "_ERRORIF_" in test_name
226 return (error_test and test_type == "negative") or (
227 not error_test and test_type == "positive"
228 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100229
230
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000231def _get_all_tests_list(test_type, test_root_dir, operator):
232 """Create test list from tests in the test_dir based on chosen type."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100233 test_dir = test_root_dir / operator
234 if not test_dir.is_dir():
235 # Tests are split into multiple dirs, for example: conv2d_1x1, conv2d_3x3
236 test_dir = test_root_dir
237 directories = [
238 tdir for tdir in test_dir.glob("*") if tdir.name.startswith(operator)
239 ]
240 else:
241 directories = [test_dir]
242
243 tests = []
244 for tdir in directories:
245 tests.extend(
246 [
247 test
248 for test in tdir.glob("*")
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000249 if _check_to_include_test(test_type, test.name)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100250 ]
251 )
252 return tests
253
254
Jeremy Johnson1271c442023-09-05 11:39:26 +0100255def generate_results(args, profile, operator, op_build_dir, supports=[], tests=None):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100256 """Run tests on reference model and save result to the test directory."""
Jeremy Johnson1271c442023-09-05 11:39:26 +0100257 if "lazy_data_gen" in supports and args.lazy_data_generation:
258 logger.info("Skipping running tests due to lazy data gen")
259 return
260
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100261 num_cores = args.num_cores
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100262
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100263 # Use the test runner
264 ref_cmd_base = [
265 "tosa_verif_run_tests",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100266 "--ref-model-path",
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100267 str(args.ref_model_path),
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100268 "--schema-path",
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100269 str(args.schema_path),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100270 "-j",
271 str(num_cores),
272 "-v",
273 "-t",
274 ]
275 ref_cmds = []
276
277 if not tests:
278 # Do not need to run ERRORIF tests as they don't have result files
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000279 tests = _get_all_tests_list("positive", op_build_dir, operator)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100280
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000281 skipped = 0
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100282 for test in tests:
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100283 desc = test / "desc.json"
284 with desc.open("r") as fd:
285 test_desc = json.load(fd)
286 if "meta" in test_desc and "compliance" in test_desc["meta"]:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000287 skipped += 1
288 logger.debug(
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100289 f"Skipping generating results for new compliance test - {str(test)}"
290 )
291 continue
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100292 ref_cmd = ref_cmd_base.copy()
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100293 ref_cmd.append(str(test.absolute()))
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100294 ref_cmds.append(ref_cmd)
295
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000296 if skipped:
297 logger.info(f"{skipped} new compliance tests skipped for results generation")
298
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100299 fail_string = "UNEXPECTED_FAILURE"
300 failed_counter = 0
301
302 job_pool = mp.Pool(args.num_cores)
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100303 sh_partial = partial(_run_sh_command, args, args.ref_model_path.parent)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100304 pool_results = job_pool.map(sh_partial, ref_cmds)
305 job_pool.close()
306 job_pool.join()
307
308 # Use captured output for run_sh_command to work out if test passed.
309 for i, rc in enumerate(pool_results):
310 if fail_string in str(rc[0]):
311 logger.error(f"Test {i+1}/{len(ref_cmds)}: {ref_cmds[i][-1]} failed.")
312 failed_counter += 1
313 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000314 logger.debug(f"Test {i+1}/{len(ref_cmds)}: {ref_cmds[i][-1]} passed.")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100315
316 logger.info(f"{len(ref_cmds)-failed_counter}/{len(ref_cmds)} tests passed")
317 logger.info("Ran tests on model and saved results of passing tests")
318
319
320def convert_tests(
321 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000322 test_type,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100323 profile,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100324 operator,
325 op_build_dir,
326 output_dir,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100327 op_profiles_list,
Jeremy Johnson1271c442023-09-05 11:39:26 +0100328 supports=[],
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100329 tests=None,
330 group=None,
331 trim_op_subdir=False,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000332 tags=None,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100333):
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100334 """Convert/copy tests to output directory."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100335 if group:
336 output_dir = output_dir / group
337
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100338 c2c_args_base = ["--strict"]
339 c2c_args_base.extend(["--schema-path", str(args.schema_path)])
340 c2c_args_base.extend(["--flatc-path", str(args.flatc_path)])
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100341 c2c_args_base.extend(["--output-type", args.output_type])
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100342 # This op maybe in more than one profile - e.g. tosa_bi and tosa_mi
343 # even if we are only producing tests for tosa_mi
344 for op_profile in op_profiles_list:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000345 c2c_args_base.extend(["--profile", op_profile])
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000346 if tags is not None:
347 for tag in tags:
348 c2c_args_base.extend(["--tag", tag])
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100349 if args.framework_schema:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000350 c2c_args_base.extend(["--framework-schema", str(args.framework_schema)])
Jeremy Johnson1271c442023-09-05 11:39:26 +0100351 if "lazy_data_gen" in supports and args.lazy_data_generation:
352 c2c_args_base.append("--lazy-data-generation")
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000353 c2c_args_base.append("--output-directory")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100354
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000355 c2c_args_list = []
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100356
357 if not tests:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000358 tests = _get_all_tests_list(test_type, op_build_dir, operator)
359 logger.info(f"Converting all {profile} profile tests of type {test_type}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100360
361 # Controls if we copy the tests in their operator sub-directory or not
362 output_dir_relative_pos = -1 if trim_op_subdir else -2
363 for test in tests:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000364 logger.debug(f"Test chosen: {test}")
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000365 c2c_args = c2c_args_base.copy()
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100366 full_output_directory = output_dir / test.relative_to(
367 *test.parts[:output_dir_relative_pos]
368 )
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000369 c2c_args.append(str(full_output_directory))
370 c2c_args.append(str(test))
371 c2c_args_list.append(c2c_args)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100372
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000373 if len(c2c_args_list) == 0:
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000374 logger.error(
375 f"No tests found for {operator}. Nothing to convert in {op_build_dir}"
376 )
377 raise (GenConformanceError())
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100378
379 job_pool = mp.Pool(args.num_cores)
380
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000381 pool_results = job_pool.map(c2c_main, c2c_args_list)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100382 job_pool.close()
383 job_pool.join()
384
385 failed_counter = 0
386 for i, result in enumerate(pool_results):
387 if result != 0:
388 logger.error(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000389 f"test {i+1}/{len(c2c_args_list)}: {c2c_args_list[i][-1]} failed to convert."
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100390 )
391 failed_counter += 1
392 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000393 logger.debug(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000394 f"test {i+1}/{len(c2c_args_list)}: {c2c_args_list[i][-1]} converted"
395 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100396 logger.info(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000397 f"{len(c2c_args_list)-failed_counter}/{len(c2c_args_list)} tests successfully converted"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100398 )
399
400 if failed_counter > 0:
401 logger.error(f"Stopping due to {failed_counter} test conversion errors")
402 raise (GenConformanceError())
403
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100404 logger.info("Converted/copied tests and saved to output directory")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100405
406 return output_dir
407
408
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100409def get_op_tests_selection(
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000410 args,
411 profile,
412 operator,
413 op_build_dir,
414 selection_config,
415 negative=False,
416 ignore_missing=False,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100417):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100418 """Use test picker to get subsection of tests generated."""
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000419 # Need a full copy of the config as the selector updates it
420 config = copy.deepcopy(selection_config)
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100421 logger.info("Choosing {} tests".format(("negative" if negative else "positive")))
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100422 try:
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100423 op = Operator.registry[operator](
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000424 op_build_dir, config, negative=negative, ignore_missing=ignore_missing
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100425 )
426 except KeyError:
427 logger.error(f"{operator} operator is not supported by test_select")
428 raise (GenConformanceError())
429
430 return op.select_tests()
431
432
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100433def check_op_tests(args, profile, operator, output_dir):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100434 """Move test folders than contain files larger than 30MB to new directory."""
435 destination_dir = str(args.output_dir) + "_large_files"
436
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000437 # Include all tests - both positive and negative
438 tests = _get_all_tests_list("both", output_dir, operator)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100439 if not tests:
440 logger.error(
441 f"Couldn't find any tests to size check for {operator} in {output_dir}"
442 )
443 raise (GenConformanceError())
444
445 for tdir in tests:
446 move_dir = False
447 test_files = [file for file in tdir.glob("*")]
448 for file in test_files:
449 file_size = os.stat(file).st_size / 1024**2
450 if file_size > 30:
451 move_dir = True
452
453 if move_dir:
454 move_destination = destination_dir / tdir.relative_to(output_dir)
455 logger.warning(
456 f"{tdir.relative_to(output_dir)} contains files that are too large (>30MB), test moved to new folder: {destination_dir}"
457 )
458
459 if move_destination.is_dir():
460 logger.warning(
461 f"{move_destination} directory already exists, deleting existing."
462 )
463 shutil.rmtree(str(move_destination))
464 shutil.move(str(tdir), move_destination)
465
466
467def copy_rename_framework_tests(args, operator, test_picks):
468 """Copy framework tests into new folder and rename them if needed.
469
470 The tests are renamed to match the framework operator names if an
471 alternate name has been used instead.
472 """
473 framework_tests_dir = args.framework_tests_dir
474 new_tests_dir = args.build_dir / "frameworks" / operator
475 os.makedirs(new_tests_dir, exist_ok=True)
476
477 # Get the framework tests operator name
478 if "alternate_names" in test_picks[operator]:
479 alternate_names = test_picks[operator]["alternate_names"]
480 else:
481 alternate_names = [operator]
482
483 # Get the alternate named test directories for the operator
484 for alt_name in alternate_names:
485 test_prefix = f"test_{alt_name}"
486 test_dirs = list(framework_tests_dir.glob(f"{test_prefix}_*"))
487
488 # Copy tests to new directory and rename to match framework operator names
489 # - if there is just 1 alternate name, replace the full test prefix
490 # test_add_... -> add_...
491 # - if there are multiple alternate names, just replace the "test"
492 # test_concatv2_... -> concatenation_concatv2_...
493 old_prefix = test_prefix if len(alternate_names) == 1 else "test"
494
495 for tdir in test_dirs:
496 new_test_name = tdir.name.replace(old_prefix, operator)
497 copy_destination = new_tests_dir / new_test_name
498 logger.debug(f"copying test folder {tdir} to {copy_destination}")
499 copy_tree(str(tdir), str(copy_destination))
500
501 logger.info(f"Copied and renamed {len(test_dirs)} framework test folders")
502 return new_tests_dir.parent
503
504
505def get_framework_tests_selection(args, operator, test_picks, op_build_dir):
506 """Get the list of pre-chosen tests with relative paths."""
507 try:
508 tests = test_picks[operator]["tests"]
509 except KeyError:
510 logger.error(f"Framework test selection not defined for {operator} operator")
511 raise (GenConformanceError())
512
513 test_paths = [op_build_dir / operator / test for test in tests]
514 return test_paths
515
516
517def parse_args(argv=None):
518 """Parse the arguments."""
519 parser = argparse.ArgumentParser()
Jeremy Johnson88588622022-07-12 16:42:29 +0100520 profiles = list(PROFILE_OPS_INFO.keys())
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100521 profiles.append(PROFILES_ALL)
Jeremy Johnson88588622022-07-12 16:42:29 +0100522 parser.add_argument(
523 "--profile",
524 dest="profile",
525 choices=profiles,
526 default=profiles[0],
527 type=str,
528 help=f"TOSA profile (default is {profiles[0]})",
529 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100530 parser.add_argument(
531 "--operators",
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100532 "--op",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100533 type=str,
534 nargs="*",
535 help="The operator(s) to create tests for, if not supplied all tests will be created",
536 )
537 parser.add_argument(
Jeremy Johnson88588622022-07-12 16:42:29 +0100538 "--unit-tests",
539 dest="unit_tests",
540 choices=["operator", "framework", "both"],
541 default="operator",
542 type=str,
543 help="Which unit tests are produced (default is operator)",
544 )
545 parser.add_argument(
546 "--test-type",
547 dest="test_type",
548 choices=["positive", "negative", "both"],
549 default="both",
550 type=str,
551 help="Type of tests produced (default is both)",
552 )
553 parser.add_argument(
Jeremy Johnson0a6d1de2023-09-27 14:59:43 +0100554 "--global-random-generation",
555 action="store_true",
556 help="Disable stable random generation of tests that support this mode",
557 )
558 parser.add_argument(
Jeremy Johnson1271c442023-09-05 11:39:26 +0100559 "--lazy-data-generation",
560 action="store_true",
561 help="Enable lazy data generation (only for tosa-mi)",
562 )
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100563 rm_group = parser.add_mutually_exclusive_group(required=True)
564 rm_group.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100565 "--ref-model-directory",
566 dest="ref_model_dir",
567 type=Path,
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100568 help="(DEPRECATED - use ref-model-path) Reference Model directory - with build directory",
569 )
570 rm_group.add_argument(
571 "--ref-model-path",
572 dest="ref_model_path",
573 type=Path,
574 help="Path to TOSA reference model executable",
575 )
576 parser.add_argument(
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100577 "--generate-lib-path",
578 dest="generate_lib_path",
579 type=Path,
580 help=(
581 "Path to TOSA generate library. Defaults to "
582 "the library in the directory of `ref-model-path`"
583 ),
584 )
585 parser.add_argument(
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100586 "--schema-path",
587 "--operator-fbs",
588 dest="schema_path",
589 type=Path,
590 help=(
591 "Path to TOSA reference model flat buffer schema. Defaults to "
592 f"`{cmf.DEFAULT_REF_MODEL_SCHEMA_PATH}` in parents parent directory of `ref-model-path`"
593 ),
594 )
595 parser.add_argument(
596 "--flatc-path",
597 dest="flatc_path",
598 type=Path,
599 help=(
600 "Path to flatc executable. Defaults to "
601 f"`{cmf.DEFAULT_REF_MODEL_BUILD_FLATC_PATH}` in parent directory of `ref-model-path`"
602 ),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100603 )
Jeremy Johnson88588622022-07-12 16:42:29 +0100604 parser.add_argument(
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100605 "--test-version",
606 dest="test_version",
607 choices=TEST_VERSIONS,
608 default=TEST_VERSION_LATEST,
609 help=f"Version of the tests to produce (default is {TEST_VERSION_LATEST})",
610 )
611 parser.add_argument(
612 "--output-type",
613 dest="output_type",
614 choices=OUTPUT_TYPES,
615 default=OUTPUT_TYPE_DEFAULT,
616 help=f"Output file type produced (default is {OUTPUT_TYPE_DEFAULT})",
617 )
618 parser.add_argument(
Jeremy Johnson93d43902022-09-27 12:26:14 +0100619 "--seed",
620 dest="random_seed",
621 default=DEFAULT_SEED,
622 type=int,
623 help="Random test seed",
624 )
625 parser.add_argument(
Jeremy Johnson88588622022-07-12 16:42:29 +0100626 "--framework-tests-directory",
627 dest="framework_tests_dir",
628 type=Path,
629 default=Path.cwd() / "tests",
630 help="The pre-built framework tests directory (default is tests)",
631 )
632 parser.add_argument(
633 "--framework-schema",
634 dest="framework_schema",
635 type=Path,
636 help="Framework flatbuffers schema needed to convert framework models",
637 )
638 parser.add_argument(
639 "--build-directory",
640 dest="build_dir",
641 type=Path,
642 default=Path.cwd() / "conformance_build",
643 help="Temporary build directory for files created during this process (default is conformance_build)",
644 )
645 parser.add_argument(
646 "--output-directory",
647 dest="output_dir",
648 type=Path,
649 default=Path.cwd() / "conformance",
650 help="Output directory (default is conformance)",
651 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100652 script_dir = Path(__file__).parent.absolute()
653 parser.add_argument(
654 "--test-param-json-directory",
655 dest="param_json_dir",
656 type=Path,
657 default=script_dir,
Jeremy Johnson88588622022-07-12 16:42:29 +0100658 help=f"Test parameters (ops info) JSON file directory (default is {script_dir})",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100659 )
660 parser.add_argument(
661 "--convert-all-tests",
662 action="store_true",
663 help="Converts all tests instead of those picked by test_select",
664 )
665 parser.add_argument(
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000666 "--list-tests-to-file",
667 dest="tests_list_file",
668 type=Path,
669 help="Lists out the tests to be generated to a file instead of generating them",
670 )
671 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100672 "--keep-large-files",
673 action="store_true",
674 help="Keeps tests that contain files larger than 30MB in output directory",
675 )
676 parser.add_argument(
677 "--capture-output",
678 action="store_true",
679 help="Prints output of running sh commands",
680 )
681 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100682 "-j",
683 dest="num_cores",
684 type=int,
685 default=6,
686 help="Number of simultaneous jobs to split the tasks into for multiprocessing",
687 )
688 parser.add_argument(
689 "-v",
690 dest="verbosity",
691 action="count",
692 default=0,
693 help="Verbosity (can be used multiple times for more details)",
694 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100695 args = parser.parse_args(argv)
696
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000697 if args.ref_model_dir is not None:
698 # Assume the ref model exe path based on the ref model directory
699 args.ref_model_path = cmf.find_tosa_file(
700 cmf.TosaFileType.REF_MODEL, args.ref_model_dir, False
701 )
702 if not args.ref_model_path.is_file():
703 logger.error(
704 f"Missing reference model binary (--ref-model-path): {args.ref_model_path}"
705 )
706 return None
707 args.ref_model_path = args.ref_model_path.absolute()
708
709 if args.generate_lib_path is None:
710 args.generate_lib_path = cmf.find_tosa_file(
711 cmf.TosaFileType.GENERATE_LIBRARY, args.ref_model_path
712 )
713 if not args.generate_lib_path.is_file():
714 logger.error(
715 f"Missing TOSA generate data library (--generate-lib-path): {args.generate_lib_path}"
716 )
717 return None
718 args.generate_lib_path = args.generate_lib_path.absolute()
719
720 if args.schema_path is None:
721 args.schema_path = cmf.find_tosa_file(
722 cmf.TosaFileType.SCHEMA, args.ref_model_path
723 )
724 if not args.schema_path.is_file():
725 logger.error(
726 f"Missing reference model schema (--schema-path): {args.schema_path}"
727 )
728 return None
729 args.schema_path = args.schema_path.absolute()
730
731 if args.flatc_path is None:
732 args.flatc_path = cmf.find_tosa_file(
733 cmf.TosaFileType.FLATC, args.ref_model_path
734 )
735 if not args.flatc_path.is_file():
736 logger.error(f"Missing flatc binary (--flatc-path): {args.flatc_path}")
737 return None
738 args.flatc_path = args.flatc_path.absolute()
739
740 args.param_json_dir = args.param_json_dir.absolute()
741
742 if args.unit_tests in ["framework", "both"]:
743 logger.warning(
744 "DEPRECATION - Framework tests are not part of TOSA conformance testing"
745 )
746 if not args.framework_schema:
747 logger.error(
748 "Need to supply location of Framework flatbuffers schema via --framework-schema"
749 )
750 return None
751 if not args.framework_tests_dir.is_dir():
752 logger.error(
753 f"Missing or invalid framework tests directory: {args.framework_tests_dir}"
754 )
755 return None
756
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100757 return args
758
759
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +0100760def in_version(test_version, gen_dict):
761 """Check if the selected test_version is compatible with the tests."""
762
763 def version_string_to_numbers(verstr):
764 # Turn the "vM.mm.pp" string into Major, Minor, Patch versions
765 if verstr == TEST_VERSION_LATEST:
766 return (TOSA_VERSION[0], TOSA_VERSION[1], TOSA_VERSION[2])
767 else:
768 match = re.match(REGEX_VERSION, verstr)
769 if match is None:
770 raise KeyError(f"Invalid version string {verstr}")
771 return (int(v) for v in match.groups())
772
773 if "from_version" in gen_dict:
774 selected_version = version_string_to_numbers(test_version)
775 from_version = version_string_to_numbers(gen_dict["from_version"])
776
777 # Check the Major version is compatible, then Minor, and lastly Patch
778 # Unless the versions match, we can exit early due to obvious precedence
779 for sel, fro in zip(selected_version, from_version):
780 if sel < fro:
781 # From version is later than selected version
782 return False
783 elif sel > fro:
784 # From version is earlier than selected version
785 return True
786 # If we get here, the version numbers match exactly
787 return True
788 else:
789 # No specific version info
790 return True
791
792
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000793def _get_log_level(verbosity):
794 loglevels = (logging.WARNING, logging.INFO, logging.DEBUG)
795 verbosity = max(verbosity, 0)
796 return loglevels[min(verbosity, len(loglevels) - 1)]
797
798
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100799def main():
800 args = parse_args()
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000801 if args is None:
802 # Argument processing error
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100803 return 2
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100804
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000805 loglevel = _get_log_level(args.verbosity)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100806 logger.setLevel(loglevel)
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000807 # Set other loggers to a quieter level
808 loglevel = _get_log_level(args.verbosity - 1)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100809 logging.getLogger("test_select").setLevel(loglevel)
810 logging.getLogger("convert2conformance").setLevel(loglevel)
811
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100812 print(f"Output directory: {args.output_dir}")
813
Jeremy Johnson93d43902022-09-27 12:26:14 +0100814 if args.random_seed != DEFAULT_SEED:
815 logger.warning(
816 "Random test seed changed from default, tests will not match official conformance"
817 )
818
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100819 args.build_dir = args.build_dir.resolve()
820 logger.debug(f"Creating build directory: {args.build_dir}")
821 args.build_dir.mkdir(parents=True, exist_ok=True)
822
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000823 if args.tests_list_file is not None:
824 # Try creating tests list file
825 with args.tests_list_file.open("w") as fd:
826 fd.write("")
827
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100828 # TODO: For tosa-mi should really generate tosa-bi profile as well
829 # - for now leave it as subset instead of as superset (for testing)
830 if args.profile == PROFILES_ALL:
831 profiles = list(PROFILE_OPS_INFO.keys())
832 else:
833 profiles = [args.profile]
834
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100835 try:
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100836 for profile in profiles:
837 print(f"Creating conformance tests for TOSA {profile} profile")
838 # Framework unit tests
839 if args.unit_tests in ["framework", "both"]:
840 logger.debug("Creating FRAMEWORK unit tests")
841 test_picks_file = (
842 args.param_json_dir / PROFILE_OPS_INFO[profile]["framework_tests"]
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100843 )
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100844 try:
845 with open(test_picks_file, "r") as fd:
846 test_picks = json.load(fd)
847 except Exception as e:
848 logger.error(
849 f"Couldn't load framework tests info - {test_picks_file}: {e}"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100850 )
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100851 return 1
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100852
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100853 operators = args.operators
854 if not operators:
855 # Create tests for all the operators
856 operators = list(test_picks.keys())
857
858 root_output_dir = (
859 args.output_dir / "frameworks" / "tflite" / "operators"
860 )
861 for op in operators:
862 logger.info(f"FRAMEWORK OP: {op}")
863 if op not in test_picks:
864 logger.warning(
865 f"Framework op {op} not found in {test_picks_file} - skipping"
866 )
867 continue
868
869 op_profiles_list = test_picks[op]["profile"]
870 if (
871 args.profile != PROFILES_ALL
872 and args.profile not in op_profiles_list
873 ):
874 # Skip this operator as not part of the profile chosen
875 logger.debug(f"Skipping {op} as not part of {args.profile}")
876 continue
877
878 logger.debug(f"Copying and renaming {op}")
879 framework_test_dir = copy_rename_framework_tests(
880 args, op, test_picks
881 )
882
883 if args.convert_all_tests:
884 logger.debug("Running and converting all framework tests")
885 framework_tests = None # Don't select any
886 else:
887 logger.debug("Running and converting selected framework tests")
888 framework_tests = get_framework_tests_selection(
889 args, op, test_picks, framework_test_dir
890 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100891 convert_tests(
892 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000893 "positive",
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100894 profile,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100895 op,
896 framework_test_dir,
897 root_output_dir,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100898 op_profiles_list,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100899 tests=framework_tests,
900 trim_op_subdir=True,
901 )
902
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100903 # Operator unit tests
904 if args.unit_tests in ["operator", "both"]:
905 logger.debug("Creating OPERATOR unit tests")
906 test_params_file = (
907 args.param_json_dir
908 / PROFILE_OPS_INFO[profile]["operator_test_params"]
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100909 )
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100910 try:
911 with open(test_params_file, "r") as fd:
912 test_params = json.load(fd)
913 except Exception as e:
914 logger.error(
915 f"Couldn't load operator test params - {test_params_file}: {e}"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100916 )
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100917 return 1
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000918 logger.debug(f"Using config file: {str(test_params_file)}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100919
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100920 operators = args.operators
921 if not operators:
922 # Create tests for all the operators
923 operators = list(test_params.keys())
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100924
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100925 for op in operators:
926 logger.info(f"OPERATOR: {op}")
927 if op not in test_params:
928 logger.warning(
929 f"{op} operator parameters not found in {test_params_file} - skipping"
930 )
931 continue
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100932
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100933 op_profiles_list = test_params[op]["profile"]
934 if (
935 args.profile != PROFILES_ALL
936 and args.profile not in op_profiles_list
937 ):
938 # Skip this operator as not part of the profile chosen
939 logger.debug(f"Skipping {op} as not part of {args.profile}")
940 continue
941
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100942 operator_group = test_params[op]["group"]
943 root_output_dir = args.output_dir / "operators"
Jeremy Johnson1271c442023-09-05 11:39:26 +0100944 supports = (
945 test_params[op]["support_for"]
946 if "support_for" in test_params[op]
947 else []
948 )
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000949 gen_filter = (
950 test_params[op]["gen_filter"]
951 if "gen_filter" in test_params[op]
952 else None
953 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000954
955 # Iterate through the generation groups selecting tests from each
956 for gen_name, gen_dict in test_params[op]["generation"].items():
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +0100957
958 if not in_version(args.test_version, gen_dict):
959 logger.warning(
960 f"{op} [{gen_name}] is not in {args.test_version} - skipping"
961 )
962 continue
963
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000964 no_neg_tests = (
965 "no_negative_tests" in gen_dict
966 and gen_dict["no_negative_tests"] == "true"
967 )
968
969 if no_neg_tests:
970 if args.test_type == "negative":
971 logger.info(
972 f"No negative tests for {op} / generation group {gen_name}"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100973 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000974 continue
975 # Only produce positive tests
976 test_type = "positive"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100977 else:
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000978 test_type = args.test_type
979
980 gen_neg_dim_range = (
981 gen_dict["negative_dim_range"]
982 if "negative_dim_range" in gen_dict
983 else None
984 )
985
Jeremy Johnson0c716862023-04-13 17:18:19 +0100986 # Work out which selection criteria we are using
987 if "selector" in gen_dict:
988 selector_name = gen_dict["selector"]
989 if selector_name not in test_params[op]["selection"]:
990 logger.warn(
991 f"Could not find {selector_name} in selection dict for {op} - using default"
992 )
993 selector_name = "default"
994 else:
995 selector_name = "default"
996 if selector_name not in test_params[op]["selection"]:
997 logger.error(
998 f"Could not find {selector_name} in selection dict for {op}"
999 )
1000 raise (GenConformanceError())
1001
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001002 op_build_dir = build_op_tests(
1003 args,
1004 test_type,
1005 profile,
1006 op,
1007 gen_name,
1008 gen_dict["generator_args"],
1009 gen_neg_dim_range,
1010 supports=supports,
1011 gen_filter=gen_filter,
1012 selector_info=(test_params_file, selector_name),
1013 )
Jeremy Johnson0c716862023-04-13 17:18:19 +01001014
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001015 if args.tests_list_file is not None:
1016 logger.info("Tests list file extended")
1017 continue
1018
1019 if args.convert_all_tests or "generator_select" in supports:
1020 if test_type in ["positive", "both"]:
1021 logger.info(f"Running and converting all {op} tests")
1022 generate_results(
1023 args, profile, op, op_build_dir, supports=supports
1024 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001025 operator_test_list = None
1026 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001027 logger.info(
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001028 f"Running and converting selection of {op} tests"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +01001029 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001030 # Selection criteria
1031 selection_config = test_params[op]["selection"][
1032 selector_name
1033 ]
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001034 if test_type in ["positive", "both"]:
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001035 if (
1036 "all" in selection_config
1037 and selection_config["all"] == "true"
1038 ):
1039 # Just get all the positive tests
1040 tests_gen, tests_gen2 = tee(
1041 _get_all_tests_list(
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001042 "positive",
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001043 op_build_dir,
1044 op,
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001045 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001046 )
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001047 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001048 ignore_missing = (
1049 gen_name != STANDARD_GENERATOR_GROUP
1050 )
1051
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001052 # Get a selection of positive tests
1053 tests_gen, tests_gen2 = tee(
1054 get_op_tests_selection(
1055 args,
1056 profile,
1057 op,
1058 op_build_dir,
1059 selection_config,
1060 ignore_missing=ignore_missing,
1061 )
1062 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001063 generate_results(
Jeremy Johnson1271c442023-09-05 11:39:26 +01001064 args,
1065 profile,
1066 op,
1067 op_build_dir,
1068 supports=supports,
1069 tests=tests_gen,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001070 )
1071 operator_test_list = list(tests_gen2)
1072 else:
1073 operator_test_list = []
1074 if test_type in ["negative", "both"]:
1075 operator_test_list.extend(
1076 get_op_tests_selection(
1077 args,
1078 profile,
1079 op,
1080 op_build_dir,
1081 selection_config,
1082 negative=True,
1083 )
1084 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001085
1086 tags = (
1087 [gen_name] if gen_name != STANDARD_GENERATOR_GROUP else None
1088 )
1089
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001090 output_dir = convert_tests(
1091 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001092 test_type,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001093 profile,
1094 op,
1095 op_build_dir,
1096 root_output_dir,
1097 op_profiles_list,
Jeremy Johnson1271c442023-09-05 11:39:26 +01001098 supports=supports,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001099 tests=operator_test_list,
1100 group=operator_group,
1101 tags=tags,
1102 )
1103 if not args.keep_large_files:
1104 check_op_tests(args, profile, op, output_dir)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +01001105 except GenConformanceError:
1106 return 1
1107
1108 return 0
1109
1110
1111if __name__ == "__main__":
1112 exit(main())