1import argparse 2import pickle 3import sys 4import subprocess 5import os 6import colorama 7from colorama import init,Fore, Back, Style 8from os import environ 9 10parser = argparse.ArgumentParser(description='Parse test description') 11parser.add_argument('-avh', nargs='?',type = str, default="C:/Keil_v5/ARM/avh-fvp/bin/models", help="AVH folder") 12parser.add_argument('-d', action='store_true', help="Debug log") 13parser.add_argument('-n', action='store_true', help="No force rebuild") 14parser.add_argument('-r', action='store_true', help="Raw results only") 15parser.add_argument('-c', action='store_true', help="Display cycles (so passing test are displayed)") 16parser.add_argument('-g', nargs='?',type = str,help="AC6 / CLANG / GCC") 17parser.add_argument('-s', action='store_true', help="Take into account AVH error code") 18 19args = parser.parse_args() 20 21 22GHACTION = False 23 24if "AVH_FVP_PLUGINS" in os.environ: 25 GHACTION = True 26 27DEBUG=False 28if args.d: 29 DEBUG=True 30 31init() 32 33sys.path.append("..") 34 35from TestScripts.Parser import TreeElem 36 37ERROR_OCCURED = False 38 39def printTitle(s): 40 print("\n" + Fore.GREEN + Style.BRIGHT + s + Style.RESET_ALL) 41 42def printSubTitle(s): 43 print("\n" + Fore.YELLOW + Style.BRIGHT + s + Style.RESET_ALL) 44 45def printError(s): 46 print("\n" + Fore.RED + Style.BRIGHT + s + Style.RESET_ALL) 47 48# Load Output.pickle files for the test description 49def loadRoot(f): 50 root = None 51 with open(f,"rb") as inf: 52 root=pickle.load(inf) 53 return(root) 54 55# Get test suites from the test descriptions 56def getSuites(node,filterList,currentList=[]): 57 if node.kind==TreeElem.SUITE: 58 currentList.append(node.data["class"]) 59 if node.kind==TreeElem.GROUP: 60 if not node.data["class"] in filterList: 61 for c in node.children: 62 getSuites(c,filterList,currentList) 63 64class Result: 65 def __init__(self,msg,error=False): 66 self._error = error 67 self._msg = msg 68 69 @property 70 def error(self): 71 return self._error 72 73 @property 74 def msg(self): 75 return self._msg 76 77 78 79# Run a command and get error or result 80# For the test report we don't need the stderr 81# in case of error since the test report is giving 82# all the details. So, there is an option to 83# disable the dump of stderr 84def run(*args,mustPrint=False,dumpStdErr=True,withExitCodeCheck=True): 85 global ERROR_OCCURED 86 global DEBUG 87 try: 88 if DEBUG: 89 print(" ".join(args)) 90 result=subprocess.run(args,text=True,capture_output=True,timeout=600) 91 if withExitCodeCheck and (result.returncode !=0) : 92 ERROR_OCCURED = True 93 if dumpStdErr: 94 return(Result(result.stderr + f"\n\nSTDOUT (error code = {result.returncode}):\n\n" + result.stdout,error=True)) 95 else: 96 return(Result(result.stdout,error=True)) 97 98 if mustPrint: 99 print(result.stdout) 100 return(Result(result.stdout)) 101 except Exception as e: 102 printError("Exception occured") 103 ERROR_OCCURED = True 104 return(Result(str(e),error=True)) 105 106 107 108 109 110# Configuration file for AVH core 111configFiles={ 112 "CS310":"ARM_VHT_Corstone_310_config.txt", 113 "CS300":{ 114 "AC6":"ARM_VHT_Corstone_300_config_ext.txt", 115 "GCC":"ARM_VHT_Corstone_300_config_ext.txt", 116 "CLANG":"ARM_VHT_Corstone_300_config_ext.txt" 117 }, 118 "M55":"ARM_VHT_MPS2_M55_config.txt", 119 "M33_DSP_FP":"ARM_VHT_MPS2_M33_DSP_FP_config.txt", 120 "M7DP":"ARM_VHT_MPS2_M7DP_config.txt", 121 "M4FP":"ARM_VHT_MPS2_M4FP_config.txt", 122 "M3":"ARM_VHT_MPS2_M3_config.txt", 123 "M23":"ARM_VHT_MPS2_M23_config.txt", 124 "M0plus":"ARM_VHT_MPS2_M0plus_config.txt", 125} 126 127# Windows executable 128avhUnixExe={ 129 "CS310":"FVP_Corstone_SSE-310_Ethos-U65", 130 "CS300":"FVP_Corstone_SSE-300_Ethos-U55", 131 "M55":"FVP_MPS2_Cortex-M55", 132 "M33_DSP_FP":"FVP_MPS2_Cortex-M33", 133 "M7DP":"FVP_MPS2_Cortex-M7", 134 "M4FP":"FVP_MPS2_Cortex-M4", 135 "M3":"FVP_MPS2_Cortex-M3", 136 "M23":"FVP_MPS2_Cortex-M23", 137 "M0plus":"FVP_MPS2_Cortex-M0plus", 138} 139 140avhWindowsExe={ 141 "CS310":"FVP_Corstone_SSE-310_Ethos-U65.exe", 142 "CS300":"FVP_Corstone_SSE-300_Ethos-U55.exe", 143 "M55":"FVP_MPS2_Cortex-M55.exe", 144 "M33_DSP_FP":"FVP_MPS2_Cortex-M33.exe", 145 "M7DP":"FVP_MPS2_Cortex-M7.exe", 146 "M4FP":"FVP_MPS2_Cortex-M4.exe", 147 "M3":"FVP_MPS2_Cortex-M3.exe", 148 "M23":"FVP_MPS2_Cortex-M23.exe", 149 "M0plus":"FVP_MPS2_Cortex-M0plus.exe", 150} 151 152AVHROOT = args.avh 153 154# Run AVH 155def runAVH(build,core,compiler): 156 axf="cprj/out/test/%s/Release/test.axf" % (build,) 157 elf="cprj/out/test/%s/Release/test.elf" % (build,) 158 app = axf 159 if os.path.exists(axf): 160 app = axf 161 if os.path.exists(elf): 162 app = elf 163 if isinstance(configFiles[core],str): 164 config = os.path.join("configs",configFiles[core]) 165 else: 166 config = os.path.join("configs",configFiles[core][compiler]) 167 168 if AVHROOT: 169 avhAttempt = os.path.join(AVHROOT,avhWindowsExe[core]) 170 if os.path.exists(avhAttempt): 171 avh = avhAttempt 172 173 avhAttempt = os.path.join(AVHROOT,avhUnixExe[core]) 174 if os.path.exists(avhAttempt): 175 avh = avhAttempt 176 else: 177 avh = avhUnixExe[core] 178 179 180 181 res=run(avh,"-f",config,app,withExitCodeCheck=args.s) 182 return(res) 183 184#################### 185 186# Test descriptions to use 187tests=["../Output.pickle","../Output_f16.pickle"] 188# Test group to avoid 189filterList=["NNTests","ExampleTests"] 190allSuites=[] 191 192# Load all the test suite to run 193for t in tests: 194 root=loadRoot(t) 195 suites=[] 196 getSuites(root,filterList,suites) 197 allSuites += [(x,t) for x in suites ] 198 199# Test suite and output pickle needed to decode the result 200#print(allSuites) 201 202 203 204#allSuites=[ 205#("MISCF32","../Output.pickle"), 206#("MISCQ31","../Output.pickle"), 207#("SupportTestsF16","../Output_f16.pickle"), 208###("BasicTestsF32","../Output.pickle"), 209##("BasicTestsF16","../Output_f16.pickle"), 210#] 211 212# Solution and build file for all 213# the tests 214# It is a pair : csolution target type and AVH identification 215# AVH identification is used to find the executable 216# and the configuration file 217compil_config={ 218 'AC6':[ 219 ("VHT-Corstone-300","CS300"), 220 ("VHT-Corstone-300-NOMVE","CS300"), 221 ("VHT_M33","M33_DSP_FP"), 222 ("VHT_M7","M7DP"), 223 ("VHT_M7_UNROLLED","M7DP"), 224 ("VHT_M4","M4FP"), 225 ("VHT_M0P","M0plus") 226 ], 227 'GCC':[ 228 ("VHT-Corstone-300","CS300"), 229 #("VHT-Corstone-300-NOMVE","CS300"), 230 ("VHT_M33","M33_DSP_FP"), 231 ("VHT_M7","M7DP"), 232 ("VHT_M7_UNROLLED","M7DP"), 233 ("VHT_M4","M4FP"), 234 ("VHT_M0P","M0plus") 235 ], 236 'CLANG':[ 237 ("VHT-Corstone-300","CS300"), 238 ("VHT-Corstone-300-NOMVE","CS300"), 239 ("VHT_M33","M33_DSP_FP"), 240 ("VHT_M7","M7DP"), 241 ("VHT_M7_UNROLLED","M7DP"), 242 ("VHT_M4","M4FP"), 243 ("VHT_M0P","M0plus") 244 ], 245} 246 247#Override previous solutions for more restricted testing. 248#compil_config={ 249# 'AC6':[ 250# ("VHT-Corstone-300","CS300"), 251# ("VHT_M33","M33_DSP_FP"), 252# ], 253# 'GCC':[ 254# ("VHT-Corstone-300","CS300"), 255# ("VHT_M33","M33_DSP_FP"), 256# ], 257# 'CLANG':[ 258# ("VHT-Corstone-300","CS300"), 259# ("VHT_M33","M33_DSP_FP"), 260# ] 261#} 262 263 264 265HTMLHEADER="""<html> 266<header> 267<title>CMSIS-DSP Test summary</title> 268</header> 269<body> 270""" 271 272HTMLFOOTER=""" 273</body></html> 274""" 275 276compilers = ["AC6", "CLANG", "GCC"] 277 278if args.g: 279 compilers=[args.g] 280 281 282# Run the tests and log the result 283# in a summary.html file 284 285if len(compilers)>1: 286 results_file = "summary.html" 287else: 288 results_file = f"summary_{compilers[0]}.html" 289 290with open(results_file,"w") as f: 291 print(HTMLHEADER,file=f) 292 for comp_nb,compiler in enumerate(compilers): 293 if compiler in compil_config: 294 solutions = compil_config[compiler] 295 printTitle("Process compiler %s (%d / %d)" % (compiler,comp_nb+1,len(compilers))) 296 print("<h1>Compiler %s</h1>" % compiler,file=f) 297 maxNbBuilds=len(solutions) 298 buildNb=0 299 for build,core in solutions: 300 buildNb = buildNb + 1 301 print("<h2>Core %s</h2>" % build,file=f) 302 printTitle("Process core %s (%d/%d)" % (build,buildNb,maxNbBuilds)) 303 buildFile="test.Release+%s" % build 304 nb = 0 305 maxNb = len(allSuites) 306 for s,pickle in allSuites: 307 nb = nb + 1 308 printSubTitle("Process suite %s (%d/%d)" % (s,nb,maxNb)) 309 res=run(sys.executable,"../processTests.py","-gen","..","-p","../Patterns","-d","../Parameters","-f",pickle,"-e",s,mustPrint=True) 310 if res.error: 311 printError("Error processTests") 312 print("<p><font color=\"red\">Error generating %s</font></p><PRE>" % s,file=f) 313 print(res.msg,file=f) 314 print("</PRE>",file=f) 315 continue 316 if nb==1: 317 # -r is needed for first 318 # build when we switch 319 # between different solutions 320 # (Like one using AC6 and the other 321 # using gcc) 322 if args.n: 323 res=run("cbuild","-O", "cprj","test.csolution.yml","-c",buildFile,"--toolchain",compiler) 324 else: 325 res=run("cbuild","-O", "cprj","test.csolution.yml","-r","--update-rte","-c",buildFile,"--toolchain",compiler) 326 else: 327 res=run("cbuild","-O", "cprj","test.csolution.yml","-c",buildFile,"--toolchain",compiler) 328 if res.error: 329 printError("Error cbuild") 330 print("<p><font color=\"red\">Error building %s</font></p><PRE>" % s,file=f) 331 print(res.msg,file=f) 332 print("</PRE>",file=f) 333 continue 334 printSubTitle("Run AVH") 335 res=runAVH(build,core,compiler) 336 if res.error: 337 printError("Error running AVH") 338 print("<p><font color=\"red\">Error running %s</font></p><PRE>" % s,file=f) 339 print(res.msg,file=f) 340 print("</PRE>",file=f) 341 continue 342 else: 343 with open("results.txt","w") as o: 344 print(res.msg,file=o) 345 # Dump raw result 346 if args.r: 347 print(res.msg) 348 # If raw result, no post processing 349 if not args.r: 350 res=run(sys.executable,"../processResult.py","-f",pickle,"-e","-ahtml","-r","results.txt",dumpStdErr=False) 351 if res.error: 352 printError("Error processResult") 353 print("<p><font color=\"red\">Error processing %s result</font></p><PRE>" % s,file=f) 354 print(res.msg,file=f) 355 print("</PRE>",file=f) 356 continue 357 else: 358 # When no error the section is 359 # included in final file on when 360 # cycles are requested 361 if args.c: 362 print(res.msg,file=f) 363 print(HTMLFOOTER,file=f) 364 365if not GHACTION: 366 if ERROR_OCCURED: 367 sys.exit("Error occurred") 368 else: 369 sys.exit(0)