diff --git a/compiler/characterizer/model_check.py b/compiler/characterizer/model_check.py index 874bb2d0..12bc5d58 100644 --- a/compiler/characterizer/model_check.py +++ b/compiler/characterizer/model_check.py @@ -26,30 +26,34 @@ class model_check(delay): def create_data_names(self): self.wl_meas_name, self.wl_model_name = "wl_measures", "wl_model" self.sae_meas_name, self.sae_model_name = "sae_measures", "sae_model" + self.wl_slew_name, self.sae_slew_name = "wl_slews", "sae_slews" def create_measurement_names(self): """Create measurement names. The names themselves currently define the type of measurement""" #Create delay measurement names - wl_en_driver_delay_names = ["delay_wl_en_dvr{}_".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())] - wl_driver_delay_names = ["delay_wl_dvr{}_".format(stage) for stage in range(1,self.get_num_wl_driver_stages())] - sen_driver_delay_names = ["delay_sen_dvr{}_".format(stage) for stage in range(1,self.get_num_sen_driver_stages())] - dc_delay_names = ["delay_delay_chain_stage{}_".format(stage) for stage in range(1,self.get_num_delay_stages()+1)] + wl_en_driver_delay_names = ["delay_wl_en_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())] + wl_driver_delay_names = ["delay_wl_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_driver_stages())] + sen_driver_delay_names = ["delay_sen_dvr_{}".format(stage) for stage in range(1,self.get_num_sen_driver_stages())] + dc_delay_names = ["delay_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)] self.wl_delay_meas_names = wl_en_driver_delay_names+["delay_wl_en", "delay_wl_bar"]+wl_driver_delay_names+["delay_wl"] self.rbl_delay_meas_names = ["delay_gated_clk_nand", "delay_delay_chain_in"]+dc_delay_names self.sae_delay_meas_names = ["delay_pre_sen"]+sen_driver_delay_names+["delay_sen"] self.delay_chain_indices = (len(self.rbl_delay_meas_names)-len(dc_delay_names), len(self.rbl_delay_meas_names)) #Create slew measurement names - wl_en_driver_slew_names = ["slew_wl_en_dvr{}_".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())] - wl_driver_slew_names = ["slew_wl_dvr{}_".format(stage) for stage in range(1,self.get_num_wl_driver_stages())] - sen_driver_slew_names = ["slew_sen_dvr{}_".format(stage) for stage in range(1,self.get_num_sen_driver_stages())] - dc_slew_names = ["slew_delay_chain_stage{}_".format(stage) for stage in range(1,self.get_num_delay_stages()+1)] + wl_en_driver_slew_names = ["slew_wl_en_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())] + wl_driver_slew_names = ["slew_wl_dvr_{}".format(stage) for stage in range(1,self.get_num_wl_driver_stages())] + sen_driver_slew_names = ["slew_sen_dvr_{}".format(stage) for stage in range(1,self.get_num_sen_driver_stages())] + dc_slew_names = ["slew_delay_chain_stage_{}".format(stage) for stage in range(1,self.get_num_delay_stages()+1)] self.wl_slew_meas_names = ["slew_wl_gated_clk_bar"]+wl_en_driver_slew_names+["slew_wl_en", "slew_wl_bar"]+wl_driver_slew_names+["slew_wl"] self.rbl_slew_meas_names = ["slew_rbl_gated_clk_bar","slew_gated_clk_nand", "slew_delay_chain_in"]+dc_slew_names self.sae_slew_meas_names = ["slew_replica_bl0", "slew_pre_sen"]+sen_driver_slew_names+["slew_sen"] def create_signal_names(self): - """Creates list of the signal names used in the spice file along the wl and sen paths.""" + """Creates list of the signal names used in the spice file along the wl and sen paths. + Names are re-harded coded here; i.e. the names are hardcoded in most of OpenRAM and are + replicated here. + """ delay.create_signal_names(self) #Signal names are all hardcoded, need to update to make it work for probe address and different configurations. wl_en_driver_signals = ["Xsram.Xcontrol0.Xbuf_wl_en.Zb{}_int".format(stage) for stage in range(1,self.get_num_wl_en_driver_stages())] @@ -317,12 +321,14 @@ class model_check(delay): data_dict[self.wl_model_name] = wl_model_delays data_dict[self.sae_meas_name] = sae_delays[read_port] data_dict[self.sae_model_name] = sae_model_delays + data_dict[self.wl_slew_name] = wl_slews[read_port] + data_dict[self.sae_slew_name] = sae_slews[read_port] #Some evaluations of the model and measured values - debug.info(1, "Comparing wordline measurements and model.") - self.compare_measured_and_model(wl_delays[read_port], wl_model_delays) - debug.info(1, "Comparing SAE measurements and model") - self.compare_measured_and_model(sae_delays[read_port], sae_model_delays) + # debug.info(1, "Comparing wordline measurements and model.") + # self.compare_measured_and_model(wl_delays[read_port], wl_model_delays) + # debug.info(1, "Comparing SAE measurements and model") + # self.compare_measured_and_model(sae_delays[read_port], sae_model_delays) return data_dict @@ -334,6 +340,8 @@ class model_check(delay): name_dict[self.wl_model_name] = name_dict["wl_measures"] #model uses same names as measured. name_dict[self.sae_meas_name] = self.rbl_en_signal_names[1:]+self.sae_signal_names[1:] name_dict[self.sae_model_name] = name_dict["sae_measures"] + name_dict[self.wl_slew_name] = self.wl_slew_meas_names + name_dict[self.sae_slew_name] = self.rbl_slew_meas_names+self.sae_slew_meas_names return name_dict diff --git a/compiler/tests/delay_data_collection.py b/compiler/tests/delay_data_collection.py index 3e56909f..ca3e26d0 100644 --- a/compiler/tests/delay_data_collection.py +++ b/compiler/tests/delay_data_collection.py @@ -18,6 +18,25 @@ from sram_config import sram_config MODEL_DIR = "model_data/" DATASET_CSV_NAME = MODEL_DIR+'datasets.csv' +# Data Collection class +# This module can perform two tasks +# 1) Collect data +# 2) Display data +# Data Collection - +# A single SRAM simulation will collect 6 datasets: wordline (WL) delays, sense amp enable (SAE) delays, +# WL slews, SAE slews, WL model delays, SAE model delays. +# Each dataset is stored in a separate csv file. Each row of the CSV refers to a different corner simulated on. +# The files names are stored in DATASET_CSV_NAME marked above. +# There are 2 main ways the collection is targeted: looking at different delay chain sizes and looking at different SRAM configurations. +# These are separated by different functions and should not be collected together. +# +# Data display - +# There are many functions in this file which will search (or told) for data using DATASET_CSV_NAME as a guide. +# Delay chain data is analyzed in analyze_delay_chain_data, graph_delays_and_inp_slews, and graph_inp_slews_and_delay_var +# WL and SAE graphing is done in analyze_sae_data and graph_delays_and_var +# +# Data collection and each analysis can be run independently, but the one you want needs to be commented in/out. + class data_collection(openram_test): def runTest(self): @@ -29,7 +48,7 @@ class data_collection(openram_test): self.run_setup() self.run_delay_chain_analysis() - + #self.run_sae_analysis() globals.end_openram() def run_setup(self): @@ -105,6 +124,123 @@ class data_collection(openram_test): return [df_row[dt] for dt in data_types] + def get_all_filenames(self, data_types): + """Gets all files from dataset.csv specified by the datatype (model/measure)""" + start_fname_ind = 4 # four query items + + datasets_df = pd.read_csv(DATASET_CSV_NAME, encoding='utf-8') + csv_data_types = list(datasets_df)[start_fname_ind:] + if not set(data_types).issubset(set(csv_data_types)): + debug.error("Dataset csv header does not match expected:\nExpected={}\nCSV={}".format(data_types, + csv_data_types),1) + + return [list(datasets_df[dt]) for dt in data_types] + + def run_sae_analysis(self): + """Generates sram with different delay chain configs over different corners and + analyzes delay average and variation.""" + #config_tuple_list = [(8, 16, 1),(8, 32, 1),(16, 32, 1), (32, 64, 1), (64, 32, 1), (64, 64, 1), (32, 128, 1)] + #config_tuple_list = [(1, 16, 1),(4, 16, 1),(16, 16, 1), (32, 32, 1)] + config_tuple_list = [(1, 16, 1),(4, 16, 1)] + self.save_sram_data_using_configs(config_tuple_list) + self.analyze_sae_data() #Uses all available data + #self.graph_delays_and_var('sae_measures') + #self.graph_delays_and_var('wl_measures') + #self.compare_wl_sae_data() + + def save_sram_data_using_configs(self, config_list): + """Get SRAM data for different configurations""" + for config in config_list: + word_size, num_words, words_per_row = config + self.init_data_gen() + self.save_data_sram_corners(word_size, num_words, words_per_row) + + def analyze_sae_data(self): + """Compare and graph delay chain variations over different configurations.""" + delay_avgs_ratio = [] + delay_vars_ratio = [] + sram_configs = [] + data_types = ["sae_measures"] + sae_filenames = self.get_all_filenames(data_types)[0] + sae_dataframes = self.get_csv_data(sae_filenames) + + for df in sae_dataframes: + #Each row in df contains sram config. Only use the first one (they should all be the same) + config = df[['word_size', 'num_words', 'words_per_row']].values.tolist()[0] + sram_configs.append(config) + delay_sums = self.get_sum(df) + delay_chain_sums = self.get_delay_chain_sums(df) + delay_avgs_ratio.append(self.get_average(delay_chain_sums)/self.get_average(delay_sums)) + delay_vars_ratio.append(self.get_variance(delay_chain_sums)/self.get_variance(delay_sums)) + debug.info(1,"DC config={}: avg ratio={} var ratio={}".format(sram_configs[-1], + delay_avgs_ratio[-1], + delay_vars_ratio[-1])) + + #Sort by the delays then graph + all_data = zip(delay_avgs_ratio,sram_configs,delay_vars_ratio) + delay_avgs_ratio,sram_configs,delay_vars_ratio = zip(*sorted(all_data)) + x_ax_label = '[word_size, num_words, words_per_row]' + y_ax_labels = ['DC/SAE Delay Ratio', 'DC/SAE Var. Ratio'] + self.plot_delay_variance_data_sets(sram_configs, x_ax_label, y_ax_labels, delay_avgs_ratio, delay_vars_ratio) + + def compare_wl_sae_data(self): + """Compare and graph delay chain variations over different configurations.""" + delay_avgs_ratio = [] + delay_vars_ratio = [] + sram_configs = [] + data_types = ["wl_measures","sae_measures"] + data_filenames = self.get_all_filenames(data_types) + wl_filenames = data_filenames[0] + wl_dataframes = self.get_csv_data(wl_filenames) + sae_filenames = data_filenames[1] + sae_dataframes = self.get_csv_data(sae_filenames) + + #Loop through all configurations found + for wl_df,sae_df in zip(wl_dataframes,sae_dataframes): + #Each row in df contains sram config. Only use the first one (they should all be the same) + config = wl_df[['word_size', 'num_words', 'words_per_row']].values.tolist()[0] + sram_configs.append(config) + wl_delays = self.get_sum(wl_df) + sae_delays = self.get_sum(sae_df) + delay_avgs_ratio.append(self.get_average(wl_delays)/self.get_average(sae_delays)) + delay_vars_ratio.append(self.get_variance(wl_delays)/self.get_variance(sae_delays)) + debug.info(1,"DC config={}: avg ratio={} var ratio={}".format(sram_configs[-1], + delay_avgs_ratio[-1], + delay_vars_ratio[-1])) + + #Sort by the delays then graph + all_data = zip(delay_avgs_ratio,sram_configs,delay_vars_ratio) + delay_avgs_ratio,sram_configs,delay_vars_ratio = zip(*sorted(all_data)) + x_ax_label = 'SRAM Config' + y_ax_labels = ['WL/SAE Delay Ratio', 'WL/SAE Var. Ratio'] + self.plot_delay_variance_data_sets(sram_configs, x_ax_label, y_ax_labels, delay_avgs_ratio, delay_vars_ratio) + + def graph_delays_and_var(self, data_type): + delay_avgs = [] + delay_vars = [] + sram_configs = [] + data_filenames = self.get_all_filenames([data_type])[0] + dataframes = self.get_csv_data(data_filenames) + + #Loop through all configurations found + for df in dataframes: + #Each row in df contains sram config. Only use the first one (they should all be the same) + config = df[['word_size', 'num_words', 'words_per_row']].values.tolist()[0] + sram_configs.append(config) + delays = self.get_sum(df) + delay_avgs.append(self.get_average(delays)) + delay_vars.append(self.get_variance(delays)) + debug.info(1,"DC config={}: avg={}, var={}".format(sram_configs[-1], + delay_avgs[-1], + delay_vars[-1])) + + #Sort by the delays then graph + all_data = zip(delay_avgs,sram_configs,delay_vars) + delay_avgs,sram_configs,delay_vars = zip(*sorted(all_data)) + x_ax_label = 'SRAM Config' + y_ax_labels = ['Avg. Delay', 'Delay Variance'] + self.plot_delay_variance_data_sets(sram_configs, x_ax_label, y_ax_labels, delay_avgs, delay_vars) + def run_delay_chain_analysis(self): """Generates sram with different delay chain configs over different corners and analyzes delay average and variation.""" @@ -116,10 +252,16 @@ class data_collection(openram_test): #dc_config_list = [(2,3), (3,3)] #fanout_configs = [[3,3], [3,3,3]] - previous_dc_configs = [[4,4,4], [2,2,2,2], [3,3,3,3], [4,4],[4,4,4,4], [5,5]] - fanout_configs = [[3,3], [3,3,3], [2,3,2,3], [2,4,2,4], [3,3,3,3]]+previous_dc_configs + old_fanout_configs = [] + fanout_configs = [[3,3], [2,3,2,3], [2,4,2,4], [2,2,2,2], [3,3,3,3], [4,4],[4,4,4,4], [5,5], \ + [2,2], [2,5,2,5], [2,6,2,6], [2,8,2,8], [3,5,3,5], [4,5,4,5], [2,2,2,2,2,2], [3,3,3,3,3,3],\ + [6,6],[7,7],[8,8],[9,9],[10,10],[11,11], + [5,2,5,2], [6,2,6,2], [8,2,8,2], [5,3,5,3], [5,4,5,4], [2,3,4,5], [7,2,7,2]] + analysis_configs = fanout_configs+old_fanout_configs #self.save_delay_chain_data(word_size, num_words, words_per_row, fanout_configs) - self.analyze_delay_chain_data(word_size, num_words, words_per_row, fanout_configs) + #self.analyze_delay_chain_data(word_size, num_words, words_per_row, analysis_configs) + #self.graph_delays_and_inp_slews(word_size, num_words, words_per_row, analysis_configs) + self.graph_inp_slews_and_delay_var(word_size, num_words, words_per_row, analysis_configs) def save_delay_chain_data(self, word_size, num_words, words_per_row, fanout_configs): """Get the delay data by only varying the delay chain size.""" @@ -130,33 +272,207 @@ class data_collection(openram_test): def analyze_delay_chain_data(self, word_size, num_words, words_per_row, fanout_configs): """Compare and graph delay chain variations over different configurations.""" - dc_avgs = [] - dc_vars = [] + if not os.path.exists(DATASET_CSV_NAME): + debug.error("Could not find dataset CSV. Aborting analysis...",1) + dc_avgs, dc_vars = [],[] + rise_avgs, rise_vars = [],[] + fall_avgs, fall_vars = [],[] for fanouts in fanout_configs: data_types = ["wl_measures","sae_measures"] filenames = self.get_filename_by_config(data_types, word_size, num_words, words_per_row, fanouts) wl_dataframe, sae_dataframe = self.get_csv_data(filenames) - + rise_delay, fall_delay = self.get_rise_fall_dc_sum(sae_dataframe) delay_sums = self.get_delay_chain_sums(sae_dataframe) dc_avgs.append(self.get_average(delay_sums)) dc_vars.append(self.get_variance(delay_sums)) + + rise_avgs.append(self.get_average(rise_delay)) + rise_vars.append(self.get_variance(rise_delay)) + + fall_avgs.append(self.get_average(fall_delay)) + fall_vars.append(self.get_variance(fall_delay)) debug.info(1,"DC config={}: avg={} variance={}".format(fanouts, dc_avgs[-1], dc_vars[-1])) - self.plot_two_data_sets(fanout_configs, dc_avgs, dc_vars) + + #Sort by the delays then graph + config_copy = list(fanout_configs) + all_data = zip(dc_avgs,config_copy,dc_vars) + dc_avgs,config_copy,dc_vars = zip(*sorted(all_data)) + x_ax_label = 'DC Fanouts' + y_ax_labels = ['Average Delay (ns)', 'Delay Variance (ns)'] + self.plot_delay_variance_data_sets(config_copy, x_ax_label, y_ax_labels, dc_avgs, dc_vars) - def get_delay_chain_sums(self, sae_dataframe): - """Calculate the total delay of the delay chain over different corners""" + config_copy = list(fanout_configs) + all_data = zip(rise_avgs,config_copy,rise_vars) + rise_avgs,config_copy,rise_vars = zip(*sorted(all_data)) + x_ax_label = 'DC Fanouts' + y_ax_labels = ['Average Rise Delay (ns)', 'Rise Delay Variance (ns)'] + self.plot_delay_variance_data_sets(config_copy, x_ax_label, y_ax_labels, rise_avgs, rise_vars) + + config_copy = list(fanout_configs) + all_data = zip(fall_avgs,config_copy,fall_vars) + fall_avgs,config_copy,fall_vars = zip(*sorted(all_data)) + x_ax_label = 'DC Fanouts' + y_ax_labels = ['Average Fall Delay (ns)', 'Fall Delay Variance (ns)'] + self.plot_delay_variance_data_sets(config_copy, x_ax_label, y_ax_labels, fall_avgs, fall_vars) + + def graph_inp_slews_and_delay_var(self, word_size, num_words, words_per_row, fanout_configs): + """Compare and graph delay chain variations over different configurations.""" + if not os.path.exists(DATASET_CSV_NAME): + debug.error("Could not find dataset CSV. Aborting analysis...",1) + dc_delays_var, dc_slews = [],[] + rise_delay_var, rise_slew_avgs = [],[] + fall_delay_var, fall_slew_avgs = [],[] + for fanouts in fanout_configs: + data_types = ["sae_measures", "sae_slews"] + filenames = self.get_filename_by_config(data_types, word_size, num_words, words_per_row, fanouts) + sae_delay_df, sae_slew_df = self.get_csv_data(filenames) + + delay_sums = self.get_delay_chain_sums(sae_delay_df) + slew_sums = self.get_delay_chain_avg(sae_slew_df) + dc_delays_var.append(self.get_variance(delay_sums)) + dc_slews.append(self.get_average(slew_sums)) + + rise_delay, fall_delay = self.get_rise_fall_dc_sum(sae_delay_df) + rise_delay_var.append(self.get_variance(rise_delay)) + fall_delay_var.append(self.get_variance(fall_delay)) + + rise_slews, fall_slews = self.get_rise_fall_dc_avg(sae_slew_df) + rise_slew_avgs.append(self.get_average(rise_slews)) + fall_slew_avgs.append(self.get_average(fall_slews)) + debug.info(1,"DC config={}: slew avg={} delay var={}".format(fanouts, dc_slews[-1], dc_delays_var[-1])) + + #Sort by the delays then graph + config_copy = list(fanout_configs) + all_data = zip(dc_slews,config_copy,dc_delays_var) + dc_slews,config_copy,dc_delays_var = zip(*sorted(all_data)) + x_ax_label = 'DC Fanouts' + y_ax_labels = ['Average Input Slew (ns)', 'Delay Variance (ns)'] + self.plot_delay_variance_data_sets(config_copy, x_ax_label, y_ax_labels, dc_slews, dc_delays_var) + + config_copy = list(fanout_configs) + all_data = zip(rise_slew_avgs,config_copy,rise_delay_var) + rise_slew_avgs,config_copy,rise_delay_var = zip(*sorted(all_data)) + x_ax_label = 'DC Fanouts' + y_ax_labels = ['Average Rise Stage Input Slew (ns)', 'Rise Delay Variance (ns)'] + self.plot_delay_variance_data_sets(config_copy, x_ax_label, y_ax_labels, rise_slew_avgs, rise_delay_var) + + config_copy = list(fanout_configs) + all_data = zip(fall_slew_avgs,config_copy,fall_delay_var) + fall_slew_avgs,config_copy,fall_delay_var = zip(*sorted(all_data)) + x_ax_label = 'DC Fanouts' + y_ax_labels = ['Average Fall Stage Input Slew (ns)', 'Fall Delay Variance (ns)'] + self.plot_delay_variance_data_sets(config_copy, x_ax_label, y_ax_labels, fall_slew_avgs, fall_delay_var) + + def graph_delays_and_inp_slews(self, word_size, num_words, words_per_row, fanout_configs): + """Compare and graph delay chain variations over different configurations.""" + if not os.path.exists(DATASET_CSV_NAME): + debug.error("Could not find dataset CSV. Aborting analysis...",1) + dc_delays, dc_slews = [],[] + rise_delay_avgs, rise_slew_avgs = [],[] + fall_delay_avgs, fall_slew_avgs = [],[] + for fanouts in fanout_configs: + data_types = ["sae_measures", "sae_slews"] + filenames = self.get_filename_by_config(data_types, word_size, num_words, words_per_row, fanouts) + sae_delay_df, sae_slew_df = self.get_csv_data(filenames) + + delay_sums = self.get_delay_chain_sums(sae_delay_df) + slew_sums = self.get_delay_chain_avg(sae_slew_df) + dc_delays.append(self.get_average(delay_sums)) + dc_slews.append(self.get_average(slew_sums)) + + rise_delay, fall_delay = self.get_rise_fall_dc_sum(sae_delay_df) + rise_delay_avgs.append(self.get_average(rise_delay)) + fall_delay_avgs.append(self.get_average(fall_delay)) + + rise_slews, fall_slews = self.get_rise_fall_dc_avg(sae_slew_df) + rise_slew_avgs.append(self.get_average(rise_slews)) + fall_slew_avgs.append(self.get_average(fall_slews)) + debug.info(1,"DC config={}: delay avg={} slew avg={}".format(fanouts, dc_delays[-1], dc_slews[-1])) + + #Sort by the delays then graph + config_copy = list(fanout_configs) + all_data = zip(dc_delays,config_copy,dc_slews) + dc_delays,config_copy,dc_slews = zip(*sorted(all_data)) + x_ax_label = 'DC Fanouts' + y_ax_labels = ['Average Delay (ns)', 'Average Input Slew (ns)'] + self.plot_delay_variance_data_sets(config_copy, x_ax_label, y_ax_labels, dc_delays, dc_slews) + + config_copy = list(fanout_configs) + all_data = zip(rise_delay_avgs,config_copy,rise_slew_avgs) + rise_delay_avgs,config_copy,rise_slew_avgs = zip(*sorted(all_data)) + x_ax_label = 'DC Fanouts' + y_ax_labels = ['Average Rise Delay (ns)', 'Average Input Slew (ns)'] + self.plot_delay_variance_data_sets(config_copy, x_ax_label, y_ax_labels, rise_delay_avgs, rise_slew_avgs) + + config_copy = list(fanout_configs) + all_data = zip(fall_delay_avgs,config_copy,fall_slew_avgs) + fall_delay_avgs,config_copy,fall_slew_avgs = zip(*sorted(all_data)) + x_ax_label = 'DC Fanouts' + y_ax_labels = ['Average Fall Delay (ns)', 'Average Input Slew (ns)'] + self.plot_delay_variance_data_sets(config_copy, x_ax_label, y_ax_labels, fall_delay_avgs, fall_slew_avgs) + + + def get_delay_chain_data(self, sae_dataframe): + """Get the data of the delay chain over different corners""" start_dc_pos = sae_dataframe.columns.get_loc('dc_start_ind') end_dc_pos = sae_dataframe.columns.get_loc('dc_end_ind') start_data_pos = len(self.config_fields)+len(self.sae_config_fields)+1 #items before this point are configuration related - delay_sums = [] - row_count = 0 + delay_data = [] #Get delay sums over different corners for sae_row in sae_dataframe.itertuples(): start_dc, end_dc = sae_row[start_dc_pos+1], sae_row[end_dc_pos+1] dc_delays = sae_row[start_data_pos+start_dc:start_data_pos+end_dc] - delay_sums.append(sum(dc_delays)) - return delay_sums + delay_data.append(dc_delays) + return delay_data + def get_delay_chain_sums(self, sae_dataframe): + """Calculate the sum of each delay chain for each corner""" + dc_data = self.get_delay_chain_data(sae_dataframe) + return [sum(data_list) for data_list in dc_data] + + def get_delay_chain_avg(self, sae_dataframe): + """Calculate the average of each delay chain for each corner""" + dc_data = self.get_delay_chain_data(sae_dataframe) + return [sum(data_list)/len(data_list) for data_list in dc_data] + + def get_rise_fall_dc_data_per_corner(self,sae_dataframe): + """Extracts the data from the dataframe which represents the delay chain. + Delay chain data is marked by indices in the CSV. + """ + start_dc_pos = sae_dataframe.columns.get_loc('dc_start_ind') + end_dc_pos = sae_dataframe.columns.get_loc('dc_end_ind') + start_data_pos = len(self.config_fields)+len(self.sae_config_fields)+1 #items before this point are configuration related + rise_data = [] + fall_data = [] + #Get delay sums over different corners + for sae_row in sae_dataframe.itertuples(): + start_dc, end_dc = sae_row[start_dc_pos+1], sae_row[end_dc_pos+1] + fall_list = sae_row[start_data_pos+start_dc:start_data_pos+end_dc:2] + rise_list = sae_row[start_data_pos+start_dc+1:start_data_pos+end_dc:2] + fall_data.append(fall_list) + rise_data.append(rise_list) + return rise_data, fall_data + + def get_rise_fall_dc_sum(self,sae_dataframe): + """Gets the delay/slew sum of the delay chain for every corner""" + #Get list of lists of delay chain data and reduce to sums + rise_data, fall_data = self.get_rise_fall_dc_data_per_corner(sae_dataframe) + rise_sums = [sum(dc_data) for dc_data in rise_data] + fall_sums = [sum(dc_data) for dc_data in fall_data] + return rise_sums,fall_sums + + def get_rise_fall_dc_avg(self,sae_dataframe): + """Gets the delay/slew average of the delay chain for every corner""" + #Get list of lists of delay chain data and reduce to sums + rise_data, fall_data = self.get_rise_fall_dc_data_per_corner(sae_dataframe) + rise_avgs = [sum(dc_data)/len(dc_data) for dc_data in rise_data] + fall_avgs = [sum(dc_data)/len(dc_data) for dc_data in fall_data] + return rise_avgs,fall_avgs + + def get_sum(self, dataframe): + """Get full delay from csv using the sum field in the df""" + return list(dataframe['sum']) + def get_variance(self, nums): avg = self.get_average(nums) delay_variance = sum((xi - avg) ** 2 for xi in nums) / len(nums) @@ -173,15 +489,15 @@ class data_collection(openram_test): plt.plot(data_range, y_values, 'ro') plt.show() - def plot_two_data_sets(self, x_labels, y1_values, y2_values): - """Plots two data sets on the same x-axis. Uses hardcoded axis names.""" + def plot_delay_variance_data_sets(self, x_labels, x_ax_name, y_labels, y1_delays, y2_vars): + """Plots two data sets on the same x-axis.""" data_range = [i for i in range(len(x_labels))] fig, ax1 = plt.subplots() color = 'tab:red' - ax1.set_xlabel('DC (Stages,Fanout)') - ax1.set_ylabel('Average Delay (ns)', color=color) - ax1.plot(data_range, y1_values, marker='o', color=color, linestyle='') + ax1.set_xlabel(str(x_ax_name)) + ax1.set_ylabel(y_labels[0], color=color) + ax1.plot(data_range, y1_delays, marker='o', color=color, linestyle='') ax1.tick_params(axis='y', labelcolor=color) ax1.tick_params(axis='x', labelrotation=-90) @@ -189,8 +505,8 @@ class data_collection(openram_test): color = 'tab:blue' #ax2.set_xticks(data_range, x_labels) - ax2.set_ylabel('Delay Variance (ns)', color=color) # we already handled the x-label with ax1 - ax2.plot(data_range, y2_values, marker='*', color=color, linestyle='') + ax2.set_ylabel(y_labels[1], color=color) # we already handled the x-label with ax1 + ax2.plot(data_range, y2_vars, marker='*', color=color, linestyle='') ax2.tick_params(axis='y', labelcolor=color) fig.tight_layout() # otherwise the right y-label is slightly clipped