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