run_all.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. import re
  2. import argparse
  3. import os.path
  4. import itertools
  5. import subprocess
  6. import sys
  7. import mps3run
  8. from colorama import init,Fore, Back, Style
  9. try:
  10. os.mkdir("ac6_results")
  11. except:
  12. pass
  13. try:
  14. os.mkdir("gcc_results")
  15. except:
  16. pass
  17. try:
  18. os.mkdir("clang_results")
  19. except:
  20. pass
  21. DEBUG = False
  22. ERROR_OCCURED = False
  23. all_errors = []
  24. def printTitle(s):
  25. print("\n" + Fore.GREEN + Style.BRIGHT + s + Style.RESET_ALL)
  26. def printSubTitle(s):
  27. print(Fore.YELLOW + Style.BRIGHT + s + Style.RESET_ALL)
  28. def printError(s):
  29. print(Fore.RED + Style.BRIGHT + s + Style.RESET_ALL+"\n")
  30. class Result:
  31. def __init__(self,msg,error=False):
  32. self._error = error
  33. self._msg = msg
  34. @property
  35. def error(self):
  36. return self._error
  37. @property
  38. def msg(self):
  39. return self._msg
  40. def is_error(res,test_name,err):
  41. if res.error:
  42. printError("Error")
  43. all_errors.append(test_name)
  44. print(test_name,file=err)
  45. print(res.msg,file=err)
  46. print("--------------",file=err)
  47. return(True)
  48. return(False)
  49. def run(args,mustPrint=False,dumpStdErr=True,timeout=20,printCmd=False):
  50. global ERROR_OCCURED
  51. global DEBUG
  52. try:
  53. if DEBUG or printCmd:
  54. print(" ".join(args))
  55. result=subprocess.run(args,text=True,capture_output=True,timeout=timeout)
  56. if result.returncode !=0 :
  57. ERROR_OCCURED = True
  58. if dumpStdErr:
  59. return(Result(result.stderr + "\n\nSTDOUT:\n\n" + result.stdout,error=True))
  60. else:
  61. return(Result(result.stdout,error=True))
  62. if mustPrint:
  63. print(result.stdout)
  64. return(Result(result.stdout))
  65. except Exception as e:
  66. printError("Exception occured")
  67. ERROR_OCCURED = True
  68. return(Result(str(e),error=True))
  69. parser = argparse.ArgumentParser(description='Parse test description')
  70. parser.add_argument('-c', nargs='?',type = str, default="M55",help="M55/M4/M0")
  71. parser.add_argument('-p', nargs='?',type = str, default="VHT",help="VHT/MPS3")
  72. parser.add_argument('-a', action='store_true', help="Generate allocator definitions")
  73. parser.add_argument('-i', action='store_true', help="Refresh global allocator index")
  74. parser.add_argument('-b', action='store_true', help="Only benchmarks")
  75. parser.add_argument('-d', action='store_true', help="Dry run")
  76. parser.add_argument('-g', nargs='?',type = str, default="AC6",help="AC6 / CLANG / GCC")
  77. parser.add_argument('-u', nargs='?',type = str, default="L85986697A",help="Debug UUID")
  78. args = parser.parse_args()
  79. init()
  80. if args.a:
  81. printTitle("Mode allocator generations")
  82. if args.i:
  83. printTitle("Allocator test index refresh")
  84. NAME_TO_BOARD = {
  85. "M55": "Corstone-300",
  86. "Corstone-300": "Corstone-300",
  87. "M4": "M4",
  88. "M0" : "M0P"
  89. }
  90. def results():
  91. if args.g == "AC6":
  92. return("ac6_results")
  93. if args.g == "GCC":
  94. return("gcc_results")
  95. if args.g == "CLANG":
  96. return("clang_results")
  97. print(f"Compiler {args.g} not known")
  98. exit(1)
  99. def target_name():
  100. return(f"{args.p}-{NAME_TO_BOARD[args.c]}")
  101. def cmd_args():
  102. # cbuild -O cprj test.csolution.yml -r --toolchain AC6 -c test.Release+MPS3-Corstone-300
  103. toolchain = args.g
  104. target = f"test.Release+{target_name()}"
  105. command = ["-O", "cprj",
  106. "test.csolution.yml",
  107. "--toolchain", toolchain,
  108. "-c", target]
  109. return(command)
  110. if args.g == "AC6":
  111. ext = ".axf"
  112. else:
  113. ext = ".elf"
  114. fvp = {"M55":"C:\\Keil_v5\\ARM\\VHT\\VHT_Corstone_SSE-300_Ethos-U55.exe",
  115. "M4":"C:\\Keil_v5\\ARM\\VHT\\VHT_MPS2_Cortex-M4.exe",
  116. "M0":"C:\\Keil_v5\\ARM\\VHT\\VHT_MPS2_Cortex-M0plus.exe"}
  117. TESTS=["DOT_TEST",
  118. "VECTOR_TEST",
  119. "ROW_TEST",
  120. "COL_TEST",
  121. "MATRIX_TEST",
  122. "FUSION_TEST"
  123. ]
  124. # Some tests are too big (code size) and needs to be decomposed
  125. # They contain SUBTEST1, SUBTEST2 ... #if in the code
  126. # This script must know how many subtests are defined in each test
  127. # suite
  128. # No need to define an entry in this dictionary when no
  129. # subtest is defined
  130. SUBTESTS = {"MATRIX_TEST":19}
  131. # Subtests that are only for testing and not benchmarks
  132. ONLY_TESTS = {"MATRIX_TEST":[3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]}
  133. def is_only_test(n,i):
  134. if n[0] in ONLY_TESTS:
  135. return(i in ONLY_TESTS[n[0]])
  136. return False
  137. DATATYPES = ["F64_DT",
  138. "F32_DT",
  139. "F16_DT",
  140. "Q31_DT",
  141. "Q15_DT",
  142. "Q7_DT"
  143. ]
  144. MODE = ["STATIC_TEST",
  145. "DYNAMIC_TEST"
  146. ]
  147. # Restricted tests for debugging
  148. #TESTS=["DOT_TEST","VECTOR_TEST"]
  149. #DATATYPES=["F32_DT"]
  150. #MODE = ["STATIC_TEST"]
  151. all_tests = list(itertools.product(TESTS,DATATYPES,MODE))
  152. ALLOC = "#define POOL_ALLOCATOR"
  153. if args.a:
  154. # Stat allocator enabled and we do stats on VHT CS300 only
  155. ALLOC = "//#define POOL_ALLOCATOR"
  156. args.c = "M55"
  157. args.p = "VHT"
  158. BENCH = "//#define ONLY_BENCHMARKS"
  159. if args.b:
  160. BENCH = "#define ONLY_BENCHMARKS"
  161. HEADER = f"""#ifndef TEST_CONFIG_H
  162. #define TEST_CONFIG_H
  163. {ALLOC}
  164. {BENCH}
  165. #define %s
  166. #define %s
  167. #define %s
  168. %s
  169. #endif
  170. """
  171. def out_path():
  172. return(os.path.join("cprj","out","test",target_name(),"Release","test"+ ext))
  173. def configure_and_build_test(test_name,test,err,subtest,first):
  174. if subtest is not None:
  175. subteststr = f"#define SUBTEST{subtest}"
  176. else:
  177. subteststr = ""
  178. with open("test_config.h","w") as c:
  179. print(HEADER % (test + (subteststr,)),file=c)
  180. if first:
  181. res = run(["cbuild"] + cmd_args() + ["-r","--update-rte"],timeout=600,printCmd=True)
  182. else:
  183. res = run(["cbuild"] +cmd_args(),timeout=600,printCmd=True)
  184. if not is_error(res,test_name,err):
  185. if DEBUG:
  186. print(res.msg)
  187. return(True)
  188. return(False)
  189. def process_allocator_data(test_name,test,msg,subtest):
  190. lines = msg.splitlines()
  191. state = 0
  192. alloc_cpp = []
  193. alloc_h = []
  194. for l in lines:
  195. if re.match(r"^ALLOC_POOL.*$",l):
  196. alloc_cpp.append(l.strip())
  197. if re.match(r"^POOL.*$",l):
  198. alloc_h.append(l.strip())
  199. if subtest is not None:
  200. HEADER=f"#if defined({test[0]}) && defined({test[1]}) && defined({test[2]}) && defined(SUBTEST{subtest})"
  201. else:
  202. HEADER=f"#if defined({test[0]}) && defined({test[1]}) && defined({test[2]})"
  203. # Gen h
  204. with open(os.path.join("allocation",test_name)+".h","w") as h:
  205. print(HEADER,file=h)
  206. for l in alloc_h:
  207. print(l,file=h)
  208. print("#endif",file=h)
  209. # Gen cpp
  210. with open(os.path.join("allocation",test_name)+".cpp","w") as h:
  211. print(HEADER,file=h)
  212. for l in alloc_cpp:
  213. print(l,file=h)
  214. print("#endif",file=h)
  215. def process_bench(test_name,test,msg,subtest):
  216. global DEBUG
  217. lines = msg.splitlines()
  218. test_name = args.p +"_" + args.c + "_" + test_name
  219. if DEBUG:
  220. print(os.path.join(results(),test_name)+".txt")
  221. with open(os.path.join(results(),test_name)+".txt","w") as h:
  222. for l in lines:
  223. print(l.rstrip(),file=h)
  224. def process_result(test_name,test,msg,subtest):
  225. printSubTitle("Process result")
  226. if args.a:
  227. process_allocator_data(test_name,test,msg,subtest)
  228. else:
  229. process_bench(test_name,test,msg,subtest)
  230. def runVHT(test_name,test,err,subtest):
  231. core = args.c
  232. target = target_name()
  233. config = os.path.join("fvp_configs",target) + ".txt"
  234. #print(target)
  235. #print(config)
  236. if core == "M55":
  237. exe = "cpu0=" + out_path()
  238. else:
  239. exe = out_path()
  240. res=run([fvp[core],"-f",config,"-a",exe])
  241. if not is_error(res,test_name,err):
  242. process_result(test_name,test,res.msg,subtest)
  243. def runMPS3(test_name,test,err,subtest):
  244. lines=""
  245. res = None
  246. try:
  247. exe = out_path()
  248. lines = mps3run.run_out(exe,args.u)
  249. res = Result(lines)
  250. except Exception as e:
  251. res = Result(str(e),error = True)
  252. if not is_error(res,test_name,err):
  253. process_result(test_name,test,res.msg,subtest)
  254. def runATest(test,file_err,nb,NB_MAX,current_nb_axf,nb_axf,first=True,subtest=None):
  255. global DEBUG
  256. if subtest is not None:
  257. maxsub = SUBTESTS[test[0]]
  258. test_name=f"{test[0]}_{test[1]}_{test[2]}_{subtest}"
  259. printTitle(test_name + f" : AXF {current_nb_axf} / {nb_axf}, TEST {nb}/{NB_MAX} (subtest {subtest}/{maxsub})")
  260. else:
  261. test_name=f"{test[0]}_{test[1]}_{test[2]}"
  262. printTitle(test_name + f" : AXF {current_nb_axf} / {nb_axf}, TEST {nb}/{NB_MAX}")
  263. if args.d:
  264. return
  265. printSubTitle("Configure and build")
  266. if configure_and_build_test(test_name,test,file_err,subtest,first):
  267. printSubTitle("Run")
  268. if args.p == "VHT":
  269. runVHT(test_name,test,file_err,subtest)
  270. if args.p == "MPS3" and args.c == "M55":
  271. runMPS3(test_name,test,file_err,subtest)
  272. nb_axf = 0
  273. for test in all_tests:
  274. if test[0] in SUBTESTS:
  275. for subtestnbb in range(SUBTESTS[test[0]]):
  276. if not args.b or not is_only_test(test,subtestnbb+1):
  277. nb_axf = nb_axf + 1
  278. else:
  279. nb_axf = nb_axf + 1
  280. print(f"Number of axf to test = {nb_axf}")
  281. with open(os.path.join(results(),"errors.txt"),"w") as err:
  282. # Generate include for allocations
  283. if args.a or args.i:
  284. with open(os.path.join("allocation","all.h"),"w") as fh:
  285. for test in all_tests:
  286. if test[0] in SUBTESTS:
  287. for subtestnbb in range(SUBTESTS[test[0]]):
  288. test_name=f"{test[0]}_{test[1]}_{test[2]}_{subtestnbb+1}"
  289. print(f"#include \"{test_name}.h\"",file=fh)
  290. else:
  291. test_name=f"{test[0]}_{test[1]}_{test[2]}"
  292. print(f"#include \"{test_name}.h\"",file=fh)
  293. with open(os.path.join("allocation","all.cpp"),"w") as fc:
  294. for test in all_tests:
  295. if test[0] in SUBTESTS:
  296. for subtestnbb in range(SUBTESTS[test[0]]):
  297. test_name=f"{test[0]}_{test[1]}_{test[2]}_{subtestnbb+1}"
  298. print(f"#include \"{test_name}.cpp\"",file=fc)
  299. else:
  300. test_name=f"{test[0]}_{test[1]}_{test[2]}"
  301. print(f"#include \"{test_name}.cpp\"",file=fc)
  302. if not args.i:
  303. NB_MAX = len(all_tests)
  304. nb = 1 # test cases
  305. current_axf = 1
  306. first = True
  307. for test in all_tests:
  308. if test[0] in SUBTESTS:
  309. for subtestnbb in range(SUBTESTS[test[0]]):
  310. if not args.b or not is_only_test(test,subtestnbb+1):
  311. runATest(test,err,nb,NB_MAX,current_axf,nb_axf,first,subtestnbb+1)
  312. current_axf = current_axf + 1
  313. first = False
  314. else:
  315. runATest(test,err,nb,NB_MAX,current_axf,nb_axf,first)
  316. current_axf = current_axf + 1
  317. first = False
  318. nb = nb + 1
  319. if ERROR_OCCURED:
  320. printError("Error in tests:")
  321. for n in all_errors:
  322. printError(n)
  323. sys.exit("Error occurred")
  324. else:
  325. sys.exit(0)