Added similar interface to linear regression as elmore

This commit is contained in:
Hunter Nichols 2020-12-14 13:59:31 -08:00
parent 0adcf8935f
commit 25544c3974
5 changed files with 85 additions and 101 deletions

View File

@ -510,7 +510,7 @@ class delay(simulation):
elif delay_obj.meta_str == sram_op.READ_ONE:
meas_cycle_delay = self.cycle_times[self.measure_cycles[port][delay_obj.meta_str]]
else:
debug.error("Unrecognised delay Index={}".format(delay_obj.meta_str),1)
debug.error("Unrecognized delay Index={}".format(delay_obj.meta_str),1)
# These measurements have there time further delayed to the neg. edge of the clock.
if delay_obj.meta_add_delay:
@ -1270,80 +1270,6 @@ class delay(simulation):
# Add test cycle of read/write port pair. One port could have been used already, but the other has not.
self.gen_test_cycles_one_port(cur_read_port, cur_write_port)
def analytical_delay(self, slews, loads):
"""
Return the analytical model results for the SRAM.
"""
if OPTS.num_rw_ports > 1 or OPTS.num_w_ports > 0 and OPTS.num_r_ports > 0:
debug.warning("In analytical mode, all ports have the timing of the first read port.")
# Probe set to 0th bit, does not matter for analytical delay.
self.set_probe('0' * self.addr_size, 0)
self.create_graph()
self.set_internal_spice_names()
self.create_measurement_names()
port = self.read_ports[0]
self.graph.get_all_paths('{}{}'.format("clk", port),
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
# Select the path with the bitline (bl)
bl_name, br_name = self.get_bl_name(self.graph.all_paths, port)
bl_path = [path for path in self.graph.all_paths if bl_name in path][0]
# Set delay/power for slews and loads
port_data = self.get_empty_measure_data_dict()
power = self.analytical_power(slews, loads)
debug.info(1, 'Slew, Load, Delay(ns), Slew(ns)')
max_delay = 0.0
for slew in slews:
for load in loads:
# Calculate delay based on slew and load
path_delays = self.graph.get_timing(bl_path, self.corner, slew, load)
total_delay = self.sum_delays(path_delays)
max_delay = max(max_delay, total_delay.delay)
debug.info(1,
'{}, {}, {}, {}'.format(slew,
load,
total_delay.delay / 1e3,
total_delay.slew / 1e3))
# Delay is only calculated on a single port and replicated for now.
for port in self.all_ports:
for mname in self.delay_meas_names + self.power_meas_names:
if "power" in mname:
port_data[port][mname].append(power.dynamic)
elif "delay" in mname and port in self.read_ports:
port_data[port][mname].append(total_delay.delay / 1e3)
elif "slew" in mname and port in self.read_ports:
port_data[port][mname].append(total_delay.slew / 1e3)
else:
debug.error("Measurement name not recognized: {}".format(mname), 1)
# Estimate the period as double the delay with margin
period_margin = 0.1
sram_data = {"min_period": (max_delay / 1e3) * 2 * period_margin,
"leakage_power": power.leakage}
debug.info(2, "SRAM Data:\n{}".format(sram_data))
debug.info(2, "Port Data:\n{}".format(port_data))
return (sram_data, port_data)
def analytical_power(self, slews, loads):
"""Get the dynamic and leakage power from the SRAM"""
# slews unused, only last load is used
load = loads[-1]
power = self.sram.analytical_power(self.corner, load)
# convert from nW to mW
power.dynamic /= 1e6
power.leakage /= 1e6
debug.info(1, "Dynamic Power: {0} mW".format(power.dynamic))
debug.info(1, "Leakage Power: {0} mW".format(power.leakage))
return power
def gen_data(self):
""" Generates the PWL data inputs for a simulation timing test. """

View File

@ -30,7 +30,7 @@ class elmore(simulation):
self.create_signal_names()
self.add_graph_exclusions()
def analytical_delay(self, slews, loads):
def get_lib_values(self, slews, loads):
"""
Return the analytical model results for the SRAM.
"""

View File

@ -591,20 +591,10 @@ class lib:
else:
debug.error("{} model not recognized. See options.py for available models.".format(OPTS.model_name))
import math
#FIXME: ML models only designed for delay. Cannot produce all values for Lib
m = model()
#temp_wpr = 2.0 #OPTS not working right now
log_num_words = math.log(OPTS.num_words, 2)
debug.info(1, "OPTS.words_per_row={}".format(OPTS.words_per_row))
model_inputs = [log_num_words,
OPTS.word_size,
OPTS.words_per_row,
self.sram.width * self.sram.height]
char_results = m.get_predictions(model_inputs)
#self.d = elmore(self.sram, self.sp_file, self.corner)
# char_results = self.d.analytical_delay(self.slews,self.loads)
# self.char_sram_results, self.char_port_results = char_results
m = model(self.sram, self.sp_file, self.corner)
char_results = m.get_lib_values(self.slews,self.loads)
else:
self.d = delay(self.sram, self.sp_file, self.corner)
if (self.sram.num_spare_rows == 0):
@ -613,7 +603,7 @@ class lib:
probe_address = "0" + "1" * (self.sram.addr_size - 1)
probe_data = self.sram.word_size - 1
char_results = self.d.analyze(probe_address, probe_data, self.slews, self.loads)
self.char_sram_results, self.char_port_results = char_results
self.char_sram_results, self.char_port_results = char_results
def compute_setup_hold(self):
""" Do the analysis if we haven't characterized a FF yet """

View File

@ -6,32 +6,100 @@
# All rights reserved.
#
import os
from sklearn.linear_model import LinearRegression
from .analytical_util import *
from .simulation import simulation
from globals import OPTS
import debug
import os
from sklearn.linear_model import LinearRegression
import math
relative_data_path = "/sim_data"
delay_data_filename = "data.csv"
power_data_filename = "power_data.csv"
data_fnames = ["delay_data.csv",
"power_data.csv",
"leakage_data.csv",
"slew_data.csv"]
tech_path = os.environ.get('OPENRAM_TECH')
data_dir = tech_path+'/'+OPTS.tech_name+relative_data_path
data_paths = [data_dir +'/'+fname for fname in data_fnames]
class linear_regression():
class linear_regression(simulation):
def __init__(self):
def __init__(self, sram, spfile, corner):
super().__init__(sram, spfile, corner)
self.set_corner(corner)
self.create_signal_names()
self.add_graph_exclusions()
self.delay_model = None
self.slew_model = None
self.power_model = None
self.leakage_model = None
def get_lib_values(self, slews, loads):
"""
A model and prediction is created for each output needed for the LIB
"""
log_num_words = math.log(OPTS.num_words, 2)
debug.info(1, "OPTS.words_per_row={}".format(OPTS.words_per_row))
model_inputs = [log_num_words,
OPTS.word_size,
OPTS.words_per_row,
self.sram.width * self.sram.height]
# List returned with value order being delay, power, leakage, slew
# FIXME: make order less hard coded
sram_vals = self.get_predictions(model_inputs)
self.create_measurement_names()
# Set delay/power for slews and loads
port_data = self.get_empty_measure_data_dict()
debug.info(1, 'Slew, Load, Delay(ns), Slew(ns)')
max_delay = 0.0
for slew in slews:
for load in loads:
# Calculate delay based on slew and load
debug.info(1,
'{}, {}, {}, {}'.format(slew,
load,
total_delay.delay / 1e3,
total_delay.slew / 1e3))
# Delay is only calculated on a single port and replicated for now.
for port in self.all_ports:
for mname in self.delay_meas_names + self.power_meas_names:
#FIXME: fix magic for indexing the data
if "power" in mname:
port_data[port][mname].append(sram_vals[1])
elif "delay" in mname and port in self.read_ports:
port_data[port][mname].append(sram_vals[0])
elif "slew" in mname and port in self.read_ports:
port_data[port][mname].append(sram_vals[3])
else:
debug.error("Measurement name not recognized: {}".format(mname), 1)
# Estimate the period as double the delay with margin
period_margin = 0.1
sram_data = {"min_period": sram_vals[0] * 2,
"leakage_power": sram_vals[2]}
debug.info(2, "SRAM Data:\n{}".format(sram_data))
debug.info(2, "Port Data:\n{}".format(port_data))
return (sram_data, port_data)
def get_predictions(self, model_inputs):
"""
Generate a model and prediction for LIB output
"""
delay_file_path = data_dir +'/'+delay_data_filename
power_file_path = data_dir +'/'+power_data_filename
scaled_inputs = np.asarray([scale_input_datapoint(model_inputs, delay_file_path)])
scaled_inputs = np.asarray([scale_input_datapoint(model_inputs, data_paths[0])])
predictions = []
for path, model in zip([delay_file_path, power_file_path], [self.delay_model, self.power_model]):
for path in data_paths:
features, labels = get_scaled_data(path)
model = self.generate_model(features, labels)
scaled_pred = self.model_prediction(model, scaled_inputs)