def __init__(self, run_data, plots_dir='plots'): self.plots_dir = plots_dir # because .sdram_controller_data_width may fail for unimplemented modules def except_none(func): try: return func() except: return None # gather results into tabular data column_mappings = { 'name': lambda d: d.config.name, 'sdram_module': lambda d: d.config.sdram_module, 'sdram_data_width': lambda d: d.config.sdram_data_width, 'bist_alternating': lambda d: d.config.bist_alternating, 'num_generators': lambda d: d.config.num_generators, 'num_checkers': lambda d: d.config.num_checkers, 'bist_length': lambda d: getattr(d.config.access_pattern, 'bist_length', None), 'bist_random': lambda d: getattr(d.config.access_pattern, 'bist_random', None), 'pattern_file': lambda d: getattr(d.config.access_pattern, 'pattern_file', None), 'length': lambda d: d.config.length, 'generator_ticks': lambda d: getattr(d.result, 'generator_ticks', None ), # None means benchmark failure 'checker_errors': lambda d: getattr(d.result, 'checker_errors', None), 'checker_ticks': lambda d: getattr(d.result, 'checker_ticks', None), 'ctrl_data_width': lambda d: except_none(lambda: d.config.sdram_controller_data_width ), 'sdram_memtype': lambda d: except_none(lambda: d.config.sdram_memtype), 'clk_freq': lambda d: d.config.sdram_clk_freq, } columns = { name: [mapping(data) for data in run_data] for name, mapping, in column_mappings.items() } self._df = df = pd.DataFrame(columns) # replace None with NaN df.fillna(value=np.nan, inplace=True) # compute other metrics based on ticks and configuration parameters df['clk_period'] = 1 / df['clk_freq'] # bandwidth is the number of bits per time # in case with N generators/checkers we actually process N times more data df['write_bandwidth'] = (8 * df['length'] * df['num_generators']) / ( df['generator_ticks'] * df['clk_period']) df['read_bandwidth'] = (8 * df['length'] * df['num_checkers']) / ( df['checker_ticks'] * df['clk_period']) # efficiency calculated as number of write/read commands to number of cycles spent on writing/reading (ticks) # for multiple generators/checkers multiply by their number df['cmd_count'] = df['length'] / (df['ctrl_data_width'] / 8) df['write_efficiency'] = df['cmd_count'] * df['num_generators'] / df[ 'generator_ticks'] df['read_efficiency'] = df['cmd_count'] * df['num_checkers'] / df[ 'checker_ticks'] df['write_latency'] = df[df['bist_length'] == 1]['generator_ticks'] df['read_latency'] = df[df['bist_length'] == 1]['checker_ticks'] # boolean distinction between latency benchmarks and sequence benchmarks, # as thier results differ significanly df['is_latency'] = ~pd.isna(df['write_latency']) assert (df['is_latency'] == ~pd.isna(df['read_latency'])).all(), \ 'write_latency and read_latency should both have a value or both be NaN' # data formatting for text summary self.text_formatters = { 'write_bandwidth': bandwidth_fmt, 'read_bandwidth': bandwidth_fmt, 'write_efficiency': efficiency_fmt, 'read_efficiency': efficiency_fmt, 'write_latency': clocks_fmt, 'read_latency': clocks_fmt, } # data formatting for plot summary self.plot_xticks_formatters = { 'write_bandwidth': FuncFormatter(lambda value, pos: bandwidth_fmt(value)), 'read_bandwidth': FuncFormatter(lambda value, pos: bandwidth_fmt(value)), 'write_efficiency': PercentFormatter(1.0), 'read_efficiency': PercentFormatter(1.0), 'write_latency': ScalarFormatter(), 'read_latency': ScalarFormatter(), }