rolling.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import sys
  2. import argparse
  3. import sqlite3
  4. import matplotlib.pyplot as plt
  5. import numpy as np
  6. # usage: single db file
  7. # python3 rolling.py plot DB_FILE_PATH [--perf-name PERF_NAME] [--aggregate AGGREGATE] [--interval INTERVAL] [--perf-file PERF_FILE]
  8. #
  9. # usage: diff mutiple db files
  10. # python3 rolling.py diff MUTI_DB_FILE_PATH [--perf-name PERF_NAME] [--aggregate AGGREGATE] [--interval INTERVAL] [--perf-file PERF_FILE]
  11. #
  12. # If you only observe one rolling counter, indicate the --perf-name parameter.
  13. # If you want to observe multiple at the same time, you can indicate the --perf-file parameter,
  14. # pointing to the path to a description file, each line in the file is a rolling counter,
  15. # and you can use the '//' comment at the beginning of the line to remove the unconcerned counter.
  16. #
  17. # Note that generally speaking, when observing multiple rolling counters,
  18. # the meaning of the x-axis needs to be the same, then you can use the intervalBased mode.
  19. #
  20. # If you want to compare multiple dbs to observe the difference between multiple runs, you can use diff mode.
  21. # This requires specifying the path of a description file. Each line in this description file contains a specific db path.
  22. #
  23. # eg.
  24. # exec emu twice with different parameters and obtained different db files (db0, db1).
  25. # want to observe the changes in IPC and prefetch accuracy.
  26. # create a file named db.txt:
  27. # path to db0
  28. # path to db1
  29. # create a file named perf.txt:
  30. # IPC
  31. # L1PrefetchAccuracy
  32. # run `python3 rolling.py diff db.txt --perf-file perf.txt -I (interval in RTL)`
  33. # eg.
  34. # want to observe the IPC rolling in single db (db0).
  35. # run `python3 rolling.py plot path-to-db0 --perf-name IPC`
  36. #
  37. class DataSet:
  38. def __init__(self, db_path):
  39. self.conn = sqlite3.connect(db_path)
  40. self.cursor = self.conn.cursor()
  41. self.xdata = []
  42. self.ydata = []
  43. def derive(self, perf_name, aggregate, clk_itval, hart):
  44. sql = "SELECT xAxisPt, yAxisPt FROM {}_rolling_{}".format(perf_name, hart)
  45. self.cursor.execute(sql)
  46. result = self.cursor.fetchall()
  47. aggcnt = 0
  48. recordcnt = 0
  49. aggydata = 0
  50. aggxdata = 0
  51. self.xdata = []
  52. self.ydata = []
  53. if clk_itval == -1:
  54. # normal mode
  55. # db log in normal mode: (xAxis, ydata)
  56. # xAxis is current position in X Axis, ydata is the Increment value between this point and last point
  57. for row in result:
  58. aggcnt += 1
  59. aggydata += row[1]
  60. if aggcnt == aggregate:
  61. self.xdata.append(row[0])
  62. self.ydata.append(aggydata/(row[0]-aggxdata))
  63. aggcnt = 0
  64. aggydata = 0
  65. aggxdata = row[0]
  66. else:
  67. # intervalBased mode, -I interval should be specified
  68. # db log in intervalBased mode: (xdata, ydata)
  69. # xdata, ydata in the Increment value in a certain interval
  70. for row in result:
  71. aggcnt += 1
  72. aggxdata += row[0]
  73. aggydata += row[1]
  74. if aggcnt == aggregate:
  75. self.xdata.append((clk_itval * aggregate) * (recordcnt + 1))
  76. self.ydata.append(0 if aggydata == 0 else aggxdata/aggydata)
  77. aggcnt = 0
  78. aggxdata = 0
  79. aggydata = 0
  80. recordcnt += 1
  81. def plot(self, lb='PERF'):
  82. plt.plot(self.xdata, self.ydata, lw=1, ls='-', label=lb)
  83. def legend():
  84. plt.legend()
  85. def show():
  86. plt.show()
  87. def err_exit(msg):
  88. print(msg)
  89. sys.exit(1)
  90. def check_args(args):
  91. if args.aggregate <= 0:
  92. err_exit("aggregation ratio must be no less than 1")
  93. if not args.perf_name and not args.perf_file:
  94. err_exit("should either specify perf-name or perf-file")
  95. def plot_dataset(path, perf_name, aggregate, clk_itval, perf_file, db_id=-1):
  96. dataset = DataSet(path)
  97. label = '_' + str(db_id) if db_id != -1 else ''
  98. if perf_file:
  99. with open(perf_file) as fp:
  100. perfs = fp.readlines()
  101. perfs = [perf.strip() for perf in perfs]
  102. perfs = list(filter(lambda x: not x.startswith('//'), perfs))
  103. for perf in perfs:
  104. dataset.derive(perf, aggregate, clk_itval, 0)
  105. dataset.plot(perf + label)
  106. else:
  107. dataset.derive(perf_name, aggregate, clk_itval, 0)
  108. dataset.plot(perf_name + label)
  109. def handle_plot(args):
  110. check_args(args)
  111. plot_dataset(args.db_path, args.perf_name, args.aggregate, args.interval, args.perf_file)
  112. DataSet.legend()
  113. DataSet.show()
  114. def handle_diff(args):
  115. check_args(args)
  116. db_path = args.db_path
  117. with open(db_path) as fp:
  118. for (idx, db) in enumerate(fp):
  119. plot_dataset(db.strip(), args.perf_name, args.aggregate, args.interval, args.perf_file, idx)
  120. DataSet.legend()
  121. DataSet.show()
  122. if __name__ == "__main__":
  123. parser = argparse.ArgumentParser(description="performance rolling plot script for xs")
  124. subparsers = parser.add_subparsers(title='useful sub function', dest='subcommand', help='useful sub function')
  125. # sub function for single db file
  126. cmd1_parser = subparsers.add_parser('plot', help='for single db file')
  127. cmd1_parser.add_argument('db_path', metavar='db_path', type=str, help='path to chiseldb file')
  128. cmd1_parser.add_argument('--perf-name', default=None, type=str, help="name of the performance counter")
  129. cmd1_parser.add_argument('--aggregate', '-A', default=1, type=int, help="aggregation ratio")
  130. cmd1_parser.add_argument('--interval', '-I', default=-1, type=int, help="interval value in the interval based mode")
  131. cmd1_parser.add_argument('--perf-file', '-F', default=None, type=str, help="path to a file including all interested performance counters")
  132. # sub function for diff multiple db files
  133. cmd2_parser = subparsers.add_parser('diff', help='for diff multiple db files')
  134. cmd2_parser.add_argument('db_path', metavar='muti_db_path', type=str, help="path to a file including all path to chiseldb files")
  135. cmd2_parser.add_argument('--perf-name', default=None, type=str, help="name of the performance counter")
  136. cmd2_parser.add_argument('--aggregate', '-A', default=1, type=int, help="aggregation ratio")
  137. cmd2_parser.add_argument('--interval', '-I', default=-1, type=int, help="interval value in the interval based mode")
  138. cmd2_parser.add_argument('--perf-file', '-F', default=None, type=str, help="path to a file including all interested performance counters")
  139. args = parser.parse_args()
  140. if args.subcommand == 'plot':
  141. handle_plot(args)
  142. elif args.subcommand == 'diff':
  143. handle_diff(args)
  144. else:
  145. err_exit('invalid command')