hpm_parse.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #!/bin/env python3
  2. import os
  3. import sys
  4. import argparse
  5. from prettytable import *
  6. import json
  7. HPM_EVENTS= [
  8. ["Reserved", "Cycle count", "Retired instruction count", "Integer load instruction (includes LR)",
  9. "Integer store instruction (includes SC)", "Atomic memory operation (do not include LR and SC)",
  10. "System instruction", "Integer computational instruction(excluding multiplication/division/remainder)",
  11. "Conditional branch", "Taken conditional branch", "JAL instruction", "JALR instruction", "Return instruction",
  12. "Control transfer instruction (CBR+JAL+JALR)", "Fence instruction(Not include fence.i)", "Integer multiplication instruction",
  13. "Integer division/remainder instruction", "Floating-point load instruction", "Floating-point store instruction",
  14. "Floating-point addition/subtraction", "Floating-point multiplication",
  15. "Floating-point fused multiply-add (FMADD, FMSUB, FNMSUB, FNMADD)", "Floating-point division or square-root",
  16. "Other floating-point instruction", "Conditional branch prediction fail", "JALR prediction fail",
  17. "POP predication fail", "FENCEI instruction", "SFENCE instruction", "ECALL instruction",
  18. "EXCEPTION instruction", "INTERRUPT instruction"],
  19. ["Reserved", "Icache miss", "Dcache miss", "ITLB miss", "DTLB miss", "Main TLB miss",
  20. "Reserved", "Reserved", "L2-Cache access count", "L2-Cache miss count",
  21. "Memory bus request count", "IFU stall cycle count", "EXU stall cycle count", "Timer count"],
  22. ["Reserved", "Reserved", "Branch instruction commit count", "Branch predict fail count"],
  23. ["Dcache read count", "Dcache read miss count", "Dcache write count", "Dcache write miss count",
  24. "Dcache prefetch count", "Dcache prefetch miss count", "Icache read count", "Reserved",
  25. "Icache prefetch count", "Icache prefetch miss count", "L2-Cache read hit count",
  26. "L2-Cache read miss count", "L2-Cache write hit count", "L2-Cache write miss count",
  27. "L2-Cache prefetch hit count", "L2-Cache prefetch miss count", "DTLB read count",
  28. "DTLB read miss count", "DTLB write count", "DTLB write miss count", "ITLB read count",
  29. "Reserved", "BTB read count", "BTB read miss count", "BTB write count", "BTB write miss count"]
  30. ]
  31. HPM_MEVENT_ENABLE = 0x8
  32. HPM_SEVENT_ENABLE = 0x4
  33. HPM_UEVENT_ENABLE = 0x1
  34. def get_hpm_evmode(ena):
  35. evmode = ""
  36. if ena & HPM_MEVENT_ENABLE:
  37. evmode += "M"
  38. if ena & HPM_SEVENT_ENABLE:
  39. evmode += "S"
  40. if ena & HPM_UEVENT_ENABLE:
  41. evmode += "U"
  42. return evmode
  43. def get_hpm_event(sel, idx):
  44. if sel >= len(HPM_EVENTS):
  45. return "INVAILD"
  46. if idx >= len(HPM_EVENTS[sel]):
  47. return "INVAILD"
  48. return HPM_EVENTS[sel][idx]
  49. def parse_hpm(logfile):
  50. if os.path.isfile(logfile) == False:
  51. return dict()
  52. hpmrecords = dict()
  53. with open(logfile, "r") as lf:
  54. for line in lf.readlines():
  55. if line.startswith("HPM"):
  56. hpmkey, proc, hpmcount = line.split(",")
  57. hpmkey = hpmkey.strip()
  58. proc = proc.strip()
  59. hpmcount = hpmcount.strip()
  60. if proc not in hpmrecords:
  61. hpmrecords[proc] = dict()
  62. hpmrecords[proc][hpmkey] = hpmcount
  63. return hpmrecords
  64. def analyze_hpm(records):
  65. x = PrettyTable()
  66. x.set_style(MARKDOWN)
  67. x.field_names = ["Process", "HPM", "Mode", "Event", "Counts"]
  68. parsed_hpm = dict()
  69. csv_hpm = [x.field_names]
  70. for proc in records:
  71. parsed_hpm[proc] = dict()
  72. for hpmkey in records[proc]:
  73. hpmcounter, hpmevent = hpmkey.split(":")
  74. hpmevent = int(hpmevent, 16)
  75. # event_sel: 3:0
  76. event_sel = hpmevent & 0xF
  77. # event_idx: 8:4
  78. event_idx = (hpmevent >> 4) & 0x1F
  79. # event_ena: m/rsv/s/u 31:28
  80. event_ena = (hpmevent >> 28) & 0xF
  81. event_name = get_hpm_event(event_sel, event_idx)
  82. event_mode = get_hpm_evmode(event_ena)
  83. event_count = int(records[proc][hpmkey])
  84. x.add_row([proc, hpmcounter, event_mode, event_name, event_count])
  85. csv_hpm.append([proc, hpmcounter, event_mode, event_name, event_count])
  86. if hpmcounter not in parsed_hpm[proc]:
  87. parsed_hpm[proc][hpmcounter] = list()
  88. parsed_hpm[proc][hpmcounter].append((event_mode, event_name, event_count))
  89. return parsed_hpm, csv_hpm, x
  90. def save_csv(csvlist, csvfile):
  91. with open(csvfile, "w") as cf:
  92. for csvline in csvlist:
  93. line = ",".join(map(str, csvline))
  94. cf.write(line + "\n")
  95. pass
  96. if __name__ == '__main__':
  97. parser = argparse.ArgumentParser(description="Nuclei SDK HPM Log Parsing")
  98. parser.add_argument('--logfile', required=True, help="log file of hpm running")
  99. args = parser.parse_args()
  100. hpmrecords = parse_hpm(args.logfile)
  101. if len(hpmrecords) == 0:
  102. print("None records found in %s!" % (args.logfile))
  103. sys.exit(1)
  104. parsedhpm, csv_hpm, table = analyze_hpm(hpmrecords)
  105. print(table)
  106. hpmresult = {"records": hpmrecords, "parsed": parsedhpm}
  107. hpmrstfile = args.logfile + ".json"
  108. with open(hpmrstfile, "w") as cf:
  109. json.dump(hpmresult, cf, indent=4)
  110. print("\nParsed HPM event saved into %s" %(hpmrstfile))
  111. hpmcsvfile = args.logfile + ".csv"
  112. save_csv(csv_hpm, hpmcsvfile)
  113. print("Save HPM CSV to %s" % (hpmcsvfile))
  114. sys.exit(0)