mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
Merge pull request #471 from stineje/main
Fix multitude of issues with plotPPA as well as issue related to Popen issuing too many synthesis
This commit is contained in:
commit
b67b1f5719
@ -4,10 +4,10 @@ binencoder,sky130,16,1000,1.0000,136.220003,77.243,0.021773774467348
|
|||||||
binencoder,sky130,32,1000,1.0000,372.400007,189.626,0.04371111111111111
|
binencoder,sky130,32,1000,1.0000,372.400007,189.626,0.04371111111111111
|
||||||
binencoder,sky130,64,1000,1.0000,797.720015,382.205,0.07393850658857981
|
binencoder,sky130,64,1000,1.0000,797.720015,382.205,0.07393850658857981
|
||||||
binencoder,sky130,128,900,1.1111,1602.300031,610.009,0.1261366969785861
|
binencoder,sky130,128,900,1.1111,1602.300031,610.009,0.1261366969785861
|
||||||
adder,sky130,8,1000,1.0000,253.820005,154.438,0.10825587752870422
|
adder,sky130,8,1700,0.588235,253.820005,154.438,0.10825587752870422
|
||||||
adder,sky130,16,1000,1.0000,722.260013,485.109,0.32460910944935417
|
adder,sky130,16,1300,0.7692307,722.260013,485.109,0.32460910944935417
|
||||||
adder,sky130,32,1000,1.0000,1440.600027,714.057,0.6580226904376014
|
adder,sky130,32,1100,0.90909,1440.600027,714.057,0.6580226904376014
|
||||||
adder,sky130,64,1000,1.0000,2781.240054,1050.0,0.9392239364188874
|
adder,sky130,64,950,1.0526315,2781.240054,1050.0,0.9392239364188874
|
||||||
adder,sky130,128,900,1.1111,6186.740118,2230.0,2.1480106100795755
|
adder,sky130,128,900,1.1111,6186.740118,2230.0,2.1480106100795755
|
||||||
csa,sky130,8,1000,1.0000,266.560005,154.202,0.13650573115665163
|
csa,sky130,8,1000,1.0000,266.560005,154.202,0.13650573115665163
|
||||||
csa,sky130,16,1000,1.0000,533.12001,308.404,0.27263530601922104
|
csa,sky130,16,1000,1.0000,533.12001,308.404,0.27263530601922104
|
||||||
@ -19,11 +19,11 @@ shifter,sky130,16,1000,1.0000,666.400006,558.433,0.19552906110283155
|
|||||||
shifter,sky130,32,1000,1.0000,1475.880027,768.262,0.3807431082700759
|
shifter,sky130,32,1000,1.0000,1475.880027,768.262,0.3807431082700759
|
||||||
shifter,sky130,64,1000,1.0000,3914.120062,2680.0,1.144802541988198
|
shifter,sky130,64,1000,1.0000,3914.120062,2680.0,1.144802541988198
|
||||||
shifter,sky130,128,900,1.1111,9192.400136,6080.0,2.9008914525432616
|
shifter,sky130,128,900,1.1111,9192.400136,6080.0,2.9008914525432616
|
||||||
comparator,sky130,8,1000,1.0000,200.900004,136.6,0.05001033271337053
|
comparator,sky130,8,1700,0.588235,200.900004,136.6,0.05001033271337053
|
||||||
comparator,sky130,16,1000,1.0000,358.680007,189.253,0.06321553011448482
|
comparator,sky130,16,1500,0.6666667,358.680007,189.253,0.06321553011448482
|
||||||
comparator,sky130,32,1500,0.666666,690.900013,315.709,0.10771793448084398
|
comparator,sky130,32,1300,0.7692307,690.900013,315.709,0.10771793448084398
|
||||||
comparator,sky130,64,1300,0.7692307,1372.980026,508.393,0.2048577820389901
|
comparator,sky130,64,1200,0.8333333,1372.980026,508.393,0.2048577820389901
|
||||||
comparator,sky130,128,1100,0.909090,2744.980052,796.047,0.34396273737011823
|
comparator,sky130,128,1150,0.869565,2744.980052,796.047,0.34396273737011823
|
||||||
flop,sky130,8,1000,1.0000,133.279999,64.8145,0.193835
|
flop,sky130,8,1000,1.0000,133.279999,64.8145,0.193835
|
||||||
flop,sky130,16,1000,1.0000,266.5599975,129.629,0.38715000000000005
|
flop,sky130,16,1000,1.0000,266.5599975,129.629,0.38715000000000005
|
||||||
flop,sky130,32,1000,1.0000,533.119995,259.258,0.7723000000000001
|
flop,sky130,32,1000,1.0000,533.119995,259.258,0.7723000000000001
|
||||||
|
|
@ -18,44 +18,61 @@ from collections import namedtuple
|
|||||||
import sklearn.metrics as skm # depricated, will need to replace with scikit-learn
|
import sklearn.metrics as skm # depricated, will need to replace with scikit-learn
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
def synthsfromcsv(filename):
|
def synthsfromcsv(filename):
|
||||||
Synth = namedtuple("Synth", "module tech width freq delay area lpower denergy")
|
Synth = namedtuple("Synth", "module tech width freq delay area lpower denergy")
|
||||||
with open(filename, newline='') as csvfile:
|
with open(filename, newline="") as csvfile:
|
||||||
csvreader = csv.reader(csvfile)
|
csvreader = csv.reader(csvfile)
|
||||||
global allSynths
|
global allSynths
|
||||||
allSynths = list(csvreader)[1:]
|
allSynths = list(csvreader)[1:]
|
||||||
for i in range(len(allSynths)):
|
for i in range(len(allSynths)):
|
||||||
for j in range(len(allSynths[0])):
|
for j in range(len(allSynths[0])):
|
||||||
try: allSynths[i][j] = int(allSynths[i][j])
|
try:
|
||||||
|
allSynths[i][j] = int(allSynths[i][j])
|
||||||
except:
|
except:
|
||||||
try: allSynths[i][j] = float(allSynths[i][j])
|
try:
|
||||||
except: pass
|
allSynths[i][j] = float(allSynths[i][j])
|
||||||
|
except:
|
||||||
|
pass
|
||||||
allSynths[i] = Synth(*allSynths[i])
|
allSynths[i] = Synth(*allSynths[i])
|
||||||
return allSynths
|
return allSynths
|
||||||
|
|
||||||
|
|
||||||
def synthsintocsv():
|
def synthsintocsv():
|
||||||
''' writes a CSV with one line for every available synthesis
|
"""writes a CSV with one line for every available synthesis
|
||||||
each line contains the module, tech, width, target freq, and resulting metrics
|
each line contains the module, tech, width, target freq, and resulting metrics
|
||||||
'''
|
"""
|
||||||
print("This takes a moment...")
|
print("This takes a moment...")
|
||||||
bashCommand = "find . -path '*runs/*' -prune"
|
bashCommand = "find . -path '*runs/*' -prune"
|
||||||
output = subprocess.check_output(['bash','-c', bashCommand])
|
output = subprocess.check_output(["bash", "-c", bashCommand])
|
||||||
allSynths = output.decode("utf-8").split('\n')[:-1]
|
allSynths = output.decode("utf-8").split("\n")[:-1]
|
||||||
|
|
||||||
specReg = re.compile('[a-zA-Z0-9]+')
|
specReg = re.compile("[a-zA-Z0-9]+")
|
||||||
metricReg = re.compile('-?\d+\.\d+[e]?[-+]?\d*')
|
metricReg = re.compile("-?\d+\.\d+[e]?[-+]?\d*")
|
||||||
|
|
||||||
file = open("ppaData.csv", "w")
|
file = open("ppaData.csv", "w")
|
||||||
writer = csv.writer(file)
|
writer = csv.writer(file)
|
||||||
writer.writerow(['Module', 'Tech', 'Width', 'Target Freq', 'Delay', 'Area', 'L Power (nW)', 'D energy (nJ)'])
|
writer.writerow(
|
||||||
|
[
|
||||||
|
"Module",
|
||||||
|
"Tech",
|
||||||
|
"Width",
|
||||||
|
"Target Freq",
|
||||||
|
"Delay",
|
||||||
|
"Area",
|
||||||
|
"L Power (nW)",
|
||||||
|
"D energy (nJ)",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
for oneSynth in allSynths:
|
for oneSynth in allSynths:
|
||||||
module, width, risc, tech, freq = specReg.findall(oneSynth)[1:6]
|
module, width, risc, tech, freq = specReg.findall(oneSynth)[1:6]
|
||||||
metrics = []
|
metrics = []
|
||||||
for phrase in [['Path Slack', 'qor'], ['Design Area', 'qor'], ['100', 'power']]:
|
for phrase in [["Path Slack", "qor"], ["Design Area", "qor"], ["100", "power"]]:
|
||||||
bashCommand = 'grep "{}" '+ oneSynth[2:]+'/reports/*{}*'
|
bashCommand = 'grep "{}" ' + oneSynth[2:] + "/reports/*{}*"
|
||||||
bashCommand = bashCommand.format(*phrase)
|
bashCommand = bashCommand.format(*phrase)
|
||||||
try: output = subprocess.check_output(['bash','-c', bashCommand])
|
try:
|
||||||
|
output = subprocess.check_output(["bash", "-c", bashCommand])
|
||||||
except:
|
except:
|
||||||
print(module + width + tech + freq + " doesn't have reports")
|
print(module + width + tech + freq + " doesn't have reports")
|
||||||
print("Consider running cleanup() first")
|
print("Consider running cleanup() first")
|
||||||
@ -65,45 +82,51 @@ def synthsintocsv():
|
|||||||
delay = 1000 / int(freq) - metrics[0]
|
delay = 1000 / int(freq) - metrics[0]
|
||||||
area = metrics[1]
|
area = metrics[1]
|
||||||
lpower = metrics[4]
|
lpower = metrics[4]
|
||||||
denergy = (metrics[2] + metrics[3])/int(freq)*1000 # (switching + internal powers)*delay, more practical units for regression coefs
|
tpower = (metrics[2] + metrics[3] + metrics[4]*.000001)
|
||||||
|
denergy = (
|
||||||
|
(tpower) / int(freq) * 1000
|
||||||
|
) # (switching + internal powers)*delay, more practical units for regression coefs
|
||||||
|
|
||||||
if ('flop' in module): # since two flops in each module
|
if "flop" in module: # since two flops in each module
|
||||||
[area, lpower, denergy] = [n / 2 for n in [area, lpower, denergy]]
|
[area, lpower, denergy] = [n / 2 for n in [area, lpower, denergy]]
|
||||||
|
|
||||||
writer.writerow([module, tech, width, freq, delay, area, lpower, denergy])
|
writer.writerow([module, tech, width, freq, delay, area, lpower, denergy])
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
|
||||||
def cleanup():
|
def cleanup():
|
||||||
''' removes runs that didn't work
|
"""removes runs that didn't work"""
|
||||||
'''
|
|
||||||
bashCommand = 'grep -r "Error" runs/ppa*/reports/*qor*'
|
bashCommand = 'grep -r "Error" runs/ppa*/reports/*qor*'
|
||||||
try:
|
try:
|
||||||
output = subprocess.check_output(['bash','-c', bashCommand])
|
output = subprocess.check_output(["bash", "-c", bashCommand])
|
||||||
allSynths = output.decode("utf-8").split('\n')[:-1]
|
allSynths = output.decode("utf-8").split("\n")[:-1]
|
||||||
for run in allSynths:
|
for run in allSynths:
|
||||||
run = run.split('MHz')[0]
|
run = run.split("MHz")[0]
|
||||||
bc = 'rm -r '+ run + '*'
|
bc = "rm -r " + run + "*"
|
||||||
output = subprocess.check_output(['bash','-c', bc])
|
output = subprocess.check_output(["bash", "-c", bc])
|
||||||
except: pass
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
bashCommand = "find . -path '*runs/*' -prune"
|
bashCommand = "find . -path '*runs/*' -prune"
|
||||||
output = subprocess.check_output(['bash','-c', bashCommand])
|
output = subprocess.check_output(["bash", "-c", bashCommand])
|
||||||
allSynths = output.decode("utf-8").split('\n')[:-1]
|
allSynths = output.decode("utf-8").split("\n")[:-1]
|
||||||
for oneSynth in allSynths:
|
for oneSynth in allSynths:
|
||||||
for phrase in [['Path Length', 'qor']]:
|
for phrase in [["Path Length", "qor"]]:
|
||||||
bashCommand = 'grep "{}" '+ oneSynth[2:]+'/reports/*{}*'
|
bashCommand = 'grep "{}" ' + oneSynth[2:] + "/reports/*{}*"
|
||||||
bashCommand = bashCommand.format(*phrase)
|
bashCommand = bashCommand.format(*phrase)
|
||||||
try: output = subprocess.check_output(['bash','-c', bashCommand])
|
try:
|
||||||
|
output = subprocess.check_output(["bash", "-c", bashCommand])
|
||||||
except:
|
except:
|
||||||
bc = 'rm -r '+ oneSynth[2:]
|
bc = "rm -r " + oneSynth[2:]
|
||||||
output = subprocess.check_output(['bash','-c', bc])
|
output = subprocess.check_output(["bash", "-c", bc])
|
||||||
print("All cleaned up!")
|
print("All cleaned up!")
|
||||||
|
|
||||||
|
|
||||||
def getVals(tech, module, var, freq=None, width=None):
|
def getVals(tech, module, var, freq=None, width=None):
|
||||||
''' for a specified tech, module, and variable/metric
|
"""for a specified tech, module, and variable/metric
|
||||||
returns a list of values for that metric in ascending width order
|
returns a list of values for that metric in ascending width order
|
||||||
works at a specified target frequency or if none is given, uses the synthesis with the best achievable delay for each width
|
works at a specified target frequency or if none is given, uses the synthesis with the best achievable delay for each width
|
||||||
'''
|
"""
|
||||||
|
|
||||||
if width != None:
|
if width != None:
|
||||||
widthsToGet = width
|
widthsToGet = width
|
||||||
@ -113,9 +136,14 @@ def getVals(tech, module, var, freq=None, width=None):
|
|||||||
metric = []
|
metric = []
|
||||||
widthL = []
|
widthL = []
|
||||||
|
|
||||||
if (freq != None):
|
if freq != None:
|
||||||
for oneSynth in allSynths:
|
for oneSynth in allSynths:
|
||||||
if (oneSynth.freq == freq) & (oneSynth.tech == tech) & (oneSynth.module == module) & (oneSynth.width != 1):
|
if (
|
||||||
|
(oneSynth.freq == freq)
|
||||||
|
& (oneSynth.tech == tech)
|
||||||
|
& (oneSynth.module == module)
|
||||||
|
& (oneSynth.width != 1)
|
||||||
|
):
|
||||||
widthL += [oneSynth.width]
|
widthL += [oneSynth.width]
|
||||||
osdict = oneSynth._asdict()
|
osdict = oneSynth._asdict()
|
||||||
metric += [osdict[var]]
|
metric += [osdict[var]]
|
||||||
@ -123,12 +151,17 @@ def getVals(tech, module, var, freq=None, width=None):
|
|||||||
else:
|
else:
|
||||||
for w in widthsToGet:
|
for w in widthsToGet:
|
||||||
for oneSynth in bestSynths:
|
for oneSynth in bestSynths:
|
||||||
if (oneSynth.width == w) & (oneSynth.tech == tech) & (oneSynth.module == module):
|
if (
|
||||||
|
(oneSynth.width == w)
|
||||||
|
& (oneSynth.tech == tech)
|
||||||
|
& (oneSynth.module == module)
|
||||||
|
):
|
||||||
osdict = oneSynth._asdict()
|
osdict = oneSynth._asdict()
|
||||||
met = osdict[var]
|
met = osdict[var]
|
||||||
metric += [met]
|
metric += [met]
|
||||||
return metric
|
return metric
|
||||||
|
|
||||||
|
|
||||||
def csvOfBest(filename):
|
def csvOfBest(filename):
|
||||||
bestSynths = []
|
bestSynths = []
|
||||||
for tech in [x.tech for x in techSpecs]:
|
for tech in [x.tech for x in techSpecs]:
|
||||||
@ -137,8 +170,14 @@ def csvOfBest(filename):
|
|||||||
m = np.Inf # large number to start
|
m = np.Inf # large number to start
|
||||||
best = None
|
best = None
|
||||||
for oneSynth in allSynths: # best achievable, rightmost green
|
for oneSynth in allSynths: # best achievable, rightmost green
|
||||||
if (oneSynth.width == w) & (oneSynth.tech == tech) & (oneSynth.module == mod):
|
if (
|
||||||
if (oneSynth.delay < m) & (1000/oneSynth.delay > oneSynth.freq):
|
(oneSynth.width == w)
|
||||||
|
& (oneSynth.tech == tech)
|
||||||
|
& (oneSynth.module == mod)
|
||||||
|
):
|
||||||
|
if (oneSynth.delay < m) & (
|
||||||
|
1000 / oneSynth.delay > oneSynth.freq
|
||||||
|
):
|
||||||
m = oneSynth.delay
|
m = oneSynth.delay
|
||||||
best = oneSynth
|
best = oneSynth
|
||||||
|
|
||||||
@ -147,33 +186,52 @@ def csvOfBest(filename):
|
|||||||
|
|
||||||
file = open(filename, "w")
|
file = open(filename, "w")
|
||||||
writer = csv.writer(file)
|
writer = csv.writer(file)
|
||||||
writer.writerow(['Module', 'Tech', 'Width', 'Target Freq', 'Delay', 'Area', 'L Power (nW)', 'D energy (nJ)'])
|
writer.writerow(
|
||||||
|
[
|
||||||
|
"Module",
|
||||||
|
"Tech",
|
||||||
|
"Width",
|
||||||
|
"Target Freq",
|
||||||
|
"Delay",
|
||||||
|
"Area",
|
||||||
|
"L Power (nW)",
|
||||||
|
"D energy (nJ)",
|
||||||
|
]
|
||||||
|
)
|
||||||
for synth in bestSynths:
|
for synth in bestSynths:
|
||||||
writer.writerow(list(synth))
|
writer.writerow(list(synth))
|
||||||
file.close()
|
file.close()
|
||||||
return bestSynths
|
return bestSynths
|
||||||
|
|
||||||
|
|
||||||
def genLegend(fits, coefs, r2=None, spec=None, ale=False):
|
def genLegend(fits, coefs, r2=None, spec=None, ale=False):
|
||||||
''' generates a list of two legend elements (or just an equation if no r2 or spec)
|
"""generates a list of two legend elements (or just an equation if no r2 or spec)
|
||||||
labels line with fit equation and dots with r squared of the fit
|
labels line with fit equation and dots with r squared of the fit
|
||||||
'''
|
"""
|
||||||
|
|
||||||
coefsr = [str(sigfig(c, 2)) for c in coefs]
|
coefsr = [str(sigfig(c, 2)) for c in coefs]
|
||||||
if ale:
|
if ale:
|
||||||
if (normAddWidth == 32):
|
if normAddWidth == 32:
|
||||||
sub = 'S'
|
sub = "S"
|
||||||
elif normAddWidth != 1:
|
elif normAddWidth != 1:
|
||||||
print('Equations are wrong, check normAddWidth')
|
print("Equations are wrong, check normAddWidth")
|
||||||
else:
|
else:
|
||||||
sub = 'N'
|
sub = "N"
|
||||||
|
|
||||||
eqDict = {'c': '', 'l': sub, 's': '$'+sub+'^2$', 'g': '$log_2$('+sub+')', 'n': ''+sub+'$log_2$('+sub+')'}
|
eqDict = {
|
||||||
eq = ''
|
"c": "",
|
||||||
|
"l": sub,
|
||||||
|
"s": "$" + sub + "^2$",
|
||||||
|
"g": "$log_2$(" + sub + ")",
|
||||||
|
"n": "" + sub + "$log_2$(" + sub + ")",
|
||||||
|
}
|
||||||
|
eq = ""
|
||||||
ind = 0
|
ind = 0
|
||||||
|
|
||||||
for k in eqDict.keys():
|
for k in eqDict.keys():
|
||||||
if k in fits:
|
if k in fits:
|
||||||
if str(coefsr[ind]) != '0': eq += " + " + coefsr[ind] + eqDict[k]
|
if str(coefsr[ind]) != "0":
|
||||||
|
eq += " + " + coefsr[ind] + eqDict[k]
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
eq = eq[3:] # chop off leading ' + '
|
eq = eq[3:] # chop off leading ' + '
|
||||||
@ -182,16 +240,28 @@ def genLegend(fits, coefs, r2=None, spec=None, ale=False):
|
|||||||
return eq
|
return eq
|
||||||
else:
|
else:
|
||||||
legend_elements = [lines.Line2D([0], [0], color=spec.color, label=eq)]
|
legend_elements = [lines.Line2D([0], [0], color=spec.color, label=eq)]
|
||||||
legend_elements += [lines.Line2D([0], [0], color=spec.color, ls='', marker=spec.shape, label='$R^2$='+ str(round(r2, 4)))]
|
legend_elements += [
|
||||||
|
lines.Line2D(
|
||||||
|
[0],
|
||||||
|
[0],
|
||||||
|
color=spec.color,
|
||||||
|
ls="",
|
||||||
|
marker=spec.shape,
|
||||||
|
label="$R^2$=" + str(round(r2, 4)),
|
||||||
|
)
|
||||||
|
]
|
||||||
return legend_elements
|
return legend_elements
|
||||||
|
|
||||||
def oneMetricPlot(module, widths, var, freq=None, ax=None, fits='clsgn', norm=True, color=None):
|
|
||||||
''' module: string module name
|
def oneMetricPlot(
|
||||||
|
module, widths, var, freq=None, ax=None, fits="clsgn", norm=True, color=None
|
||||||
|
):
|
||||||
|
"""module: string module name
|
||||||
freq: int freq (MHz)
|
freq: int freq (MHz)
|
||||||
var: string delay, area, lpower, or denergy
|
var: string delay, area, lpower, or denergy
|
||||||
fits: constant, linear, square, log2, Nlog2
|
fits: constant, linear, square, log2, Nlog2
|
||||||
plots given variable vs width for all matching syntheses with regression
|
plots given variable vs width for all matching syntheses with regression
|
||||||
'''
|
"""
|
||||||
singlePlot = True
|
singlePlot = True
|
||||||
if ax or (freq == 10):
|
if ax or (freq == 10):
|
||||||
singlePlot = False
|
singlePlot = False
|
||||||
@ -202,24 +272,27 @@ def oneMetricPlot(module, widths, var, freq=None, ax=None, fits='clsgn', norm=Tr
|
|||||||
allWidths = []
|
allWidths = []
|
||||||
allMetrics = []
|
allMetrics = []
|
||||||
|
|
||||||
ale = (var != 'delay') # if not delay, must be area, leakage, or energy
|
ale = var != "delay" # if not delay, must be area, leakage, or energy
|
||||||
modFit = fitDict[module]
|
modFit = fitDict[module]
|
||||||
fits = modFit[ale]
|
fits = modFit[ale]
|
||||||
|
|
||||||
if freq:
|
if freq:
|
||||||
ls = '--'
|
ls = "--"
|
||||||
else:
|
else:
|
||||||
ls = '-'
|
ls = "-"
|
||||||
|
|
||||||
for spec in techSpecs:
|
for spec in techSpecs:
|
||||||
|
# print(f"Searching for module of spec {spec} and module {module} and var {var}")
|
||||||
metric = getVals(spec.tech, module, var, freq=freq)
|
metric = getVals(spec.tech, module, var, freq=freq)
|
||||||
|
# print(f"Found metric : {metric}")
|
||||||
if norm:
|
if norm:
|
||||||
techdict = spec._asdict()
|
techdict = spec._asdict()
|
||||||
norm = techdict[var]
|
norm = techdict[var]
|
||||||
metric = [m / norm for m in metric]
|
metric = [m / norm for m in metric]
|
||||||
|
|
||||||
if len(metric) == 5: # don't include the spec if we don't have points for all widths
|
if len(widths) == len(metric):
|
||||||
|
# don't include the spec if we don't have points for all widths
|
||||||
|
# print(f"Width \neq Metric")
|
||||||
xp, pred, coefs, r2 = regress(widths, metric, fits, ale)
|
xp, pred, coefs, r2 = regress(widths, metric, fits, ale)
|
||||||
fullLeg += genLegend(fits, coefs, r2, spec, ale=ale)
|
fullLeg += genLegend(fits, coefs, r2, spec, ale=ale)
|
||||||
c = color if color else spec.color
|
c = color if color else spec.color
|
||||||
@ -228,37 +301,70 @@ def oneMetricPlot(module, widths, var, freq=None, ax=None, fits='clsgn', norm=Tr
|
|||||||
allWidths += widths
|
allWidths += widths
|
||||||
allMetrics += metric
|
allMetrics += metric
|
||||||
|
|
||||||
|
# print(f"Widths passed into regress : {allWidths}")
|
||||||
|
if len(allWidths) > 0:
|
||||||
xp, pred, coefs, r2 = regress(allWidths, allMetrics, fits)
|
xp, pred, coefs, r2 = regress(allWidths, allMetrics, fits)
|
||||||
ax.plot(xp, pred, color='red', linestyle=ls)
|
ax.plot(xp, pred, color="orange", linestyle=ls)
|
||||||
|
else:
|
||||||
|
xp, pred, coefs, r2 = regress(widths, metric, fits)
|
||||||
|
ax.plot(xp, pred, color="orange", linestyle=ls)
|
||||||
|
|
||||||
if norm:
|
if norm:
|
||||||
ylabeldic = {"lpower": "Leakage Power (add32)", "denergy": "Energy/Op (add32)", "area": "Area (add32)", "delay": "Delay (FO4)"}
|
ylabeldic = {
|
||||||
|
"lpower": "Leakage Power (add32)",
|
||||||
|
"denergy": "Energy/Op (add32)",
|
||||||
|
"area": "Area (add32)",
|
||||||
|
"delay": "Delay (FO4)",
|
||||||
|
}
|
||||||
else:
|
else:
|
||||||
ylabeldic = {"lpower": "Leakage Power (nW)", "denergy": "Dynamic Energy (nJ)", "area": "Area (sq microns)", "delay": "Delay (ns)"}
|
ylabeldic = {
|
||||||
|
"lpower": "Leakage Power (nW)",
|
||||||
|
"denergy": "Dynamic Energy (nJ)",
|
||||||
|
"area": "Area (sq microns)",
|
||||||
|
"delay": "Delay (ns)",
|
||||||
|
}
|
||||||
|
|
||||||
ax.set_ylabel(ylabeldic[var])
|
ax.set_ylabel(ylabeldic[var])
|
||||||
ax.set_xticks(widths)
|
ax.set_xticks(widths)
|
||||||
|
|
||||||
if singlePlot or (var == 'lpower') or (var == 'denergy'):
|
if singlePlot or (var == "lpower") or (var == "denergy"):
|
||||||
ax.set_xlabel("Width (bits)")
|
ax.set_xlabel("Width (bits)")
|
||||||
if not singlePlot and ((var == 'delay') or (var == 'area')):
|
if not singlePlot and ((var == "delay") or (var == "area")):
|
||||||
ax.tick_params(labelbottom=False)
|
ax.tick_params(labelbottom=False)
|
||||||
|
|
||||||
if singlePlot:
|
if singlePlot:
|
||||||
fullLeg += genLegend(fits, coefs, r2, combined, ale=ale)
|
fullLeg += genLegend(fits, coefs, r2, combined, ale=ale)
|
||||||
legLoc = 'upper left' if ale else 'center right'
|
legLoc = "upper left" if ale else "center right"
|
||||||
ax.add_artist(ax.legend(handles=fullLeg, loc=legLoc))
|
ax.add_artist(ax.legend(handles=fullLeg, loc=legLoc))
|
||||||
titleStr = " (target " + str(freq)+ "MHz)" if freq != None else " (best achievable delay)"
|
titleStr = (
|
||||||
|
" (target " + str(freq) + "MHz)"
|
||||||
|
if freq != None
|
||||||
|
else " (best achievable delay)"
|
||||||
|
)
|
||||||
ax.set_title(module + titleStr)
|
ax.set_title(module + titleStr)
|
||||||
plt.savefig('.plots/'+ module + '_' + var + '.png')
|
plt.savefig(".plots/" + module + "_" + var + ".png")
|
||||||
# plt.show()
|
# plt.show()
|
||||||
return r2
|
return r2
|
||||||
|
|
||||||
def regress(widths, var, fits='clsgn', ale=False):
|
|
||||||
''' fits a curve to the given points
|
|
||||||
returns lists of x and y values to plot that curve and coefs for the eq with r2
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
def regress(widths, var, fits="clsgn", ale=False):
|
||||||
|
"""fits a curve to the given points
|
||||||
|
returns lists of x and y values to plot that curve and coefs for the eq with r2
|
||||||
|
"""
|
||||||
|
if len(var) != len(widths):
|
||||||
|
# print(
|
||||||
|
# f"There are not enough variables to match widths. Widths : {widths} Variables Found : {var}, padding to match may affect correctness (doing it anyways)\n"
|
||||||
|
# )
|
||||||
|
if len(widths) > len(var):
|
||||||
|
while len(widths) > len(var):
|
||||||
|
var.append(0.0)
|
||||||
|
if len(var) > len(widths):
|
||||||
|
while len(var) > len(widths):
|
||||||
|
widths.append(0)
|
||||||
|
|
||||||
|
# widths = [8, 16, 32, 64, 128]
|
||||||
|
# print(f"Regress var : {var}")
|
||||||
|
# print(f"Regress widths : {widths}")
|
||||||
funcArr = genFuncs(fits)
|
funcArr = genFuncs(fits)
|
||||||
xp = np.linspace(min(widths) / 2, max(widths) * 1.1, 200)
|
xp = np.linspace(min(widths) / 2, max(widths) * 1.1, 200)
|
||||||
xpToCalc = xp
|
xpToCalc = xp
|
||||||
@ -274,7 +380,8 @@ def regress(widths, var, fits='clsgn', ale=False):
|
|||||||
row += [func(w)]
|
row += [func(w)]
|
||||||
mat += [row]
|
mat += [row]
|
||||||
|
|
||||||
y = np.array(var, dtype=np.float)
|
# var = [0, 1, 2, 3, 4]
|
||||||
|
y = np.array(var, dtype=np.float64)
|
||||||
coefs = opt.nnls(mat, y)[0]
|
coefs = opt.nnls(mat, y)[0]
|
||||||
|
|
||||||
yp = []
|
yp = []
|
||||||
@ -290,19 +397,22 @@ def regress(widths, var, fits='clsgn', ale=False):
|
|||||||
|
|
||||||
return xp, pred, coefs, r2
|
return xp, pred, coefs, r2
|
||||||
|
|
||||||
|
|
||||||
def makeCoefTable():
|
def makeCoefTable():
|
||||||
''' writes CSV with each line containing the coefficients for a regression fit
|
"""writes CSV with each line containing the coefficients for a regression fit
|
||||||
to a particular combination of module, metric (including both techs, normalized)
|
to a particular combination of module, metric (including both techs, normalized)
|
||||||
'''
|
"""
|
||||||
file = open("ppaFitting.csv", "w")
|
file = open("ppaFitting.csv", "w")
|
||||||
writer = csv.writer(file)
|
writer = csv.writer(file)
|
||||||
writer.writerow(['Module', 'Metric', 'Target', '1', 'N', 'N^2', 'log2(N)', 'Nlog2(N)', 'R^2'])
|
writer.writerow(
|
||||||
|
["Module", "Metric", "Target", "1", "N", "N^2", "log2(N)", "Nlog2(N)", "R^2"]
|
||||||
|
)
|
||||||
|
|
||||||
for module in modules:
|
for module in modules:
|
||||||
for freq in [10, None]:
|
for freq in [10, None]:
|
||||||
target = 'easy' if freq else 'hard'
|
target = "easy" if freq else "hard"
|
||||||
for var in ['delay', 'area', 'lpower', 'denergy']:
|
for var in ["delay", "area", "lpower", "denergy"]:
|
||||||
ale = (var != 'delay')
|
ale = var != "delay"
|
||||||
metL = []
|
metL = []
|
||||||
modFit = fitDict[module]
|
modFit = fitDict[module]
|
||||||
fits = modFit[ale]
|
fits = modFit[ale]
|
||||||
@ -316,7 +426,7 @@ def makeCoefTable():
|
|||||||
xp, pred, coefs, r2 = regress(widths * 2, metL, fits, ale)
|
xp, pred, coefs, r2 = regress(widths * 2, metL, fits, ale)
|
||||||
coefs = np.ndarray.tolist(coefs)
|
coefs = np.ndarray.tolist(coefs)
|
||||||
coefsToWrite = [None] * 5
|
coefsToWrite = [None] * 5
|
||||||
fitTerms = 'clsgn'
|
fitTerms = "clsgn"
|
||||||
ind = 0
|
ind = 0
|
||||||
for i in range(len(fitTerms)):
|
for i in range(len(fitTerms)):
|
||||||
if fitTerms[i] in fits:
|
if fitTerms[i] in fits:
|
||||||
@ -327,25 +437,38 @@ def makeCoefTable():
|
|||||||
|
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
|
||||||
def sigfig(num, figs):
|
def sigfig(num, figs):
|
||||||
return '{:g}'.format(float('{:.{p}g}'.format(num, p=figs)))
|
return "{:g}".format(float("{:.{p}g}".format(num, p=figs)))
|
||||||
|
|
||||||
|
|
||||||
def makeEqTable():
|
def makeEqTable():
|
||||||
''' writes CSV with each line containing the equations for fits for each metric
|
"""writes CSV with each line containing the equations for fits for each metric
|
||||||
to a particular module (including both techs, normalized)
|
to a particular module (including both techs, normalized)
|
||||||
'''
|
"""
|
||||||
file = open("ppaEquations.csv", "w")
|
file = open("ppaEquations.csv", "w")
|
||||||
writer = csv.writer(file)
|
writer = csv.writer(file)
|
||||||
writer.writerow(['Element', 'Best delay', 'Fast area', 'Fast leakage', 'Fast energy', 'Small area', 'Small leakage', 'Small energy'])
|
writer.writerow(
|
||||||
|
[
|
||||||
|
"Element",
|
||||||
|
"Best delay",
|
||||||
|
"Fast area",
|
||||||
|
"Fast leakage",
|
||||||
|
"Fast energy",
|
||||||
|
"Small area",
|
||||||
|
"Small leakage",
|
||||||
|
"Small energy",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
for module in modules:
|
for module in modules:
|
||||||
eqs = []
|
eqs = []
|
||||||
for freq in [None, 10]:
|
for freq in [None, 10]:
|
||||||
for var in ['delay', 'area', 'lpower', 'denergy']:
|
for var in ["delay", "area", "lpower", "denergy"]:
|
||||||
if (var == 'delay') and (freq == 10):
|
if (var == "delay") and (freq == 10):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
ale = (var != 'delay')
|
ale = var != "delay"
|
||||||
metL = []
|
metL = []
|
||||||
modFit = fitDict[module]
|
modFit = fitDict[module]
|
||||||
fits = modFit[ale]
|
fits = modFit[ale]
|
||||||
@ -364,28 +487,30 @@ def makeEqTable():
|
|||||||
|
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
def genFuncs(fits='clsgn'):
|
|
||||||
''' helper function for regress()
|
def genFuncs(fits="clsgn"):
|
||||||
|
"""helper function for regress()
|
||||||
returns array of functions with one for each term desired in the regression fit
|
returns array of functions with one for each term desired in the regression fit
|
||||||
'''
|
"""
|
||||||
funcArr = []
|
funcArr = []
|
||||||
if 'c' in fits:
|
if "c" in fits:
|
||||||
funcArr += [lambda x: 1]
|
funcArr += [lambda x: 1]
|
||||||
if 'l' in fits:
|
if "l" in fits:
|
||||||
funcArr += [lambda x: x]
|
funcArr += [lambda x: x]
|
||||||
if 's' in fits:
|
if "s" in fits:
|
||||||
funcArr += [lambda x: x**2]
|
funcArr += [lambda x: x**2]
|
||||||
if 'g' in fits:
|
if "g" in fits:
|
||||||
funcArr += [lambda x: np.log2(x)]
|
funcArr += [lambda x: np.log2(x)]
|
||||||
if 'n' in fits:
|
if "n" in fits:
|
||||||
funcArr += [lambda x: x * np.log2(x)]
|
funcArr += [lambda x: x * np.log2(x)]
|
||||||
return funcArr
|
return funcArr
|
||||||
|
|
||||||
|
|
||||||
def noOutliers(median, freqs, delays, areas):
|
def noOutliers(median, freqs, delays, areas):
|
||||||
''' returns a pared down list of freqs, delays, and areas
|
"""returns a pared down list of freqs, delays, and areas
|
||||||
cuts out any syntheses in which target freq isn't within 75% of the min delay target to focus on interesting area
|
cuts out any syntheses in which target freq isn't within 75% of the min delay target to focus on interesting area
|
||||||
helper function to freqPlot()
|
helper function to freqPlot()
|
||||||
'''
|
"""
|
||||||
f = []
|
f = []
|
||||||
d = []
|
d = []
|
||||||
a = []
|
a = []
|
||||||
@ -398,14 +523,20 @@ def noOutliers(median, freqs, delays, areas):
|
|||||||
|
|
||||||
return f, d, a
|
return f, d, a
|
||||||
|
|
||||||
|
|
||||||
def freqPlot(tech, mod, width):
|
def freqPlot(tech, mod, width):
|
||||||
''' plots delay, area, area*delay, and area*delay^2 for syntheses with specified tech, module, width
|
"""plots delay, area, area*delay, and area*delay^2 for syntheses with specified tech, module, width"""
|
||||||
'''
|
|
||||||
|
|
||||||
freqsL, delaysL, areasL = ([[], []] for i in range(3))
|
freqsL, delaysL, areasL = ([[], []] for i in range(3))
|
||||||
for oneSynth in allSynths:
|
for oneSynth in allSynths:
|
||||||
if (mod == oneSynth.module) & (width == oneSynth.width) & (tech == oneSynth.tech):
|
if (
|
||||||
ind = (1000/oneSynth.delay < oneSynth.freq) # when delay is within target clock period
|
(mod == oneSynth.module)
|
||||||
|
& (width == oneSynth.width)
|
||||||
|
& (tech == oneSynth.tech)
|
||||||
|
):
|
||||||
|
ind = (
|
||||||
|
1000 / oneSynth.delay < oneSynth.freq
|
||||||
|
) # when delay is within target clock period
|
||||||
freqsL[ind] += [oneSynth.freq]
|
freqsL[ind] += [oneSynth.freq]
|
||||||
delaysL[ind] += [oneSynth.delay]
|
delaysL[ind] += [oneSynth.delay]
|
||||||
areasL[ind] += [oneSynth.area]
|
areasL[ind] += [oneSynth.area]
|
||||||
@ -414,43 +545,55 @@ def freqPlot(tech, mod, width):
|
|||||||
|
|
||||||
f, (ax1, ax2) = plt.subplots(2, 1, sharex=True)
|
f, (ax1, ax2) = plt.subplots(2, 1, sharex=True)
|
||||||
for ax in (ax1, ax2):
|
for ax in (ax1, ax2):
|
||||||
ax.ticklabel_format(useOffset=False, style='plain')
|
ax.ticklabel_format(useOffset=False, style="plain")
|
||||||
|
|
||||||
for ind in [0, 1]:
|
for ind in [0, 1]:
|
||||||
areas = areasL[ind]
|
areas = areasL[ind]
|
||||||
delays = delaysL[ind]
|
delays = delaysL[ind]
|
||||||
freqs = freqsL[ind]
|
freqs = freqsL[ind]
|
||||||
|
|
||||||
freqs, delays, areas = noOutliers(median, freqs, delays, areas) # comment out to see all syntheses
|
freqs, delays, areas = noOutliers(
|
||||||
|
median, freqs, delays, areas
|
||||||
|
) # comment out to see all syntheses
|
||||||
|
|
||||||
c = 'blue' if ind else 'green'
|
c = "blue" if ind else "green"
|
||||||
ax1.scatter(freqs, delays, color=c)
|
ax1.scatter(freqs, delays, color=c)
|
||||||
ax2.scatter(freqs, areas, color=c)
|
ax2.scatter(freqs, areas, color=c)
|
||||||
|
|
||||||
legend_elements = [lines.Line2D([0], [0], color='green', ls='', marker='o', label='timing achieved'),
|
legend_elements = [
|
||||||
lines.Line2D([0], [0], color='blue', ls='', marker='o', label='slack violated')]
|
lines.Line2D(
|
||||||
|
[0], [0], color="green", ls="", marker="o", label="timing achieved"
|
||||||
|
),
|
||||||
|
lines.Line2D([0], [0], color="blue", ls="", marker="o", label="slack violated"),
|
||||||
|
]
|
||||||
|
|
||||||
ax1.legend(handles=legend_elements)
|
ax1.legend(handles=legend_elements)
|
||||||
width = str(width)
|
width = str(width)
|
||||||
|
|
||||||
ax2.set_xlabel("Target Freq (MHz)")
|
ax2.set_xlabel("Target Freq (MHz)")
|
||||||
ax1.set_ylabel('Delay (ns)')
|
ax1.set_ylabel("Delay (ns)")
|
||||||
ax2.set_ylabel('Area (sq microns)')
|
ax2.set_ylabel("Area (sq microns)")
|
||||||
ax1.set_title(mod + '_' + width)
|
ax1.set_title(mod + "_" + width)
|
||||||
if ('mux' in mod) & ('d' in mod):
|
if ("mux" in mod) & ("d" in mod):
|
||||||
width = mod
|
width = mod
|
||||||
mod = 'muxd'
|
mod = "muxd"
|
||||||
plt.savefig('./plots/freqBuckshot/' + tech + '/' + mod + '/' + width + '.png')
|
plt.savefig("./plots/freqBuckshot/" + tech + "/" + mod + "/" + width + ".png")
|
||||||
# plt.show()
|
# plt.show()
|
||||||
|
|
||||||
|
|
||||||
def squareAreaDelay(tech, mod, width):
|
def squareAreaDelay(tech, mod, width):
|
||||||
''' plots delay, area, area*delay, and area*delay^2 for syntheses with specified tech, module, width
|
"""plots delay, area, area*delay, and area*delay^2 for syntheses with specified tech, module, width"""
|
||||||
'''
|
|
||||||
global allSynths
|
global allSynths
|
||||||
freqsL, delaysL, areasL = ([[], []] for i in range(3))
|
freqsL, delaysL, areasL = ([[], []] for i in range(3))
|
||||||
for oneSynth in allSynths:
|
for oneSynth in allSynths:
|
||||||
if (mod == oneSynth.module) & (width == oneSynth.width) & (tech == oneSynth.tech):
|
if (
|
||||||
ind = (1000/oneSynth.delay < oneSynth.freq) # when delay is within target clock period
|
(mod == oneSynth.module)
|
||||||
|
& (width == oneSynth.width)
|
||||||
|
& (tech == oneSynth.tech)
|
||||||
|
):
|
||||||
|
ind = (
|
||||||
|
1000 / oneSynth.delay < oneSynth.freq
|
||||||
|
) # when delay is within target clock period
|
||||||
freqsL[ind] += [oneSynth.freq]
|
freqsL[ind] += [oneSynth.freq]
|
||||||
delaysL[ind] += [oneSynth.delay]
|
delaysL[ind] += [oneSynth.delay]
|
||||||
areasL[ind] += [oneSynth.area]
|
areasL[ind] += [oneSynth.area]
|
||||||
@ -464,28 +607,40 @@ def squareAreaDelay(tech, mod, width):
|
|||||||
targets = freqsL[ind]
|
targets = freqsL[ind]
|
||||||
targets = [1000 / f for f in targets]
|
targets = [1000 / f for f in targets]
|
||||||
|
|
||||||
targets, delays, areas = noOutliers(targets, delays, areas) # comment out to see all
|
targets, delays, areas = noOutliers(
|
||||||
|
targets, delays, areas
|
||||||
|
) # comment out to see all
|
||||||
|
|
||||||
if not ind:
|
if not ind:
|
||||||
achievedDelays = delays
|
achievedDelays = delays
|
||||||
|
|
||||||
c = 'blue' if ind else 'green'
|
c = "blue" if ind else "green"
|
||||||
ax1.scatter(targets, delays, marker='^', color=c)
|
ax1.scatter(targets, delays, marker="^", color=c)
|
||||||
ax2.scatter(targets, areas, marker='s', color=c)
|
ax2.scatter(targets, areas, marker="s", color=c)
|
||||||
|
|
||||||
bestAchieved = min(achievedDelays)
|
bestAchieved = min(achievedDelays)
|
||||||
|
|
||||||
legend_elements = [lines.Line2D([0], [0], color='green', ls='', marker='^', label='delay (timing achieved)'),
|
legend_elements = [
|
||||||
lines.Line2D([0], [0], color='green', ls='', marker='s', label='area (timing achieved)'),
|
lines.Line2D(
|
||||||
lines.Line2D([0], [0], color='blue', ls='', marker='^', label='delay (timing violated)'),
|
[0], [0], color="green", ls="", marker="^", label="delay (timing achieved)"
|
||||||
lines.Line2D([0], [0], color='blue', ls='', marker='s', label='area (timing violated)')]
|
),
|
||||||
|
lines.Line2D(
|
||||||
|
[0], [0], color="green", ls="", marker="s", label="area (timing achieved)"
|
||||||
|
),
|
||||||
|
lines.Line2D(
|
||||||
|
[0], [0], color="blue", ls="", marker="^", label="delay (timing violated)"
|
||||||
|
),
|
||||||
|
lines.Line2D(
|
||||||
|
[0], [0], color="blue", ls="", marker="s", label="area (timing violated)"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
ax2.legend(handles=legend_elements, loc='upper left')
|
ax2.legend(handles=legend_elements, loc="upper left")
|
||||||
|
|
||||||
ax1.set_xlabel("Delay Targeted (ns)")
|
ax1.set_xlabel("Delay Targeted (ns)")
|
||||||
ax1.set_ylabel("Delay Achieved (ns)")
|
ax1.set_ylabel("Delay Achieved (ns)")
|
||||||
ax2.set_ylabel('Area (sq microns)')
|
ax2.set_ylabel("Area (sq microns)")
|
||||||
ax1.set_title(mod + '_' + str(width))
|
ax1.set_title(mod + "_" + str(width))
|
||||||
|
|
||||||
squarify(f)
|
squarify(f)
|
||||||
|
|
||||||
@ -495,54 +650,68 @@ def squareAreaDelay(tech, mod, width):
|
|||||||
areaUpperLim = max(flatten(areasL)) / frac + areaLowerLim
|
areaUpperLim = max(flatten(areasL)) / frac + areaLowerLim
|
||||||
ax2.set_ylim([areaLowerLim, areaUpperLim])
|
ax2.set_ylim([areaLowerLim, areaUpperLim])
|
||||||
ax1.plot(xvals, xvals, ls="--", c=".3")
|
ax1.plot(xvals, xvals, ls="--", c=".3")
|
||||||
ax1.hlines(y=bestAchieved, xmin=xvals[0], xmax=xvals[1], color="black", ls='--')
|
ax1.hlines(y=bestAchieved, xmin=xvals[0], xmax=xvals[1], color="black", ls="--")
|
||||||
|
|
||||||
plt.savefig('./plots/squareareadelay_' + mod + '_' + str(width) + '.png')
|
plt.savefig("./plots/squareareadelay_" + mod + "_" + str(width) + ".png")
|
||||||
# plt.show()
|
# plt.show()
|
||||||
|
|
||||||
|
|
||||||
def squarify(fig):
|
def squarify(fig):
|
||||||
''' helper function for squareAreaDelay()
|
"""helper function for squareAreaDelay()
|
||||||
forces matplotlib figure to be a square
|
forces matplotlib figure to be a square
|
||||||
'''
|
"""
|
||||||
w, h = fig.get_size_inches()
|
w, h = fig.get_size_inches()
|
||||||
if w > h:
|
if w > h:
|
||||||
t = fig.subplotpars.top
|
t = fig.subplotpars.top
|
||||||
b = fig.subplotpars.bottom
|
b = fig.subplotpars.bottom
|
||||||
axs = h * (t - b)
|
axs = h * (t - b)
|
||||||
l = (1.-axs/w)/2
|
l = (1.0 - axs / w) / 2
|
||||||
fig.subplots_adjust(left=l, right=1 - l)
|
fig.subplots_adjust(left=l, right=1 - l)
|
||||||
else:
|
else:
|
||||||
t = fig.subplotpars.right
|
t = fig.subplotpars.right
|
||||||
b = fig.subplotpars.left
|
b = fig.subplotpars.left
|
||||||
axs = w * (t - b)
|
axs = w * (t - b)
|
||||||
l = (1.-axs/h)/2
|
l = (1.0 - axs / h) / 2
|
||||||
fig.subplots_adjust(bottom=l, top=1 - l)
|
fig.subplots_adjust(bottom=l, top=1 - l)
|
||||||
|
|
||||||
def plotPPA(mod, widths, freq=None, norm=True, aleOpt=False):
|
|
||||||
''' for the module specified, plots width vs delay, area, leakage power, and dynamic energy with fits
|
def plotPPA(mod, freq=None, norm=True, aleOpt=False):
|
||||||
|
"""for the module specified, plots width vs delay, area, leakage power, and dynamic energy with fits
|
||||||
if no freq specified, uses the synthesis with best achievable delay for each width
|
if no freq specified, uses the synthesis with best achievable delay for each width
|
||||||
overlays data from both techs
|
overlays data from both techs
|
||||||
'''
|
"""
|
||||||
with mpl.rc_context({"figure.figsize": (7, 3.46)}):
|
with mpl.rc_context({"figure.figsize": (7, 3.46)}):
|
||||||
fig, axs = plt.subplots(2, 2)
|
fig, axs = plt.subplots(2, 2)
|
||||||
|
|
||||||
arr = [['delay', 'area'], ['lpower', 'denergy']]
|
arr = [["delay", "area"], ["lpower", "denergy"]]
|
||||||
|
|
||||||
freqs = [freq]
|
freqs = [freq]
|
||||||
if aleOpt: freqs += [10]
|
if aleOpt:
|
||||||
|
freqs += [10]
|
||||||
|
|
||||||
for i in [0, 1]:
|
for i in [0, 1]:
|
||||||
for j in [0, 1]:
|
for j in [0, 1]:
|
||||||
leg = []
|
leg = []
|
||||||
for f in freqs:
|
for f in freqs:
|
||||||
if (arr[i][j]=='delay') and (f==10):
|
if (arr[i][j] == "delay") and (f == 10):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
r2 = oneMetricPlot(mod, widths, arr[i][j], ax=axs[i, j], freq=f, norm=norm)
|
# print(f"Pasing in widths {widths}")
|
||||||
ls = '--' if f else '-'
|
r2 = oneMetricPlot(
|
||||||
leg += [lines.Line2D([0], [0], color='red', label='$R^2$='+str(round(r2, 4)), linestyle=ls)]
|
mod, widths, arr[i][j], ax=axs[i, j], freq=f, norm=norm
|
||||||
|
)
|
||||||
|
ls = "--" if f else "-"
|
||||||
|
leg += [
|
||||||
|
lines.Line2D(
|
||||||
|
[0],
|
||||||
|
[0],
|
||||||
|
color="orange",
|
||||||
|
label="$R^2$=" + str(round(r2, 4)),
|
||||||
|
linestyle=ls,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
if (mod in ['flop', 'csa']) & (arr[i][j] == 'delay'):
|
if (mod in ["flop", "csa"]) & (arr[i][j] == "delay"):
|
||||||
axs[i, j].set_ylim(ymin=0)
|
axs[i, j].set_ylim(ymin=0)
|
||||||
ytop = axs[i, j].get_ylim()[1]
|
ytop = axs[i, j].get_ylim()[1]
|
||||||
axs[i, j].set_ylim(ymax=1.1 * ytop)
|
axs[i, j].set_ylim(ymax=1.1 * ytop)
|
||||||
@ -554,86 +723,90 @@ def plotPPA(mod, widths, freq=None, norm=True, aleOpt=False):
|
|||||||
plt.tight_layout(pad=0.05, w_pad=1, h_pad=0.5, rect=(0, 0, 1, 0.97))
|
plt.tight_layout(pad=0.05, w_pad=1, h_pad=0.5, rect=(0, 0, 1, 0.97))
|
||||||
|
|
||||||
if freq != 10:
|
if freq != 10:
|
||||||
n = 'normalized' if norm else 'unnormalized'
|
n = "normalized" if norm else "unnormalized"
|
||||||
saveStr = './plots/'+ n + '/' + mod + '.png'
|
saveStr = "./plots/" + n + "/" + mod + "_" + ".png"
|
||||||
|
print(f"Saving to {saveStr}")
|
||||||
plt.savefig(saveStr)
|
plt.savefig(saveStr)
|
||||||
# plt.show()
|
# plt.show()
|
||||||
|
|
||||||
|
|
||||||
def makeLineLegend():
|
def makeLineLegend():
|
||||||
''' generates legend to accompany normalized plots
|
"""generates legend to accompany normalized plots"""
|
||||||
'''
|
|
||||||
plt.rcParams["figure.figsize"] = (5.5, 0.3)
|
plt.rcParams["figure.figsize"] = (5.5, 0.3)
|
||||||
fig = plt.figure()
|
fig = plt.figure()
|
||||||
fullLeg = [lines.Line2D([0], [0], color='black', label='fastest', linestyle='-')]
|
fullLeg = [lines.Line2D([0], [0], color="black", label="fastest", linestyle="-")]
|
||||||
fullLeg += [lines.Line2D([0], [0], color='black', label='smallest', linestyle='--')]
|
fullLeg += [lines.Line2D([0], [0], color="black", label="smallest", linestyle="--")]
|
||||||
fullLeg += [lines.Line2D([0], [0], color='blue', label='tsmc28', marker='^')]
|
fullLeg += [lines.Line2D([0], [0], color="blue", label="tsmc28", marker="^")]
|
||||||
fullLeg += [lines.Line2D([0], [0], color='blue', label='tsmc28psyn', marker='x')]
|
fullLeg += [lines.Line2D([0], [0], color="blue", label="tsmc28psyn", marker="x")]
|
||||||
fullLeg += [lines.Line2D([0], [0], color='green', label='sky90', marker='o')]
|
fullLeg += [lines.Line2D([0], [0], color="green", label="sky90", marker="o")]
|
||||||
fullLeg += [lines.Line2D([0], [0], color='green', label='sky130', marker='+')]
|
fullLeg += [lines.Line2D([0], [0], color="purple", label="sky130", marker="+")]
|
||||||
fullLeg += [lines.Line2D([0], [0], color='red', label='combined', marker='_')]
|
fullLeg += [lines.Line2D([0], [0], color="orange", label="combined", marker="_")]
|
||||||
fig.legend(handles=fullLeg, ncol=5, handlelength=1.4, loc='center')
|
fig.legend(handles=fullLeg, ncol=5, handlelength=1.4, loc="center")
|
||||||
saveStr = './plots/legend.png'
|
saveStr = "./plots/legend.png"
|
||||||
plt.savefig(saveStr)
|
plt.savefig(saveStr)
|
||||||
|
|
||||||
def muxPlot(fits='clsgn', norm=True):
|
|
||||||
''' module: string module name
|
def muxPlot(fits="clsgn", norm=True):
|
||||||
|
"""module: string module name
|
||||||
freq: int freq (MHz)
|
freq: int freq (MHz)
|
||||||
var: string delay, area, lpower, or denergy
|
var: string delay, area, lpower, or denergy
|
||||||
fits: constant, linear, square, log2, Nlog2
|
fits: constant, linear, square, log2, Nlog2
|
||||||
plots given variable vs width for all matching syntheses with regression
|
plots given variable vs width for all matching syntheses with regression
|
||||||
'''
|
"""
|
||||||
ax = plt.gca()
|
ax = plt.gca()
|
||||||
|
|
||||||
inputs = [2, 4, 8]
|
inputs = [2, 4, 8]
|
||||||
allInputs = inputs * 2
|
allInputs = inputs * 2
|
||||||
fullLeg = []
|
fullLeg = []
|
||||||
|
|
||||||
for crit in ['data', 'control']:
|
for crit in ["data", "control"]:
|
||||||
allMetrics = []
|
allMetrics = []
|
||||||
muxes = ['mux2', 'mux4', 'mux8']
|
muxes = ["mux2", "mux4", "mux8"]
|
||||||
|
|
||||||
if crit == 'data':
|
if crit == "data":
|
||||||
ls = '--'
|
ls = "--"
|
||||||
muxes = [m + 'd' for m in muxes]
|
muxes = [m + "d" for m in muxes]
|
||||||
elif crit == 'control':
|
elif crit == "control":
|
||||||
ls = '-'
|
ls = "-"
|
||||||
|
|
||||||
for spec in techSpecs:
|
for spec in techSpecs:
|
||||||
metric = []
|
metric = []
|
||||||
for module in muxes:
|
for module in muxes:
|
||||||
metric += getVals(spec.tech, module, 'delay', width=[1])
|
metric += getVals(spec.tech, module, "delay", width=[1])
|
||||||
|
|
||||||
if norm:
|
if norm:
|
||||||
techdict = spec._asdict()
|
techdict = spec._asdict()
|
||||||
norm = techdict['delay']
|
norm = techdict["delay"]
|
||||||
metric = [m / norm for m in metric]
|
metric = [m / norm for m in metric]
|
||||||
# print(spec.tech, ' ', metric)
|
# print(spec.tech, ' ', metric)
|
||||||
|
|
||||||
if len(metric) == 3: # don't include the spec if we don't have points for all
|
if (
|
||||||
|
len(metric) == 3
|
||||||
|
): # don't include the spec if we don't have points for all
|
||||||
xp, pred, coefs, r2 = regress(inputs, metric, fits, ale=False)
|
xp, pred, coefs, r2 = regress(inputs, metric, fits, ale=False)
|
||||||
ax.scatter(inputs, metric, color=spec.color, marker=spec.shape)
|
ax.scatter(inputs, metric, color=spec.color, marker=spec.shape)
|
||||||
ax.plot(xp, pred, color=spec.color, linestyle=ls)
|
ax.plot(xp, pred, color=spec.color, linestyle=ls)
|
||||||
allMetrics += metric
|
allMetrics += metric
|
||||||
|
|
||||||
xp, pred, coefs, r2 = regress(allInputs, allMetrics, fits)
|
xp, pred, coefs, r2 = regress(allInputs, allMetrics, fits)
|
||||||
ax.plot(xp, pred, color='red', linestyle=ls)
|
ax.plot(xp, pred, color="red", linestyle=ls)
|
||||||
fullLeg += [lines.Line2D([0], [0], color='red', label=crit, linestyle=ls)]
|
fullLeg += [lines.Line2D([0], [0], color="red", label=crit, linestyle=ls)]
|
||||||
|
|
||||||
ax.set_ylabel('Delay (FO4)')
|
ax.set_ylabel("Delay (FO4)")
|
||||||
ax.set_xticks(inputs)
|
ax.set_xticks(inputs)
|
||||||
ax.set_xlabel("Number of inputs")
|
ax.set_xlabel("Number of inputs")
|
||||||
ax.set_title('mux timing')
|
ax.set_title("mux timing")
|
||||||
|
|
||||||
ax.legend(handles=fullLeg)
|
ax.legend(handles=fullLeg)
|
||||||
plt.savefig('./plots/mux.png')
|
plt.savefig("./plots/mux.png")
|
||||||
|
|
||||||
|
|
||||||
def stdDevError():
|
def stdDevError():
|
||||||
''' calculates std deviation and error for paper-writing purposes
|
"""calculates std deviation and error for paper-writing purposes"""
|
||||||
'''
|
for var in ["delay", "area", "lpower", "denergy"]:
|
||||||
for var in ['delay', 'area', 'lpower', 'denergy']:
|
|
||||||
errlist = []
|
errlist = []
|
||||||
for module in modules:
|
for module in modules:
|
||||||
ale = (var != 'delay')
|
ale = var != "delay"
|
||||||
metL = []
|
metL = []
|
||||||
modFit = fitDict[module]
|
modFit = fitDict[module]
|
||||||
fits = modFit[ale]
|
fits = modFit[ale]
|
||||||
@ -665,9 +838,9 @@ def stdDevError():
|
|||||||
n = [func(w) for func in funcArr]
|
n = [func(w) for func in funcArr]
|
||||||
yp += [sum(np.multiply(coefs, n))]
|
yp += [sum(np.multiply(coefs, n))]
|
||||||
|
|
||||||
if (var == 'delay') & (module == 'flop'):
|
if (var == "delay") & (module == "flop"):
|
||||||
pass
|
pass
|
||||||
elif (module == 'mult') & ale:
|
elif (module == "mult") & ale:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
for i in range(len(y)):
|
for i in range(len(y)):
|
||||||
@ -677,55 +850,71 @@ def stdDevError():
|
|||||||
avgErr = np.mean(errlist)
|
avgErr = np.mean(errlist)
|
||||||
stdv = np.std(errlist)
|
stdv = np.std(errlist)
|
||||||
|
|
||||||
print(var, ' ', avgErr, ' ', stdv)
|
print(var, " ", avgErr, " ", stdv)
|
||||||
|
|
||||||
|
|
||||||
def makePlotDirectory():
|
def makePlotDirectory():
|
||||||
''' creates plots directory in same level as this script to store plots in
|
"""creates plots directory in same level as this script to store plots in"""
|
||||||
'''
|
|
||||||
current_directory = os.getcwd()
|
current_directory = os.getcwd()
|
||||||
final_directory = os.path.join(current_directory, 'plots')
|
final_directory = os.path.join(current_directory, "plots")
|
||||||
if not os.path.exists(final_directory):
|
if not os.path.exists(final_directory):
|
||||||
os.makedirs(final_directory)
|
os.makedirs(final_directory)
|
||||||
os.chdir(final_directory)
|
os.chdir(final_directory)
|
||||||
|
|
||||||
for folder in ['freqBuckshot', 'normalized', 'unnormalized']:
|
for folder in ["freqBuckshot", "normalized", "unnormalized"]:
|
||||||
new_directory = os.path.join(final_directory, folder)
|
new_directory = os.path.join(final_directory, folder)
|
||||||
if not os.path.exists(new_directory):
|
if not os.path.exists(new_directory):
|
||||||
os.makedirs(new_directory)
|
os.makedirs(new_directory)
|
||||||
os.chdir(new_directory)
|
os.chdir(new_directory)
|
||||||
if 'freq' in folder:
|
if "freq" in folder:
|
||||||
for tech in ['sky90', 'sky130', 'tsmc28', 'tsmc28psyn']:
|
for tech in ["sky90", "sky130", "tsmc28", "tsmc28psyn"]:
|
||||||
for mod in modules:
|
for mod in modules:
|
||||||
tech_directory = os.path.join(new_directory, tech)
|
tech_directory = os.path.join(new_directory, tech)
|
||||||
mod_directory = os.path.join(tech_directory, mod)
|
mod_directory = os.path.join(tech_directory, mod)
|
||||||
if not os.path.exists(mod_directory):
|
if not os.path.exists(mod_directory):
|
||||||
os.makedirs(mod_directory)
|
os.makedirs(mod_directory)
|
||||||
os.chdir('..')
|
os.chdir("..")
|
||||||
|
|
||||||
os.chdir(current_directory)
|
os.chdir(current_directory)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
if __name__ == "__main__":
|
||||||
##############################
|
##############################
|
||||||
# set up stuff, global variables
|
# set up stuff, global variables
|
||||||
widths = [64, 128]
|
widths = [8, 16, 32, 64, 128]
|
||||||
modules = ['adder', 'comparator']
|
modules = ["adder"]
|
||||||
|
|
||||||
normAddWidth = 32 # divisor to use with N since normalizing to add_32
|
normAddWidth = 32 # divisor to use with N since normalizing to add_32
|
||||||
|
|
||||||
fitDict = {'adder': ['cg', 'l', 'l'], 'mul': ['cg', 's', 's'], 'comparator': ['cg', 'l', 'l'], 'csa': ['c', 'l', 'l'], 'shifter': ['cg', 'l', 'ln'], 'flop': ['c', 'l', 'l'], 'binencoder': ['cg', 'l', 'l']}
|
fitDict = {
|
||||||
fitDict.update(dict.fromkeys(['mux2', 'mux4', 'mux8'], ['cg', 'l', 'l']))
|
"adder": ["cg", "l", "l"],
|
||||||
|
"mul": ["cg", "s", "s"],
|
||||||
|
"comparator": ["cg", "l", "l"],
|
||||||
|
"csa": ["c", "l", "l"],
|
||||||
|
"shifter": ["cg", "l", "ln"],
|
||||||
|
"flop": ["c", "l", "l"],
|
||||||
|
"binencoder": ["cg", "l", "l"],
|
||||||
|
}
|
||||||
|
fitDict.update(dict.fromkeys(["mux2", "mux4", "mux8"], ["cg", "l", "l"]))
|
||||||
|
|
||||||
TechSpec = namedtuple("TechSpec", "tech color shape delay area lpower denergy")
|
TechSpec = namedtuple("TechSpec", "tech color shape delay area lpower denergy")
|
||||||
techSpecs = [['sky90', 'green', 'o', 43.2e-3, 1440.600027, 714.057, 0.658022690438], ['sky130', 'red', 'o', 43.2e-3, 1440.600027, 714.057, 0.658022690438], ['tsmc28', 'blue', '^', 12.2e-3, 209.286002, 1060.0, .08153281695882594], ['tsmc28psyn', 'blue', '^', 12.2e-3, 209.286002, 1060.0, .08153281695882594]]
|
# FO4 delay information information
|
||||||
|
techSpecs = [
|
||||||
|
#["sky90", "green", "o", 43.2e-3, 1440.600027, 714.057, 0.658022690438],
|
||||||
|
# Area/Lpower/Denergy needs to be corrected here (jes)
|
||||||
|
["sky130", "orange", "o", 99.5e-3, 1440.600027, 714.057, 0.658022690438],
|
||||||
|
# ["tsmc28", "blue", "^", 12.2e-3, 209.286002, 1060.0, 0.08153281695882594],
|
||||||
|
# ["tsmc28psyn", "blue", "^", 12.2e-3, 209.286002, 1060.0, 0.08153281695882594],
|
||||||
|
]
|
||||||
techSpecs = [TechSpec(*t) for t in techSpecs]
|
techSpecs = [TechSpec(*t) for t in techSpecs]
|
||||||
combined = TechSpec('combined fit', 'red', '_', 0, 0, 0, 0)
|
combined = TechSpec("combined fit", "red", "_", 0, 0, 0, 0)
|
||||||
##############################
|
##############################
|
||||||
|
|
||||||
# cleanup() # run to remove garbage synth runs
|
# cleanup() # run to remove garbage synth runs
|
||||||
synthsintocsv() # slow, run only when new synth runs to add to csv
|
synthsintocsv() # slow, run only when new synth runs to add to csv
|
||||||
|
|
||||||
allSynths = synthsfromcsv('ppaData.csv') # your csv here!
|
allSynths = synthsfromcsv("ppaData.csv") # your csv here!
|
||||||
bestSynths = csvOfBest('bestSynths.csv')
|
bestSynths = csvOfBest("bestSynths.csv")
|
||||||
makePlotDirectory()
|
makePlotDirectory()
|
||||||
|
|
||||||
# ### other functions
|
# ### other functions
|
||||||
@ -737,9 +926,9 @@ if __name__ == '__main__':
|
|||||||
for mod in modules:
|
for mod in modules:
|
||||||
for w in widths:
|
for w in widths:
|
||||||
#freqPlot('sky90', mod, w)
|
#freqPlot('sky90', mod, w)
|
||||||
freqPlot('sky130', mod, w)
|
freqPlot("sky130", mod, w)
|
||||||
# freqPlot('tsmc28', mod, w)
|
# freqPlot('tsmc28', mod, w)
|
||||||
# freqPlot('tsmc28psyn', mod, w)
|
# freqPlot('tsmc28psyn', mod, w)
|
||||||
#plotPPA(mod, widths, norm=False)
|
plotPPA(mod, norm=False)
|
||||||
#plotPPA(mod, aleOpt=True)
|
plotPPA(mod, aleOpt=True)
|
||||||
plt.close('all')
|
plt.close("all")
|
||||||
|
@ -12,11 +12,11 @@ from ppaAnalyze import synthsfromcsv
|
|||||||
|
|
||||||
def runCommand(module, width, tech, freq):
|
def runCommand(module, width, tech, freq):
|
||||||
command = "make synth DESIGN={} WIDTH={} TECH={} DRIVE=INV FREQ={} MAXOPT=1 MAXCORES=1".format(module, width, tech, freq)
|
command = "make synth DESIGN={} WIDTH={} TECH={} DRIVE=INV FREQ={} MAXOPT=1 MAXCORES=1".format(module, width, tech, freq)
|
||||||
subprocess.Popen(command, shell=True)
|
subprocess.call(command, shell=True)
|
||||||
|
|
||||||
def deleteRedundant(synthsToRun):
|
def deleteRedundant(synthsToRun):
|
||||||
'''removes any previous runs for the current synthesis specifications'''
|
'''removes any previous runs for the current synthesis specifications'''
|
||||||
synthStr = "rm -rf runs/ppa_{}_{}_rv32e_{}nm_{}_*"
|
synthStr = "rm -rf runs/{}_{}_rv32e_{}_{}_*"
|
||||||
for synth in synthsToRun:
|
for synth in synthsToRun:
|
||||||
bashCommand = synthStr.format(*synth)
|
bashCommand = synthStr.format(*synth)
|
||||||
outputCPL = subprocess.check_output(['bash','-c', bashCommand])
|
outputCPL = subprocess.check_output(['bash','-c', bashCommand])
|
||||||
@ -46,7 +46,7 @@ def freqModuleSweep(widths, modules, tech):
|
|||||||
return synthsToRun
|
return synthsToRun
|
||||||
|
|
||||||
def filterRedundant(synthsToRun):
|
def filterRedundant(synthsToRun):
|
||||||
bashCommand = "find . -path '*runs/ppa*rv32e*' -prune"
|
bashCommand = "find . -path '*runs/*' -prune"
|
||||||
output = subprocess.check_output(['bash','-c', bashCommand])
|
output = subprocess.check_output(['bash','-c', bashCommand])
|
||||||
specReg = re.compile('[a-zA-Z0-9]+')
|
specReg = re.compile('[a-zA-Z0-9]+')
|
||||||
allSynths = output.decode("utf-8").split('\n')[:-1]
|
allSynths = output.decode("utf-8").split('\n')[:-1]
|
||||||
@ -84,14 +84,15 @@ if __name__ == '__main__':
|
|||||||
synthsToRun = freqSweep(module, width, tech)
|
synthsToRun = freqSweep(module, width, tech)
|
||||||
|
|
||||||
##### Run a sweep for multiple modules/widths based on best delay found in existing syntheses
|
##### Run a sweep for multiple modules/widths based on best delay found in existing syntheses
|
||||||
modules = ['adder', 'comparator']
|
modules = ['adder']
|
||||||
widths = [64, 128]
|
widths = [8, 16, 32, 64, 128]
|
||||||
tech = 'sky130'
|
tech = 'sky130'
|
||||||
synthsToRun = freqModuleSweep(widths, modules, tech)
|
synthsToRun = freqModuleSweep(widths, modules, tech)
|
||||||
|
|
||||||
##### Only do syntheses for which a run doesn't already exist
|
##### Only do syntheses for which a run doesn't already exist
|
||||||
synthsToRun = filterRedundant(synthsToRun)
|
synthsToRun = filterRedundant(synthsToRun)
|
||||||
|
|
||||||
pool = Pool(processes=25)
|
pool = Pool(processes=25)
|
||||||
|
|
||||||
pool.starmap(runCommand, synthsToRun)
|
pool.starmap(runCommand, synthsToRun)
|
||||||
|
pool.close()
|
||||||
|
pool.join()
|
Loading…
Reference in New Issue
Block a user