blob: 3b7c2df02bb345f4342f667edb54f9602689f59a [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 Johnson1271c442023-09-05 11:39:26 +0100145
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000146 if "generator_select" in supports:
147 if selector_info is None:
148 logger.error(
149 "build_op_tests error: generator_select mode without selector information"
150 )
151 raise (GenConformanceError())
152 selector_config, selector_name = selector_info
153 build_cmd_base.extend(
154 [
155 "--test-selection-config",
156 str(selector_config),
157 "--test-selection-criteria",
158 selector_name,
159 ]
160 )
161
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000162 build_cmds_list = []
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100163
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000164 if test_type in ["positive", "both"]:
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100165 # Append extra parameters and run test generator for each set of parameters.
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000166 for arglist in gen_args_list:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000167 build_cmd_pos_test = build_cmd_base.copy()
168 build_cmd_pos_test.extend(["--test-type", "positive"])
169 build_cmd_pos_test.extend(arglist)
170 build_cmds_list.append(build_cmd_pos_test)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100171
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000172 if test_type in ["negative", "both"]:
Jeremy Johnson35396f22023-01-04 17:05:25 +0000173 # Get target-dtypes options and any filter string to limit tests
Jeremy Johnson93d43902022-09-27 12:26:14 +0100174 target_dtypes_args = []
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000175 for arglist in gen_args_list:
Jeremy Johnson93d43902022-09-27 12:26:14 +0100176 idx = 0
177 while idx < len(arglist):
178 if arglist[idx] == "--target-dtype":
179 if arglist[idx + 1] not in target_dtypes_args:
180 target_dtypes_args.extend(arglist[idx : idx + 2])
181 idx += 1 # skip over option (and then argument below)
182 idx += 1
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000183 build_cmd_neg_test = build_cmd_base.copy()
184 build_cmd_neg_test.extend(["--test-type", "negative"])
Jeremy Johnson93d43902022-09-27 12:26:14 +0100185 # Limit sizes of negative tests
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000186 dim_range = gen_neg_dim_range if gen_neg_dim_range is not None else "1,16"
187
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000188 build_cmd_neg_test.extend(["--tensor-dim-range", dim_range])
189 build_cmd_neg_test.extend(target_dtypes_args)
190 build_cmds_list.append(build_cmd_neg_test)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100191
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000192 logger.info(f"Creating {operator} tests in {len(build_cmds_list)} batch(es)")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100193 error = False
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000194 for i, cmd in enumerate(build_cmds_list):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100195 try:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000196 raw_stdout, _ = _run_sh_command(args, args.ref_model_path.parent, cmd)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100197 logger.info(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000198 f"{operator} test batch {(i+1)}/{len(build_cmds_list)} created successfully"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100199 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000200
201 if args.tests_list_file is not None:
202 with args.tests_list_file.open("a") as fd:
203 fd.write(raw_stdout.decode("utf-8"))
204
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100205 except Exception as e:
206 logger.error(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000207 f"{operator} test batch {(i+1)}/{len(build_cmds_list)} unsuccessful, skipping"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100208 )
209 logger.error(f" build_op_tests error: {e} ")
210 error = True
211 if error:
212 raise (GenConformanceError())
213
214 return op_build_dir
215
216
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000217def _check_to_include_test(test_type, test_name):
218 """Check test name for inclusion based on test_type, returns True to include."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100219
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000220 if test_type == "both":
221 return True
222 else:
223 error_test = "_ERRORIF_" in test_name
224 return (error_test and test_type == "negative") or (
225 not error_test and test_type == "positive"
226 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100227
228
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000229def _get_all_tests_list(test_type, test_root_dir, operator):
230 """Create test list from tests in the test_dir based on chosen type."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100231 test_dir = test_root_dir / operator
232 if not test_dir.is_dir():
233 # Tests are split into multiple dirs, for example: conv2d_1x1, conv2d_3x3
234 test_dir = test_root_dir
235 directories = [
236 tdir for tdir in test_dir.glob("*") if tdir.name.startswith(operator)
237 ]
238 else:
239 directories = [test_dir]
240
241 tests = []
242 for tdir in directories:
243 tests.extend(
244 [
245 test
246 for test in tdir.glob("*")
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000247 if _check_to_include_test(test_type, test.name)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100248 ]
249 )
250 return tests
251
252
Jeremy Johnson1271c442023-09-05 11:39:26 +0100253def generate_results(args, profile, operator, op_build_dir, supports=[], tests=None):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100254 """Run tests on reference model and save result to the test directory."""
Jeremy Johnson1271c442023-09-05 11:39:26 +0100255 if "lazy_data_gen" in supports and args.lazy_data_generation:
256 logger.info("Skipping running tests due to lazy data gen")
257 return
258
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100259 num_cores = args.num_cores
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100260
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100261 # Use the test runner
262 ref_cmd_base = [
263 "tosa_verif_run_tests",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100264 "--ref-model-path",
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100265 str(args.ref_model_path),
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100266 "--schema-path",
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100267 str(args.schema_path),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100268 "-j",
269 str(num_cores),
270 "-v",
271 "-t",
272 ]
273 ref_cmds = []
274
275 if not tests:
276 # Do not need to run ERRORIF tests as they don't have result files
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000277 tests = _get_all_tests_list("positive", op_build_dir, operator)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100278
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000279 skipped = 0
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100280 for test in tests:
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100281 desc = test / "desc.json"
282 with desc.open("r") as fd:
283 test_desc = json.load(fd)
284 if "meta" in test_desc and "compliance" in test_desc["meta"]:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000285 skipped += 1
286 logger.debug(
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100287 f"Skipping generating results for new compliance test - {str(test)}"
288 )
289 continue
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100290 ref_cmd = ref_cmd_base.copy()
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100291 ref_cmd.append(str(test.absolute()))
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100292 ref_cmds.append(ref_cmd)
293
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000294 if skipped:
295 logger.info(f"{skipped} new compliance tests skipped for results generation")
296
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100297 fail_string = "UNEXPECTED_FAILURE"
298 failed_counter = 0
299
300 job_pool = mp.Pool(args.num_cores)
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100301 sh_partial = partial(_run_sh_command, args, args.ref_model_path.parent)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100302 pool_results = job_pool.map(sh_partial, ref_cmds)
303 job_pool.close()
304 job_pool.join()
305
306 # Use captured output for run_sh_command to work out if test passed.
307 for i, rc in enumerate(pool_results):
308 if fail_string in str(rc[0]):
309 logger.error(f"Test {i+1}/{len(ref_cmds)}: {ref_cmds[i][-1]} failed.")
310 failed_counter += 1
311 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000312 logger.debug(f"Test {i+1}/{len(ref_cmds)}: {ref_cmds[i][-1]} passed.")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100313
314 logger.info(f"{len(ref_cmds)-failed_counter}/{len(ref_cmds)} tests passed")
315 logger.info("Ran tests on model and saved results of passing tests")
316
317
318def convert_tests(
319 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000320 test_type,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100321 profile,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100322 operator,
323 op_build_dir,
324 output_dir,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100325 op_profiles_list,
Jeremy Johnson1271c442023-09-05 11:39:26 +0100326 supports=[],
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100327 tests=None,
328 group=None,
329 trim_op_subdir=False,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000330 tags=None,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100331):
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100332 """Convert/copy tests to output directory."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100333 if group:
334 output_dir = output_dir / group
335
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100336 c2c_args_base = ["--strict"]
337 c2c_args_base.extend(["--schema-path", str(args.schema_path)])
338 c2c_args_base.extend(["--flatc-path", str(args.flatc_path)])
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100339 c2c_args_base.extend(["--output-type", args.output_type])
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100340 # This op maybe in more than one profile - e.g. tosa_bi and tosa_mi
341 # even if we are only producing tests for tosa_mi
342 for op_profile in op_profiles_list:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000343 c2c_args_base.extend(["--profile", op_profile])
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000344 if tags is not None:
345 for tag in tags:
346 c2c_args_base.extend(["--tag", tag])
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100347 if args.framework_schema:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000348 c2c_args_base.extend(["--framework-schema", str(args.framework_schema)])
Jeremy Johnson1271c442023-09-05 11:39:26 +0100349 if "lazy_data_gen" in supports and args.lazy_data_generation:
350 c2c_args_base.append("--lazy-data-generation")
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000351 c2c_args_base.append("--output-directory")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100352
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000353 c2c_args_list = []
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100354
355 if not tests:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000356 tests = _get_all_tests_list(test_type, op_build_dir, operator)
357 logger.info(f"Converting all {profile} profile tests of type {test_type}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100358
359 # Controls if we copy the tests in their operator sub-directory or not
360 output_dir_relative_pos = -1 if trim_op_subdir else -2
361 for test in tests:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000362 logger.debug(f"Test chosen: {test}")
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000363 c2c_args = c2c_args_base.copy()
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100364 full_output_directory = output_dir / test.relative_to(
365 *test.parts[:output_dir_relative_pos]
366 )
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000367 c2c_args.append(str(full_output_directory))
368 c2c_args.append(str(test))
369 c2c_args_list.append(c2c_args)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100370
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000371 if len(c2c_args_list) == 0:
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000372 logger.error(
373 f"No tests found for {operator}. Nothing to convert in {op_build_dir}"
374 )
375 raise (GenConformanceError())
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100376
377 job_pool = mp.Pool(args.num_cores)
378
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000379 pool_results = job_pool.map(c2c_main, c2c_args_list)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100380 job_pool.close()
381 job_pool.join()
382
383 failed_counter = 0
384 for i, result in enumerate(pool_results):
385 if result != 0:
386 logger.error(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000387 f"test {i+1}/{len(c2c_args_list)}: {c2c_args_list[i][-1]} failed to convert."
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100388 )
389 failed_counter += 1
390 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000391 logger.debug(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000392 f"test {i+1}/{len(c2c_args_list)}: {c2c_args_list[i][-1]} converted"
393 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100394 logger.info(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000395 f"{len(c2c_args_list)-failed_counter}/{len(c2c_args_list)} tests successfully converted"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100396 )
397
398 if failed_counter > 0:
399 logger.error(f"Stopping due to {failed_counter} test conversion errors")
400 raise (GenConformanceError())
401
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100402 logger.info("Converted/copied tests and saved to output directory")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100403
404 return output_dir
405
406
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100407def get_op_tests_selection(
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000408 args,
409 profile,
410 operator,
411 op_build_dir,
412 selection_config,
413 negative=False,
414 ignore_missing=False,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100415):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100416 """Use test picker to get subsection of tests generated."""
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000417 # Need a full copy of the config as the selector updates it
418 config = copy.deepcopy(selection_config)
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100419 logger.info("Choosing {} tests".format(("negative" if negative else "positive")))
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100420 try:
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100421 op = Operator.registry[operator](
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000422 op_build_dir, config, negative=negative, ignore_missing=ignore_missing
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100423 )
424 except KeyError:
425 logger.error(f"{operator} operator is not supported by test_select")
426 raise (GenConformanceError())
427
428 return op.select_tests()
429
430
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100431def check_op_tests(args, profile, operator, output_dir):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100432 """Move test folders than contain files larger than 30MB to new directory."""
433 destination_dir = str(args.output_dir) + "_large_files"
434
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000435 # Include all tests - both positive and negative
436 tests = _get_all_tests_list("both", output_dir, operator)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100437 if not tests:
438 logger.error(
439 f"Couldn't find any tests to size check for {operator} in {output_dir}"
440 )
441 raise (GenConformanceError())
442
443 for tdir in tests:
444 move_dir = False
445 test_files = [file for file in tdir.glob("*")]
446 for file in test_files:
447 file_size = os.stat(file).st_size / 1024**2
448 if file_size > 30:
449 move_dir = True
450
451 if move_dir:
452 move_destination = destination_dir / tdir.relative_to(output_dir)
453 logger.warning(
454 f"{tdir.relative_to(output_dir)} contains files that are too large (>30MB), test moved to new folder: {destination_dir}"
455 )
456
457 if move_destination.is_dir():
458 logger.warning(
459 f"{move_destination} directory already exists, deleting existing."
460 )
461 shutil.rmtree(str(move_destination))
462 shutil.move(str(tdir), move_destination)
463
464
465def copy_rename_framework_tests(args, operator, test_picks):
466 """Copy framework tests into new folder and rename them if needed.
467
468 The tests are renamed to match the framework operator names if an
469 alternate name has been used instead.
470 """
471 framework_tests_dir = args.framework_tests_dir
472 new_tests_dir = args.build_dir / "frameworks" / operator
473 os.makedirs(new_tests_dir, exist_ok=True)
474
475 # Get the framework tests operator name
476 if "alternate_names" in test_picks[operator]:
477 alternate_names = test_picks[operator]["alternate_names"]
478 else:
479 alternate_names = [operator]
480
481 # Get the alternate named test directories for the operator
482 for alt_name in alternate_names:
483 test_prefix = f"test_{alt_name}"
484 test_dirs = list(framework_tests_dir.glob(f"{test_prefix}_*"))
485
486 # Copy tests to new directory and rename to match framework operator names
487 # - if there is just 1 alternate name, replace the full test prefix
488 # test_add_... -> add_...
489 # - if there are multiple alternate names, just replace the "test"
490 # test_concatv2_... -> concatenation_concatv2_...
491 old_prefix = test_prefix if len(alternate_names) == 1 else "test"
492
493 for tdir in test_dirs:
494 new_test_name = tdir.name.replace(old_prefix, operator)
495 copy_destination = new_tests_dir / new_test_name
496 logger.debug(f"copying test folder {tdir} to {copy_destination}")
497 copy_tree(str(tdir), str(copy_destination))
498
499 logger.info(f"Copied and renamed {len(test_dirs)} framework test folders")
500 return new_tests_dir.parent
501
502
503def get_framework_tests_selection(args, operator, test_picks, op_build_dir):
504 """Get the list of pre-chosen tests with relative paths."""
505 try:
506 tests = test_picks[operator]["tests"]
507 except KeyError:
508 logger.error(f"Framework test selection not defined for {operator} operator")
509 raise (GenConformanceError())
510
511 test_paths = [op_build_dir / operator / test for test in tests]
512 return test_paths
513
514
515def parse_args(argv=None):
516 """Parse the arguments."""
517 parser = argparse.ArgumentParser()
Jeremy Johnson88588622022-07-12 16:42:29 +0100518 profiles = list(PROFILE_OPS_INFO.keys())
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100519 profiles.append(PROFILES_ALL)
Jeremy Johnson88588622022-07-12 16:42:29 +0100520 parser.add_argument(
521 "--profile",
522 dest="profile",
523 choices=profiles,
524 default=profiles[0],
525 type=str,
526 help=f"TOSA profile (default is {profiles[0]})",
527 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100528 parser.add_argument(
529 "--operators",
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100530 "--op",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100531 type=str,
532 nargs="*",
533 help="The operator(s) to create tests for, if not supplied all tests will be created",
534 )
535 parser.add_argument(
Jeremy Johnson88588622022-07-12 16:42:29 +0100536 "--unit-tests",
537 dest="unit_tests",
538 choices=["operator", "framework", "both"],
539 default="operator",
540 type=str,
541 help="Which unit tests are produced (default is operator)",
542 )
543 parser.add_argument(
544 "--test-type",
545 dest="test_type",
546 choices=["positive", "negative", "both"],
547 default="both",
548 type=str,
549 help="Type of tests produced (default is both)",
550 )
551 parser.add_argument(
Jeremy Johnson0a6d1de2023-09-27 14:59:43 +0100552 "--global-random-generation",
553 action="store_true",
554 help="Disable stable random generation of tests that support this mode",
555 )
556 parser.add_argument(
Jeremy Johnson1271c442023-09-05 11:39:26 +0100557 "--lazy-data-generation",
558 action="store_true",
559 help="Enable lazy data generation (only for tosa-mi)",
560 )
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100561 rm_group = parser.add_mutually_exclusive_group(required=True)
562 rm_group.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100563 "--ref-model-directory",
564 dest="ref_model_dir",
565 type=Path,
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100566 help="(DEPRECATED - use ref-model-path) Reference Model directory - with build directory",
567 )
568 rm_group.add_argument(
569 "--ref-model-path",
570 dest="ref_model_path",
571 type=Path,
572 help="Path to TOSA reference model executable",
573 )
574 parser.add_argument(
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100575 "--generate-lib-path",
576 dest="generate_lib_path",
577 type=Path,
578 help=(
579 "Path to TOSA generate library. Defaults to "
580 "the library in the directory of `ref-model-path`"
581 ),
582 )
583 parser.add_argument(
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100584 "--schema-path",
585 "--operator-fbs",
586 dest="schema_path",
587 type=Path,
588 help=(
589 "Path to TOSA reference model flat buffer schema. Defaults to "
590 f"`{cmf.DEFAULT_REF_MODEL_SCHEMA_PATH}` in parents parent directory of `ref-model-path`"
591 ),
592 )
593 parser.add_argument(
594 "--flatc-path",
595 dest="flatc_path",
596 type=Path,
597 help=(
598 "Path to flatc executable. Defaults to "
599 f"`{cmf.DEFAULT_REF_MODEL_BUILD_FLATC_PATH}` in parent directory of `ref-model-path`"
600 ),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100601 )
Jeremy Johnson88588622022-07-12 16:42:29 +0100602 parser.add_argument(
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100603 "--test-version",
604 dest="test_version",
605 choices=TEST_VERSIONS,
606 default=TEST_VERSION_LATEST,
607 help=f"Version of the tests to produce (default is {TEST_VERSION_LATEST})",
608 )
609 parser.add_argument(
610 "--output-type",
611 dest="output_type",
612 choices=OUTPUT_TYPES,
613 default=OUTPUT_TYPE_DEFAULT,
614 help=f"Output file type produced (default is {OUTPUT_TYPE_DEFAULT})",
615 )
616 parser.add_argument(
Jeremy Johnson93d43902022-09-27 12:26:14 +0100617 "--seed",
618 dest="random_seed",
619 default=DEFAULT_SEED,
620 type=int,
621 help="Random test seed",
622 )
623 parser.add_argument(
Jeremy Johnson88588622022-07-12 16:42:29 +0100624 "--framework-tests-directory",
625 dest="framework_tests_dir",
626 type=Path,
627 default=Path.cwd() / "tests",
628 help="The pre-built framework tests directory (default is tests)",
629 )
630 parser.add_argument(
631 "--framework-schema",
632 dest="framework_schema",
633 type=Path,
634 help="Framework flatbuffers schema needed to convert framework models",
635 )
636 parser.add_argument(
637 "--build-directory",
638 dest="build_dir",
639 type=Path,
640 default=Path.cwd() / "conformance_build",
641 help="Temporary build directory for files created during this process (default is conformance_build)",
642 )
643 parser.add_argument(
644 "--output-directory",
645 dest="output_dir",
646 type=Path,
647 default=Path.cwd() / "conformance",
648 help="Output directory (default is conformance)",
649 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100650 script_dir = Path(__file__).parent.absolute()
651 parser.add_argument(
652 "--test-param-json-directory",
653 dest="param_json_dir",
654 type=Path,
655 default=script_dir,
Jeremy Johnson88588622022-07-12 16:42:29 +0100656 help=f"Test parameters (ops info) JSON file directory (default is {script_dir})",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100657 )
658 parser.add_argument(
659 "--convert-all-tests",
660 action="store_true",
661 help="Converts all tests instead of those picked by test_select",
662 )
663 parser.add_argument(
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000664 "--list-tests-to-file",
665 dest="tests_list_file",
666 type=Path,
667 help="Lists out the tests to be generated to a file instead of generating them",
668 )
669 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100670 "--keep-large-files",
671 action="store_true",
672 help="Keeps tests that contain files larger than 30MB in output directory",
673 )
674 parser.add_argument(
675 "--capture-output",
676 action="store_true",
677 help="Prints output of running sh commands",
678 )
679 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100680 "-j",
681 dest="num_cores",
682 type=int,
683 default=6,
684 help="Number of simultaneous jobs to split the tasks into for multiprocessing",
685 )
686 parser.add_argument(
687 "-v",
688 dest="verbosity",
689 action="count",
690 default=0,
691 help="Verbosity (can be used multiple times for more details)",
692 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100693 args = parser.parse_args(argv)
694
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000695 if args.ref_model_dir is not None:
696 # Assume the ref model exe path based on the ref model directory
697 args.ref_model_path = cmf.find_tosa_file(
698 cmf.TosaFileType.REF_MODEL, args.ref_model_dir, False
699 )
700 if not args.ref_model_path.is_file():
701 logger.error(
702 f"Missing reference model binary (--ref-model-path): {args.ref_model_path}"
703 )
704 return None
705 args.ref_model_path = args.ref_model_path.absolute()
706
707 if args.generate_lib_path is None:
708 args.generate_lib_path = cmf.find_tosa_file(
709 cmf.TosaFileType.GENERATE_LIBRARY, args.ref_model_path
710 )
711 if not args.generate_lib_path.is_file():
712 logger.error(
713 f"Missing TOSA generate data library (--generate-lib-path): {args.generate_lib_path}"
714 )
715 return None
716 args.generate_lib_path = args.generate_lib_path.absolute()
717
718 if args.schema_path is None:
719 args.schema_path = cmf.find_tosa_file(
720 cmf.TosaFileType.SCHEMA, args.ref_model_path
721 )
722 if not args.schema_path.is_file():
723 logger.error(
724 f"Missing reference model schema (--schema-path): {args.schema_path}"
725 )
726 return None
727 args.schema_path = args.schema_path.absolute()
728
729 if args.flatc_path is None:
730 args.flatc_path = cmf.find_tosa_file(
731 cmf.TosaFileType.FLATC, args.ref_model_path
732 )
733 if not args.flatc_path.is_file():
734 logger.error(f"Missing flatc binary (--flatc-path): {args.flatc_path}")
735 return None
736 args.flatc_path = args.flatc_path.absolute()
737
738 args.param_json_dir = args.param_json_dir.absolute()
739
740 if args.unit_tests in ["framework", "both"]:
741 logger.warning(
742 "DEPRECATION - Framework tests are not part of TOSA conformance testing"
743 )
744 if not args.framework_schema:
745 logger.error(
746 "Need to supply location of Framework flatbuffers schema via --framework-schema"
747 )
748 return None
749 if not args.framework_tests_dir.is_dir():
750 logger.error(
751 f"Missing or invalid framework tests directory: {args.framework_tests_dir}"
752 )
753 return None
754
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100755 return args
756
757
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +0100758def in_version(test_version, gen_dict):
759 """Check if the selected test_version is compatible with the tests."""
760
761 def version_string_to_numbers(verstr):
762 # Turn the "vM.mm.pp" string into Major, Minor, Patch versions
763 if verstr == TEST_VERSION_LATEST:
764 return (TOSA_VERSION[0], TOSA_VERSION[1], TOSA_VERSION[2])
765 else:
766 match = re.match(REGEX_VERSION, verstr)
767 if match is None:
768 raise KeyError(f"Invalid version string {verstr}")
769 return (int(v) for v in match.groups())
770
771 if "from_version" in gen_dict:
772 selected_version = version_string_to_numbers(test_version)
773 from_version = version_string_to_numbers(gen_dict["from_version"])
774
775 # Check the Major version is compatible, then Minor, and lastly Patch
776 # Unless the versions match, we can exit early due to obvious precedence
777 for sel, fro in zip(selected_version, from_version):
778 if sel < fro:
779 # From version is later than selected version
780 return False
781 elif sel > fro:
782 # From version is earlier than selected version
783 return True
784 # If we get here, the version numbers match exactly
785 return True
786 else:
787 # No specific version info
788 return True
789
790
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000791def _get_log_level(verbosity):
792 loglevels = (logging.WARNING, logging.INFO, logging.DEBUG)
793 verbosity = max(verbosity, 0)
794 return loglevels[min(verbosity, len(loglevels) - 1)]
795
796
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100797def main():
798 args = parse_args()
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000799 if args is None:
800 # Argument processing error
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100801 return 2
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100802
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000803 loglevel = _get_log_level(args.verbosity)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100804 logger.setLevel(loglevel)
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000805 # Set other loggers to a quieter level
806 loglevel = _get_log_level(args.verbosity - 1)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100807 logging.getLogger("test_select").setLevel(loglevel)
808 logging.getLogger("convert2conformance").setLevel(loglevel)
809
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100810 print(f"Output directory: {args.output_dir}")
811
Jeremy Johnson93d43902022-09-27 12:26:14 +0100812 if args.random_seed != DEFAULT_SEED:
813 logger.warning(
814 "Random test seed changed from default, tests will not match official conformance"
815 )
816
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100817 args.build_dir = args.build_dir.resolve()
818 logger.debug(f"Creating build directory: {args.build_dir}")
819 args.build_dir.mkdir(parents=True, exist_ok=True)
820
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000821 if args.tests_list_file is not None:
822 # Try creating tests list file
823 with args.tests_list_file.open("w") as fd:
824 fd.write("")
825
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100826 # TODO: For tosa-mi should really generate tosa-bi profile as well
827 # - for now leave it as subset instead of as superset (for testing)
828 if args.profile == PROFILES_ALL:
829 profiles = list(PROFILE_OPS_INFO.keys())
830 else:
831 profiles = [args.profile]
832
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100833 try:
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100834 for profile in profiles:
835 print(f"Creating conformance tests for TOSA {profile} profile")
836 # Framework unit tests
837 if args.unit_tests in ["framework", "both"]:
838 logger.debug("Creating FRAMEWORK unit tests")
839 test_picks_file = (
840 args.param_json_dir / PROFILE_OPS_INFO[profile]["framework_tests"]
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100841 )
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100842 try:
843 with open(test_picks_file, "r") as fd:
844 test_picks = json.load(fd)
845 except Exception as e:
846 logger.error(
847 f"Couldn't load framework tests info - {test_picks_file}: {e}"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100848 )
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100849 return 1
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100850
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100851 operators = args.operators
852 if not operators:
853 # Create tests for all the operators
854 operators = list(test_picks.keys())
855
856 root_output_dir = (
857 args.output_dir / "frameworks" / "tflite" / "operators"
858 )
859 for op in operators:
860 logger.info(f"FRAMEWORK OP: {op}")
861 if op not in test_picks:
862 logger.warning(
863 f"Framework op {op} not found in {test_picks_file} - skipping"
864 )
865 continue
866
867 op_profiles_list = test_picks[op]["profile"]
868 if (
869 args.profile != PROFILES_ALL
870 and args.profile not in op_profiles_list
871 ):
872 # Skip this operator as not part of the profile chosen
873 logger.debug(f"Skipping {op} as not part of {args.profile}")
874 continue
875
876 logger.debug(f"Copying and renaming {op}")
877 framework_test_dir = copy_rename_framework_tests(
878 args, op, test_picks
879 )
880
881 if args.convert_all_tests:
882 logger.debug("Running and converting all framework tests")
883 framework_tests = None # Don't select any
884 else:
885 logger.debug("Running and converting selected framework tests")
886 framework_tests = get_framework_tests_selection(
887 args, op, test_picks, framework_test_dir
888 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100889 convert_tests(
890 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000891 "positive",
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100892 profile,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100893 op,
894 framework_test_dir,
895 root_output_dir,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100896 op_profiles_list,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100897 tests=framework_tests,
898 trim_op_subdir=True,
899 )
900
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100901 # Operator unit tests
902 if args.unit_tests in ["operator", "both"]:
903 logger.debug("Creating OPERATOR unit tests")
904 test_params_file = (
905 args.param_json_dir
906 / PROFILE_OPS_INFO[profile]["operator_test_params"]
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100907 )
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100908 try:
909 with open(test_params_file, "r") as fd:
910 test_params = json.load(fd)
911 except Exception as e:
912 logger.error(
913 f"Couldn't load operator test params - {test_params_file}: {e}"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100914 )
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100915 return 1
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000916 logger.debug(f"Using config file: {str(test_params_file)}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100917
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100918 operators = args.operators
919 if not operators:
920 # Create tests for all the operators
921 operators = list(test_params.keys())
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100922
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100923 for op in operators:
924 logger.info(f"OPERATOR: {op}")
925 if op not in test_params:
926 logger.warning(
927 f"{op} operator parameters not found in {test_params_file} - skipping"
928 )
929 continue
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100930
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100931 op_profiles_list = test_params[op]["profile"]
932 if (
933 args.profile != PROFILES_ALL
934 and args.profile not in op_profiles_list
935 ):
936 # Skip this operator as not part of the profile chosen
937 logger.debug(f"Skipping {op} as not part of {args.profile}")
938 continue
939
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100940 operator_group = test_params[op]["group"]
941 root_output_dir = args.output_dir / "operators"
Jeremy Johnson1271c442023-09-05 11:39:26 +0100942 supports = (
943 test_params[op]["support_for"]
944 if "support_for" in test_params[op]
945 else []
946 )
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000947 gen_filter = (
948 test_params[op]["gen_filter"]
949 if "gen_filter" in test_params[op]
950 else None
951 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000952
953 # Iterate through the generation groups selecting tests from each
954 for gen_name, gen_dict in test_params[op]["generation"].items():
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +0100955
956 if not in_version(args.test_version, gen_dict):
957 logger.warning(
958 f"{op} [{gen_name}] is not in {args.test_version} - skipping"
959 )
960 continue
961
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000962 no_neg_tests = (
963 "no_negative_tests" in gen_dict
964 and gen_dict["no_negative_tests"] == "true"
965 )
966
967 if no_neg_tests:
968 if args.test_type == "negative":
969 logger.info(
970 f"No negative tests for {op} / generation group {gen_name}"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100971 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000972 continue
973 # Only produce positive tests
974 test_type = "positive"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100975 else:
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000976 test_type = args.test_type
977
978 gen_neg_dim_range = (
979 gen_dict["negative_dim_range"]
980 if "negative_dim_range" in gen_dict
981 else None
982 )
983
Jeremy Johnson0c716862023-04-13 17:18:19 +0100984 # Work out which selection criteria we are using
985 if "selector" in gen_dict:
986 selector_name = gen_dict["selector"]
987 if selector_name not in test_params[op]["selection"]:
988 logger.warn(
989 f"Could not find {selector_name} in selection dict for {op} - using default"
990 )
991 selector_name = "default"
992 else:
993 selector_name = "default"
994 if selector_name not in test_params[op]["selection"]:
995 logger.error(
996 f"Could not find {selector_name} in selection dict for {op}"
997 )
998 raise (GenConformanceError())
999
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001000 op_build_dir = build_op_tests(
1001 args,
1002 test_type,
1003 profile,
1004 op,
1005 gen_name,
1006 gen_dict["generator_args"],
1007 gen_neg_dim_range,
1008 supports=supports,
1009 gen_filter=gen_filter,
1010 selector_info=(test_params_file, selector_name),
1011 )
Jeremy Johnson0c716862023-04-13 17:18:19 +01001012
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001013 if args.tests_list_file is not None:
1014 logger.info("Tests list file extended")
1015 continue
1016
1017 if args.convert_all_tests or "generator_select" in supports:
1018 if test_type in ["positive", "both"]:
1019 logger.info(f"Running and converting all {op} tests")
1020 generate_results(
1021 args, profile, op, op_build_dir, supports=supports
1022 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001023 operator_test_list = None
1024 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001025 logger.info(
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001026 f"Running and converting selection of {op} tests"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +01001027 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001028 # Selection criteria
1029 selection_config = test_params[op]["selection"][
1030 selector_name
1031 ]
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001032 if test_type in ["positive", "both"]:
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001033 if (
1034 "all" in selection_config
1035 and selection_config["all"] == "true"
1036 ):
1037 # Just get all the positive tests
1038 tests_gen, tests_gen2 = tee(
1039 _get_all_tests_list(
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001040 "positive",
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001041 op_build_dir,
1042 op,
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001043 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001044 )
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001045 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001046 ignore_missing = (
1047 gen_name != STANDARD_GENERATOR_GROUP
1048 )
1049
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001050 # Get a selection of positive tests
1051 tests_gen, tests_gen2 = tee(
1052 get_op_tests_selection(
1053 args,
1054 profile,
1055 op,
1056 op_build_dir,
1057 selection_config,
1058 ignore_missing=ignore_missing,
1059 )
1060 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001061 generate_results(
Jeremy Johnson1271c442023-09-05 11:39:26 +01001062 args,
1063 profile,
1064 op,
1065 op_build_dir,
1066 supports=supports,
1067 tests=tests_gen,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001068 )
1069 operator_test_list = list(tests_gen2)
1070 else:
1071 operator_test_list = []
1072 if test_type in ["negative", "both"]:
1073 operator_test_list.extend(
1074 get_op_tests_selection(
1075 args,
1076 profile,
1077 op,
1078 op_build_dir,
1079 selection_config,
1080 negative=True,
1081 )
1082 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001083
1084 tags = (
1085 [gen_name] if gen_name != STANDARD_GENERATOR_GROUP else None
1086 )
1087
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001088 output_dir = convert_tests(
1089 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001090 test_type,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001091 profile,
1092 op,
1093 op_build_dir,
1094 root_output_dir,
1095 op_profiles_list,
Jeremy Johnson1271c442023-09-05 11:39:26 +01001096 supports=supports,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001097 tests=operator_test_list,
1098 group=operator_group,
1099 tags=tags,
1100 )
1101 if not args.keep_large_files:
1102 check_op_tests(args, profile, op, output_dir)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +01001103 except GenConformanceError:
1104 return 1
1105
1106 return 0
1107
1108
1109if __name__ == "__main__":
1110 exit(main())