blob: b348f508695217ad335cd9408d4027431d22cf7e [file] [log] [blame]
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +00001"""Template test runner class for running TOSA tests."""
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +01002# Copyright (c) 2020-2023, ARM Limited.
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +00003# SPDX-License-Identifier: Apache-2.0
Eric Kunzee5e26762020-10-13 16:11:07 -07004import json
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +00005from enum import IntEnum
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +00006
Jeremy Johnsone2b5e872023-09-14 17:02:09 +01007import schemavalidation.schemavalidation as sch
8from checker.color_print import LogColors
9from checker.color_print import print_color
10from checker.color_print import set_print_in_color
11from checker.tosa_result_checker import set_print_result
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000012from checker.tosa_result_checker import test_check
13from json2fbbin import json2fbbin
Jeremy Johnsone2b5e872023-09-14 17:02:09 +010014from runner.tosa_test_presets import TOSA_REFCOMPLIANCE_RUNNER
15
16
17def isComplianceModeDotProduct(testDesc):
18 """Checks the test descriptor for DOT_PRODUCT compliance mode."""
19 if (
20 "meta" in testDesc
21 and "compliance" in testDesc["meta"]
22 and "tensors" in testDesc["meta"]["compliance"]
23 ):
24 for _, t in testDesc["meta"]["compliance"]["tensors"].items():
25 if "mode" in t and t["mode"] == "DOT_PRODUCT":
26 return True
27 return False
28
29
30def getRunnerResultFilePath(resultFilePath, sutModule):
31 """Return the result file path with the runner specific naming."""
32 return resultFilePath.with_suffix(f".{sutModule}{resultFilePath.suffix}")
33
34
35def getBoundsResultFilePath(resultFilePath, sutModule=None):
36 """Return the bounds result file with/without runner specific naming."""
37 boundsFilePath = resultFilePath.parent / f"bounds_{resultFilePath.name}"
38 if sutModule is not None:
39 boundsFilePath = boundsFilePath.with_suffix(
40 f".{sutModule}{boundsFilePath.suffix}"
41 )
42 return boundsFilePath
Eric Kunzee5e26762020-10-13 16:11:07 -070043
Kevin Cheng550ccc52021-03-03 11:21:43 -080044
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000045class TosaTestInvalid(Exception):
46 """Exception raised for errors loading test description.
Eric Kunzee5e26762020-10-13 16:11:07 -070047
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000048 Attributes:
49 path - full path to missing test description file
50 exception = underlying exception
51 """
Eric Kunzee5e26762020-10-13 16:11:07 -070052
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000053 def __init__(self, path, exception):
54 """Initialize test not found error."""
55 self.path = path
56 self.exception = exception
57 self.message = "Invalid test, could not read test description {}: {}".format(
58 self.path, str(self.exception)
59 )
60 super().__init__(self.message)
Kevin Cheng550ccc52021-03-03 11:21:43 -080061
Eric Kunzee5e26762020-10-13 16:11:07 -070062
63class TosaTestRunner:
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000064 """TOSA Test Runner template class for systems under test."""
Eric Kunzee5e26762020-10-13 16:11:07 -070065
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010066 def __init__(self, args, runnerArgs, testDirPath):
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000067 """Initialize and load JSON meta data file."""
Eric Kunzee5e26762020-10-13 16:11:07 -070068 self.args = args
69 self.runnerArgs = runnerArgs
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010070 self.testDir = str(testDirPath)
71 self.testDirPath = testDirPath
72 self.testName = self.testDirPath.name
Jeremy Johnson9c2fe6e2023-10-04 16:55:04 +010073 self.verify_lib_path = args.verify_lib_path
Eric Kunzee5e26762020-10-13 16:11:07 -070074
Jeremy Johnson015c3552022-02-23 12:15:03 +000075 set_print_in_color(not args.no_color)
Jeremy Johnsone2b5e872023-09-14 17:02:09 +010076 # Stop the result checker printing anything - we will do it
77 set_print_result(False)
Jeremy Johnson015c3552022-02-23 12:15:03 +000078
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000079 # Check if we want to run binary and if its already converted
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010080 descFilePath = testDirPath / "desc.json"
81 descBinFilePath = testDirPath / "desc_binary.json"
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000082 if args.binary:
83 if descBinFilePath.is_file():
84 descFilePath = descBinFilePath
Eric Kunzee5e26762020-10-13 16:11:07 -070085
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000086 try:
87 # Load the json test file
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010088 with descFilePath.open("r") as fd:
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000089 self.testDesc = json.load(fd)
Jeremy Johnsone2b5e872023-09-14 17:02:09 +010090 # Validate the json with the schema
91 sch.TestDescSchemaValidator().validate_config(self.testDesc)
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000092 except Exception as e:
93 raise TosaTestInvalid(str(descFilePath), e)
94
95 # Convert to binary if needed
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +010096 tosaFilePath = testDirPath / self.testDesc["tosa_file"]
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +000097 if args.binary and tosaFilePath.suffix == ".json":
98 # Convert tosa JSON to binary
99 json2fbbin.json_to_fbbin(
Jeremy Johnsonf0348ea2023-09-27 16:10:59 +0100100 args.flatc_path,
101 args.schema_path,
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000102 tosaFilePath,
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100103 testDirPath,
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000104 )
105 # Write new desc_binary file
106 self.testDesc["tosa_file"] = tosaFilePath.stem + ".tosa"
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100107 with descBinFilePath.open("w") as fd:
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000108 json.dump(self.testDesc, fd, indent=2)
109 descFilePath = descBinFilePath
110
111 # Set location of desc.json (or desc_binary.json) file in use
112 self.descFile = str(descFilePath)
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100113 self.descFilePath = descFilePath
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000114
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100115 # Check for compliance mode - need to run refmodel to get results
116 if "meta" in self.testDesc and "compliance" in self.testDesc["meta"]:
117 self.complianceMode = True
118 if "expected_result" in self.testDesc:
119 if self.args.verbose:
120 print("Warning: fixing conflicting compliance mode in test.desc")
121 self.testDesc.pop("expected_result")
122 else:
123 self.complianceMode = False
124
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000125 def skipTest(self):
Jeremy Johnson88588622022-07-12 16:42:29 +0100126 """Check if the test is skipped due to test type or profile selection."""
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000127 expectedFailure = self.testDesc["expected_failure"]
128 if self.args.test_type == "negative" and not expectedFailure:
Jeremy Johnson88588622022-07-12 16:42:29 +0100129 return True, "non-negative type"
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000130 elif self.args.test_type == "positive" and expectedFailure:
Jeremy Johnson88588622022-07-12 16:42:29 +0100131 return True, "non-positive type"
132 if self.args.profile:
133 profile = self.testDesc["profile"] if "profile" in self.testDesc else []
134 if self.args.profile not in profile:
135 return True, "non-{} profile".format(self.args.profile)
136 return False, ""
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000137
138 def runTestGraph(self):
139 """Override with function that calls system under test."""
Eric Kunzee5e26762020-10-13 16:11:07 -0700140 pass
141
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000142 def testResult(self, tosaGraphResult, graphMessage=None):
143 """Work out test result based on graph result and output files."""
144 expectedFailure = self.testDesc["expected_failure"]
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100145 print_check_result = False
146
147 sutModule = self.__module__
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000148
149 if tosaGraphResult == TosaTestRunner.TosaGraphResult.TOSA_VALID:
150 if expectedFailure:
151 result = TosaTestRunner.Result.UNEXPECTED_PASS
152 resultMessage = "Expected failure test incorrectly passed"
153 else:
154 # Work through all the results produced by the testing, assuming success
155 # but overriding this with any failures found
156 result = TosaTestRunner.Result.EXPECTED_PASS
157 messages = []
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100158
159 # Go through each output result checking it
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000160 for resultNum, resultFileName in enumerate(self.testDesc["ofm_file"]):
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100161 resultFilePath = self.testDirPath / resultFileName
162
163 # Work out the file to check against (if any)
164 if self.complianceMode and sutModule != TOSA_REFCOMPLIANCE_RUNNER:
165 conformanceFilePath = getRunnerResultFilePath(
166 resultFilePath, TOSA_REFCOMPLIANCE_RUNNER
167 )
168 if isComplianceModeDotProduct(self.testDesc):
169 conformanceBoundsPath = getBoundsResultFilePath(
170 resultFilePath, TOSA_REFCOMPLIANCE_RUNNER
171 )
172 else:
173 # Not expecting a bounds file for this test
174 conformanceBoundsPath = None
175 elif "expected_result_file" in self.testDesc:
176 conformanceBoundsPath = None
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000177 try:
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100178 conformanceFilePath = (
179 self.testDirPath
180 / self.testDesc["expected_result_file"][resultNum]
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000181 )
182 except IndexError:
183 result = TosaTestRunner.Result.INTERNAL_ERROR
184 msg = "Internal error: Missing expected_result_file {} in {}".format(
185 resultNum, self.descFile
186 )
187 messages.append(msg)
188 print(msg)
189 break
190 else:
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100191 # Nothing to check against
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100192 conformanceFilePath = None
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100193 conformanceBoundsPath = None
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000194
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100195 if conformanceFilePath:
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100196 print_check_result = True # Result from checker
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000197 chkResult, tolerance, msg = test_check(
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100198 conformanceFilePath,
199 resultFilePath,
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000200 test_name=self.testName,
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100201 test_desc=self.testDesc,
202 bnd_result_path=conformanceBoundsPath,
203 ofm_name=self.testDesc["ofm_name"][resultNum],
204 verify_lib_path=self.verify_lib_path,
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000205 )
206 # Change EXPECTED_PASS assumption if we have any failures
207 if chkResult != 0:
208 result = TosaTestRunner.Result.UNEXPECTED_FAILURE
209 messages.append(msg)
210 if self.args.verbose:
211 print(msg)
212 else:
213 # No conformance file to verify, just check results file exists
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100214 if not resultFilePath.is_file():
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000215 result = TosaTestRunner.Result.UNEXPECTED_FAILURE
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100216 msg = f"Results file is missing: {resultFilePath}"
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000217 messages.append(msg)
218 print(msg)
219
Jeremy Johnsone4b08ff2022-09-15 10:38:17 +0100220 if resultFilePath.is_file():
221 # Move the resultFilePath to allow subsequent system under
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000222 # tests to create them and to test they have been created
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100223 # and to enable compliance testing against refmodel results
224 resultFilePath.rename(
225 getRunnerResultFilePath(resultFilePath, sutModule)
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000226 )
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100227 if (
228 isComplianceModeDotProduct(self.testDesc)
229 and sutModule == TOSA_REFCOMPLIANCE_RUNNER
230 ):
231 boundsFilePath = getBoundsResultFilePath(resultFilePath)
232 if boundsFilePath.is_file():
233 boundsFilePath = boundsFilePath.rename(
234 getBoundsResultFilePath(resultFilePath, sutModule)
235 )
236 else:
237 result = TosaTestRunner.Result.INTERNAL_ERROR
238 msg = f"Internal error: Missing expected dot product compliance bounds file {boundsFilePath}"
239 messages.append(msg)
240 print(msg)
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000241
242 resultMessage = "\n".join(messages) if len(messages) > 0 else None
243 else:
244 if (
245 expectedFailure
246 and tosaGraphResult == TosaTestRunner.TosaGraphResult.TOSA_ERROR
247 ):
248 result = TosaTestRunner.Result.EXPECTED_FAILURE
249 resultMessage = None
250 else:
251 result = TosaTestRunner.Result.UNEXPECTED_FAILURE
252 resultMessage = graphMessage
253
Jeremy Johnsone2b5e872023-09-14 17:02:09 +0100254 status = "Result" if print_check_result else "Result code"
255 if (
256 result == TosaTestRunner.Result.EXPECTED_FAILURE
257 or result == TosaTestRunner.Result.EXPECTED_PASS
258 ):
259 print_color(LogColors.GREEN, f"{sutModule}: {status} PASS {self.testName}")
260 else:
261 print_color(LogColors.RED, f"{sutModule}: {status} FAIL {self.testName}")
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000262
263 return result, resultMessage
264
Eric Kunzee5e26762020-10-13 16:11:07 -0700265 class Result(IntEnum):
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000266 """Test result codes."""
267
Eric Kunzee5e26762020-10-13 16:11:07 -0700268 EXPECTED_PASS = 0
269 EXPECTED_FAILURE = 1
270 UNEXPECTED_PASS = 2
271 UNEXPECTED_FAILURE = 3
272 INTERNAL_ERROR = 4
Jeremy Johnsonbe1a9402021-12-15 17:14:56 +0000273 SKIPPED = 5
274
275 class TosaGraphResult(IntEnum):
276 """The tosa_graph_result codes."""
277
278 TOSA_VALID = 0
279 TOSA_UNPREDICTABLE = 1
280 TOSA_ERROR = 2
281 OTHER_ERROR = 3