xref: /XiangShan/scripts/rolling/rolling.py (revision 7cf78eb25d45a53e97cb143ddd0185eddc10672c)
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')