blob: a914cfb471d60d6c32035b3fe9a8af704920bf9e [file] [log] [blame]
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +02001# Process the test results
2# Test status (like passed, or failed with error code)
3
4import argparse
5import re
6import TestScripts.NewParser as parse
7import TestScripts.CodeGen
8from collections import deque
9import os.path
10import csv
Christophe Favergeonf76a8032019-08-09 09:15:50 +010011import TestScripts.ParseTrace
Christophe Favergeon30c03792019-10-03 12:47:41 +010012import colorama
13from colorama import init,Fore, Back, Style
Christophe Favergeon512b1482020-02-07 11:25:11 +010014import sys
15
16resultStatus=0
Christophe Favergeonf76a8032019-08-09 09:15:50 +010017
Christophe Favergeon30c03792019-10-03 12:47:41 +010018init()
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +020019
Christophe Favergeon2942a332020-01-20 14:18:48 +010020
Christophe Favergeon6f8eee92019-10-09 12:21:27 +010021def errorStr(id):
22 if id == 1:
23 return("UNKNOWN_ERROR")
24 if id == 2:
25 return("Equality error")
26 if id == 3:
27 return("Absolute difference error")
28 if id == 4:
29 return("Relative difference error")
30 if id == 5:
31 return("SNR error")
32 if id == 6:
33 return("Different length error")
34 if id == 7:
35 return("Assertion error")
36 if id == 8:
37 return("Memory allocation error")
38 if id == 9:
39 return("Empty pattern error")
40 if id == 10:
41 return("Buffer tail corrupted")
Christophe Favergeonf055bd32019-10-15 12:30:30 +010042 if id == 11:
43 return("Close float error")
Christophe Favergeon6f8eee92019-10-09 12:21:27 +010044
45 return("Unknown error %d" % id)
46
47
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +020048def findItem(root,path):
49 """ Find a node in a tree
50
51 Args:
52 path (list) : A list of node ID
53 This list is describing a path in the tree.
54 By starting from the root and following this path,
55 we can find the node in the tree.
56 Raises:
57 Nothing
58 Returns:
59 TreeItem : A node
60 """
61 # The list is converted into a queue.
62 q = deque(path)
63 q.popleft()
64 c = root
65 while q:
66 n = q.popleft()
67 # We get the children based on its ID and continue
68 c = c[n-1]
69 return(c)
70
71def joinit(iterable, delimiter):
72 # Intersperse a delimiter between element of a list
73 it = iter(iterable)
74 yield next(it)
75 for x in it:
76 yield delimiter
77 yield x
78
79# Return test result as a text tree
80class TextFormatter:
81 def start(self):
82 None
83
84 def printGroup(self,elem,theId):
85 if elem is None:
86 elem = root
87 message=elem.data["message"]
88 if not elem.data["deprecated"]:
89 kind = "Suite"
90 ident = " " * elem.ident
91 if elem.kind == TestScripts.Parser.TreeElem.GROUP:
92 kind = "Group"
93 #print(elem.path)
Christophe Favergeon30c03792019-10-03 12:47:41 +010094 print(Style.BRIGHT + ("%s%s : %s (%d)" % (ident,kind,message,theId)) + Style.RESET_ALL)
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +020095
Christophe Favergeon4f462732019-11-13 14:11:14 +010096 def printTest(self,elem, theId, theError,errorDetail,theLine,passed,cycles,params):
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +020097 message=elem.data["message"]
98 if not elem.data["deprecated"]:
99 kind = "Test"
100 ident = " " * elem.ident
Christophe Favergeon30c03792019-10-03 12:47:41 +0100101 p=Fore.RED + "FAILED" + Style.RESET_ALL
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200102 if passed == 1:
Christophe Favergeon30c03792019-10-03 12:47:41 +0100103 p= Fore.GREEN + "PASSED" + Style.RESET_ALL
104 print("%s%s %s(%d)%s : %s (cycles = %d)" % (ident,message,Style.BRIGHT,theId,Style.RESET_ALL,p,cycles))
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200105 if params:
106 print("%s %s" % (ident,params))
107 if passed != 1:
Christophe Favergeon6f8eee92019-10-09 12:21:27 +0100108 print(Fore.RED + ("%s %s at line %d" % (ident, errorStr(theError), theLine)) + Style.RESET_ALL)
Christophe Favergeon4f462732019-11-13 14:11:14 +0100109 if (len(errorDetail)>0):
110 print(Fore.RED + ident + " " + errorDetail + Style.RESET_ALL)
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200111
112 def pop(self):
113 None
114
115 def end(self):
116 None
117
Christophe Favergeone972cbd2019-11-19 15:54:13 +0100118# Return test result as a text tree
119class HTMLFormatter:
120 def __init__(self):
121 self.nb=1
122 self.suite=False
123
124 def start(self):
125 print("<html><head><title>Test Results</title></head><body>")
126
127 def printGroup(self,elem,theId):
128 if elem is None:
129 elem = root
130 message=elem.data["message"]
131 if not elem.data["deprecated"]:
132 kind = "Suite"
133 ident = " " * elem.ident
134 if elem.kind == TestScripts.Parser.TreeElem.GROUP:
135 kind = "Group"
136 if kind == "Group":
137 print("<h%d> %s (%d) </h%d>" % (self.nb,message,theId,self.nb))
138 else:
139 print("<h%d> %s (%d) </h%d>" % (self.nb,message,theId,self.nb))
140 self.suite=True
141 print("<table style=\"width:100%\">")
142 print("<tr>")
143 print("<td>Name</td>")
144 print("<td>ID</td>")
145 print("<td>Status</td>")
Christophe Favergeon59aeeea2019-11-20 13:39:05 +0100146 print("<td>Params</td>")
Christophe Favergeone972cbd2019-11-19 15:54:13 +0100147 print("<td>Cycles</td>")
148 print("</tr>")
149 self.nb = self.nb + 1
150
151 def printTest(self,elem, theId, theError,errorDetail,theLine,passed,cycles,params):
152 message=elem.data["message"]
153 if not elem.data["deprecated"]:
154 kind = "Test"
155 ident = " " * elem.ident
156 p="<font color=\"red\">FAILED</font>"
157 if passed == 1:
158 p= "<font color=\"green\">PASSED</font>"
159 print("<tr>")
160 print("<td><pre>%s</pre></td>" % message)
161 print("<td>%d</td>" % theId)
162 print("<td>%s</td>" % p)
Christophe Favergeon59aeeea2019-11-20 13:39:05 +0100163 if params:
164 print("<td>%s</td>\n" % (params))
165 else:
166 print("<td></td>\n")
Christophe Favergeone972cbd2019-11-19 15:54:13 +0100167 print("<td>%d</td>" % cycles)
168 print("</tr>")
Christophe Favergeon59aeeea2019-11-20 13:39:05 +0100169
Christophe Favergeone972cbd2019-11-19 15:54:13 +0100170 if passed != 1:
171
172 print("<tr><td colspan=4><font color=\"red\">%s at line %d</font></td></tr>" % (errorStr(theError), theLine))
173 if (len(errorDetail)>0):
174 print("<tr><td colspan=4><font color=\"red\">" + errorDetail + "</font></td></tr>")
175
176 def pop(self):
177 if self.suite:
178 print("</table>")
179 self.nb = self.nb - 1
180 self.suite=False
181
182 def end(self):
183 print("</body></html>")
184
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200185# Return test result as a CSV
186class CSVFormatter:
187
188 def __init__(self):
189 self.name=[]
190 self._start=True
191
192 def start(self):
193 print("CATEGORY,NAME,ID,STATUS,CYCLES,PARAMS")
194
195 def printGroup(self,elem,theId):
196 if elem is None:
197 elem = root
198 # Remove Root from category name in CSV file.
199 if not self._start:
200 self.name.append(elem.data["class"])
201 else:
202 self._start=False
203 message=elem.data["message"]
204 if not elem.data["deprecated"]:
205 kind = "Suite"
206 ident = " " * elem.ident
207 if elem.kind == TestScripts.Parser.TreeElem.GROUP:
208 kind = "Group"
209
Christophe Favergeon4f462732019-11-13 14:11:14 +0100210 def printTest(self,elem, theId, theError, errorDetail,theLine,passed,cycles,params):
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200211 message=elem.data["message"]
212 if not elem.data["deprecated"]:
213 kind = "Test"
214 name=elem.data["class"]
215 category= "".join(list(joinit(self.name,":")))
216 print("%s,%s,%d,%d,%d,\"%s\"" % (category,name,theId,passed,cycles,params))
217
218 def pop(self):
219 if self.name:
220 self.name.pop()
221
222 def end(self):
223 None
224
225class MathematicaFormatter:
226
227 def __init__(self):
228 self._hasContent=[False]
229 self._toPop=[]
230
231 def start(self):
232 None
233
234 def printGroup(self,elem,theId):
235 if self._hasContent[len(self._hasContent)-1]:
236 print(",",end="")
237
238 print("<|")
239 self._hasContent[len(self._hasContent)-1] = True
240 self._hasContent.append(False)
241 if elem is None:
242 elem = root
243 message=elem.data["message"]
244 if not elem.data["deprecated"]:
245
246 kind = "Suite"
247 ident = " " * elem.ident
248 if elem.kind == TestScripts.Parser.TreeElem.GROUP:
249 kind = "Group"
250 print("\"%s\" ->" % (message))
251 #if kind == "Suite":
252 print("{",end="")
253 self._toPop.append("}")
254 #else:
255 # self._toPop.append("")
256
Christophe Favergeon4f462732019-11-13 14:11:14 +0100257 def printTest(self,elem, theId, theError,errorDetail,theLine,passed,cycles,params):
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200258 message=elem.data["message"]
259 if not elem.data["deprecated"]:
260 kind = "Test"
261 ident = " " * elem.ident
262 p="FAILED"
263 if passed == 1:
264 p="PASSED"
265 parameters=""
266 if params:
267 parameters = "%s" % params
268 if self._hasContent[len(self._hasContent)-1]:
269 print(",",end="")
270 print("<|\"NAME\" -> \"%s\",\"ID\" -> %d,\"STATUS\" -> \"%s\",\"CYCLES\" -> %d,\"PARAMS\" -> \"%s\"|>" % (message,theId,p,cycles,parameters))
271 self._hasContent[len(self._hasContent)-1] = True
272 #if passed != 1:
273 # print("%s Error = %d at line %d" % (ident, theError, theLine))
274
275 def pop(self):
276 print(self._toPop.pop(),end="")
277 print("|>")
278 self._hasContent.pop()
279
280 def end(self):
281 None
282
283NORMAL = 1
284INTEST = 2
285TESTPARAM = 3
Christophe Favergeon4f462732019-11-13 14:11:14 +0100286ERRORDESC = 4
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200287
288def createMissingDir(destPath):
289 theDir=os.path.normpath(os.path.dirname(destPath))
290 if not os.path.exists(theDir):
291 os.makedirs(theDir)
292
293def correctPath(path):
294 while (path[0]=="/") or (path[0] == "\\"):
295 path = path[1:]
296 return(path)
297
298def extractDataFiles(results,outputDir):
299 infile = False
300 f = None
301 for l in results:
302 if re.match(r'^.*D:[ ].*$',l):
303 if infile:
304 if re.match(r'^.*D:[ ]END$',l):
305 infile = False
306 if f:
307 f.close()
308 else:
309 if f:
310 m = re.match(r'^.*D:[ ](.*)$',l)
311 data = m.group(1)
312 f.write(data)
313 f.write("\n")
314
315 else:
316 m = re.match(r'^.*D:[ ](.*)$',l)
317 path = str(m.group(1))
318 infile = True
319 destPath = os.path.join(outputDir,correctPath(path))
320 createMissingDir(destPath)
321 f = open(destPath,"w")
322
323
324
325def writeBenchmark(elem,benchFile,theId,theError,passed,cycles,params,config):
326 if benchFile:
327 name=elem.data["class"]
328 category= elem.categoryDesc()
Christophe Favergeon37b86222019-07-17 11:49:00 +0200329 old=""
330 if "testData" in elem.data:
331 if "oldID" in elem.data["testData"]:
332 old=elem.data["testData"]["oldID"]
333 benchFile.write("\"%s\",\"%s\",%d,\"%s\",%s,%d,%s\n" % (category,name,theId,old,params,cycles,config))
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200334
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100335def getCyclesFromTrace(trace):
336 if not trace:
337 return(0)
338 else:
339 return(TestScripts.ParseTrace.getCycles(trace))
340
Christophe Favergeon5cacf9d2019-08-14 10:41:17 +0200341def analyseResult(resultPath,root,results,embedded,benchmark,trace,formatter):
Christophe Favergeon512b1482020-02-07 11:25:11 +0100342 global resultStatus
Christophe Favergeonbe7efb42019-08-09 10:17:03 +0100343 calibration = 0
344 if trace:
345 # First cycle in the trace is the calibration data
346 # The noramlisation factor must be coherent with the C code one.
347 calibration = int(getCyclesFromTrace(trace) / 20)
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200348 formatter.start()
349 path = []
350 state = NORMAL
351 prefix=""
352 elem=None
353 theId=None
354 theError=None
Christophe Favergeon4f462732019-11-13 14:11:14 +0100355 errorDetail=""
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200356 theLine=None
357 passed=0
358 cycles=None
359 benchFile = None
360 config=""
361 if embedded:
Christophe Favergeon830283b2020-04-27 14:51:08 +0200362 prefix = ".*[S]+:[ ]"
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200363
364 # Parse the result file.
365 # NORMAL mode is when we are parsing suite or group.
366 # Otherwise we are parsing a test and we need to analyse the
367 # test result.
368 # TESTPARAM is used to read parameters of the test.
369 # Format of output is:
370 #node ident : s id or g id or t or u
371 #test status : id error linenb status Y or N (Y when passing)
372 #param for this test b x,x,x,x or b alone if not param
373 #node end : p
374 # In FPGA mode:
375 #Prefix S:[ ] before driver dump
376 # D:[ ] before data dump (output patterns)
377
378 for l in results:
379 l = l.strip()
380 if not re.match(r'^.*D:[ ].*$',l):
381 if state == NORMAL:
382 if len(l) > 0:
383 # Line starting with g or s is a suite or group.
384 # In FPGA mode, those line are prefixed with 'S: '
385 # and data file with 'D: '
386 if re.match(r'^%s[gs][ ]+[0-9]+.*$' % prefix,l):
387 # Extract the test id
388 theId=re.sub(r'^%s[gs][ ]+([0-9]+).*$' % prefix,r'\1',l)
389 theId=int(theId)
390 path.append(theId)
391 # From a list of id, find the TreeElem in the Parsed tree
392 # to know what is the node.
393 elem = findItem(root,path)
394 # Display formatted output for this node
395 if elem.params:
396 #print(elem.params.full)
397 benchPath = os.path.join(benchmark,elem.fullPath(),"fullBenchmark.csv")
398 createMissingDir(benchPath)
399 if benchFile:
400 printf("ERROR BENCH FILE %s ALREADY OPEN" % benchPath)
401 benchFile.close()
402 benchFile=None
403 benchFile=open(benchPath,"w")
404 header = "".join(list(joinit(elem.params.full,",")))
405 # A test and a benchmark are different
406 # so we don't dump a status and error
407 # A status and error in a benchmark would
408 # impact the cycles since the test
409 # would be taken into account in the measurement
410 # So benchmark are always passing and contain no test
411 #benchFile.write("ID,%s,PASSED,ERROR,CYCLES\n" % header)
412 csvheaders = ""
413
Christophe Favergeon5cacf9d2019-08-14 10:41:17 +0200414 with open(os.path.join(resultPath,'currentConfig.csv'), 'r') as f:
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200415 reader = csv.reader(f)
416 csvheaders = next(reader, None)
417 configList = list(reader)
418 #print(configList)
419 config = "".join(list(joinit(configList[0],",")))
420 configHeaders = "".join(list(joinit(csvheaders,",")))
Christophe Favergeon37b86222019-07-17 11:49:00 +0200421 benchFile.write("CATEGORY,NAME,ID,OLDID,%s,CYCLES,%s\n" % (header,configHeaders))
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200422
423 formatter.printGroup(elem,theId)
424
425 # If we have detected a test, we switch to test mode
426 if re.match(r'^%s[t][ ]*$' % prefix,l):
427 state = INTEST
428
429
430 # Pop
431 # End of suite or group
432 if re.match(r'^%sp.*$' % prefix,l):
433 if benchFile:
434 benchFile.close()
435 benchFile=None
436 path.pop()
437 formatter.pop()
438 elif state == INTEST:
439 if len(l) > 0:
440 # In test mode, we are looking for test status.
441 # A line starting with S
442 # (There may be empty lines or line for data files)
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100443 passRe = r'^%s([0-9]+)[ ]+([0-9]+)[ ]+([0-9]+)[ ]+([t0-9]+)[ ]+([YN]).*$' % prefix
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200444 if re.match(passRe,l):
445 # If we have found a test status then we will start again
446 # in normal mode after this.
447
448 m = re.match(passRe,l)
449
450 # Extract test ID, test error code, line number and status
451 theId=m.group(1)
452 theId=int(theId)
453
454 theError=m.group(2)
455 theError=int(theError)
456
457 theLine=m.group(3)
458 theLine=int(theLine)
459
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100460 maybeCycles = m.group(4)
461 if maybeCycles == "t":
Christophe Favergeonbe7efb42019-08-09 10:17:03 +0100462 cycles = getCyclesFromTrace(trace) - calibration
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100463 else:
464 cycles = int(maybeCycles)
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200465
466 status=m.group(5)
467 passed=0
468
469 # Convert status to number as used by formatter.
470 if status=="Y":
471 passed = 1
472 if status=="N":
473 passed = 0
474 # Compute path to this node
475 newPath=path.copy()
476 newPath.append(theId)
477 # Find the node in the Tree
478 elem = findItem(root,newPath)
479
480
Christophe Favergeon4f462732019-11-13 14:11:14 +0100481 state = ERRORDESC
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200482 else:
483 if re.match(r'^%sp.*$' % prefix,l):
484 if benchFile:
485 benchFile.close()
486 benchFile=None
487 path.pop()
488 formatter.pop()
489 if re.match(r'^%s[t][ ]*$' % prefix,l):
490 state = INTEST
491 else:
492 state = NORMAL
Christophe Favergeon4f462732019-11-13 14:11:14 +0100493 elif state == ERRORDESC:
494 if len(l) > 0:
495 if re.match(r'^.*E:.*$',l):
496 if re.match(r'^.*E:[ ].*$',l):
497 m = re.match(r'^.*E:[ ](.*)$',l)
498 errorDetail = m.group(1)
499 else:
500 errorDetail = ""
501 state = TESTPARAM
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200502 else:
503 if len(l) > 0:
504 state = INTEST
505 params=""
506 if re.match(r'^.*b[ ]+([0-9,]+)$',l):
507 m=re.match(r'^.*b[ ]+([0-9,]+)$',l)
508 params=m.group(1).strip()
509 # Format the node
510 #print(elem.fullPath())
511 #createMissingDir(destPath)
512 writeBenchmark(elem,benchFile,theId,theError,passed,cycles,params,config)
513 else:
514 params=""
515 writeBenchmark(elem,benchFile,theId,theError,passed,cycles,params,config)
516 # Format the node
Christophe Favergeon512b1482020-02-07 11:25:11 +0100517 if not passed:
518 resultStatus=1
Christophe Favergeon4f462732019-11-13 14:11:14 +0100519 formatter.printTest(elem,theId,theError,errorDetail,theLine,passed,cycles,params)
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200520
521
522 formatter.end()
523
524
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100525def analyze(root,results,args,trace):
Christophe Favergeon5cacf9d2019-08-14 10:41:17 +0200526 # currentConfig.csv should be in the same place
527 resultPath=os.path.dirname(args.r)
528
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100529 if args.c:
Christophe Favergeon5cacf9d2019-08-14 10:41:17 +0200530 analyseResult(resultPath,root,results,args.e,args.b,trace,CSVFormatter())
Christophe Favergeone972cbd2019-11-19 15:54:13 +0100531 elif args.html:
532 analyseResult(resultPath,root,results,args.e,args.b,trace,HTMLFormatter())
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100533 elif args.m:
Christophe Favergeon5cacf9d2019-08-14 10:41:17 +0200534 analyseResult(resultPath,root,results,args.e,args.b,trace,MathematicaFormatter())
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100535 else:
Christophe Favergeon2942a332020-01-20 14:18:48 +0100536 print("")
537 print(Fore.RED + "The cycles displayed by this script must not be trusted." + Style.RESET_ALL)
538 print(Fore.RED + "They are just an indication. The timing code has not yet been validated." + Style.RESET_ALL)
539 print("")
540
Christophe Favergeon5cacf9d2019-08-14 10:41:17 +0200541 analyseResult(resultPath,root,results,args.e,args.b,trace,TextFormatter())
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100542
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200543parser = argparse.ArgumentParser(description='Parse test description')
544
Christophe Favergeon6f8eee92019-10-09 12:21:27 +0100545parser.add_argument('-f', nargs='?',type = str, default="Output.pickle", help="Test description file path")
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200546# Where the result file can be found
547parser.add_argument('-r', nargs='?',type = str, default=None, help="Result file path")
548parser.add_argument('-c', action='store_true', help="CSV output")
Christophe Favergeone972cbd2019-11-19 15:54:13 +0100549parser.add_argument('-html', action='store_true', help="HTML output")
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200550parser.add_argument('-e', action='store_true', help="Embedded test")
551# -o needed when -e is true to know where to extract the output files
552parser.add_argument('-o', nargs='?',type = str, default="Output", help="Output dir path")
553
554parser.add_argument('-b', nargs='?',type = str, default="FullBenchmark", help="Full Benchmark dir path")
555parser.add_argument('-m', action='store_true', help="Mathematica output")
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100556parser.add_argument('-t', nargs='?',type = str, default=None, help="External trace file")
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200557
558args = parser.parse_args()
559
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100560
Christophe Favergeon512b1482020-02-07 11:25:11 +0100561
562
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200563if args.f is not None:
Christophe Favergeon6f8eee92019-10-09 12:21:27 +0100564 #p = parse.Parser()
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200565 # Parse the test description file
Christophe Favergeon6f8eee92019-10-09 12:21:27 +0100566 #root = p.parse(args.f)
567 root=parse.loadRoot(args.f)
Christophe Favergeonf76a8032019-08-09 09:15:50 +0100568 if args.t:
569 with open(args.t,"r") as trace:
570 with open(args.r,"r") as results:
571 analyze(root,results,args,iter(trace))
572 else:
573 with open(args.r,"r") as results:
574 analyze(root,results,args,None)
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200575 if args.e:
576 # In FPGA mode, extract output files from stdout (result file)
577 with open(args.r,"r") as results:
578 extractDataFiles(results,args.o)
Christophe Favergeon512b1482020-02-07 11:25:11 +0100579
580 sys.exit(resultStatus)
Christophe Favergeon3b2a0ee2019-06-12 13:29:14 +0200581
582else:
583 parser.print_help()