parse_report.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. import argparse
  2. import json
  3. import os
  4. import openpyxl.styles
  5. import openpyxl.utils
  6. import openpyxl.workbook
  7. import pyexcel as pe
  8. import openpyxl as openpyxl
  9. # TODO:
  10. # 1. Make the generated excel more readable and beautiful
  11. # - Make column widths more suitable for the table header
  12. # - Make excel content with more beautiful colors and fonts
  13. def parse_runresult(runresult_file, CAREVAR="bench", BENCHTYPE="barebench"):
  14. runresult = dict()
  15. # Load json result from runresult file runresult.json
  16. with open(runresult_file) as f:
  17. runresult = json.load(f)
  18. parsed_bench = dict()
  19. olevels = ["O0", "O1", "O2", "O3", "Ofast", "Os", "Oz"]
  20. # parse the bench results from runresult json
  21. for archcfg in runresult:
  22. for benchtype in runresult[archcfg]:
  23. # TODO only check barebench results now
  24. if benchtype != "barebench":
  25. continue
  26. for subtype in runresult[archcfg][benchtype]:
  27. sheettype = subtype
  28. if BENCHTYPE == "toolbench":
  29. matcholv = None
  30. for olv in olevels:
  31. if olv in archcfg:
  32. matcholv = olv
  33. break
  34. if matcholv is not None:
  35. sheettype = "%s_%s" % (subtype, matcholv)
  36. # collect the results of barebench
  37. # TODO ignore a lot meta data such as code size and compiler info
  38. if sheettype not in parsed_bench:
  39. parsed_bench[sheettype] = dict()
  40. if CAREVAR == "bench":
  41. # benchval is a dict like this
  42. # {"DMIPS/MHz": 1.426 } or {"CoreMark/MHz": 1.212} or {"MWIPS/MHz": 0.068}
  43. benchval = runresult[archcfg][benchtype][subtype]["value"]
  44. try:
  45. parsed_bench[sheettype][archcfg] = list(benchval.values())[0]
  46. except:
  47. # No value get from value dict
  48. parsed_bench[sheettype][archcfg] = ""
  49. elif CAREVAR.startswith("size"):
  50. sizeval = runresult[archcfg][benchtype][subtype]["size"]
  51. whichsize = CAREVAR.lstrip("size").split("+")
  52. # by default return total size
  53. if len(whichsize) == 1 and whichsize[0] not in ("text", "data", "bss"):
  54. parsed_bench[sheettype][archcfg] = sizeval["total"]
  55. else:
  56. # sum the key found in whichsize
  57. # eg. size:text+data will return the sum of text+data section
  58. sizesum = 0
  59. for szkey in whichsize:
  60. szkey = szkey.strip()
  61. if szkey in ("text", "data", "bss"):
  62. sizesum += sizeval[szkey]
  63. parsed_bench[sheettype][archcfg] = sizesum
  64. # return the parsed bench result
  65. return parsed_bench
  66. def parse_genreport(rptdir, BENCHTYPE="barebench", CAREVAR="bench"):
  67. # get the list of directory list in rptdir
  68. rv32_bench = dict()
  69. rv64_bench = dict()
  70. for d in os.listdir(rptdir):
  71. if d.startswith("."):
  72. continue
  73. # not a valid barebench directory
  74. if os.path.isdir(os.path.join(rptdir, d, BENCHTYPE)) == False:
  75. continue
  76. runresult_json_file = os.path.join(rptdir, d, BENCHTYPE, "runresult.json")
  77. if d.startswith("ux") or d.startswith("nx"):
  78. rv64_bench[d] = parse_runresult(runresult_json_file, BENCHTYPE=BENCHTYPE, CAREVAR=CAREVAR)
  79. else:
  80. rv32_bench[d] = parse_runresult(runresult_json_file, BENCHTYPE=BENCHTYPE, CAREVAR=CAREVAR)
  81. return rv32_bench, rv64_bench
  82. def shorten_bitname(bitname):
  83. first_part = bitname.split("_config")[0]
  84. last_part = bitname.split("_")[-1][4:-4]
  85. shortname = ""
  86. # if "_best" in first_part:
  87. # first_part = first_part.replace("_best", "_b")
  88. # if "_dual" in first_part:
  89. # first_part = first_part.replace("_dual", "_DI")
  90. if "single" in bitname:
  91. shortname = "%s_SI-%s" % (first_part, last_part)
  92. else:
  93. shortname = "%s-%s" % (first_part, last_part)
  94. return shortname
  95. def generate_excel_from_bench(rvbench, xlsname):
  96. # generate excel using rvbench
  97. rvsheets = dict()
  98. for bitname in rvbench:
  99. for subtype in rvbench[bitname]:
  100. if subtype not in rvsheets:
  101. rvsheets[subtype] = set()
  102. rvsheets[subtype] = set(rvbench[bitname][subtype].keys()).union(rvsheets[subtype])
  103. rvwbdict = dict()
  104. for subtype in rvsheets:
  105. rvsheets[subtype] = sorted(rvsheets[subtype])
  106. parsed_configs = []
  107. for bitname in rvbench:
  108. shortbitname = shorten_bitname(bitname)
  109. if shortbitname in parsed_configs:
  110. continue
  111. parsed_configs.append(shortbitname)
  112. for subtype in rvbench[bitname]:
  113. if subtype not in rvwbdict:
  114. rvwbdict[subtype] = [["config"]]
  115. for cfgname in rvsheets[subtype]:
  116. rvwbdict[subtype].append([cfgname])
  117. rvwbdict[subtype][0].extend([shorten_bitname(bitname)])
  118. cfgindex = 1
  119. for cfgname in rvsheets[subtype]:
  120. if cfgname in rvbench[bitname][subtype]:
  121. rvwbdict[subtype][cfgindex].extend([rvbench[bitname][subtype][cfgname]])
  122. else:
  123. rvwbdict[subtype][cfgindex].extend([""])
  124. cfgindex += 1
  125. print("Save Excel as %s\n" % (xlsname))
  126. # book = pe.isave_book_as(bookdict=rvwbdict, dest_file_name=xlsname)
  127. book = pe.get_book(bookdict=rvwbdict)
  128. print(book)
  129. book.save_as(xlsname)
  130. book.save_as(xlsname + ".html")
  131. pass
  132. def beautify_excel(excelfile):
  133. wb = openpyxl.load_workbook(filename=excelfile)
  134. for ws in wb.worksheets:
  135. bold_font_style = openpyxl.styles.Font(name="阿里巴巴普惠体 3.0 55 Regular", bold=True, size=11)
  136. font_stype = openpyxl.styles.Font(name="阿里巴巴普惠体 3.0 55 Regular", bold=False, size=11)
  137. alignment_style = openpyxl.styles.Alignment(horizontal="center", vertical="center", wrap_text=True)
  138. fill_style = openpyxl.styles.PatternFill(start_color="FFFF00", end_color="FFFF00", fill_type="solid")
  139. ws.row_dimensions[1].height = 60
  140. ws.column_dimensions['A'].width = 50
  141. for colidx in range(1, ws.max_row):
  142. ws.column_dimensions[openpyxl.utils.get_column_letter(colidx+1)].width = 10
  143. for col in ws.iter_cols(min_row=1, max_row=ws.max_row, min_col=1, max_col=ws.max_column):
  144. maxval = None
  145. if col[0].column > 1:
  146. colvals = [cell.value for cell in col][1:]
  147. maxval = max(colvals, key=lambda x: x if x else 0)
  148. for cell in col:
  149. cell.alignment = alignment_style
  150. if cell.row == 1 or cell.column == 1:
  151. cell.font = bold_font_style
  152. else:
  153. cell.font = font_stype
  154. if cell.column > 1 and maxval and cell.value == maxval:
  155. cell.fill = fill_style
  156. wb.save(excelfile.replace(".xlsx", "_styled.xlsx"))
  157. pass
  158. def generate_bench_excel(rptdir, BENCHTYPE="barebench", CAREVAR="bench"):
  159. rv32_bench, rv64_bench = parse_genreport(rptdir, BENCHTYPE=BENCHTYPE, CAREVAR=CAREVAR)
  160. # generate excel using rv32_bench
  161. generate_excel_from_bench(rv32_bench, os.path.join(rptdir, "rv32_%s.xlsx" % (BENCHTYPE)))
  162. beautify_excel(os.path.join(rptdir, "rv32_%s.xlsx" % (BENCHTYPE)))
  163. generate_excel_from_bench(rv64_bench, os.path.join(rptdir, "rv64_%s.xlsx" % (BENCHTYPE)))
  164. beautify_excel(os.path.join(rptdir, "rv64_%s.xlsx" % (BENCHTYPE)))
  165. pass
  166. # 使用argpaser 解析参数,-d 表示待解析的目录
  167. parser = argparse.ArgumentParser(description='Parse the nsdk_cli run reports')
  168. parser.add_argument('-d', '--dir', help='directory to parse')
  169. args = parser.parse_args()
  170. reportdir = args.dir.strip()
  171. for benchtype in ["barebench", "toolbench"]:
  172. generate_bench_excel(reportdir, benchtype)