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:
David Harris 2023-11-14 05:51:20 -08:00 committed by GitHub
commit b67b1f5719
3 changed files with 510 additions and 320 deletions

View File

@ -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

1 Module Tech Width Target Freq Delay Area L Power (nW) D energy (nJ)
4 binencoder sky130 32 1000 1.0000 372.400007 189.626 0.04371111111111111
5 binencoder sky130 64 1000 1.0000 797.720015 382.205 0.07393850658857981
6 binencoder sky130 128 900 1.1111 1602.300031 610.009 0.1261366969785861
7 adder sky130 8 1000 1700 1.0000 0.588235 253.820005 154.438 0.10825587752870422
8 adder sky130 16 1000 1300 1.0000 0.7692307 722.260013 485.109 0.32460910944935417
9 adder sky130 32 1000 1100 1.0000 0.90909 1440.600027 714.057 0.6580226904376014
10 adder sky130 64 1000 950 1.0000 1.0526315 2781.240054 1050.0 0.9392239364188874
11 adder sky130 128 900 1.1111 6186.740118 2230.0 2.1480106100795755
12 csa sky130 8 1000 1.0000 266.560005 154.202 0.13650573115665163
13 csa sky130 16 1000 1.0000 533.12001 308.404 0.27263530601922104
19 shifter sky130 32 1000 1.0000 1475.880027 768.262 0.3807431082700759
20 shifter sky130 64 1000 1.0000 3914.120062 2680.0 1.144802541988198
21 shifter sky130 128 900 1.1111 9192.400136 6080.0 2.9008914525432616
22 comparator sky130 8 1000 1700 1.0000 0.588235 200.900004 136.6 0.05001033271337053
23 comparator sky130 16 1000 1500 1.0000 0.6666667 358.680007 189.253 0.06321553011448482
24 comparator sky130 32 1500 1300 0.666666 0.7692307 690.900013 315.709 0.10771793448084398
25 comparator sky130 64 1300 1200 0.7692307 0.8333333 1372.980026 508.393 0.2048577820389901
26 comparator sky130 128 1100 1150 0.909090 0.869565 2744.980052 796.047 0.34396273737011823
27 flop sky130 8 1000 1.0000 133.279999 64.8145 0.193835
28 flop sky130 16 1000 1.0000 266.5599975 129.629 0.38715000000000005
29 flop sky130 32 1000 1.0000 533.119995 259.258 0.7723000000000001

View File

@ -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")

View File

@ -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()