xref: /XiangShan/scripts/top-down/top_down.py (revision effccb7d09c4946a549cc139dc1b99ed9e726752)
1*effccb7dSTang Haojinfrom multiprocessing import Process, Manager
2*effccb7dSTang Haojinimport threading
3*effccb7dSTang Haojinimport os.path as osp
4*effccb7dSTang Haojinimport os
5*effccb7dSTang Haojinimport resource
6*effccb7dSTang Haojinimport json
7*effccb7dSTang Haojinimport argparse
8*effccb7dSTang Haojinimport psutil
9*effccb7dSTang Haojinimport numpy as np
10*effccb7dSTang Haojinimport pandas as pd
11*effccb7dSTang Haojinimport utils as u
12*effccb7dSTang Haojinimport configs as cf
13*effccb7dSTang Haojinfrom draw import draw
14eb163ef0SHaojin Tang
15eb163ef0SHaojin Tang
16*effccb7dSTang Haojindef batch():
17*effccb7dSTang Haojin    paths = u.glob_stats(cf.stats_dir, fname='simulator_err.txt')
18*effccb7dSTang Haojin
19*effccb7dSTang Haojin    manager = Manager()
20*effccb7dSTang Haojin    all_bmk_dict = manager.dict()
21*effccb7dSTang Haojin
22*effccb7dSTang Haojin    semaphore = threading.Semaphore(psutil.cpu_count())
23*effccb7dSTang Haojin
24*effccb7dSTang Haojin    # for workload, path in paths:
25*effccb7dSTang Haojin    def extract_and_post_process(gloabl_dict, workload, path):
26*effccb7dSTang Haojin        with semaphore:
27*effccb7dSTang Haojin            flag_file = osp.join(osp.dirname(path), 'simulator_out.txt')
28*effccb7dSTang Haojin            with open(flag_file, encoding='utf-8') as f:
29*effccb7dSTang Haojin                contents = f.read()
30*effccb7dSTang Haojin                if 'EXCEEDING CYCLE/INSTR LIMIT' not in contents and 'HIT GOOD TRAP' not in contents:
31*effccb7dSTang Haojin                    print('Skip unfinished job:', workload)
32*effccb7dSTang Haojin                    return
33*effccb7dSTang Haojin
34*effccb7dSTang Haojin            print('Process finished job:', workload)
35*effccb7dSTang Haojin
36*effccb7dSTang Haojin            d = u.xs_get_stats(path, cf.targets)
37*effccb7dSTang Haojin            if len(d):
38*effccb7dSTang Haojin
39*effccb7dSTang Haojin                # add bmk and point after topdown processing
40*effccb7dSTang Haojin                segments = workload.split('_')
41*effccb7dSTang Haojin                if len(segments):
42*effccb7dSTang Haojin                    d['point'] = segments[-1]
43*effccb7dSTang Haojin                    d['workload'] = '_'.join(segments[:-1])
44*effccb7dSTang Haojin                    d['bmk'] = segments[0]
45*effccb7dSTang Haojin
46*effccb7dSTang Haojin            gloabl_dict[workload] = d
47*effccb7dSTang Haojin        return
48*effccb7dSTang Haojin
49*effccb7dSTang Haojin    jobs = [Process(target=extract_and_post_process, args=(
50*effccb7dSTang Haojin        all_bmk_dict, workload, path)) for workload, path in paths]
51*effccb7dSTang Haojin    _ = [p.start() for p in jobs]
52*effccb7dSTang Haojin    _ = [p.join() for p in jobs]
53*effccb7dSTang Haojin
54*effccb7dSTang Haojin    df = pd.DataFrame.from_dict(all_bmk_dict, orient='index')
55*effccb7dSTang Haojin    df = df.sort_index()
56*effccb7dSTang Haojin    df = df.reindex(sorted(df.columns), axis=1)
57*effccb7dSTang Haojin
58*effccb7dSTang Haojin    df = df.fillna(0)
59*effccb7dSTang Haojin
60*effccb7dSTang Haojin    df.to_csv(cf.CSV_PATH, index=True)
61*effccb7dSTang Haojin
62*effccb7dSTang Haojin
63*effccb7dSTang Haojindef proc_input(wl_df: pd.DataFrame, js: dict, workload: str):
64*effccb7dSTang Haojin    # we implement the weighted metrics computation with the following formula:
65*effccb7dSTang Haojin    # weight = vec_weight matmul matrix_perf
66*effccb7dSTang Haojin    # (N, 1) = (1, W) matmul (W, N)
67*effccb7dSTang Haojin    # To make sure the matrix_perf is in the same order as the vec_weight,
68*effccb7dSTang Haojin    # we sort the matrix_perf by point
69*effccb7dSTang Haojin    assert isinstance(wl_df['point'][0], np.int64)
70*effccb7dSTang Haojin    wl_df = wl_df.sort_values(by=['point'])
71*effccb7dSTang Haojin    # We also sort the vec_weight by point
72*effccb7dSTang Haojin    wl_js = dict(js[workload])
73*effccb7dSTang Haojin    wl_df['cpi'] = 1.0 / wl_df['ipc']
74*effccb7dSTang Haojin    vec_weight = pd.DataFrame.from_dict(wl_js['points'], orient='index')
75*effccb7dSTang Haojin
76*effccb7dSTang Haojin    # convert string index into int64
77*effccb7dSTang Haojin    vec_weight.index = vec_weight.index.astype(np.int64)
78*effccb7dSTang Haojin    # select only existing points
79*effccb7dSTang Haojin    vec_weight = vec_weight.loc[wl_df['point']]
80*effccb7dSTang Haojin    # make their sum equals 1.0
81*effccb7dSTang Haojin    vec_weight.columns = ['weight']
82*effccb7dSTang Haojin
83*effccb7dSTang Haojin    vec_weight['weight'] = vec_weight['weight'].astype(np.float64)
84*effccb7dSTang Haojin    coverage = np.sum(vec_weight.values)
85*effccb7dSTang Haojin    vec_weight = vec_weight / coverage
86*effccb7dSTang Haojin
87*effccb7dSTang Haojin    # Drop these auxiliary fields
88*effccb7dSTang Haojin    to_drop = {'bmk', 'point', 'workload', 'ipc'}
89*effccb7dSTang Haojin    to_drop = to_drop.intersection(set(wl_df.columns.to_list()))
90*effccb7dSTang Haojin    wl_df = wl_df.drop(to_drop, axis=1)
91*effccb7dSTang Haojin
92*effccb7dSTang Haojin    weight_metrics = np.matmul(vec_weight.values.reshape(1, -1), wl_df.values)
93*effccb7dSTang Haojin    weight_metrics_df = pd.DataFrame(weight_metrics, columns=wl_df.columns)
94*effccb7dSTang Haojin    # We have to process coverage here to avoid apply weight on top of weight
95*effccb7dSTang Haojin    weight_metrics_df['coverage'] = coverage
96*effccb7dSTang Haojin    return weight_metrics_df.values, weight_metrics_df.columns
97*effccb7dSTang Haojin
98*effccb7dSTang Haojin
99*effccb7dSTang Haojindef proc_bmk(bmk_df: pd.DataFrame, js: dict):
100*effccb7dSTang Haojin    # Similar to per-input proc, we view the instruction count as the weight
101*effccb7dSTang Haojin    # and compute weighted metrics with matrix multiplication
102*effccb7dSTang Haojin    workloads = bmk_df['workload'].unique()
103*effccb7dSTang Haojin    metric_list = []
104*effccb7dSTang Haojin    for wl in workloads:
105*effccb7dSTang Haojin        metrics, cols = proc_input(bmk_df[bmk_df['workload'] == wl], js, wl)
106*effccb7dSTang Haojin        metric_list.append(metrics)
107*effccb7dSTang Haojin    metrics = np.concatenate(metric_list, axis=0)
108*effccb7dSTang Haojin    metrics = pd.DataFrame(metrics, columns=cols)
109*effccb7dSTang Haojin
110*effccb7dSTang Haojin    input_dict = {}
111*effccb7dSTang Haojin    for workload in workloads:
112*effccb7dSTang Haojin        if workload.startswith(workload):
113*effccb7dSTang Haojin            input_dict[workload] = int(js[workload]['insts'])
114*effccb7dSTang Haojin    input_insts = pd.DataFrame.from_dict(
115*effccb7dSTang Haojin        input_dict, orient='index', columns=['insts'])
116*effccb7dSTang Haojin    # make their sum equals 1.0
117*effccb7dSTang Haojin    vec_weight = input_insts / np.sum(input_insts.values)
118*effccb7dSTang Haojin    weight_metric = np.matmul(vec_weight.values.reshape(1, -1), metrics.values)
119*effccb7dSTang Haojin    return weight_metric, metrics.columns
120*effccb7dSTang Haojin
121*effccb7dSTang Haojin
122*effccb7dSTang Haojindef compute_weighted_metrics():
123*effccb7dSTang Haojin    df = pd.read_csv(cf.CSV_PATH, index_col=0)
124*effccb7dSTang Haojin    bmks = df['bmk'].unique()
125*effccb7dSTang Haojin    with open(cf.JSON_FILE, 'r', encoding='utf-8') as f:
126*effccb7dSTang Haojin        js = json.load(f)
127*effccb7dSTang Haojin    weighted = {}
128*effccb7dSTang Haojin    for bmk in bmks:
129*effccb7dSTang Haojin        if bmk not in cf.spec_bmks['06']['int'] and cf.INT_ONLY:
130*effccb7dSTang Haojin            continue
131*effccb7dSTang Haojin        if bmk not in cf.spec_bmks['06']['float'] and cf.FP_ONLY:
132*effccb7dSTang Haojin            continue
133*effccb7dSTang Haojin        df_bmk = df[df['bmk'] == bmk]
134*effccb7dSTang Haojin        workloads = df_bmk['workload'].unique()
135*effccb7dSTang Haojin        n_wl = len(workloads)
136*effccb7dSTang Haojin        if n_wl == 1:
137*effccb7dSTang Haojin            metrics, cols = proc_input(df_bmk, js, workloads[0])
138eb163ef0SHaojin Tang        else:
139*effccb7dSTang Haojin            metrics, cols = proc_bmk(df_bmk, js)
140*effccb7dSTang Haojin        weighted[bmk] = metrics[0]
141*effccb7dSTang Haojin    weighted_df = pd.DataFrame.from_dict(
142*effccb7dSTang Haojin        weighted, orient='index', columns=cols)
143*effccb7dSTang Haojin    if 'cpi' in weighted_df.columns:
144*effccb7dSTang Haojin        weighted_df = weighted_df.sort_values(by='cpi', ascending=False)
145*effccb7dSTang Haojin    else:
146*effccb7dSTang Haojin        weighted_df = weighted_df.sort_index()
147*effccb7dSTang Haojin    weighted_df.to_csv(cf.OUT_CSV)
148eb163ef0SHaojin Tang
149eb163ef0SHaojin Tang
150*effccb7dSTang Haojinif __name__ == '__main__':
151*effccb7dSTang Haojin    parser = argparse.ArgumentParser(usage='generate top-down results')
152*effccb7dSTang Haojin    parser.add_argument('-s', '--stat-dir', action='store', required=True,
153*effccb7dSTang Haojin                        help='stat output directory')
154*effccb7dSTang Haojin    parser.add_argument('-j', '--json', action='store', required=True,
155*effccb7dSTang Haojin                        help='specify json file', default='resources/spec06_rv64gcb_o2_20m.json')
156*effccb7dSTang Haojin    opt = parser.parse_args()
157*effccb7dSTang Haojin    cf.stats_dir = opt.stat_dir
158*effccb7dSTang Haojin    cf.JSON_FILE = opt.json
159*effccb7dSTang Haojin    if not osp.exists('results'):
160*effccb7dSTang Haojin        os.makedirs('results')
161*effccb7dSTang Haojin    if resource.getrlimit(resource.RLIMIT_NOFILE)[0] <= 8192:
162*effccb7dSTang Haojin        resource.setrlimit(resource.RLIMIT_NOFILE, (8192, 8192))
163eb163ef0SHaojin Tang
164*effccb7dSTang Haojin    batch()
165*effccb7dSTang Haojin    compute_weighted_metrics()
166*effccb7dSTang Haojin    draw()
167