blob: fcdb089d76cd98ddad32866d880f9345c645b032 [file] [log] [blame]
Jeremy Johnson0ecfa372022-06-30 14:27:56 +01001#!/usr/bin/env python3
Jeremy Johnson14087952024-02-29 16:13:10 +00002# Copyright (c) 2021-2024, ARM Limited.
Jeremy Johnson0ecfa372022-06-30 14:27:56 +01003# SPDX-License-Identifier: Apache-2.0
4"""Build conformance tests.
5
6Steps:
7- Specific input shapes (or tests) are specified and produced by using the
8 settings in the .json files.
9- Tests are selected to produce a good coverage.
10- Tests are run on the reference model to produce the correct output files.
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010011- Tests are converted to JSON and/or copied and saved to desired output directory.
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010012"""
13import argparse
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +000014import copy
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010015import json
16import logging
17import multiprocessing as mp
18import os
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +010019import re
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010020import shlex
21import shutil
22import subprocess
23from functools import partial
24from itertools import tee
25from pathlib import Path
26
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +010027import conformance.model_files as cmf
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010028from conformance.test_select import Operator
Won Jeon3eec59b2024-03-11 22:17:13 +000029from conformance.tosa_profiles import TosaProfiles
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010030from convert2conformance.convert2conformance import main as c2c_main
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010031from convert2conformance.convert2conformance import OUTPUT_TYPE_DEFAULT
32from convert2conformance.convert2conformance import OUTPUT_TYPES
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010033from distutils.dir_util import copy_tree
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +010034from serializer.tosa_serializer import TOSA_VERSION
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010035
36logging.basicConfig()
37logger = logging.getLogger("tosa_verif_conformance_generator")
38
Jeremy Johnsonbf9ee052024-05-01 17:26:24 +010039# Configuration
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010040PROFILE_OPS_INFO = {
Jeremy Johnsonbf9ee052024-05-01 17:26:24 +010041 "operator_test_params": "tosa_ext_profile_ops_info.json",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010042}
Won Jeon3eec59b2024-03-11 22:17:13 +000043PROFILES_EXTENSIONS_ALL = "all"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010044
Jeremy Johnson93d43902022-09-27 12:26:14 +010045DEFAULT_SEED = 42
46
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +000047# When there is a dictionary of generator argument lists (groups) only the
48# standard group will have negative tests generated for it
49STANDARD_GENERATOR_GROUP = "standard"
50
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010051TEST_VERSION_LATEST = "latest"
52TEST_VERSION_V0_60_0 = "v0.60.0"
53TEST_VERSIONS = (TEST_VERSION_LATEST, TEST_VERSION_V0_60_0)
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +010054REGEX_VERSION = re.compile(r"v([0-9]+)\.([0-9]+)\.([0-9]+)")
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010055
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010056
57class GenConformanceError(Exception):
58 """Generation error reporting exception."""
59
60 pass
61
62
63def _run_sh_command(args, cwd, full_cmd):
64 """Run an external command and capture stdout/stderr."""
65 # Quote the command line for printing
Jeremy Johnsonaf090182024-02-13 18:25:39 +000066 try:
67 full_cmd_esc = [shlex.quote(x) for x in full_cmd]
68 except Exception as e:
69 raise Exception(f"Error quoting command: {e}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010070 if args.capture_output:
Jeremy Johnsonaf090182024-02-13 18:25:39 +000071 logger.info(f"Command: {full_cmd_esc}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010072
73 rc = subprocess.run(
74 full_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
75 )
76
77 if args.capture_output:
Jeremy Johnsondd975b82024-02-28 17:29:13 +000078 stderr = rc.stderr.decode("utf-8")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010079 stdout = rc.stdout.decode("utf-8")
Jeremy Johnsondd975b82024-02-28 17:29:13 +000080 logger.info(f"stderr: \n{stderr}")
Jeremy Johnsonaf090182024-02-13 18:25:39 +000081 logger.info(f"stdout: \n{stdout}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +010082 if rc.returncode != 0:
83
84 raise Exception(
85 "Error running command: {}.\n{}".format(
86 " ".join(full_cmd_esc), rc.stderr.decode("utf-8")
87 )
88 )
89 return (rc.stdout, rc.stderr)
90
91
Won Jeon3eec59b2024-03-11 22:17:13 +000092def _supports_for_enabled(profile_ext):
93 # The "supports_for" part of the config only works for MI and related extensions
94 # TODO - Update with TosaBI etc in future
95 return profile_ext in (
96 TosaProfiles.TosaMI,
97 TosaProfiles.TosaExtFP8E4M3,
98 TosaProfiles.TosaExtFP8E5M2,
99 TosaProfiles.TosaExtBF16,
100 TosaProfiles.TosaExtFFT,
101 )
102
103
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000104def build_op_tests(
Jeremy Johnson1271c442023-09-05 11:39:26 +0100105 args,
106 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +0000107 profile_ext,
Jeremy Johnson1271c442023-09-05 11:39:26 +0100108 operator,
109 group,
110 gen_args_list,
111 gen_neg_dim_range,
112 supports=[],
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000113 gen_filter=None,
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000114 selector_info=None,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000115):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100116 """Build tests for a given operator.
117
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000118 Builds a set of tests based on the given generator arguments list
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100119
120 Returns operator output directory
121 """
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100122 build_tests_cmd = "tosa_verif_build_tests"
Won Jeon3eec59b2024-03-11 22:17:13 +0000123 op_build_dir = args.build_dir / profile_ext / group
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100124
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000125 if gen_filter is None:
126 gen_filter = f"^{operator}$"
127
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000128 build_cmd_base = [
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100129 build_tests_cmd,
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100130 "--generate-lib-path",
131 str(args.generate_lib_path),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100132 "--filter",
Jeremy Johnson1d5dded2024-03-06 10:11:10 +0000133 gen_filter,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100134 "-o",
135 str(op_build_dir),
136 "--seed",
Jeremy Johnson93d43902022-09-27 12:26:14 +0100137 str(args.random_seed),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100138 ]
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000139 if args.verbosity:
140 build_cmd_base.append("-" + ("v" * args.verbosity))
141
142 if args.tests_list_file is not None:
143 build_cmd_base.append("--list-tests")
144
Won Jeon3eec59b2024-03-11 22:17:13 +0000145 if _supports_for_enabled(profile_ext):
146 if "lazy_data_gen" in supports and args.lazy_data_generation:
147 build_cmd_base.append("--lazy-data-generation")
148 if "stable_random_gen" in supports and not args.global_random_generation:
149 build_cmd_base.append("--stable-random-generation")
150 if "random_const_inputs" in supports:
151 build_cmd_base.append("--random-const-inputs")
Jeremy Johnson1271c442023-09-05 11:39:26 +0100152
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000153 if "generator_select" in supports:
154 if selector_info is None:
155 logger.error(
156 "build_op_tests error: generator_select mode without selector information"
157 )
158 raise (GenConformanceError())
159 selector_config, selector_name = selector_info
160 build_cmd_base.extend(
161 [
162 "--test-selection-config",
163 str(selector_config),
164 "--test-selection-criteria",
165 selector_name,
166 ]
167 )
168
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000169 build_cmds_list = []
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100170
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000171 if test_type in ["positive", "both"]:
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100172 # Append extra parameters and run test generator for each set of parameters.
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000173 for arglist in gen_args_list:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000174 build_cmd_pos_test = build_cmd_base.copy()
175 build_cmd_pos_test.extend(["--test-type", "positive"])
176 build_cmd_pos_test.extend(arglist)
177 build_cmds_list.append(build_cmd_pos_test)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100178
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000179 if test_type in ["negative", "both"]:
Jeremy Johnson35396f22023-01-04 17:05:25 +0000180 # Get target-dtypes options and any filter string to limit tests
Jeremy Johnson93d43902022-09-27 12:26:14 +0100181 target_dtypes_args = []
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000182 for arglist in gen_args_list:
Jeremy Johnson93d43902022-09-27 12:26:14 +0100183 idx = 0
184 while idx < len(arglist):
185 if arglist[idx] == "--target-dtype":
186 if arglist[idx + 1] not in target_dtypes_args:
187 target_dtypes_args.extend(arglist[idx : idx + 2])
188 idx += 1 # skip over option (and then argument below)
189 idx += 1
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000190 build_cmd_neg_test = build_cmd_base.copy()
191 build_cmd_neg_test.extend(["--test-type", "negative"])
Jeremy Johnson93d43902022-09-27 12:26:14 +0100192 # Limit sizes of negative tests
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000193 dim_range = gen_neg_dim_range if gen_neg_dim_range is not None else "1,16"
194
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000195 build_cmd_neg_test.extend(["--tensor-dim-range", dim_range])
196 build_cmd_neg_test.extend(target_dtypes_args)
197 build_cmds_list.append(build_cmd_neg_test)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100198
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000199 logger.info(f"Creating {operator} tests in {len(build_cmds_list)} batch(es)")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100200 error = False
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000201 for i, cmd in enumerate(build_cmds_list):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100202 try:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000203 raw_stdout, _ = _run_sh_command(args, args.ref_model_path.parent, cmd)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100204 logger.info(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000205 f"{operator} test batch {(i+1)}/{len(build_cmds_list)} created successfully"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100206 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000207
208 if args.tests_list_file is not None:
209 with args.tests_list_file.open("a") as fd:
210 fd.write(raw_stdout.decode("utf-8"))
211
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100212 except Exception as e:
213 logger.error(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000214 f"{operator} test batch {(i+1)}/{len(build_cmds_list)} unsuccessful, skipping"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100215 )
216 logger.error(f" build_op_tests error: {e} ")
217 error = True
218 if error:
219 raise (GenConformanceError())
220
221 return op_build_dir
222
223
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000224def _check_to_include_test(test_type, test_name):
225 """Check test name for inclusion based on test_type, returns True to include."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100226
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000227 if test_type == "both":
228 return True
229 else:
230 error_test = "_ERRORIF_" in test_name
231 return (error_test and test_type == "negative") or (
232 not error_test and test_type == "positive"
233 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100234
235
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000236def _get_all_tests_list(test_type, test_root_dir, operator):
237 """Create test list from tests in the test_dir based on chosen type."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100238 test_dir = test_root_dir / operator
239 if not test_dir.is_dir():
240 # Tests are split into multiple dirs, for example: conv2d_1x1, conv2d_3x3
241 test_dir = test_root_dir
242 directories = [
243 tdir for tdir in test_dir.glob("*") if tdir.name.startswith(operator)
244 ]
245 else:
246 directories = [test_dir]
247
248 tests = []
249 for tdir in directories:
250 tests.extend(
251 [
252 test
253 for test in tdir.glob("*")
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000254 if _check_to_include_test(test_type, test.name)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100255 ]
256 )
257 return tests
258
259
Won Jeon3eec59b2024-03-11 22:17:13 +0000260def generate_results(
261 args, profile_ext, operator, op_build_dir, supports=[], tests=None
262):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100263 """Run tests on reference model and save result to the test directory."""
Won Jeon3eec59b2024-03-11 22:17:13 +0000264 if _supports_for_enabled(profile_ext):
265 if "lazy_data_gen" in supports and args.lazy_data_generation:
266 logger.info("Skipping running tests due to lazy data gen")
267 return
Jeremy Johnson1271c442023-09-05 11:39:26 +0100268
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100269 num_cores = args.num_cores
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100270
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100271 # Use the test runner
272 ref_cmd_base = [
273 "tosa_verif_run_tests",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100274 "--ref-model-path",
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100275 str(args.ref_model_path),
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100276 "--schema-path",
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100277 str(args.schema_path),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100278 "-j",
279 str(num_cores),
280 "-v",
281 "-t",
282 ]
283 ref_cmds = []
284
285 if not tests:
286 # Do not need to run ERRORIF tests as they don't have result files
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000287 tests = _get_all_tests_list("positive", op_build_dir, operator)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100288
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000289 skipped = 0
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100290 for test in tests:
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100291 desc = test / "desc.json"
292 with desc.open("r") as fd:
293 test_desc = json.load(fd)
294 if "meta" in test_desc and "compliance" in test_desc["meta"]:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000295 skipped += 1
296 logger.debug(
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100297 f"Skipping generating results for new compliance test - {str(test)}"
298 )
299 continue
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100300 ref_cmd = ref_cmd_base.copy()
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100301 ref_cmd.append(str(test.absolute()))
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100302 ref_cmds.append(ref_cmd)
303
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000304 if skipped:
305 logger.info(f"{skipped} new compliance tests skipped for results generation")
306
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100307 fail_string = "UNEXPECTED_FAILURE"
308 failed_counter = 0
309
310 job_pool = mp.Pool(args.num_cores)
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100311 sh_partial = partial(_run_sh_command, args, args.ref_model_path.parent)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100312 pool_results = job_pool.map(sh_partial, ref_cmds)
313 job_pool.close()
314 job_pool.join()
315
316 # Use captured output for run_sh_command to work out if test passed.
317 for i, rc in enumerate(pool_results):
318 if fail_string in str(rc[0]):
319 logger.error(f"Test {i+1}/{len(ref_cmds)}: {ref_cmds[i][-1]} failed.")
320 failed_counter += 1
321 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000322 logger.debug(f"Test {i+1}/{len(ref_cmds)}: {ref_cmds[i][-1]} passed.")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100323
324 logger.info(f"{len(ref_cmds)-failed_counter}/{len(ref_cmds)} tests passed")
325 logger.info("Ran tests on model and saved results of passing tests")
326
327
328def convert_tests(
329 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000330 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +0000331 profile_ext,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100332 operator,
333 op_build_dir,
334 output_dir,
Won Jeon3eec59b2024-03-11 22:17:13 +0000335 op_profiles_extensions_list,
Jeremy Johnson1271c442023-09-05 11:39:26 +0100336 supports=[],
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100337 tests=None,
338 group=None,
339 trim_op_subdir=False,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000340 tags=None,
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100341):
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100342 """Convert/copy tests to output directory."""
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100343 if group:
344 output_dir = output_dir / group
345
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100346 c2c_args_base = ["--strict"]
347 c2c_args_base.extend(["--schema-path", str(args.schema_path)])
348 c2c_args_base.extend(["--flatc-path", str(args.flatc_path)])
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100349 c2c_args_base.extend(["--output-type", args.output_type])
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100350 # This op maybe in more than one profile - e.g. tosa_bi and tosa_mi
351 # even if we are only producing tests for tosa_mi
Won Jeon3eec59b2024-03-11 22:17:13 +0000352 for op_profile in op_profiles_extensions_list:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000353 c2c_args_base.extend(["--profile", op_profile])
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000354 if tags is not None:
355 for tag in tags:
356 c2c_args_base.extend(["--tag", tag])
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100357 if args.framework_schema:
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000358 c2c_args_base.extend(["--framework-schema", str(args.framework_schema)])
Won Jeon3eec59b2024-03-11 22:17:13 +0000359 if _supports_for_enabled(profile_ext):
360 if "lazy_data_gen" in supports and args.lazy_data_generation:
361 c2c_args_base.append("--lazy-data-generation")
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000362 c2c_args_base.append("--output-directory")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100363
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000364 c2c_args_list = []
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100365
366 if not tests:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000367 tests = _get_all_tests_list(test_type, op_build_dir, operator)
Won Jeon3eec59b2024-03-11 22:17:13 +0000368 logger.info(f"Converting all {profile_ext} profile tests of type {test_type}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100369
370 # Controls if we copy the tests in their operator sub-directory or not
371 output_dir_relative_pos = -1 if trim_op_subdir else -2
372 for test in tests:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000373 logger.debug(f"Test chosen: {test}")
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000374 c2c_args = c2c_args_base.copy()
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100375 full_output_directory = output_dir / test.relative_to(
376 *test.parts[:output_dir_relative_pos]
377 )
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000378 c2c_args.append(str(full_output_directory))
379 c2c_args.append(str(test))
380 c2c_args_list.append(c2c_args)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100381
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000382 if len(c2c_args_list) == 0:
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000383 logger.error(
384 f"No tests found for {operator}. Nothing to convert in {op_build_dir}"
385 )
386 raise (GenConformanceError())
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100387
388 job_pool = mp.Pool(args.num_cores)
389
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000390 pool_results = job_pool.map(c2c_main, c2c_args_list)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100391 job_pool.close()
392 job_pool.join()
393
394 failed_counter = 0
395 for i, result in enumerate(pool_results):
396 if result != 0:
397 logger.error(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000398 f"test {i+1}/{len(c2c_args_list)}: {c2c_args_list[i][-1]} failed to convert."
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100399 )
400 failed_counter += 1
401 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000402 logger.debug(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000403 f"test {i+1}/{len(c2c_args_list)}: {c2c_args_list[i][-1]} converted"
404 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100405 logger.info(
Jeremy Johnsondd8d9c22022-12-12 14:18:10 +0000406 f"{len(c2c_args_list)-failed_counter}/{len(c2c_args_list)} tests successfully converted"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100407 )
408
409 if failed_counter > 0:
410 logger.error(f"Stopping due to {failed_counter} test conversion errors")
411 raise (GenConformanceError())
412
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100413 logger.info("Converted/copied tests and saved to output directory")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100414
415 return output_dir
416
417
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100418def get_op_tests_selection(
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000419 args,
Won Jeon3eec59b2024-03-11 22:17:13 +0000420 profile_ext,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000421 operator,
422 op_build_dir,
423 selection_config,
424 negative=False,
425 ignore_missing=False,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100426):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100427 """Use test picker to get subsection of tests generated."""
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000428 # Need a full copy of the config as the selector updates it
429 config = copy.deepcopy(selection_config)
Won Jeon3eec59b2024-03-11 22:17:13 +0000430 logger.info(
431 "Choosing {} tests for {}".format(
432 ("negative" if negative else "positive"), profile_ext
433 )
434 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100435 try:
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100436 op = Operator.registry[operator](
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000437 op_build_dir, config, negative=negative, ignore_missing=ignore_missing
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100438 )
439 except KeyError:
440 logger.error(f"{operator} operator is not supported by test_select")
441 raise (GenConformanceError())
442
443 return op.select_tests()
444
445
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100446def check_op_tests(args, profile, operator, output_dir):
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100447 """Move test folders than contain files larger than 30MB to new directory."""
448 destination_dir = str(args.output_dir) + "_large_files"
449
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000450 # Include all tests - both positive and negative
451 tests = _get_all_tests_list("both", output_dir, operator)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100452 if not tests:
453 logger.error(
454 f"Couldn't find any tests to size check for {operator} in {output_dir}"
455 )
456 raise (GenConformanceError())
457
458 for tdir in tests:
459 move_dir = False
460 test_files = [file for file in tdir.glob("*")]
461 for file in test_files:
462 file_size = os.stat(file).st_size / 1024**2
463 if file_size > 30:
464 move_dir = True
465
466 if move_dir:
467 move_destination = destination_dir / tdir.relative_to(output_dir)
468 logger.warning(
469 f"{tdir.relative_to(output_dir)} contains files that are too large (>30MB), test moved to new folder: {destination_dir}"
470 )
471
472 if move_destination.is_dir():
473 logger.warning(
474 f"{move_destination} directory already exists, deleting existing."
475 )
476 shutil.rmtree(str(move_destination))
477 shutil.move(str(tdir), move_destination)
478
479
480def copy_rename_framework_tests(args, operator, test_picks):
481 """Copy framework tests into new folder and rename them if needed.
482
483 The tests are renamed to match the framework operator names if an
484 alternate name has been used instead.
485 """
486 framework_tests_dir = args.framework_tests_dir
487 new_tests_dir = args.build_dir / "frameworks" / operator
488 os.makedirs(new_tests_dir, exist_ok=True)
489
490 # Get the framework tests operator name
491 if "alternate_names" in test_picks[operator]:
492 alternate_names = test_picks[operator]["alternate_names"]
493 else:
494 alternate_names = [operator]
495
496 # Get the alternate named test directories for the operator
497 for alt_name in alternate_names:
498 test_prefix = f"test_{alt_name}"
499 test_dirs = list(framework_tests_dir.glob(f"{test_prefix}_*"))
500
501 # Copy tests to new directory and rename to match framework operator names
502 # - if there is just 1 alternate name, replace the full test prefix
503 # test_add_... -> add_...
504 # - if there are multiple alternate names, just replace the "test"
505 # test_concatv2_... -> concatenation_concatv2_...
506 old_prefix = test_prefix if len(alternate_names) == 1 else "test"
507
508 for tdir in test_dirs:
509 new_test_name = tdir.name.replace(old_prefix, operator)
510 copy_destination = new_tests_dir / new_test_name
511 logger.debug(f"copying test folder {tdir} to {copy_destination}")
512 copy_tree(str(tdir), str(copy_destination))
513
514 logger.info(f"Copied and renamed {len(test_dirs)} framework test folders")
515 return new_tests_dir.parent
516
517
518def get_framework_tests_selection(args, operator, test_picks, op_build_dir):
519 """Get the list of pre-chosen tests with relative paths."""
520 try:
521 tests = test_picks[operator]["tests"]
522 except KeyError:
523 logger.error(f"Framework test selection not defined for {operator} operator")
524 raise (GenConformanceError())
525
526 test_paths = [op_build_dir / operator / test for test in tests]
527 return test_paths
528
529
530def parse_args(argv=None):
531 """Parse the arguments."""
532 parser = argparse.ArgumentParser()
Won Jeon3eec59b2024-03-11 22:17:13 +0000533 profiles = TosaProfiles.profiles()
534 profiles.append(PROFILES_EXTENSIONS_ALL)
Jeremy Johnson88588622022-07-12 16:42:29 +0100535 parser.add_argument(
536 "--profile",
537 dest="profile",
538 choices=profiles,
Won Jeon3eec59b2024-03-11 22:17:13 +0000539 default=[TosaProfiles.TosaBI],
Jeremy Johnson88588622022-07-12 16:42:29 +0100540 type=str,
Won Jeon3eec59b2024-03-11 22:17:13 +0000541 nargs="*",
542 help=f"TOSA profile (default is {TosaProfiles.TosaBI})",
Jeremy Johnson88588622022-07-12 16:42:29 +0100543 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100544 parser.add_argument(
545 "--operators",
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100546 "--op",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100547 type=str,
548 nargs="*",
549 help="The operator(s) to create tests for, if not supplied all tests will be created",
550 )
551 parser.add_argument(
Won Jeon3eec59b2024-03-11 22:17:13 +0000552 "--extension",
553 dest="extension",
554 choices=TosaProfiles.extensions() + [PROFILES_EXTENSIONS_ALL],
555 default=[],
556 type=str,
557 nargs="*",
558 help="TOSA extension(s) to create tests for, if not supplied all tests will be created",
559 )
560 parser.add_argument(
Jeremy Johnson88588622022-07-12 16:42:29 +0100561 "--unit-tests",
562 dest="unit_tests",
563 choices=["operator", "framework", "both"],
564 default="operator",
565 type=str,
566 help="Which unit tests are produced (default is operator)",
567 )
568 parser.add_argument(
569 "--test-type",
570 dest="test_type",
571 choices=["positive", "negative", "both"],
572 default="both",
573 type=str,
574 help="Type of tests produced (default is both)",
575 )
576 parser.add_argument(
Jeremy Johnson0a6d1de2023-09-27 14:59:43 +0100577 "--global-random-generation",
578 action="store_true",
579 help="Disable stable random generation of tests that support this mode",
580 )
581 parser.add_argument(
Jeremy Johnson1271c442023-09-05 11:39:26 +0100582 "--lazy-data-generation",
583 action="store_true",
584 help="Enable lazy data generation (only for tosa-mi)",
585 )
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100586 rm_group = parser.add_mutually_exclusive_group(required=True)
587 rm_group.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100588 "--ref-model-directory",
589 dest="ref_model_dir",
590 type=Path,
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100591 help="(DEPRECATED - use ref-model-path) Reference Model directory - with build directory",
592 )
593 rm_group.add_argument(
594 "--ref-model-path",
595 dest="ref_model_path",
596 type=Path,
597 help="Path to TOSA reference model executable",
598 )
599 parser.add_argument(
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100600 "--generate-lib-path",
601 dest="generate_lib_path",
602 type=Path,
603 help=(
604 "Path to TOSA generate library. Defaults to "
605 "the library in the directory of `ref-model-path`"
606 ),
607 )
608 parser.add_argument(
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100609 "--schema-path",
610 "--operator-fbs",
611 dest="schema_path",
612 type=Path,
613 help=(
614 "Path to TOSA reference model flat buffer schema. Defaults to "
615 f"`{cmf.DEFAULT_REF_MODEL_SCHEMA_PATH}` in parents parent directory of `ref-model-path`"
616 ),
617 )
618 parser.add_argument(
619 "--flatc-path",
620 dest="flatc_path",
621 type=Path,
622 help=(
623 "Path to flatc executable. Defaults to "
624 f"`{cmf.DEFAULT_REF_MODEL_BUILD_FLATC_PATH}` in parent directory of `ref-model-path`"
625 ),
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100626 )
Jeremy Johnson88588622022-07-12 16:42:29 +0100627 parser.add_argument(
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +0100628 "--test-version",
629 dest="test_version",
630 choices=TEST_VERSIONS,
631 default=TEST_VERSION_LATEST,
632 help=f"Version of the tests to produce (default is {TEST_VERSION_LATEST})",
633 )
634 parser.add_argument(
635 "--output-type",
636 dest="output_type",
637 choices=OUTPUT_TYPES,
638 default=OUTPUT_TYPE_DEFAULT,
639 help=f"Output file type produced (default is {OUTPUT_TYPE_DEFAULT})",
640 )
641 parser.add_argument(
Jeremy Johnson93d43902022-09-27 12:26:14 +0100642 "--seed",
643 dest="random_seed",
644 default=DEFAULT_SEED,
645 type=int,
646 help="Random test seed",
647 )
648 parser.add_argument(
Jeremy Johnson88588622022-07-12 16:42:29 +0100649 "--framework-tests-directory",
650 dest="framework_tests_dir",
651 type=Path,
652 default=Path.cwd() / "tests",
653 help="The pre-built framework tests directory (default is tests)",
654 )
655 parser.add_argument(
656 "--framework-schema",
657 dest="framework_schema",
658 type=Path,
659 help="Framework flatbuffers schema needed to convert framework models",
660 )
661 parser.add_argument(
662 "--build-directory",
663 dest="build_dir",
664 type=Path,
665 default=Path.cwd() / "conformance_build",
666 help="Temporary build directory for files created during this process (default is conformance_build)",
667 )
668 parser.add_argument(
669 "--output-directory",
670 dest="output_dir",
671 type=Path,
672 default=Path.cwd() / "conformance",
673 help="Output directory (default is conformance)",
674 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100675 script_dir = Path(__file__).parent.absolute()
676 parser.add_argument(
677 "--test-param-json-directory",
678 dest="param_json_dir",
679 type=Path,
680 default=script_dir,
Jeremy Johnson88588622022-07-12 16:42:29 +0100681 help=f"Test parameters (ops info) JSON file directory (default is {script_dir})",
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100682 )
683 parser.add_argument(
Won Jeon3eec59b2024-03-11 22:17:13 +0000684 "--test-params-json-config",
685 "--config",
686 dest="param_config",
687 type=Path,
688 help="Test parameters (ops info) JSON file (overrides --test-param-json-directory)",
689 )
690 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100691 "--convert-all-tests",
692 action="store_true",
693 help="Converts all tests instead of those picked by test_select",
694 )
695 parser.add_argument(
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000696 "--list-tests-to-file",
697 dest="tests_list_file",
698 type=Path,
699 help="Lists out the tests to be generated to a file instead of generating them",
700 )
701 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100702 "--keep-large-files",
703 action="store_true",
704 help="Keeps tests that contain files larger than 30MB in output directory",
705 )
706 parser.add_argument(
707 "--capture-output",
708 action="store_true",
709 help="Prints output of running sh commands",
710 )
711 parser.add_argument(
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100712 "-j",
713 dest="num_cores",
714 type=int,
715 default=6,
716 help="Number of simultaneous jobs to split the tasks into for multiprocessing",
717 )
718 parser.add_argument(
719 "-v",
720 dest="verbosity",
721 action="count",
722 default=0,
723 help="Verbosity (can be used multiple times for more details)",
724 )
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100725 args = parser.parse_args(argv)
726
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000727 if args.ref_model_dir is not None:
728 # Assume the ref model exe path based on the ref model directory
729 args.ref_model_path = cmf.find_tosa_file(
730 cmf.TosaFileType.REF_MODEL, args.ref_model_dir, False
731 )
732 if not args.ref_model_path.is_file():
733 logger.error(
734 f"Missing reference model binary (--ref-model-path): {args.ref_model_path}"
735 )
736 return None
737 args.ref_model_path = args.ref_model_path.absolute()
738
739 if args.generate_lib_path is None:
740 args.generate_lib_path = cmf.find_tosa_file(
741 cmf.TosaFileType.GENERATE_LIBRARY, args.ref_model_path
742 )
743 if not args.generate_lib_path.is_file():
744 logger.error(
745 f"Missing TOSA generate data library (--generate-lib-path): {args.generate_lib_path}"
746 )
747 return None
748 args.generate_lib_path = args.generate_lib_path.absolute()
749
750 if args.schema_path is None:
751 args.schema_path = cmf.find_tosa_file(
752 cmf.TosaFileType.SCHEMA, args.ref_model_path
753 )
754 if not args.schema_path.is_file():
755 logger.error(
756 f"Missing reference model schema (--schema-path): {args.schema_path}"
757 )
758 return None
759 args.schema_path = args.schema_path.absolute()
760
761 if args.flatc_path is None:
762 args.flatc_path = cmf.find_tosa_file(
763 cmf.TosaFileType.FLATC, args.ref_model_path
764 )
765 if not args.flatc_path.is_file():
766 logger.error(f"Missing flatc binary (--flatc-path): {args.flatc_path}")
767 return None
768 args.flatc_path = args.flatc_path.absolute()
769
770 args.param_json_dir = args.param_json_dir.absolute()
771
Won Jeon3eec59b2024-03-11 22:17:13 +0000772 if args.param_config is not None:
773 args.param_config = args.param_config.absolute()
774
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000775 if args.unit_tests in ["framework", "both"]:
776 logger.warning(
777 "DEPRECATION - Framework tests are not part of TOSA conformance testing"
778 )
779 if not args.framework_schema:
780 logger.error(
781 "Need to supply location of Framework flatbuffers schema via --framework-schema"
782 )
783 return None
784 if not args.framework_tests_dir.is_dir():
785 logger.error(
786 f"Missing or invalid framework tests directory: {args.framework_tests_dir}"
787 )
788 return None
789
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100790 return args
791
792
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +0100793def in_version(test_version, gen_dict):
794 """Check if the selected test_version is compatible with the tests."""
795
796 def version_string_to_numbers(verstr):
797 # Turn the "vM.mm.pp" string into Major, Minor, Patch versions
798 if verstr == TEST_VERSION_LATEST:
799 return (TOSA_VERSION[0], TOSA_VERSION[1], TOSA_VERSION[2])
800 else:
801 match = re.match(REGEX_VERSION, verstr)
802 if match is None:
803 raise KeyError(f"Invalid version string {verstr}")
804 return (int(v) for v in match.groups())
805
806 if "from_version" in gen_dict:
807 selected_version = version_string_to_numbers(test_version)
808 from_version = version_string_to_numbers(gen_dict["from_version"])
809
810 # Check the Major version is compatible, then Minor, and lastly Patch
811 # Unless the versions match, we can exit early due to obvious precedence
812 for sel, fro in zip(selected_version, from_version):
813 if sel < fro:
814 # From version is later than selected version
815 return False
816 elif sel > fro:
817 # From version is earlier than selected version
818 return True
819 # If we get here, the version numbers match exactly
820 return True
821 else:
822 # No specific version info
823 return True
824
825
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000826def _get_log_level(verbosity):
827 loglevels = (logging.WARNING, logging.INFO, logging.DEBUG)
828 verbosity = max(verbosity, 0)
829 return loglevels[min(verbosity, len(loglevels) - 1)]
830
831
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100832def main():
833 args = parse_args()
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000834 if args is None:
835 # Argument processing error
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100836 return 2
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100837
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000838 loglevel = _get_log_level(args.verbosity)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100839 logger.setLevel(loglevel)
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000840 # Set other loggers to a quieter level
841 loglevel = _get_log_level(args.verbosity - 1)
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100842 logging.getLogger("test_select").setLevel(loglevel)
843 logging.getLogger("convert2conformance").setLevel(loglevel)
844
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100845 print(f"Output directory: {args.output_dir}")
846
Jeremy Johnson93d43902022-09-27 12:26:14 +0100847 if args.random_seed != DEFAULT_SEED:
848 logger.warning(
849 "Random test seed changed from default, tests will not match official conformance"
850 )
851
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100852 args.build_dir = args.build_dir.resolve()
853 logger.debug(f"Creating build directory: {args.build_dir}")
854 args.build_dir.mkdir(parents=True, exist_ok=True)
855
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000856 if args.tests_list_file is not None:
857 # Try creating tests list file
858 with args.tests_list_file.open("w") as fd:
859 fd.write("")
860
Won Jeon3eec59b2024-03-11 22:17:13 +0000861 if PROFILES_EXTENSIONS_ALL in args.profile:
862 profiles = TosaProfiles.profiles()
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100863 else:
Won Jeon3eec59b2024-03-11 22:17:13 +0000864 profiles = args.profile
865
866 if PROFILES_EXTENSIONS_ALL in args.extension:
867 extensions = TosaProfiles.extensions()
868 else:
869 extensions = args.extension
Jeremy Johnsonbf9ee052024-05-01 17:26:24 +0100870
Won Jeon3eec59b2024-03-11 22:17:13 +0000871 profileExtList = profiles + extensions
872 profileExtDone = []
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100873
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100874 try:
Won Jeon3eec59b2024-03-11 22:17:13 +0000875 for profile_ext in profileExtList:
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100876 # Framework unit tests
877 if args.unit_tests in ["framework", "both"]:
Won Jeon3eec59b2024-03-11 22:17:13 +0000878 logger.error("Framework test support has been removed")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100879
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100880 # Operator unit tests
881 if args.unit_tests in ["operator", "both"]:
882 logger.debug("Creating OPERATOR unit tests")
Won Jeon3eec59b2024-03-11 22:17:13 +0000883 if args.param_config is None:
Jeremy Johnsonbf9ee052024-05-01 17:26:24 +0100884 # Use default config
885 config = PROFILE_OPS_INFO["operator_test_params"]
886 test_params_file = args.param_json_dir / config
Won Jeon3eec59b2024-03-11 22:17:13 +0000887 else:
888 test_params_file = args.param_config
889
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100890 try:
891 with open(test_params_file, "r") as fd:
892 test_params = json.load(fd)
893 except Exception as e:
894 logger.error(
895 f"Couldn't load operator test params - {test_params_file}: {e}"
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100896 )
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100897 return 1
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000898 logger.debug(f"Using config file: {str(test_params_file)}")
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100899
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100900 operators = args.operators
901 if not operators:
902 # Create tests for all the operators
903 operators = list(test_params.keys())
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100904
Won Jeon3eec59b2024-03-11 22:17:13 +0000905 print(
906 f"Creating conformance tests for TOSA {profile_ext} profile/extension"
907 )
908
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100909 for op in operators:
910 logger.info(f"OPERATOR: {op}")
911 if op not in test_params:
912 logger.warning(
913 f"{op} operator parameters not found in {test_params_file} - skipping"
914 )
915 continue
Jeremy Johnson0ecfa372022-06-30 14:27:56 +0100916
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100917 operator_group = test_params[op]["group"]
918 root_output_dir = args.output_dir / "operators"
Won Jeon3eec59b2024-03-11 22:17:13 +0000919 supports = test_params[op].get("support_for", [])
920 gen_filter = test_params[op].get("gen_filter", None)
921 old_profile_info = test_params[op].get("profile", [])
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000922
923 # Iterate through the generation groups selecting tests from each
924 for gen_name, gen_dict in test_params[op]["generation"].items():
Won Jeon3eec59b2024-03-11 22:17:13 +0000925 supports_any = gen_dict.get("supports_any", [])
926 supports_all = gen_dict.get("supports_all", [])
927
928 # Fall back for old configs
929 if not supports_all and not supports_any:
930 if not old_profile_info:
931 logger.error(
932 f"generator {gen_name} for {op} is missing supports_all/supports_any"
933 )
934 raise (GenConformanceError())
935 else:
936 supports_any = old_profile_info
937
938 supported = supports_any + supports_all
939
940 if profile_ext not in supported:
941 logger.info(
942 f"No match for profile/extension {profile_ext} for generation group {gen_name} - skipping"
943 )
944 continue
945
946 if any(p in supported for p in profileExtDone):
947 logger.info(
948 f"Already used this generator {gen_name} before - skipping"
949 )
950 continue
951
952 if profile_ext not in supports_any and not (
953 len(supports_all) > 0
954 and all(p in profileExtList for p in supports_all)
955 ):
956 logger.info(
957 f"Profile/extension {profile_ext} is not in {supports_any} or the profiles/extensions chosen do not meet all the requirements of {supports_all} - skipping"
958 )
959 continue
Jeremy Johnsonfd8c8fe2023-10-23 11:55:38 +0100960
961 if not in_version(args.test_version, gen_dict):
962 logger.warning(
963 f"{op} [{gen_name}] is not in {args.test_version} - skipping"
964 )
965 continue
966
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000967 no_neg_tests = (
968 "no_negative_tests" in gen_dict
969 and gen_dict["no_negative_tests"] == "true"
970 )
971
972 if no_neg_tests:
973 if args.test_type == "negative":
974 logger.info(
975 f"No negative tests for {op} / generation group {gen_name}"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100976 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000977 continue
978 # Only produce positive tests
979 test_type = "positive"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100980 else:
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +0000981 test_type = args.test_type
982
983 gen_neg_dim_range = (
984 gen_dict["negative_dim_range"]
985 if "negative_dim_range" in gen_dict
986 else None
987 )
988
Jeremy Johnson0c716862023-04-13 17:18:19 +0100989 # Work out which selection criteria we are using
990 if "selector" in gen_dict:
991 selector_name = gen_dict["selector"]
992 if selector_name not in test_params[op]["selection"]:
993 logger.warn(
994 f"Could not find {selector_name} in selection dict for {op} - using default"
995 )
996 selector_name = "default"
997 else:
998 selector_name = "default"
Won Jeon3eec59b2024-03-11 22:17:13 +0000999
Jeremy Johnson0c716862023-04-13 17:18:19 +01001000 if selector_name not in test_params[op]["selection"]:
1001 logger.error(
1002 f"Could not find {selector_name} in selection dict for {op}"
1003 )
1004 raise (GenConformanceError())
1005
Won Jeon3eec59b2024-03-11 22:17:13 +00001006 if test_params[op]["selection"][selector_name].get(
1007 "generator_select", False
1008 ):
1009 # Extend the support to include the new test selection in the generator
1010 supports = supports + ["generator_select"]
1011
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001012 op_build_dir = build_op_tests(
1013 args,
1014 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +00001015 profile_ext,
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001016 op,
1017 gen_name,
1018 gen_dict["generator_args"],
1019 gen_neg_dim_range,
1020 supports=supports,
1021 gen_filter=gen_filter,
1022 selector_info=(test_params_file, selector_name),
1023 )
Jeremy Johnson0c716862023-04-13 17:18:19 +01001024
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001025 if args.tests_list_file is not None:
1026 logger.info("Tests list file extended")
1027 continue
1028
1029 if args.convert_all_tests or "generator_select" in supports:
1030 if test_type in ["positive", "both"]:
1031 logger.info(f"Running and converting all {op} tests")
1032 generate_results(
Won Jeon3eec59b2024-03-11 22:17:13 +00001033 args,
1034 profile_ext,
1035 op,
1036 op_build_dir,
1037 supports=supports,
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001038 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001039 operator_test_list = None
1040 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001041 logger.info(
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001042 f"Running and converting selection of {op} tests"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +01001043 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001044 # Selection criteria
1045 selection_config = test_params[op]["selection"][
1046 selector_name
1047 ]
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001048 if test_type in ["positive", "both"]:
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001049 if (
1050 "all" in selection_config
1051 and selection_config["all"] == "true"
1052 ):
1053 # Just get all the positive tests
1054 tests_gen, tests_gen2 = tee(
1055 _get_all_tests_list(
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001056 "positive",
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001057 op_build_dir,
1058 op,
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001059 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001060 )
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001061 else:
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001062 ignore_missing = (
1063 gen_name != STANDARD_GENERATOR_GROUP
1064 )
1065
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001066 # Get a selection of positive tests
1067 tests_gen, tests_gen2 = tee(
1068 get_op_tests_selection(
1069 args,
Won Jeon3eec59b2024-03-11 22:17:13 +00001070 profile_ext,
Jeremy Johnson76c6a552023-09-11 09:30:02 +01001071 op,
1072 op_build_dir,
1073 selection_config,
1074 ignore_missing=ignore_missing,
1075 )
1076 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001077 generate_results(
Jeremy Johnson1271c442023-09-05 11:39:26 +01001078 args,
Won Jeon3eec59b2024-03-11 22:17:13 +00001079 profile_ext,
Jeremy Johnson1271c442023-09-05 11:39:26 +01001080 op,
1081 op_build_dir,
1082 supports=supports,
1083 tests=tests_gen,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001084 )
1085 operator_test_list = list(tests_gen2)
1086 else:
1087 operator_test_list = []
1088 if test_type in ["negative", "both"]:
1089 operator_test_list.extend(
1090 get_op_tests_selection(
1091 args,
Won Jeon3eec59b2024-03-11 22:17:13 +00001092 profile_ext,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001093 op,
1094 op_build_dir,
1095 selection_config,
1096 negative=True,
1097 )
1098 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001099
1100 tags = (
1101 [gen_name] if gen_name != STANDARD_GENERATOR_GROUP else None
1102 )
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001103 output_dir = convert_tests(
1104 args,
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001105 test_type,
Won Jeon3eec59b2024-03-11 22:17:13 +00001106 profile_ext,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001107 op,
1108 op_build_dir,
1109 root_output_dir,
Won Jeon3eec59b2024-03-11 22:17:13 +00001110 supported,
Jeremy Johnson1271c442023-09-05 11:39:26 +01001111 supports=supports,
Jeremy Johnsonfd05bb32023-02-07 16:39:24 +00001112 tests=operator_test_list,
1113 group=operator_group,
1114 tags=tags,
1115 )
1116 if not args.keep_large_files:
Won Jeon3eec59b2024-03-11 22:17:13 +00001117 check_op_tests(args, profile_ext, op, output_dir)
1118
1119 profileExtDone.append(profile_ext)
1120
Jeremy Johnson0ecfa372022-06-30 14:27:56 +01001121 except GenConformanceError:
1122 return 1
1123
1124 return 0
1125
1126
1127if __name__ == "__main__":
1128 exit(main())