1import csv 2import sys 3from pyecharts.charts import Page, Sunburst 4from pyecharts import options as opts 5 6 7class TopDown: 8 """TopDown node""" 9 def __init__(self, name, percentage): 10 self.name = name 11 if isinstance(percentage, TopDown): 12 self.percentage = percentage.percentage 13 else: 14 self.percentage = percentage 15 self.down = {} 16 self.top = None 17 self.level = 0 18 19 def __add__(self, rhs): 20 if isinstance(rhs, TopDown): 21 return self.percentage + rhs.percentage 22 return self.percentage + rhs 23 24 def __radd__(self, lhs): 25 if isinstance(lhs, TopDown): 26 return lhs.percentage + self.percentage 27 return lhs + self.percentage 28 29 def __sub__(self, rhs): 30 if isinstance(rhs, TopDown): 31 return self.percentage - rhs.percentage 32 return self.percentage - rhs 33 34 def __rsub__(self, lhs): 35 if isinstance(lhs, TopDown): 36 return lhs.percentage - self.percentage 37 return lhs - self.percentage 38 39 def __mul__(self, rhs): 40 if isinstance(rhs, TopDown): 41 return self.percentage * rhs.percentage 42 return self.percentage * rhs 43 44 def __rmul__(self, lhs): 45 if isinstance(lhs, TopDown): 46 return lhs.percentage * self.percentage 47 return lhs * self.percentage 48 49 def __truediv__(self, rhs): 50 if isinstance(rhs, TopDown): 51 return self.percentage / rhs.percentage 52 return self.percentage / rhs 53 54 def __rtruediv__(self, lhs): 55 if isinstance(lhs, TopDown): 56 return lhs.percentage / self.percentage 57 return lhs / self.percentage 58 59 def add_down(self, name, percentage): 60 """Add a leaf node 61 62 Args: 63 name (str): Name of leaf node 64 percentage (float): Percentage of leaf node 65 66 Returns: 67 TopDown: leaf 68 """ 69 self.down[name] = TopDown(name, percentage) 70 self.down[name].top = self 71 self.down[name].level = self.level + 1 72 return self.down[name] 73 74 def draw(self): 75 """Draw the TopDown sunburst chart 76 77 Returns: 78 _type_: _description_ 79 """ 80 if not self.down: 81 return [opts.SunburstItem(name=self.name, value=self.percentage)] 82 items = [] 83 for value in self.down.values(): 84 items.append(value.draw()[0]) 85 if self.top: 86 return [opts.SunburstItem(name=self.name, value=self.percentage, children=items)] 87 return items 88 89 90def process_one(path, head): 91 """Process one chart 92 93 Args: 94 path (String): csv path 95 head (String): chart head 96 97 Returns: 98 Sunburst chart 99 """ 100 with open(path, encoding='UTF-8') as file: 101 csv_file = dict(csv.reader(file)) 102 103 def use(name): 104 return float(csv_file[name]) 105 106 csv_file['total_slots'] = use('total_cycles') * 6 107 csv_file['ifu2id_allNO_slots'] = use('ifu2id_allNO_cycle') * 6 108 csv_file['ifu2id_hvButNotFull_slots'] = use('fetch_bubbles') - use('ifu2id_allNO_slots') 109 110 stall_cycles_core = use('stall_cycle_fp') + use('stall_cycle_int') + use('stall_cycle_rob') + use('stall_cycle_int_dq') + use('stall_cycle_fp_dq') + use('ls_dq_bound_cycles') 111 112 top = TopDown("Top", 1.0) 113 114# top 115 frontend_bound = top.add_down("Frontend Bound", use('decode_bubbles') / use('total_slots')) 116 bad_speculation = top.add_down("Bad Speculation", (use('slots_issued') - use('slots_retired') + use('recovery_bubbles')) / use('total_slots')) 117 retiring = top.add_down("Retiring", use('slots_retired') / use('total_slots')) 118 backend_bound = top.add_down("Backend Bound", top - frontend_bound - bad_speculation - retiring) 119 120#top->frontend_bound 121 fetch_latency = frontend_bound.add_down("Fetch Latency", use('fetch_bubbles') / use('total_slots')) 122 fetch_bandwidth = frontend_bound.add_down("Fetch Bandwidth", frontend_bound - fetch_latency) 123 124# top->frontend_bound->fetch_latency 125 itlb_miss = fetch_latency.add_down("iTLB Miss", use('itlb_miss_cycles') / use('total_cycles')) 126 icache_miss = fetch_latency.add_down("iCache Miss", use('icache_miss_cycles') / use('total_cycles')) 127 stage2_redirect_cycles = fetch_latency.add_down("Stage2 Redirect", use('stage2_redirect_cycles') / use('total_cycles')) 128 if2id_bandwidth = fetch_latency.add_down("IF2ID Bandwidth", use('ifu2id_hvButNotFull_slots') / use('total_slots')) 129 fetch_latency_others = fetch_latency.add_down("Fetch Latency Others", fetch_latency - itlb_miss - icache_miss - stage2_redirect_cycles - if2id_bandwidth) 130 131# top->frontend_bound->fetch_latency->stage2_redirect_cycles 132 branch_resteers = stage2_redirect_cycles.add_down("Branch Resteers", use('branch_resteers_cycles') / use('total_cycles')) 133 robFlush_bubble = stage2_redirect_cycles.add_down("RobFlush Bubble", use('robFlush_bubble_cycles') / use('total_cycles')) 134 ldReplay_bubble = stage2_redirect_cycles.add_down("LdReplay Bubble", use('ldReplay_bubble_cycles') / use('total_cycles')) 135 136# top->bad_speculation 137 branch_mispredicts = bad_speculation.add_down("Branch Mispredicts", bad_speculation) 138 139# top->backend_bound 140 memory_bound = backend_bound.add_down("Memory Bound", backend_bound * (use('store_bound_cycles') + use('load_bound_cycles')) / ( 141 stall_cycles_core + use('store_bound_cycles') + use('load_bound_cycles'))) 142 core_bound = backend_bound.add_down("Core Bound", backend_bound - memory_bound) 143 144# top->backend_bound->memory_bound 145 stores_bound = memory_bound.add_down("Stores Bound", use('store_bound_cycles') / use('total_cycles')) 146 loads_bound = memory_bound.add_down("Loads Bound", use('load_bound_cycles') / use('total_cycles')) 147 148# top->backend_bound->core_bound 149 integer_dq = core_bound.add_down("Integer DQ", core_bound * use('stall_cycle_int_dq') / stall_cycles_core) 150 floatpoint_dq = core_bound.add_down("Floatpoint DQ", core_bound * use('stall_cycle_fp_dq') / stall_cycles_core) 151 rob = core_bound.add_down("ROB", core_bound * use('stall_cycle_rob') / stall_cycles_core) 152 integer_prf = core_bound.add_down("Integer PRF", core_bound * use('stall_cycle_int') / stall_cycles_core) 153 floatpoint_prf = core_bound.add_down("Floatpoint PRF", core_bound * use('stall_cycle_fp') / stall_cycles_core) 154 lsu_ports = core_bound.add_down("LSU Ports", core_bound * use('ls_dq_bound_cycles') / stall_cycles_core) 155 156# top->backend_bound->memory_bound->loads_bound 157 l1d_loads_bound = loads_bound.add_down("L1D Loads", use('l1d_loads_bound_cycles') / use('total_cycles')) 158 l2_loads_bound = loads_bound.add_down("L2 Loads", use('l2_loads_bound_cycles') / use('total_cycles')) 159 l3_loads_bound = loads_bound.add_down("L3 Loads", use('l3_loads_bound_cycles') / use('total_cycles')) 160 ddr_loads_bound = loads_bound.add_down("DDR Loads", use('ddr_loads_bound_cycles') / use('total_cycles')) 161 162# top->backend_bound->memory_bound->loads_bound->l1d_loads_bound 163 l1d_loads_mshr_bound = l1d_loads_bound.add_down("L1D Loads MSHR", use('l1d_loads_mshr_bound') / use('total_cycles')) 164 l1d_loads_tlb_bound = l1d_loads_bound.add_down("L1D Loads TLB", use('l1d_loads_tlb_bound') / use('total_cycles')) 165 l1d_loads_store_data_bound = l1d_loads_bound.add_down("L1D Loads sdata", use('l1d_loads_store_data_bound') / use('total_cycles')) 166 l1d_loads_bank_conflict_bound = l1d_loads_bound.add_down("L1D Loads\nBank Conflict", use('l1d_loads_bank_conflict_bound') / use('total_cycles')) 167 l1d_loads_vio_check_redo_bound = l1d_loads_bound.add_down("L1D Loads VioRedo", use('l1d_loads_vio_check_redo_bound') / use('total_cycles')) 168 169 170 return ( 171 Sunburst(init_opts=opts.InitOpts(width="1000px", height="1200px")) 172 .add(series_name="", data_pair=top.draw(), radius=[0, "90%"]) 173 .set_global_opts(title_opts=opts.TitleOpts(title=head)) 174 .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}"))) 175 176 177title = sys.argv[1] 178directory = sys.argv[2] 179suffix = sys.argv[3] 180print(title) 181( 182 Page(page_title=title, layout=Page.SimplePageLayout) 183 .add(process_one(directory + "/csv/" + title + ".log.csv", title + "_" + suffix)) 184 .render(directory + "/html/" + title + ".html")) 185