nsdk_utils.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. #!/usr/bin/env python3
  2. import os
  3. import sys
  4. import time
  5. import copy
  6. import serial
  7. import tempfile
  8. import collections
  9. from threading import Thread
  10. import subprocess
  11. import asyncio
  12. import glob
  13. import json
  14. class NThread(Thread):
  15. def __init__(self, func, args):
  16. super(NThread, self).__init__()
  17. self.func = func
  18. self.args = args
  19. def run(self):
  20. self.result = self.func(*self.args)
  21. def get_result(self):
  22. try:
  23. return self.result
  24. except Exception:
  25. return None
  26. JSON_OK=0
  27. JSON_NOFILE=1
  28. JSON_INVAILD=2
  29. def load_json(file):
  30. if isinstance(file, str) == False or os.path.isfile(file) == False:
  31. return JSON_NOFILE, None
  32. try:
  33. data = json.load(open(file, 'r'))
  34. return JSON_OK, data
  35. except:
  36. print("Error: %s is an invalid json file!" % (file))
  37. return JSON_INVAILD, None
  38. def save_json(file, data):
  39. if isinstance(file, str) == False:
  40. return False
  41. try:
  42. with open(file, "w") as cf:
  43. json.dump(data, cf, indent=4)
  44. return True
  45. except:
  46. print("Error: Data can't be serialized to json file!")
  47. return False
  48. # get from https://gist.github.com/angstwad/bf22d1822c38a92ec0a9
  49. def dict_merge(dct, merge_dct):
  50. """ Recursive dict merge. Inspired by :meth:``dict.update()``, instead of
  51. updating only top-level keys, dict_merge recurses down into dicts nested
  52. to an arbitrary depth, updating keys. The ``merge_dct`` is merged into
  53. ``dct``.
  54. :param dct: dict onto which the merge is executed
  55. :param merge_dct: dct merged into dct
  56. :return: None
  57. """
  58. for k, v in merge_dct.items():
  59. if (k in dct and isinstance(dct[k], dict)
  60. and isinstance(merge_dct[k], collections.Mapping)):
  61. dict_merge(dct[k], merge_dct[k])
  62. else:
  63. dct[k] = merge_dct[k]
  64. def get_make_csv(app, config):
  65. make_options = " "
  66. SUPPORT_KEYS = ["SOC", "BOARD", "CORE", "DOWNLOAD", "VARIANT", \
  67. "BENCH_UNIT", "BENCH_FLAGS", "DSP_ENABLE", "SILENT", "V"]
  68. csv_print = "CSV, APP=%s" % (app)
  69. if isinstance(config, dict):
  70. for key in config:
  71. if key not in SUPPORT_KEYS:
  72. continue
  73. option = "%s=%s"%(key, config[key])
  74. make_options = " %s %s " % (make_options, option)
  75. csv_print = "%s, %s" % (csv_print, option)
  76. return make_options, csv_print
  77. def try_decode_bytes(bytes):
  78. ENCODING_LIST = ['utf-8', 'gbk', 'gb18030']
  79. destr = ""
  80. for encoding in ENCODING_LIST:
  81. try:
  82. destr = bytes.decode(encoding)
  83. break
  84. except:
  85. continue
  86. return destr
  87. COMMAND_RUNOK=0
  88. COMMAND_INVALID=1
  89. COMMAND_FAIL=2
  90. COMMAND_INTERRUPTED=3
  91. COMMAND_EXCEPTION=4
  92. COMMAND_NOTAPP=5
  93. COMMAND_TIMEOUT=6
  94. RUNSTATUS_OK=0
  95. RUNSTATUS_FAIL=1
  96. RUNSTATUS_NOTSTART=2
  97. def run_command(command, show_output=True, logfile=None, append=False):
  98. logfh = None
  99. ret = COMMAND_RUNOK
  100. cmd_elapsed_ticks = 0
  101. if isinstance(command, str) == False:
  102. return COMMAND_INVALID, cmd_elapsed_ticks
  103. startticks = time.time()
  104. process = None
  105. try:
  106. if isinstance(logfile, str):
  107. if append:
  108. logfh = open(logfile, "ab")
  109. else:
  110. logfh = open(logfile, "wb")
  111. process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, \
  112. stderr=subprocess.STDOUT)
  113. while True:
  114. line = process.stdout.readline()
  115. if (not line) and process.poll() is not None:
  116. break
  117. if show_output:
  118. print(try_decode_bytes(line), end="")
  119. if logfh:
  120. logfh.write(line)
  121. time.sleep(0.01)
  122. process.communicate(30)
  123. if process.returncode != 0:
  124. ret = COMMAND_FAIL
  125. except (KeyboardInterrupt):
  126. print("Key CTRL-C pressed, command executing stopped!")
  127. ret = COMMAND_INTERRUPTED
  128. except subprocess.TimeoutExpired:
  129. process.kill()
  130. ret = COMMAND_TIMEOUT
  131. except Exception as exc:
  132. print("Unexpected exception happened: %s" %(str(exc)))
  133. ret = COMMAND_EXCEPTION
  134. finally:
  135. if process:
  136. del process
  137. if logfh:
  138. logfh.close()
  139. cmd_elapsed_ticks = time.time() - startticks
  140. return ret, cmd_elapsed_ticks
  141. # def run_command(command, show_output=True, logfile=None):
  142. # if sys.platform == "win32":
  143. # loop = asyncio.ProactorEventLoop() # For subprocess' pipes on Windows
  144. # asyncio.set_event_loop(loop)
  145. # else:
  146. # loop = asyncio.get_event_loop()
  147. # ret, cmd_elapsed_ticks = loop.run_until_complete(run_command_async(command, show_output, logfile, timeout=10))
  148. # loop.close()
  149. # return ret, cmd_elapsed_ticks
  150. # async def run_command_async(command, show_output=True, logfile=None, timeout=30):
  151. # logfh = None
  152. # ret = COMMAND_RUNOK
  153. # cmd_elapsed_ticks = 0
  154. # if isinstance(command, str) == False:
  155. # return COMMAND_INVALID, cmd_elapsed_ticks
  156. # startticks = time.time()
  157. # process = None
  158. # try:
  159. # if isinstance(logfile, str):
  160. # logfh = open(logfile, "wb")
  161. # process = await asyncio.create_subprocess_shell(command, stdout=asyncio.subprocess.PIPE, \
  162. # stderr=asyncio.subprocess.STDOUT)
  163. # while True:
  164. # try:
  165. # line = await asyncio.wait_for(process.stdout.readline(), timeout)
  166. # except asyncio.TimeoutError:
  167. # break
  168. # except (KeyboardInterrupt):
  169. # print("Key CTRL-C pressed, command executing stopped!")
  170. # ret = COMMAND_INTERRUPTED
  171. # break
  172. # else:
  173. # if not line: #EOF
  174. # break
  175. # if show_output:
  176. # print(try_decode_bytes(line), end="")
  177. # if logfh:
  178. # logfh.write(line)
  179. # continue
  180. # await process.communicate()
  181. # if process.returncode != 0:
  182. # ret = COMMAND_FAIL
  183. # except (KeyboardInterrupt):
  184. # print("Key CTRL-C pressed, command executing stopped!")
  185. # ret = COMMAND_INTERRUPTED
  186. # except Exception as exc:
  187. # print("Unexpected exception happened: %s" %(str(exc)))
  188. # ret = COMMAND_EXCEPTION
  189. # finally:
  190. # if process:
  191. # del process
  192. # if logfh:
  193. # logfh.close()
  194. # cmd_elapsed_ticks = time.time() - startticks
  195. # return ret, cmd_elapsed_ticks
  196. def find_files(fndir, pattern, recursive=False):
  197. fndir = os.path.normpath(fndir)
  198. files = glob.glob(os.path.join(fndir, pattern), recursive=recursive)
  199. return files
  200. def get_logfile(appdir, startdir, logdir, logname):
  201. relpath = os.path.relpath(appdir, startdir)
  202. startdir_basename = os.path.basename(startdir)
  203. applogdir = os.path.join(logdir, startdir_basename, relpath)
  204. applog = os.path.join(applogdir, logname)
  205. applogdir = os.path.dirname(applog)
  206. if os.path.isdir(applogdir) == False:
  207. os.makedirs(applogdir)
  208. return applog
  209. def get_elfsize(elf):
  210. sizeinfo = {"text": -1, "data": -1, "bss": -1, "total": -1}
  211. if os.path.isfile(elf) == False:
  212. return sizeinfo
  213. sizecmd = "riscv-nuclei-elf-size %s" % (elf)
  214. sizelog = tempfile.mktemp()
  215. ret, _ = run_command(sizecmd, show_output=False, logfile=sizelog)
  216. if ret == COMMAND_RUNOK:
  217. with open(sizelog, "r") as sf:
  218. lines = sf.readlines()
  219. datas = lines[1].strip().split()
  220. sizeinfo["text"] = int(datas[0])
  221. sizeinfo["data"] = int(datas[1])
  222. sizeinfo["bss"] = int(datas[2])
  223. sizeinfo["total"] = int(datas[3])
  224. os.remove(sizelog)
  225. return sizeinfo
  226. def find_local_appconfig(appdir, localcfgs):
  227. if isinstance(appdir, str) and isinstance(localcfgs, dict):
  228. if appdir in localcfgs:
  229. return appdir
  230. else:
  231. foundcfg = None
  232. for localcfg in localcfgs:
  233. localcfgtp = localcfg.strip('/')
  234. striped_dir = appdir.split(localcfgtp, 1)
  235. if len(striped_dir) == 2:
  236. striped_dir = striped_dir[1]
  237. else:
  238. striped_dir = appdir
  239. if striped_dir != appdir:
  240. if striped_dir.startswith('/'):
  241. if foundcfg is None:
  242. foundcfg = localcfg
  243. else:
  244. if len(foundcfg) < len(localcfg):
  245. foundcfg = localcfg
  246. return foundcfg
  247. else:
  248. return None
  249. PROGRAM_UNKNOWN="unknown"
  250. PROGRAM_COREMARK="coremark"
  251. PROGRAM_DHRYSTONE="dhrystone"
  252. PROGRAM_WHETSTONE="whetstone"
  253. def parse_benchmark_runlog(lines):
  254. if isinstance(lines, list) == False:
  255. return False, None
  256. result = None
  257. program_type = PROGRAM_UNKNOWN
  258. for line in lines:
  259. # Coremark
  260. if "CoreMark" in line:
  261. program_type = PROGRAM_COREMARK
  262. if "Iterations*1000000/total_ticks" in line:
  263. value = line.split("=")[1].strip().split()[0]
  264. result = dict()
  265. result["CoreMark/MHz"] = (float)(value)
  266. # Dhrystone
  267. if "Dhrystone" in line:
  268. program_type = PROGRAM_DHRYSTONE
  269. if "1000000/(User_Cycle/Number_Of_Runs)" in line:
  270. value = line.split("=")[1].strip().split()[0]
  271. result = dict()
  272. result["DMIPS/MHz"] = (float)(value)
  273. # Whetstone
  274. if "Whetstone" in line:
  275. program_type = PROGRAM_WHETSTONE
  276. if "MWIPS/MHz" in line:
  277. value = line.strip().split()[1:2]
  278. result = dict()
  279. result["MWIPS/MHz"] = (float)(value[0])
  280. return program_type, result