def check_pandas_or_run(sim, dataframe, sim_sweep_csv, batch_size=1, config_file='./conf.ini'): ld = {} ld['N'] = sim.accelerator.N ld['M'] = sim.accelerator.M ld['Max Precision (bits)'] = sim.accelerator.pmax ld['Min Precision (bits)'] = sim.accelerator.pmin ld['Bandwidth (bits/cycle)'] = sim.accelerator.mem_if_width ld['WBUF Size (bits)'] = sim.accelerator.sram['wgt'] ld['OBUF Size (bits)'] = sim.accelerator.sram['out'] ld['IBUF Size (bits)'] = sim.accelerator.sram['act'] ld['Batch size'] = batch_size results = lookup_pandas_dataframe(dataframe, ld) if len(results) == 0: sweep_obj = SimulatorSweep(sim_sweep_csv, config_file) dataframe = sweep_obj.sweep(sim, list_batch=[batch_size]) dataframe.to_csv(sim_sweep_csv, index=False) return lookup_pandas_dataframe(dataframe, ld) else: return results
def plot(self, outputFileName, dataframe, x_plot, y_plot, bar_plot, x_plot_list=None, y_plot_list=None, bar_list=None, lookup_dict=None, add_geomean=False, baseline=None): stacked = isinstance(y_plot, list) and len(y_plot) > 1 if not stacked: y_plot = [y_plot] self.log.info('Plotting BarChart to file: {}'.format(outputFileName)) self.log.info('bar_plot: {}'.format(bar_plot)) self.log.info('x-axis: {}'.format(x_plot)) self.log.info('y-axis: {}'.format(y_plot)) assert bar_list is not None, 'Expected list of bar_plot' num_bar_plot = len(bar_list) if x_plot_list is None: x_plot_list = list(dataframe[x_plot].unique()) if add_geomean: # Add an additional 'Gmean' x_plot_list.append('Gmean') if stacked: num_colors = len(y_plot) else: num_colors = num_bar_plot if self.COLOR is None or len(self.COLOR) != num_colors: self.COLOR = [] diff = (self.COLOR_MAX - self.COLOR_MIN) / (num_colors - 1) for i in range(num_colors): self.COLOR.append(tuple(self.COLOR_MAX - i * diff)) self.log.info('Using colors: {}'.format(self.COLOR)) with PdfPages(outputFileName) as pdf: fig, ax = plt.subplots(figsize=(self.FIG_WIDTH, self.FIG_HEIGHT)) num_benchmarks = len(x_plot_list) N = num_benchmarks ind = np.arange(N) legendLocation = [] rectsList = [] xbegin = np.arange(N) self.BAR_WIDTH = 1. / (num_bar_plot * (1+self.BAR_GAP) + self.BAR_LEFT_MARGIN) if lookup_dict is None: default_lookup = {} else: default_lookup = lookup_dict default_lookup[bar_plot] = bar_list[0] left_margin = float(self.BAR_LEFT_MARGIN * self.BAR_WIDTH) edgecolors = ['black'] * num_benchmarks for i in range(0, num_bar_plot): bottom = np.zeros(num_benchmarks) for _y in range(len(y_plot)): _y_plot = y_plot[_y] if lookup_dict is None: data_lookup = {} base_lookup = {} else: data_lookup = lookup_dict base_lookup = {} dataLine = [] data_lookup[bar_plot] = bar_list[i] for j in range(num_benchmarks - add_geomean): data_lookup[x_plot] = x_plot_list[j] data_row = lookup_pandas_dataframe(dataframe, data_lookup) dataLine.append(float(data_row[_y_plot])) if baseline is None: baseLine = [1]*len(dataLine) else: base_lookup[bar_plot] = baseline baseLine = [] for j in range(num_benchmarks - add_geomean): base_lookup[x_plot] = x_plot_list[j] base_row = lookup_pandas_dataframe(dataframe, base_lookup) baseLine.append(float(base_row[_y_plot])) assert len(baseLine) == len(dataLine) dataLine = [x/y for x,y in zip(dataLine, baseLine)] if add_geomean: dataLine.append(gmean(dataLine)) if stacked: color = self.COLOR[_y] else: color = self.COLOR[i] if self.LOG_SCALE == False: rects = ax.bar(ind + left_margin, dataLine, self.BAR_WIDTH, color=color, bottom=bottom, edgecolor=edgecolors) else: rects = ax.bar(ind + left_margin, dataLine, self.BAR_WIDTH, log=1, color=color, bottom=bottom, edgecolor=edgecolors) legendLocation.append(rects[0]) rectsList.append(rects) if stacked: bottom += dataLine left_margin += self.BAR_WIDTH + self.BAR_GAP if self.LOG_SCALE == True: ax.set_yscale('log', nonposy='clip') ax.set_xlim(0, len(x_plot_list)) ax.set_ylim(self.YAXIS_MIN, self.YAXIS_MAX) if stacked: num_minor_ticks = len(x_plot_list) * len(bar_plot) num_major_ticks = len(x_plot_list) minor_ticks = [] minor_ind = [] for i in range(len(x_plot_list)): offset = self.BAR_LEFT_MARGIN * self.BAR_WIDTH + i for j in range(len(bar_list)): minor_ticks.append(bar_list[j]) minor_ind.append(offset) offset += self.BAR_WIDTH + self.BAR_GAP ax.set_xticks(minor_ind, minor=True) ax.set_xticklabels(minor_ticks, rotation=self.XAXIS_LABEL_ROTATE, minor=True) ax.set_xticks(ind+0.5, minor=False) ax.set_xticklabels(x_plot_list, rotation=self.XAXIS_LABEL_ROTATE, minor=False) ax.tick_params(axis='x', which='major', direction='out', length=0) # vertical alignment of xtick labels va = [ -0.10 for i in range(len(x_plot_list))] for t, y in zip( ax.get_xticklabels( ), va ): t.set_y( y ) else: ax.set_xticks(ind+0.5, minor=False) ax.set_xticklabels(x_plot_list, rotation=self.XAXIS_LABEL_ROTATE) ax.spines['top'].set_visible(False) ax.spines['right'].set_visible(False) fig.subplots_adjust(top=self.TOP_MARGIN) if self.BENCH_NEWLINE == True: fig.subplots_adjust(bottom=self.BOTTOM_MARGIN) else: fig.subplots_adjust(bottom=self.BOTTOM_MARGIN * 0.5) fig.subplots_adjust(left=self.LEFT_MARGIN) fig.subplots_adjust(right=self.RIGHT_MARGIN) if self.ISRATES == True: formatter = FuncFormatter(self.to_percent) ax.yaxis.set_major_formatter(formatter) elif self.ISTIMES == True: formatter = FuncFormatter(self.to_times2) ax.yaxis.set_major_formatter(formatter) else: formatter = FuncFormatter(self.to_text) ax.yaxis.set_major_formatter(formatter) if self.yaxis != '': ax.set_ylabel(self.yaxis, fontsize=self.AXIS_TITLE_FONTSIZE, labelpad=5.0) if self.xaxis != '': ax.set_xlabel(self.xaxis, fontsize=self.AXIS_TITLE_FONTSIZE, labelpad=20.0) # for i in range(0, len(x_plot_list)): # loc = (1.0 / len(x_plot_list)) * (i + 0.5) # space4line = 0.075 # if self.BENCH_NEWLINE == True: # space4text = space4line * 2 # else: # space4text = space4line # ax.text(loc, -space4text, x_plot_list[i], horizontalalignment='center', fontsize=self.XAXIS_FONTSIZE, # transform=ax.transAxes, rotation=self.XAXIS_LABEL_ROTATE) # is stacked, show the stacks as legends; otherwise show the bars as legend if stacked: legend_list = y_plot else: legend_list = bar_list if self.MV_LEGEND_OUTSIDE_X != 0.0 or self.MV_LEGEND_OUTSIDE_Y != 1.0: ax.legend(tuple(legendLocation), legend_list, loc=self.LEGEND_LOCATION, fontsize=self.LEGEND_FONTSIZE, borderpad=0.2, borderaxespad=0.3, labelspacing=0.05, ncol=self.LEGEND_NCOLUMN, bbox_to_anchor=(self.MV_LEGEND_OUTSIDE_X, self.MV_LEGEND_OUTSIDE_Y)) else: ax.legend(tuple(legendLocation), legend_list, loc=self.LEGEND_LOCATION, fontsize=self.LEGEND_FONTSIZE, borderpad=0.2, borderaxespad=0.3, labelspacing=0.05, ncol=self.LEGEND_NCOLUMN) length = len(rectsList) for i in range(0, length): rects = rectsList[i] self.autolabel(ax, rects) ax.set_axisbelow(True) for tick in ax.get_yaxis().get_major_ticks(): tick.set_pad(self.YAXIS_PAD) tick.label1 = tick._get_text1() if x_plot_list[len(x_plot_list) - 1] == '\sf{Gmean}' or x_plot_list[len(x_plot_list) - 1] == 'Gmean' or x_plot_list[len(x_plot_list) - 1] == 'Avg' or x_plot_list[len(x_plot_list) - 1] == 'Average': plt.axvline(x=len(x_plot_list) - 1, c="black", lw=1.2) # plt.axhline(y=1.0, c="black", lw=2) pdf.savefig(fig, bbox_inches='tight', pad_inches=0.02)
def get_energy_cost(self): if self.energy_costs is not None: return self.energy_costs frequency = self.accelerator.frequency ################################################## N = self.accelerator.N M = self.accelerator.M pmax = self.accelerator.pmax pmin = self.accelerator.pmin wbuf_size = self.accelerator.sram['wgt'] * 8 ibuf_size = self.accelerator.sram['act'] * 8 obuf_size = self.accelerator.sram['out'] * 8 wbuf_bank = N * M ibuf_bank = N obuf_bank = M wbuf_bits = (pmax * pmax / pmin) ibuf_bits = (pmax * pmax / pmin) obuf_bits = 32 wbuf_word = ceil_a_by_b(wbuf_size, wbuf_bank * wbuf_bits) ibuf_word = ceil_a_by_b(ibuf_size, ibuf_bank * ibuf_bits) obuf_word = ceil_a_by_b(obuf_size, obuf_bank * obuf_bits) wbuf_bank_size = wbuf_word * wbuf_bits ibuf_bank_size = ibuf_word * ibuf_bits obuf_bank_size = obuf_word * obuf_bits assert wbuf_bank_size * wbuf_bank == wbuf_size assert ibuf_bank_size * ibuf_bank == ibuf_size assert obuf_bank_size * obuf_bank == obuf_size ################################################## cfg_dict = { 'size (bytes)': wbuf_bank_size / 8., 'block size (bytes)': wbuf_bits / 8., 'read-write port': 0 } wbuf_data = self.sram_obj.get_data_clean(cfg_dict) wbuf_read_energy = float(wbuf_data['read_energy_nJ']) / wbuf_bits wbuf_write_energy = float(wbuf_data['write_energy_nJ']) / wbuf_bits wbuf_leak_power = float(wbuf_data['leak_power_mW']) * wbuf_bank wbuf_area = float(wbuf_data['area_mm^2']) * wbuf_bank self.logger.debug('WBUF :') self.logger.debug( '\tBanks : {0:>8}'.format(wbuf_bank)) self.logger.debug( '\tBitWidth : {0:>8} bits'.format(wbuf_bits)) self.logger.debug( '\tWords : {0:>8}'.format(wbuf_word)) self.logger.debug( '\tTotal Size : {0:>8} kBytes'.format(wbuf_size / 8. / 1024.)) self.logger.debug( '\tTotal Area : {0:>8.2f} mm^2'.format(wbuf_area)) self.logger.debug( '\tLeak Energy (per clock) : {0:>8.4f} mWatt'.format( wbuf_leak_power)) self.logger.debug( '\tRead Energy : {0:>8.4f} pJ/bit'.format( wbuf_read_energy * 1.e3)) self.logger.debug( '\tWrite Energy : {0:>8.4f} pJ/bit'.format( wbuf_write_energy * 1.e3)) ################################################## cfg_dict = { 'size (bytes)': ibuf_bank_size / 8., 'block size (bytes)': ibuf_bits / 8., 'read-write port': 0 } ibuf_data = self.sram_obj.get_data_clean(cfg_dict) ibuf_read_energy = float(ibuf_data['read_energy_nJ']) / ibuf_bits ibuf_write_energy = float(ibuf_data['write_energy_nJ']) / ibuf_bits ibuf_leak_power = float(ibuf_data['leak_power_mW']) * ibuf_bank ibuf_area = float(ibuf_data['area_mm^2']) * ibuf_bank self.logger.debug('IBUF :') self.logger.debug( '\tBanks : {0:>8}'.format(ibuf_bank)) self.logger.debug( '\tBitWidth : {0:>8} bits'.format(ibuf_bits)) self.logger.debug( '\tWords : {0:>8}'.format(ibuf_word)) self.logger.debug( '\tTotal Size : {0:>8} kBytes'.format(ibuf_size / 8. / 1024.)) self.logger.debug( '\tTotal Area : {0:>8.2f} mm^2'.format(ibuf_area)) self.logger.debug( '\tLeak Energy (per clock) : {0:>8.4f} mWatt'.format( ibuf_leak_power)) self.logger.debug( '\tRead Energy : {0:>8.4f} pJ/bit'.format( ibuf_read_energy * 1.e3)) self.logger.debug( '\tWrite Energy : {0:>8.4f} pJ/bit'.format( ibuf_write_energy * 1.e3)) ################################################## cfg_dict = { 'size (bytes)': obuf_bank_size / 8., 'block size (bytes)': obuf_bits / 8., 'read-write port': 1 } obuf_data = self.sram_obj.get_data_clean(cfg_dict) obuf_read_energy = float(obuf_data['read_energy_nJ']) / obuf_bits obuf_write_energy = float(obuf_data['write_energy_nJ']) / obuf_bits obuf_leak_power = float(obuf_data['leak_power_mW']) * obuf_bank obuf_area = float(obuf_data['area_mm^2']) * obuf_bank self.logger.debug('OBUF :') self.logger.debug( '\tBanks : {0:>8}'.format(obuf_bank)) self.logger.debug( '\tBitWidth : {0:>8} bits'.format(obuf_bits)) self.logger.debug( '\tWords : {0:>8}'.format(obuf_word)) self.logger.debug( '\tTotal Size : {0:>8} kBytes'.format(obuf_size / 8. / 1024.)) self.logger.debug( '\tTotal Area : {0:>8.2f} mm^2'.format(obuf_area)) self.logger.debug( '\tLeak Energy (per clock) : {0:>8.4f} mWatt'.format( obuf_leak_power)) self.logger.debug( '\tRead Energy : {0:>8.4f} pJ/bit'.format( obuf_read_energy * 1.e3)) self.logger.debug( '\tWrite Energy : {0:>8.4f} pJ/bit'.format( obuf_write_energy * 1.e3)) ################################################## # Get stats for systolic array core_csv = os.path.join('./results', 'systolic_array_synth.csv') core_synth_data = pandas.read_csv(core_csv) lookup_dict = {} lookup_dict['Max Precision (bits)'] = pmax lookup_dict['Min Precision (bits)'] = pmin lookup_dict['N'] = N lookup_dict['M'] = M core_data = lookup_pandas_dataframe(core_synth_data, lookup_dict) if len(core_data) == 0: lookup_dict['N'] = 4 lookup_dict['M'] = 4 core_data = lookup_pandas_dataframe(core_synth_data, lookup_dict) assert len(core_data) == 1 core_area = float(core_data['Area (um^2)']) * 1.e-6 * (N * M) / 16. core_dyn_power = float( core_data['Dynamic Power (nW)']) * (N * M) / 16. core_dyn_energy = core_dyn_power / float(core_data['Frequency']) core_leak_power = float( core_data['Leakage Power (nW)']) * (N * M) / 16. core_leak_energy = core_leak_power / float(core_data['Frequency']) else: core_area = float(core_data['Area (um^2)']) * 1.e-6 core_dyn_power = float(core_data['Dynamic Power (nW)']) core_dyn_energy = core_dyn_power / float(core_data['Frequency']) core_leak_power = float(core_data['Leakage Power (nW)']) core_leak_energy = core_leak_power / float(core_data['Frequency']) self.logger.debug('Core :') self.logger.debug( '\tDimensions : {0}x{1}-systolic array'.format(N, M)) self.logger.debug('\tMax-Precision : {}'.format(pmax)) self.logger.debug('\tMin-Precision : {}'.format(pmin)) self.logger.debug( '\tLeak power : {} (nW)'.format(core_leak_energy)) self.logger.debug( '\tDynamic Energy (nJ) : {}'.format(core_dyn_energy)) self.logger.debug('\tArea (mm^2) : {}'.format(core_area)) ################################################## energy_tuple = EnergyTuple(core_dyn_energy, wbuf_read_energy, wbuf_write_energy, ibuf_read_energy, ibuf_write_energy, obuf_read_energy, obuf_write_energy) return energy_tuple
def sweep(self, sim_obj, list_n=None, list_m=None, list_pmax=None, list_pmin=None, list_bw=None, list_bench=None, list_wbuf=None, list_ibuf=None, list_obuf=None, list_batch=None): """ Sweep the parameters of the accelerator """ if list_n is None: list_n = [sim_obj.accelerator.N] if list_m is None: list_m = [sim_obj.accelerator.M] if list_pmax is None: list_pmax = [sim_obj.accelerator.pmax] if list_pmin is None: list_pmin = [sim_obj.accelerator.pmin] if list_bw is None: list_bw = [sim_obj.accelerator.mem_if_width] if list_bench is None: list_bench = benchmarks.benchlist if list_wbuf is None: list_wbuf = [sim_obj.accelerator.sram['wgt']] if list_ibuf is None: list_ibuf = [sim_obj.accelerator.sram['act']] if list_obuf is None: list_obuf = [sim_obj.accelerator.sram['out']] if list_batch is None: list_batch = [1] data_line = [] for batch_size in list_batch: for n in list_n: for m in list_m: # self.logger.info('N x M = {} x {}'.format(n, m)) for pmax in list_pmax: for pmin in list_pmin: if pmin > pmax: continue for wbuf in list_wbuf: for ibuf in list_ibuf: for obuf in list_obuf: for bw in list_bw: sim_obj.accelerator.N = n sim_obj.accelerator.M = m sim_obj.accelerator.pmax = pmax sim_obj.accelerator.pmin = pmin sim_obj.accelerator.mem_if_width = bw sim_obj.accelerator.sram[ 'wgt'] = wbuf sim_obj.accelerator.sram[ 'out'] = obuf sim_obj.accelerator.sram[ 'act'] = ibuf for b in list_bench: lookup_dict = {} lookup_dict['N'] = n lookup_dict['M'] = m lookup_dict[ 'Max Precision (bits)'] = pmax lookup_dict[ 'Min Precision (bits)'] = pmin lookup_dict['Network'] = b lookup_dict[ 'Bandwidth (bits/cycle)'] = sim_obj.accelerator.mem_if_width lookup_dict[ 'WBUF Size (bits)'] = wbuf lookup_dict[ 'OBUF Size (bits)'] = obuf lookup_dict[ 'IBUF Size (bits)'] = ibuf lookup_dict[ 'Batch size'] = batch_size results = lookup_pandas_dataframe( self.sweep_df, lookup_dict) nn = benchmarks.get_bench_nn( b, WRPN=True) if len(results) == 0: self.logger.info( 'Simulating Benchmark: {}' .format(b)) self.logger.info( 'N x M = {} x {}'. format(n, m)) self.logger.info( 'Max Precision (bits): {}' .format(pmax)) self.logger.info( 'Min Precision (bits): {}' .format(pmin)) self.logger.info( 'Batch size: {}'. format(batch_size)) self.logger.info( 'Bandwidth (bits/cycle): {}' .format(bw)) stats = benchmarks.get_bench_numbers( nn, sim_obj, batch_size) for layer in stats: cycles = stats[ layer].total_cycles reads = stats[ layer].reads writes = stats[ layer].writes stalls = stats[ layer].mem_stall_cycles data_line.append(( n, m, pmax, pmin, b, layer, cycles, stalls, reads['wgt'], writes['wgt'], reads['out'], writes['out'], reads['act'], writes['act'], reads['dram'], writes['dram'], sim_obj.accelerator .mem_if_width, wbuf, obuf, ibuf, batch_size)) if len(data_line) > 0: if os.path.exists( self.csv_filename): self.sweep_df = pandas.read_csv( self.csv_filename) else: self.sweep_df = pandas.DataFrame( columns=self.columns) self.sweep_df = self.sweep_df.append( pandas.DataFrame( data_line, columns=self.columns)) self.sweep_df.to_csv( self.csv_filename, index=False) data_line = [] return self.sweep_df