blob: 0839cec67c2313418b1026a51aa1d4788a2b4442 [file] [log] [blame]
Jeremy Johnsonaf090182024-02-13 18:25:39 +00001# Copyright (c) 2020-2024, ARM Limited.
Jeremy Johnson5c1364c2022-01-13 15:04:21 +00002# SPDX-License-Identifier: Apache-2.0
Eric Kunzee5e26762020-10-13 16:11:07 -07003import argparse
Jeremy Johnsonaf090182024-02-13 18:25:39 +00004import json
5import logging
Eric Kunzee5e26762020-10-13 16:11:07 -07006import re
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +01007import sys
Jeremy Johnson65ba8092023-10-09 16:31:13 +01008from pathlib import Path
Eric Kunzee5e26762020-10-13 16:11:07 -07009
Jeremy Johnson65ba8092023-10-09 16:31:13 +010010import conformance.model_files as cmf
Jeremy Johnsonaf090182024-02-13 18:25:39 +000011import generator.tosa_test_select as tts
Jeremy Johnson2ec34942021-12-14 16:34:05 +000012from generator.tosa_test_gen import TosaTestGen
13from serializer.tosa_serializer import dtype_str_to_val
James Ward24dbc422022-10-19 12:20:31 +010014from serializer.tosa_serializer import DTypeNames
Eric Kunzee5e26762020-10-13 16:11:07 -070015
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010016OPTION_FP_VALUES_RANGE = "--fp-values-range"
17
Jeremy Johnsonaf090182024-02-13 18:25:39 +000018logging.basicConfig()
19logger = logging.getLogger("tosa_verif_build_tests")
20
Jeremy Johnson5c1364c2022-01-13 15:04:21 +000021
Jeremy Johnsona4d907e2023-10-26 13:53:14 +010022# Used for parsing a comma-separated list of integers/floats in a string
23# to an actual list of integers/floats with special case max
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010024def str_to_list(in_s, is_float=False):
Jeremy Johnsona4d907e2023-10-26 13:53:14 +010025 """Converts a comma-separated list string to a python list of numbers."""
Kevin Cheng550ccc52021-03-03 11:21:43 -080026 lst = in_s.split(",")
Eric Kunzee5e26762020-10-13 16:11:07 -070027 out_list = []
28 for i in lst:
Jeremy Johnsona4d907e2023-10-26 13:53:14 +010029 # Special case for allowing maximum FP numbers
30 if is_float and i in ("-max", "max"):
31 val = i
32 else:
33 val = float(i) if is_float else int(i)
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010034 out_list.append(val)
Eric Kunzee5e26762020-10-13 16:11:07 -070035 return out_list
36
Kevin Cheng550ccc52021-03-03 11:21:43 -080037
Eric Kunzee5e26762020-10-13 16:11:07 -070038def auto_int(x):
Kevin Cheng550ccc52021-03-03 11:21:43 -080039 """Converts hex/dec argument values to an int"""
Eric Kunzee5e26762020-10-13 16:11:07 -070040 return int(x, 0)
41
Kevin Cheng550ccc52021-03-03 11:21:43 -080042
Jeremy Johnson00423432022-09-12 17:27:37 +010043def parseArgs(argv):
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010044 """Parse the command line arguments."""
45 if argv is None:
46 argv = sys.argv[1:]
47
48 if OPTION_FP_VALUES_RANGE in argv:
49 # Argparse fix for hyphen (minus values) in argument values
50 # convert "ARG VAL" into "ARG=VAL"
51 # Example --fp-values-range -2.0,2.0 -> --fp-values-range=-2.0,2.0
52 new_argv = []
53 idx = 0
54 while idx < len(argv):
55 arg = argv[idx]
56 if arg == OPTION_FP_VALUES_RANGE and idx + 1 < len(argv):
57 val = argv[idx + 1]
58 if val.startswith("-"):
59 arg = f"{arg}={val}"
60 idx += 1
61 new_argv.append(arg)
62 idx += 1
63 argv = new_argv
Eric Kunzee5e26762020-10-13 16:11:07 -070064
65 parser = argparse.ArgumentParser()
Jeremy Johnson1271c442023-09-05 11:39:26 +010066
Jeremy Johnsonaf090182024-02-13 18:25:39 +000067 filter_group = parser.add_argument_group("test filter options")
Jeremy Johnson1271c442023-09-05 11:39:26 +010068 ops_group = parser.add_argument_group("operator options")
69 tens_group = parser.add_argument_group("tensor options")
70
Kevin Cheng550ccc52021-03-03 11:21:43 -080071 parser.add_argument(
72 "-o", dest="output_dir", type=str, default="vtest", help="Test output directory"
73 )
Eric Kunzee5e26762020-10-13 16:11:07 -070074
Kevin Cheng550ccc52021-03-03 11:21:43 -080075 parser.add_argument(
76 "--seed",
77 dest="random_seed",
78 default=42,
79 type=int,
80 help="Random seed for test generation",
81 )
Eric Kunzee5e26762020-10-13 16:11:07 -070082
Jeremy Johnson0a6d1de2023-09-27 14:59:43 +010083 parser.add_argument(
84 "--stable-random-generation",
85 dest="stable_rng",
86 action="store_true",
87 help="Produces less variation (when the test-generator changes) in the test output using the same options",
88 )
89
Jeremy Johnsonaf090182024-02-13 18:25:39 +000090 filter_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -080091 "--filter",
92 dest="filter",
93 default="",
94 type=str,
95 help="Filter operator test names by this expression",
96 )
Eric Kunzee5e26762020-10-13 16:11:07 -070097
Kevin Cheng550ccc52021-03-03 11:21:43 -080098 parser.add_argument(
Jeremy Johnsonaf090182024-02-13 18:25:39 +000099 "-v",
100 "--verbose",
101 dest="verbose",
102 action="count",
103 default=0,
104 help="Verbose operation",
Kevin Cheng550ccc52021-03-03 11:21:43 -0800105 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700106
Kevin Cheng550ccc52021-03-03 11:21:43 -0800107 parser.add_argument(
Jeremy Johnson1271c442023-09-05 11:39:26 +0100108 "--lazy-data-generation",
109 dest="lazy_data_gen",
110 action="store_true",
111 help="Tensor data generation is delayed til test running",
112 )
113
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100114 parser.add_argument(
115 "--generate-lib-path",
116 dest="generate_lib_path",
117 type=Path,
118 help="Path to TOSA generate library.",
119 )
120
Jeremy Johnson1271c442023-09-05 11:39:26 +0100121 # Constraints on tests
122 tens_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800123 "--tensor-dim-range",
124 dest="tensor_shape_range",
125 default="1,64",
126 type=lambda x: str_to_list(x),
127 help="Min,Max range of tensor shapes",
128 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700129
Jeremy Johnson1271c442023-09-05 11:39:26 +0100130 tens_group.add_argument(
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100131 OPTION_FP_VALUES_RANGE,
132 dest="tensor_fp_value_range",
133 default="0.0,1.0",
134 type=lambda x: str_to_list(x, is_float=True),
135 help="Min,Max range of floating point tensor values",
136 )
137
Jeremy Johnson1271c442023-09-05 11:39:26 +0100138 ops_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800139 "--max-batch-size",
140 dest="max_batch_size",
141 default=1,
James Ward30124a82023-02-02 14:56:33 +0000142 type=positive_integer_type,
Kevin Cheng550ccc52021-03-03 11:21:43 -0800143 help="Maximum batch size for NHWC tests",
144 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700145
Jeremy Johnson1271c442023-09-05 11:39:26 +0100146 ops_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800147 "--max-conv-padding",
148 dest="max_conv_padding",
149 default=1,
150 type=int,
151 help="Maximum padding for Conv tests",
152 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700153
Jeremy Johnson1271c442023-09-05 11:39:26 +0100154 ops_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800155 "--max-conv-dilation",
156 dest="max_conv_dilation",
157 default=2,
158 type=int,
159 help="Maximum dilation for Conv tests",
160 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700161
Jeremy Johnson1271c442023-09-05 11:39:26 +0100162 ops_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800163 "--max-conv-stride",
164 dest="max_conv_stride",
165 default=2,
166 type=int,
167 help="Maximum stride for Conv tests",
168 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700169
Jeremy Johnson1271c442023-09-05 11:39:26 +0100170 ops_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800171 "--max-pooling-padding",
172 dest="max_pooling_padding",
173 default=1,
174 type=int,
175 help="Maximum padding for pooling tests",
176 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700177
Jeremy Johnson1271c442023-09-05 11:39:26 +0100178 ops_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800179 "--max-pooling-stride",
180 dest="max_pooling_stride",
181 default=2,
182 type=int,
183 help="Maximum stride for pooling tests",
184 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700185
Jeremy Johnson1271c442023-09-05 11:39:26 +0100186 ops_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800187 "--max-pooling-kernel",
188 dest="max_pooling_kernel",
Jeremy Johnson39f127b2022-01-25 17:51:26 +0000189 default=3,
Kevin Cheng550ccc52021-03-03 11:21:43 -0800190 type=int,
Jeremy Johnson39f127b2022-01-25 17:51:26 +0000191 help="Maximum kernel for pooling tests",
Kevin Cheng550ccc52021-03-03 11:21:43 -0800192 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700193
Jeremy Johnson1271c442023-09-05 11:39:26 +0100194 ops_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800195 "--num-rand-permutations",
196 dest="num_rand_permutations",
197 default=6,
198 type=int,
199 help="Number of random permutations for a given shape/rank for randomly-sampled parameter spaces",
200 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700201
Jeremy Johnson1271c442023-09-05 11:39:26 +0100202 ops_group.add_argument(
Jeremy Johnsona0e03f32022-06-13 17:48:09 +0100203 "--max-resize-output-dim",
204 dest="max_resize_output_dim",
205 default=1000,
206 type=int,
207 help="Upper limit on width and height output dimensions for `resize` op. Default: 1000",
208 )
209
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100210 # Targeting a specific shape/rank/dtype
Jeremy Johnson1271c442023-09-05 11:39:26 +0100211 tens_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800212 "--target-shape",
213 dest="target_shapes",
214 action="append",
215 default=[],
216 type=lambda x: str_to_list(x),
217 help="Create tests with a particular input tensor shape, e.g., 1,4,4,8 (may be repeated for tests that require multiple input shapes)",
218 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700219
Jeremy Johnson1271c442023-09-05 11:39:26 +0100220 tens_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800221 "--target-rank",
222 dest="target_ranks",
223 action="append",
224 default=None,
225 type=lambda x: auto_int(x),
226 help="Create tests with a particular input tensor rank",
227 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700228
James Ward24dbc422022-10-19 12:20:31 +0100229 # Used for parsing a comma-separated list of integers in a string
Jeremy Johnson1271c442023-09-05 11:39:26 +0100230 tens_group.add_argument(
Kevin Cheng550ccc52021-03-03 11:21:43 -0800231 "--target-dtype",
232 dest="target_dtypes",
233 action="append",
234 default=None,
235 type=lambda x: dtype_str_to_val(x),
James Ward24dbc422022-10-19 12:20:31 +0100236 help=f"Create test with a particular DType: [{', '.join([d.lower() for d in DTypeNames[1:]])}] (may be repeated)",
Kevin Cheng550ccc52021-03-03 11:21:43 -0800237 )
Eric Kunzee5e26762020-10-13 16:11:07 -0700238
Jeremy Johnson1271c442023-09-05 11:39:26 +0100239 ops_group.add_argument(
Matthew Haddon818ab902021-07-27 09:12:49 +0100240 "--num-const-inputs-concat",
241 dest="num_const_inputs_concat",
242 default=0,
243 choices=[0, 1, 2, 3],
244 type=int,
245 help="Allow constant input tensors for concat operator",
246 )
247
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000248 filter_group.add_argument(
Matthew Haddon74567092021-07-16 15:38:20 +0100249 "--test-type",
250 dest="test_type",
Jeremy Johnson5c1364c2022-01-13 15:04:21 +0000251 choices=["positive", "negative", "both"],
Matthew Haddon74567092021-07-16 15:38:20 +0100252 default="positive",
253 type=str,
Jeremy Johnson39f127b2022-01-25 17:51:26 +0000254 help="type of tests produced, positive, negative, or both",
Matthew Haddon74567092021-07-16 15:38:20 +0100255 )
Jeremy Johnson39f127b2022-01-25 17:51:26 +0000256
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000257 filter_group.add_argument(
258 "--test-selection-config",
259 dest="selection_config",
260 type=Path,
261 help="enables test selection, this is the path to the JSON test selection config file, will use the default selection specified for each op unless --selection-criteria is supplied",
262 )
263
264 filter_group.add_argument(
265 "--test-selection-criteria",
266 dest="selection_criteria",
267 help="enables test selection, this is the selection criteria to use from the selection config",
268 )
269
270 parser.add_argument(
271 "--list-tests",
272 dest="list_tests",
273 action="store_true",
274 help="lists the tests that will be generated and then exits",
275 )
276
Jeremy Johnson1271c442023-09-05 11:39:26 +0100277 ops_group.add_argument(
Jeremy Johnson39f127b2022-01-25 17:51:26 +0000278 "--allow-pooling-and-conv-oversizes",
279 dest="oversize",
Jeremy Johnsonae0c1c62022-02-10 17:27:34 +0000280 action="store_true",
Jeremy Johnson39f127b2022-01-25 17:51:26 +0000281 help="allow oversize padding, stride and kernel tests",
282 )
283
Jeremy Johnson1271c442023-09-05 11:39:26 +0100284 ops_group.add_argument(
Jeremy Johnson00423432022-09-12 17:27:37 +0100285 "--zero-point",
286 dest="zeropoint",
287 default=None,
288 type=int,
289 help="set a particular zero point for all valid positive tests",
290 )
291
Jeremy Johnsona0848c62022-09-15 15:01:30 +0100292 parser.add_argument(
293 "--dump-const-tensors",
294 dest="dump_consts",
295 action="store_true",
296 help="output const tensors as numpy files for inspection",
297 )
298
Jeremy Johnson1271c442023-09-05 11:39:26 +0100299 ops_group.add_argument(
Jeremy Johnsonb2099702023-04-12 15:59:01 +0100300 "--level-8k-sizes",
301 dest="level8k",
302 action="store_true",
Jeremy Johnson1271c442023-09-05 11:39:26 +0100303 help="create level 8k size tests",
Jeremy Johnsonb2099702023-04-12 15:59:01 +0100304 )
305
Jeremy Johnson00423432022-09-12 17:27:37 +0100306 args = parser.parse_args(argv)
Eric Kunzee5e26762020-10-13 16:11:07 -0700307
308 return args
309
Eric Kunzee5e26762020-10-13 16:11:07 -0700310
James Ward30124a82023-02-02 14:56:33 +0000311def positive_integer_type(argv_str):
312 value = int(argv_str)
313 if value <= 0:
314 msg = f"{argv_str} is not a valid positive integer"
315 raise argparse.ArgumentTypeError(msg)
316 return value
317
318
Jeremy Johnson00423432022-09-12 17:27:37 +0100319def main(argv=None):
Eric Kunzee5e26762020-10-13 16:11:07 -0700320
Jeremy Johnson00423432022-09-12 17:27:37 +0100321 args = parseArgs(argv)
Eric Kunzee5e26762020-10-13 16:11:07 -0700322
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000323 loglevels = (logging.WARNING, logging.INFO, logging.DEBUG)
324 loglevel = loglevels[min(args.verbose, len(loglevels) - 1)]
325 logger.setLevel(loglevel)
326
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100327 if not args.lazy_data_gen:
328 if args.generate_lib_path is None:
329 args.generate_lib_path = cmf.find_tosa_file(
330 cmf.TosaFileType.GENERATE_LIBRARY, Path("reference_model"), False
331 )
332 if not args.generate_lib_path.is_file():
333 print(
334 f"Argument error: Generate library (--generate-lib-path) not found - {str(args.generate_lib_path)}"
335 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000336 return 2
Jeremy Johnson65ba8092023-10-09 16:31:13 +0100337
Eric Kunzee5e26762020-10-13 16:11:07 -0700338 ttg = TosaTestGen(args)
339
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000340 # Determine if test selection mode is enabled or not
341 selectionMode = (
342 args.selection_config is not None or args.selection_criteria is not None
343 )
344 selectionCriteria = (
345 "default" if args.selection_criteria is None else args.selection_criteria
346 )
347 if args.selection_config is not None:
348 # Try loading the selection config
349 if not args.generate_lib_path.is_file():
350 print(
351 f"Argument error: Test selection config (--test-selection-config) not found {str(args.selection_config)}"
352 )
353 return 2
354 with args.selection_config.open("r") as fd:
355 selectionCfg = json.load(fd)
356 else:
357 # Fallback to using anything defined in the TosaTestGen list
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000358 selectionCfg = ttg.TOSA_OP_LIST
Jeremy Johnson00dc22e2024-03-13 17:06:06 +0000359 # Set up some defaults to create a quick testing selection
360 selectDefault = {"default": {"permutes": ["rank", "dtype"], "maximum": 10}}
361 for opName in selectionCfg:
362 if (
363 "selection" not in selectionCfg[opName]
364 or "default" not in selectionCfg[opName]["selection"]
365 ):
366 selectionCfg[opName]["selection"] = selectDefault
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000367
Jeremy Johnson5c1364c2022-01-13 15:04:21 +0000368 if args.test_type == "both":
369 testType = ["positive", "negative"]
Matthew Haddon1c00b712021-10-01 15:51:03 +0100370 else:
371 testType = [args.test_type]
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000372
Matthew Haddon74567092021-07-16 15:38:20 +0100373 results = []
Matthew Haddon1c00b712021-10-01 15:51:03 +0100374 for test_type in testType:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000375 testList = tts.TestList(selectionCfg, selectionCriteria=selectionCriteria)
Jeremy Johnson7bf0cb92023-10-31 14:37:54 +0000376 try:
377 for opName in ttg.TOSA_OP_LIST:
378 if re.match(args.filter + ".*", opName):
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000379 tests = ttg.genOpTestList(
380 opName,
381 shapeFilter=args.target_shapes,
382 rankFilter=args.target_ranks,
383 dtypeFilter=args.target_dtypes,
384 testType=test_type,
Matthew Haddon1c00b712021-10-01 15:51:03 +0100385 )
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000386 for testOpName, testStr, dtype, error, shapeList, argsDict in tests:
387 if "real_name" in ttg.TOSA_OP_LIST[testOpName]:
388 name = ttg.TOSA_OP_LIST[testOpName]["real_name"]
389 else:
390 name = testOpName
391 test = tts.Test(
392 name, testStr, dtype, error, shapeList, argsDict, testOpName
393 )
394 testList.add(test)
Jeremy Johnson7bf0cb92023-10-31 14:37:54 +0000395 except Exception as e:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000396 logger.error(f"INTERNAL ERROR: Failure generating test lists for {opName}")
Jeremy Johnson7bf0cb92023-10-31 14:37:54 +0000397 raise e
Matthew Haddon848efb42021-09-09 12:30:53 +0100398
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000399 if not selectionMode:
400 # Allow all tests to be selected
401 tests = testList.all()
402 else:
403 # Use the random number generator to shuffle the test list
404 # and select the per op tests from it
Jeremy Johnson0a6d1de2023-09-27 14:59:43 +0100405 tests = testList.select(ttg.global_rng)
Matthew Haddon1c00b712021-10-01 15:51:03 +0100406
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000407 if args.list_tests:
408 for test in tests:
409 print(test)
410 continue
411
412 print(f"{len(tests)} matching {test_type} tests")
413
Jeremy Johnson7bf0cb92023-10-31 14:37:54 +0000414 try:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000415 for test in tests:
416 opName = test.testOpName
Jeremy Johnson7bf0cb92023-10-31 14:37:54 +0000417 results.append(
418 ttg.serializeTest(
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000419 opName,
420 str(test),
421 test.dtype,
422 test.error,
423 test.shapeList,
424 test.argsDict,
Jeremy Johnson7bf0cb92023-10-31 14:37:54 +0000425 )
426 )
427 except Exception as e:
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000428 logger.error(f"INTERNAL ERROR: Failure creating test output for {opName}")
Jeremy Johnson7bf0cb92023-10-31 14:37:54 +0000429 raise e
Matthew Haddon74567092021-07-16 15:38:20 +0100430
Jeremy Johnsondd975b82024-02-28 17:29:13 +0000431 if results.count(False):
432 raise Exception(f"Failed to create {results.count(False)} tests")
433
Jeremy Johnsonaf090182024-02-13 18:25:39 +0000434 if not args.list_tests:
435 print(f"Done creating {len(results)} tests")
436 return 0
Matthew Haddon74567092021-07-16 15:38:20 +0100437
Eric Kunzee5e26762020-10-13 16:11:07 -0700438
Kevin Cheng550ccc52021-03-03 11:21:43 -0800439if __name__ == "__main__":
Eric Kunzee5e26762020-10-13 16:11:07 -0700440 exit(main())