top_down.py 5.9 KB

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