nsdk_bench.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #!/usr/bin/env python3
  2. import os
  3. import sys
  4. import time
  5. import copy
  6. import glob
  7. import tempfile
  8. import json
  9. import argparse
  10. from nsdk_builder import *
  11. from nsdk_utils import *
  12. from nsdk_report import *
  13. class nsdk_bench(nsdk_runner):
  14. def __init__(self):
  15. super().__init__()
  16. pass
  17. def build_apps(self, config:dict, show_output=True, logdir=None, stoponfail=False):
  18. if isinstance(config, dict) == False:
  19. return False, None
  20. global_build_config = config.get("build_config", dict())
  21. global_build_configs = config.get("build_configs", dict())
  22. global_target = config.get("build_target", "all")
  23. global_parallel = config.get("parallel", "")
  24. global_cpobjs = config.get("copy_objects", False)
  25. rootdirs = config.get("appdirs", [])
  26. ignored_rootdirs = config.get("appdirs_ignore", [])
  27. if (isinstance(rootdirs, list) and isinstance(ignored_rootdirs, list)) == False:
  28. print("appdirs type in config should be list, please check!")
  29. return False, None
  30. if len(rootdirs) == 0:
  31. print("No appdirs specified in config, please check!")
  32. return False, None
  33. root_appdirs = dict()
  34. appnum = 0
  35. # Find all the apps in rootdirs
  36. for rootdir in rootdirs:
  37. root_appdirs[rootdir] = self.find_apps(rootdir)
  38. appnum += len(root_appdirs[rootdir])
  39. # Find all the ignored apps in ignored_rootdirs
  40. ignored_apps = []
  41. for ig_rootdir in ignored_rootdirs:
  42. ignored_apps.extend(self.find_apps(ig_rootdir))
  43. if appnum == 0:
  44. print("No application found in appdirs specified in config")
  45. return False, None
  46. createlog = False
  47. if isinstance(logdir, str):
  48. createlog = True
  49. if os.path.isdir(logdir) == False:
  50. os.makedirs(logdir)
  51. appconfigs = config.get("appconfig", dict())
  52. # Construct all the applications' configuration
  53. apps_config = dict()
  54. for rootdir in root_appdirs:
  55. for appdir in root_appdirs[rootdir]:
  56. if appdir in ignored_apps:
  57. print("%s is ignored by appdirs_ignore section" % (appdir))
  58. continue
  59. appdir = appdir.replace("\\", "/") # Change windows \\ path to /
  60. app_buildcfg = copy.deepcopy(global_build_config)
  61. app_buildcfgs = copy.deepcopy(global_build_configs)
  62. app_buildtarget = copy.deepcopy(global_target)
  63. app_parallel = copy.deepcopy(global_parallel)
  64. app_cpobjs = copy.deepcopy(global_cpobjs)
  65. found_cfg = find_local_appconfig(appdir, appconfigs)
  66. if found_cfg:
  67. appcfg = appconfigs[found_cfg]
  68. # merge_global is True if not present
  69. merge_global = appcfg.get("merge_global", True)
  70. # Merge global config when merge_global is True
  71. if merge_global:
  72. app_buildcfg.update(appcfg.get("build_config", dict()))
  73. app_buildcfgs.update(appcfg.get("build_configs", dict()))
  74. if "build_target" in appcfg:
  75. app_buildtarget = appcfg["build_target"]
  76. if "parallel" in appcfg:
  77. app_parallel = appcfg["parallel"]
  78. if "copy_objects" in appcfg:
  79. app_cpobjs = appcfg["copy_objects"]
  80. else: # if merge_global is false, then use app config only
  81. app_buildcfg = appcfg.get("build_config", dict())
  82. app_buildcfgs = appcfg.get("build_configs", dict())
  83. app_buildtarget = appcfg.get("build_target", "all")
  84. app_parallel = appcfg.get("parallel", "")
  85. app_cpobjs = appcfg.get("copy_objects", False)
  86. app_allconfigs = {"configs": {}}
  87. if len(app_buildcfgs) == 0:
  88. app_buildcfgs = { "default": {} }
  89. for cfgname in app_buildcfgs:
  90. if createlog:
  91. buildlog_name = os.path.join(cfgname, "build.log")
  92. applogfile = get_logfile(appdir, rootdir, logdir, buildlog_name)
  93. else:
  94. applogfile = None
  95. percfg_appbuildcfg = copy.deepcopy(app_buildcfg)
  96. percfg_appbuildcfg.update(app_buildcfgs[cfgname])
  97. app_allconfigs["configs"][cfgname] = {"build_config": percfg_appbuildcfg, "build_target": app_buildtarget, \
  98. "copy_objects": app_cpobjs, "parallel": app_parallel, "logs": {"build": applogfile}}
  99. apps_config[appdir] = copy.deepcopy(app_allconfigs)
  100. if len(apps_config) == 0:
  101. print("No applications need to be run according to the configuration")
  102. return False, None
  103. # Build all the applications
  104. print("Build %d applications defined by configuration" % (len(apps_config)))
  105. cmdsts, build_status = self.build_apps_with_configs(apps_config, show_output, stoponfail)
  106. return cmdsts, build_status
  107. def run_apps(self, config:dict, show_output=True, logdir=None, stoponfail=False):
  108. if isinstance(config, dict) == False:
  109. return False, None
  110. global_build_config = config.get("build_config", dict())
  111. global_build_configs = config.get("build_configs", dict())
  112. global_target = config.get("build_target", "clean all")
  113. global_parallel = config.get("parallel", "")
  114. global_cpobjs = config.get("copy_objects", False)
  115. global_run_config = config.get("run_config", dict())
  116. global_checks = config.get("checks", dict())
  117. rootdirs = config.get("appdirs", [])
  118. ignored_rootdirs = config.get("appdirs_ignore", [])
  119. if (isinstance(rootdirs, list) and isinstance(ignored_rootdirs, list)) == False:
  120. print("appdirs type in config should be list, please check!")
  121. return False, None
  122. if len(rootdirs) == 0:
  123. print("No appdirs specified in config, please check!")
  124. return False, None
  125. root_appdirs = dict()
  126. appnum = 0
  127. # Find all the apps in rootdirs
  128. for rootdir in rootdirs:
  129. root_appdirs[rootdir] = self.find_apps(rootdir)
  130. appnum += len(root_appdirs[rootdir])
  131. # Find all the ignored apps in ignored_rootdirs
  132. ignored_apps = []
  133. for ig_rootdir in ignored_rootdirs:
  134. ignored_apps.extend(self.find_apps(ig_rootdir))
  135. if appnum == 0:
  136. print("No application found in appdirs specified in config")
  137. return False, None
  138. createlog = False
  139. if isinstance(logdir, str):
  140. createlog = True
  141. if os.path.isdir(logdir) == False:
  142. os.makedirs(logdir)
  143. appconfigs = config.get("appconfig", dict())
  144. # Construct all the applications' configuration
  145. apps_config = dict()
  146. for rootdir in root_appdirs:
  147. for appdir in root_appdirs[rootdir]:
  148. if appdir in ignored_apps:
  149. print("%s is ignored according to appdirs_ignore settings in configuration" % (appdir))
  150. continue
  151. appdir = appdir.replace("\\", "/") # Change windows \\ path to /
  152. app_buildcfg = copy.deepcopy(global_build_config)
  153. app_buildcfgs = copy.deepcopy(global_build_configs)
  154. app_buildtarget = copy.deepcopy(global_target)
  155. app_parallel = copy.deepcopy(global_parallel)
  156. app_cpobjs = copy.deepcopy(global_cpobjs)
  157. app_runcfg = copy.deepcopy(global_run_config)
  158. app_checks = copy.deepcopy(global_checks)
  159. found_cfg = find_local_appconfig(appdir, appconfigs)
  160. if found_cfg:
  161. appcfg = appconfigs[found_cfg]
  162. # merge_global is True if not present
  163. merge_global = appcfg.get("merge_global", True)
  164. # Merge global config when merge_global is True
  165. if merge_global:
  166. app_buildcfg.update(appcfg.get("build_config", dict()))
  167. app_buildcfgs.update(appcfg.get("build_configs", dict()))
  168. app_runcfg.update(appcfg.get("run_config", dict()))
  169. app_checks.update(appcfg.get("checks", dict()))
  170. if "build_target" in appcfg:
  171. app_buildtarget = appcfg["build_target"]
  172. if "parallel" in appcfg:
  173. app_parallel = appcfg["parallel"]
  174. if "copy_objects" in appcfg:
  175. app_cpobjs = appcfg["copy_objects"]
  176. else: # if merge_global is false, then use app config only
  177. app_buildcfg = appcfg.get("build_config", dict())
  178. app_buildcfgs = appcfg.get("build_configs", dict())
  179. app_buildtarget = appcfg.get("build_target", "clean all")
  180. app_parallel = appcfg.get("parallel", "")
  181. app_runcfg = appcfg.get("run_config", dict())
  182. app_checks = appcfg.get("checks", dict())
  183. app_cpobjs = appcfg.get("copy_objects", False)
  184. app_allconfigs = {"configs": {}}
  185. if len(app_buildcfgs) == 0:
  186. app_buildcfgs = { "default": {} }
  187. for cfgname in app_buildcfgs:
  188. if createlog:
  189. buildlog_name = os.path.join(cfgname, "build.log")
  190. runlog_name = os.path.join(cfgname, "run.log")
  191. app_buildlogfile = get_logfile(appdir, rootdir, logdir, buildlog_name)
  192. app_runlogfile = get_logfile(appdir, rootdir, logdir, runlog_name)
  193. else:
  194. app_buildlogfile = None
  195. app_runlogfile = None
  196. percfg_appbuildcfg = copy.deepcopy(app_buildcfg)
  197. percfg_appbuildcfg.update(app_buildcfgs[cfgname])
  198. app_allconfigs["configs"][cfgname] = {"build_config": percfg_appbuildcfg, "build_target": app_buildtarget, \
  199. "copy_objects": app_cpobjs, "parallel": app_parallel, "run_config": app_runcfg, "checks": app_checks, \
  200. "logs": {"build": app_buildlogfile, "run": app_runlogfile}}
  201. apps_config[appdir] = copy.deepcopy(app_allconfigs)
  202. if len(apps_config) == 0:
  203. print("No applications need to be run according to the configuration")
  204. return False, None
  205. print("Run %d applications defined by configuration" % (len(apps_config)))
  206. # Run all the applications
  207. cmdsts, build_status = self.run_apps_with_configs(apps_config, show_output, stoponfail)
  208. return cmdsts, build_status
  209. def merge_config(appcfg, hwcfg):
  210. return merge_two_config(appcfg, hwcfg)
  211. def merge_cmd_config(config, args_dict):
  212. return merge_config_with_args(config, args_dict)
  213. if __name__ == '__main__':
  214. parser = argparse.ArgumentParser(description="Nuclei SDK Benchmark and Report Tool")
  215. parser.add_argument('--appcfg', required=True, help="Application JSON Configuration File")
  216. parser.add_argument('--hwcfg', help="Hardware Target JSON Configuration File, if specified, will overwrite configuration defined in appcfg")
  217. parser.add_argument('--logdir', default='logs', help="logs directory, default logs")
  218. parser.add_argument('--serport', help="Serial port for monitor, if not specified, it will use the specified by appcfg and hwcfg")
  219. parser.add_argument('--baudrate', help="Serial port baudrate for monitor, it will use the specified by appcfg and hwcfg")
  220. parser.add_argument('--make_options', help="Extra make options passed to overwrite default build configuration passed via appcfg and hwcfg")
  221. parser.add_argument('--build_target', help="Build target passed to make, to overwrite default build_target defined in configuration file")
  222. parser.add_argument('--run_target', help="Run target which program will run, such as hardware, qemu or xlspike")
  223. parser.add_argument('--parallel', help="parallel value, such as -j4 or -j or -j8, default None")
  224. parser.add_argument('--run', action='store_true', help="If specified, will do run not build process")
  225. parser.add_argument('--ncycm', help="If specified, will use cycle model specified here")
  226. parser.add_argument("--timeout", help="If specified, will use timeout value specified here")
  227. parser.add_argument('--verbose', action='store_true', help="If specified, will show detailed build/run messsage")
  228. parser.add_argument('--uniqueid', default="", help="Pass pipeline$CI_PIPELINE_ID, such as pipeline123456")
  229. args = parser.parse_args()
  230. # Load appcfg and hwcfg
  231. ret, appcfg = load_json(args.appcfg)
  232. if ret != JSON_OK:
  233. print("Please provide valid json config file")
  234. sys.exit(1)
  235. # record start time
  236. start_time = time.time()
  237. ret, hwcfg = load_json(args.hwcfg)
  238. # Merge appcfg and hwcfg, hwcfg has higher priority
  239. config = merge_config(appcfg, hwcfg)
  240. if args.ncycm and os.path.isfile(args.ncycm) == False:
  241. print("ERROR: cycle model %s doesn't exist, please check!" % (args.ncycm))
  242. sys.exit(0)
  243. # Merge options passed by serport, baudrate, make_options
  244. config = merge_cmd_config(config, vars(args))
  245. set_global_variables(config)
  246. nsdk_ext = nsdk_bench()
  247. if args.run:
  248. cmdsts, result = nsdk_ext.run_apps(config, args.verbose, args.logdir, False)
  249. else:
  250. cmdsts, result = nsdk_ext.build_apps(config, args.verbose, args.logdir, False)
  251. runtime = round(time.time() - start_time, 2)
  252. print("Applications specified in %s build or run status: %s, time cost %s seconds" % (args.appcfg, cmdsts, runtime))
  253. ret = check_expected(result, config, args.run)
  254. print("Application build as expected: %s" % (ret))
  255. save_results(appcfg, hwcfg, config, result, args.logdir)
  256. if result:
  257. # Generate build or run report
  258. save_report_files(args.logdir, config, result, args.run)
  259. print("This bench cost about %s seconds" % (runtime))
  260. # Exit with ret value
  261. if ret:
  262. sys.exit(0)
  263. else:
  264. sys.exit(1)