From 6374d1a200329fcd4dd758833f75a7a13a155a28 Mon Sep 17 00:00:00 2001 From: "James E. Stine" Date: Tue, 14 Nov 2023 01:04:37 -0600 Subject: [PATCH 1/3] Modify ppaSynth.py to be able to not issue excess number of operations with Pool command. This is due to the original command using the Popen command, whereas, using the subprocess.call command solves this issue. The relieves the python script from issuing a ton of synthesis commands and using up all the licenses --- synthDC/ppa/ppaSynth.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/synthDC/ppa/ppaSynth.py b/synthDC/ppa/ppaSynth.py index ceb6edbd2..07a342e26 100755 --- a/synthDC/ppa/ppaSynth.py +++ b/synthDC/ppa/ppaSynth.py @@ -12,11 +12,11 @@ from ppaAnalyze import synthsfromcsv def runCommand(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): '''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: bashCommand = synthStr.format(*synth) outputCPL = subprocess.check_output(['bash','-c', bashCommand]) @@ -46,7 +46,7 @@ def freqModuleSweep(widths, modules, tech): return synthsToRun def filterRedundant(synthsToRun): - bashCommand = "find . -path '*runs/ppa*rv32e*' -prune" + bashCommand = "find . -path '*runs/*' -prune" output = subprocess.check_output(['bash','-c', bashCommand]) specReg = re.compile('[a-zA-Z0-9]+') allSynths = output.decode("utf-8").split('\n')[:-1] @@ -84,14 +84,15 @@ if __name__ == '__main__': synthsToRun = freqSweep(module, width, tech) ##### Run a sweep for multiple modules/widths based on best delay found in existing syntheses - modules = ['adder', 'comparator'] - widths = [64, 128] + modules = ['adder', "comparator"] + widths = [8, 16, 32, 64, 128] tech = 'sky130' synthsToRun = freqModuleSweep(widths, modules, tech) ##### Only do syntheses for which a run doesn't already exist - synthsToRun = filterRedundant(synthsToRun) - + synthsToRun = filterRedundant(synthsToRun) pool = Pool(processes=25) -pool.starmap(runCommand, synthsToRun) \ No newline at end of file +pool.starmap(runCommand, synthsToRun) +pool.close() +pool.join() \ No newline at end of file From c722e2c59da4e9473194d4abd4eda8b36277416c Mon Sep 17 00:00:00 2001 From: "James E. Stine" Date: Tue, 14 Nov 2023 01:06:14 -0600 Subject: [PATCH 2/3] fix plotPPA and other excruciatingly painful problems related to using allWidths and causing empty arrays to be used. This generates the normalized/unnormalized plots --- synthDC/ppa/bestSynths.csv | 18 +- synthDC/ppa/ppaAnalyze.py | 798 +++++++++++++++++++++++-------------- 2 files changed, 504 insertions(+), 312 deletions(-) diff --git a/synthDC/ppa/bestSynths.csv b/synthDC/ppa/bestSynths.csv index 885eeb962..655f171a1 100644 --- a/synthDC/ppa/bestSynths.csv +++ b/synthDC/ppa/bestSynths.csv @@ -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,64,1000,1.0000,797.720015,382.205,0.07393850658857981 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,16,1000,1.0000,722.260013,485.109,0.32460910944935417 -adder,sky130,32,1000,1.0000,1440.600027,714.057,0.6580226904376014 -adder,sky130,64,1000,1.0000,2781.240054,1050.0,0.9392239364188874 +adder,sky130,8,1700,0.588235,253.820005,154.438,0.10825587752870422 +adder,sky130,16,1300,0.7692307,722.260013,485.109,0.32460910944935417 +adder,sky130,32,1100,0.90909,1440.600027,714.057,0.6580226904376014 +adder,sky130,64,950,1.0526315,2781.240054,1050.0,0.9392239364188874 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,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,64,1000,1.0000,3914.120062,2680.0,1.144802541988198 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,16,1000,1.0000,358.680007,189.253,0.06321553011448482 -comparator,sky130,32,1500,0.666666,690.900013,315.709,0.10771793448084398 -comparator,sky130,64,1300,0.7692307,1372.980026,508.393,0.2048577820389901 -comparator,sky130,128,1100,0.909090,2744.980052,796.047,0.34396273737011823 +comparator,sky130,8,1700,0.588235,200.900004,136.6,0.05001033271337053 +comparator,sky130,16,1500,0.6666667,358.680007,189.253,0.06321553011448482 +comparator,sky130,32,1300,0.7692307,690.900013,315.709,0.10771793448084398 +comparator,sky130,64,1200,0.8333333,1372.980026,508.393,0.2048577820389901 +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,16,1000,1.0000,266.5599975,129.629,0.38715000000000005 flop,sky130,32,1000,1.0000,533.119995,259.258,0.7723000000000001 diff --git a/synthDC/ppa/ppaAnalyze.py b/synthDC/ppa/ppaAnalyze.py index 73cd353c4..9af15fd80 100755 --- a/synthDC/ppa/ppaAnalyze.py +++ b/synthDC/ppa/ppaAnalyze.py @@ -18,92 +18,117 @@ from collections import namedtuple import sklearn.metrics as skm # depricated, will need to replace with scikit-learn import os + def synthsfromcsv(filename): 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) global allSynths allSynths = list(csvreader)[1:] for i in range(len(allSynths)): for j in range(len(allSynths[0])): - try: allSynths[i][j] = int(allSynths[i][j]) - except: - try: allSynths[i][j] = float(allSynths[i][j]) - except: pass + try: + allSynths[i][j] = int(allSynths[i][j]) + except: + try: + allSynths[i][j] = float(allSynths[i][j]) + except: + pass allSynths[i] = Synth(*allSynths[i]) return allSynths - + + def synthsintocsv(): - ''' writes a CSV with one line for every available synthesis - each line contains the module, tech, width, target freq, and resulting metrics - ''' + """writes a CSV with one line for every available synthesis + each line contains the module, tech, width, target freq, and resulting metrics + """ print("This takes a moment...") bashCommand = "find . -path '*runs/*' -prune" - output = subprocess.check_output(['bash','-c', bashCommand]) - allSynths = output.decode("utf-8").split('\n')[:-1] + output = subprocess.check_output(["bash", "-c", bashCommand]) + allSynths = output.decode("utf-8").split("\n")[:-1] - specReg = re.compile('[a-zA-Z0-9]+') - metricReg = re.compile('-?\d+\.\d+[e]?[-+]?\d*') + specReg = re.compile("[a-zA-Z0-9]+") + metricReg = re.compile("-?\d+\.\d+[e]?[-+]?\d*") file = open("ppaData.csv", "w") 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: module, width, risc, tech, freq = specReg.findall(oneSynth)[1:6] metrics = [] - for phrase in [['Path Slack', 'qor'], ['Design Area', 'qor'], ['100', 'power']]: - bashCommand = 'grep "{}" '+ oneSynth[2:]+'/reports/*{}*' + for phrase in [["Path Slack", "qor"], ["Design Area", "qor"], ["100", "power"]]: + bashCommand = 'grep "{}" ' + oneSynth[2:] + "/reports/*{}*" bashCommand = bashCommand.format(*phrase) - try: output = subprocess.check_output(['bash','-c', bashCommand]) - except: + try: + output = subprocess.check_output(["bash", "-c", bashCommand]) + except: print(module + width + tech + freq + " doesn't have reports") print("Consider running cleanup() first") nums = metricReg.findall(str(output)) nums = [float(m) for m in nums] metrics += nums - delay = 1000/int(freq) - metrics[0] + delay = 1000 / int(freq) - metrics[0] area = metrics[1] lpower = metrics[4] - denergy = (metrics[2] + metrics[3])/int(freq)*1000 # (switching + internal powers)*delay, more practical units for regression coefs + # switching, internal power in mW and leakage in nW + tpower = metrics[2] + metrics[3] + metrics[4]*0.000001 + # EDP (fJ/GHz) + denergy = ( + (metrics[2] + metrics[3] + metrics[4]*0.000001) / int(freq) + ) # (switching + internal powers)*delay, more practical units for regression coefs - if ('flop' in module): # since two flops in each module - [area, lpower, denergy] = [n/2 for n in [area, lpower, denergy]] + if "flop" in module: # since two flops in each module + [area, lpower, denergy] = [n / 2 for n in [area, lpower, denergy]] writer.writerow([module, tech, width, freq, delay, area, lpower, denergy]) file.close() + def cleanup(): - ''' removes runs that didn't work - ''' + """removes runs that didn't work""" bashCommand = 'grep -r "Error" runs/ppa*/reports/*qor*' - try: - output = subprocess.check_output(['bash','-c', bashCommand]) - allSynths = output.decode("utf-8").split('\n')[:-1] + try: + output = subprocess.check_output(["bash", "-c", bashCommand]) + allSynths = output.decode("utf-8").split("\n")[:-1] for run in allSynths: - run = run.split('MHz')[0] - bc = 'rm -r '+ run + '*' - output = subprocess.check_output(['bash','-c', bc]) - except: pass + run = run.split("MHz")[0] + bc = "rm -r " + run + "*" + output = subprocess.check_output(["bash", "-c", bc]) + except: + pass bashCommand = "find . -path '*runs/*' -prune" - output = subprocess.check_output(['bash','-c', bashCommand]) - allSynths = output.decode("utf-8").split('\n')[:-1] + output = subprocess.check_output(["bash", "-c", bashCommand]) + allSynths = output.decode("utf-8").split("\n")[:-1] for oneSynth in allSynths: - for phrase in [['Path Length', 'qor']]: - bashCommand = 'grep "{}" '+ oneSynth[2:]+'/reports/*{}*' + for phrase in [["Path Length", "qor"]]: + bashCommand = 'grep "{}" ' + oneSynth[2:] + "/reports/*{}*" bashCommand = bashCommand.format(*phrase) - try: output = subprocess.check_output(['bash','-c', bashCommand]) - except: - bc = 'rm -r '+ oneSynth[2:] - output = subprocess.check_output(['bash','-c', bc]) + try: + output = subprocess.check_output(["bash", "-c", bashCommand]) + except: + bc = "rm -r " + oneSynth[2:] + output = subprocess.check_output(["bash", "-c", bc]) print("All cleaned up!") + def getVals(tech, module, var, freq=None, width=None): - ''' for a specified tech, module, and variable/metric - 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 - ''' + """for a specified tech, module, and variable/metric + 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 + """ if width != None: widthsToGet = width @@ -113,85 +138,132 @@ def getVals(tech, module, var, freq=None, width=None): metric = [] widthL = [] - if (freq != None): + if freq != None: 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] osdict = oneSynth._asdict() metric += [osdict[var]] - metric = [x for _, x in sorted(zip(widthL, metric))] # ordering + metric = [x for _, x in sorted(zip(widthL, metric))] # ordering else: for w in widthsToGet: 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() met = osdict[var] metric += [met] return metric + def csvOfBest(filename): bestSynths = [] for tech in [x.tech for x in techSpecs]: for mod in modules: for w in widths: - m = np.Inf # large number to start + m = np.Inf # large number to start best = None - for oneSynth in allSynths: # best achievable, rightmost green - if (oneSynth.width == w) & (oneSynth.tech == tech) & (oneSynth.module == mod): - if (oneSynth.delay < m) & (1000/oneSynth.delay > oneSynth.freq): + for oneSynth in allSynths: # best achievable, rightmost green + if ( + (oneSynth.width == w) + & (oneSynth.tech == tech) + & (oneSynth.module == mod) + ): + if (oneSynth.delay < m) & ( + 1000 / oneSynth.delay > oneSynth.freq + ): m = oneSynth.delay best = oneSynth if (best != None) & (best not in bestSynths): bestSynths += [best] - + file = open(filename, "w") 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: writer.writerow(list(synth)) file.close() return bestSynths - + + 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) - labels line with fit equation and dots with r squared of the fit - ''' + """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 + """ coefsr = [str(sigfig(c, 2)) for c in coefs] if ale: - if (normAddWidth == 32): - sub = 'S' + if normAddWidth == 32: + sub = "S" elif normAddWidth != 1: - print('Equations are wrong, check normAddWidth') + print("Equations are wrong, check normAddWidth") else: - sub = 'N' + sub = "N" - eqDict = {'c': '', 'l': sub, 's': '$'+sub+'^2$', 'g': '$log_2$('+sub+')', 'n': ''+sub+'$log_2$('+sub+')'} - eq = '' - ind = 0 + eqDict = { + "c": "", + "l": sub, + "s": "$" + sub + "^2$", + "g": "$log_2$(" + sub + ")", + "n": "" + sub + "$log_2$(" + sub + ")", + } + eq = "" + ind = 0 for k in eqDict.keys(): 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 - eq = eq[3:] # chop off leading ' + ' + eq = eq[3:] # chop off leading ' + ' - if (r2==None) or (spec==None): + if (r2 == None) or (spec == None): return eq else: 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 -def oneMetricPlot(module, widths, var, freq=None, ax=None, fits='clsgn', norm=True, color=None): - ''' module: string module name - freq: int freq (MHz) - var: string delay, area, lpower, or denergy - fits: constant, linear, square, log2, Nlog2 - plots given variable vs width for all matching syntheses with regression - ''' + +def oneMetricPlot( + module, widths, var, freq=None, ax=None, fits="clsgn", norm=True, color=None +): + """module: string module name + freq: int freq (MHz) + var: string delay, area, lpower, or denergy + fits: constant, linear, square, log2, Nlog2 + plots given variable vs width for all matching syntheses with regression + """ singlePlot = True if ax or (freq == 10): singlePlot = False @@ -202,24 +274,27 @@ def oneMetricPlot(module, widths, var, freq=None, ax=None, fits='clsgn', norm=Tr allWidths = [] 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] fits = modFit[ale] if freq: - ls = '--' + ls = "--" else: - ls = '-' + ls = "-" 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) - + # print(f"Found metric : {metric}") if norm: techdict = spec._asdict() 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) fullLeg += genLegend(fits, coefs, r2, spec, ale=ale) c = color if color else spec.color @@ -228,44 +303,78 @@ def oneMetricPlot(module, widths, var, freq=None, ax=None, fits='clsgn', norm=Tr allWidths += widths allMetrics += metric - xp, pred, coefs, r2 = regress(allWidths, allMetrics, fits) - ax.plot(xp, pred, color='red', linestyle=ls) + # print(f"Widths passed into regress : {allWidths}") + # Not sure why this works (jes) - if allWidths doesn't have data widths does + if len(allWidths) > 0: + xp, pred, coefs, r2 = regress(allWidths, allMetrics, fits) + 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: - 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: - ylabeldic = {"lpower": "Leakage Power (nW)", "denergy": "Dynamic Energy (nJ)", "area": "Area (sq microns)", "delay": "Delay (ns)"} + ylabeldic = { + "lpower": "Leakage Power (nW)", + "denergy": "EDP (fJ/GHz)", + "area": "Area (sq microns)", + "delay": "Delay (ns)", + } ax.set_ylabel(ylabeldic[var]) 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)") - if not singlePlot and ((var == 'delay') or (var == 'area')): - ax.tick_params(labelbottom=False) + if not singlePlot and ((var == "delay") or (var == "area")): + ax.tick_params(labelbottom=False) if singlePlot: 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)) - 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) - plt.savefig('.plots/'+ module + '_' + var + '.png') + plt.savefig(".plots/" + module + "_" + var + ".png") # plt.show() 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) - xp = np.linspace(min(widths)/2, max(widths)*1.1, 200) + xp = np.linspace(min(widths) / 2, max(widths) * 1.1, 200) xpToCalc = xp if ale: - widths = [w/normAddWidth for w in widths] - xpToCalc = [x/normAddWidth for x in xp] + widths = [w / normAddWidth for w in widths] + xpToCalc = [x / normAddWidth for x in xp] mat = [] for w in widths: @@ -273,8 +382,9 @@ def regress(widths, var, fits='clsgn', ale=False): for func in funcArr: row += [func(w)] 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] yp = [] @@ -290,19 +400,22 @@ def regress(widths, var, fits='clsgn', ale=False): return xp, pred, coefs, r2 + def makeCoefTable(): - ''' writes CSV with each line containing the coefficients for a regression fit - to a particular combination of module, metric (including both techs, normalized) - ''' + """writes CSV with each line containing the coefficients for a regression fit + to a particular combination of module, metric (including both techs, normalized) + """ file = open("ppaFitting.csv", "w") 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 freq in [10, None]: - target = 'easy' if freq else 'hard' - for var in ['delay', 'area', 'lpower', 'denergy']: - ale = (var != 'delay') + target = "easy" if freq else "hard" + for var in ["delay", "area", "lpower", "denergy"]: + ale = var != "delay" metL = [] modFit = fitDict[module] fits = modFit[ale] @@ -311,12 +424,12 @@ def makeCoefTable(): metric = getVals(spec.tech, module, var, freq=freq) techdict = spec._asdict() norm = techdict[var] - metL += [m/norm for m in metric] + metL += [m / norm for m in metric] - 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) - coefsToWrite = [None]*5 - fitTerms = 'clsgn' + coefsToWrite = [None] * 5 + fitTerms = "clsgn" ind = 0 for i in range(len(fitTerms)): if fitTerms[i] in fits: @@ -327,25 +440,38 @@ def makeCoefTable(): file.close() + 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(): - ''' writes CSV with each line containing the equations for fits for each metric - to a particular module (including both techs, normalized) - ''' + """writes CSV with each line containing the equations for fits for each metric + to a particular module (including both techs, normalized) + """ file = open("ppaEquations.csv", "w") 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: eqs = [] for freq in [None, 10]: - for var in ['delay', 'area', 'lpower', 'denergy']: - if (var == 'delay') and (freq == 10): + for var in ["delay", "area", "lpower", "denergy"]: + if (var == "delay") and (freq == 10): pass else: - ale = (var != 'delay') + ale = var != "delay" metL = [] modFit = fitDict[module] fits = modFit[ale] @@ -354,9 +480,9 @@ def makeEqTable(): metric = getVals(spec.tech, module, var, freq=freq) techdict = spec._asdict() norm = techdict[var] - metL += [m/norm for m in metric] + metL += [m / norm for m in metric] - 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) eqs += [genLegend(fits, coefs, ale=ale)] row = [module] + eqs @@ -364,93 +490,113 @@ def makeEqTable(): file.close() -def genFuncs(fits='clsgn'): - ''' helper function for regress() - returns array of functions with one for each term desired in the regression fit - ''' + +def genFuncs(fits="clsgn"): + """helper function for regress() + returns array of functions with one for each term desired in the regression fit + """ funcArr = [] - if 'c' in fits: + if "c" in fits: funcArr += [lambda x: 1] - if 'l' in fits: + if "l" in fits: funcArr += [lambda x: x] - if 's' in fits: + if "s" in fits: funcArr += [lambda x: x**2] - if 'g' in fits: + if "g" in fits: funcArr += [lambda x: np.log2(x)] - if 'n' in fits: - funcArr += [lambda x: x*np.log2(x)] + if "n" in fits: + funcArr += [lambda x: x * np.log2(x)] return funcArr + def noOutliers(median, freqs, delays, 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 - helper function to freqPlot() - ''' - f=[] - d=[] - a=[] + """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 + helper function to freqPlot() + """ + f = [] + d = [] + a = [] for i in range(len(freqs)): - norm = freqs[i]/median - if (norm > 0.4) & (norm<1.4): + norm = freqs[i] / median + if (norm > 0.4) & (norm < 1.4): f += [freqs[i]] d += [delays[i]] a += [areas[i]] - + return f, d, a + 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)) for oneSynth in allSynths: - if (mod == oneSynth.module) & (width == oneSynth.width) & (tech == oneSynth.tech): - ind = (1000/oneSynth.delay < oneSynth.freq) # when delay is within target clock period + if ( + (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] delaysL[ind] += [oneSynth.delay] areasL[ind] += [oneSynth.area] median = np.median(list(flatten(freqsL))) - + f, (ax1, ax2) = plt.subplots(2, 1, sharex=True) 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] delays = delaysL[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) ax2.scatter(freqs, areas, color=c) - legend_elements = [lines.Line2D([0], [0], color='green', ls='', marker='o', label='timing achieved'), - lines.Line2D([0], [0], color='blue', ls='', marker='o', label='slack violated')] + legend_elements = [ + 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) width = str(width) - + ax2.set_xlabel("Target Freq (MHz)") - ax1.set_ylabel('Delay (ns)') - ax2.set_ylabel('Area (sq microns)') - ax1.set_title(mod + '_' + width) - if ('mux' in mod) & ('d' in mod): + ax1.set_ylabel("Delay (ns)") + ax2.set_ylabel("Area (sq microns)") + ax1.set_title(mod + "_" + width) + if ("mux" in mod) & ("d" in mod): width = mod - mod = 'muxd' - plt.savefig('./plots/freqBuckshot/' + tech + '/' + mod + '/' + width + '.png') + mod = "muxd" + plt.savefig("./plots/freqBuckshot/" + tech + "/" + mod + "/" + width + ".png") # plt.show() + 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 freqsL, delaysL, areasL = ([[], []] for i in range(3)) for oneSynth in allSynths: - if (mod == oneSynth.module) & (width == oneSynth.width) & (tech == oneSynth.tech): - ind = (1000/oneSynth.delay < oneSynth.freq) # when delay is within target clock period + if ( + (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] delaysL[ind] += [oneSynth.delay] areasL[ind] += [oneSynth.area] @@ -458,182 +604,212 @@ def squareAreaDelay(tech, mod, width): f, (ax1) = plt.subplots(1, 1) ax2 = ax1.twinx() - for ind in [0,1]: + for ind in [0, 1]: areas = areasL[ind] delays = delaysL[ind] targets = freqsL[ind] - targets = [1000/f for f in targets] - - targets, delays, areas = noOutliers(targets, delays, areas) # comment out to see all - + targets = [1000 / f for f in targets] + + targets, delays, areas = noOutliers( + targets, delays, areas + ) # comment out to see all + if not ind: achievedDelays = delays - c = 'blue' if ind else 'green' - ax1.scatter(targets, delays, marker='^', color=c) - ax2.scatter(targets, areas, marker='s', color=c) - - bestAchieved = min(achievedDelays) - - legend_elements = [lines.Line2D([0], [0], color='green', ls='', marker='^', label='delay (timing achieved)'), - 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)')] + c = "blue" if ind else "green" + ax1.scatter(targets, delays, marker="^", color=c) + ax2.scatter(targets, areas, marker="s", color=c) + + bestAchieved = min(achievedDelays) + + legend_elements = [ + lines.Line2D( + [0], [0], color="green", ls="", marker="^", label="delay (timing achieved)" + ), + 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_ylabel("Delay Achieved (ns)") - ax2.set_ylabel('Area (sq microns)') - ax1.set_title(mod + '_' + str(width)) + ax2.set_ylabel("Area (sq microns)") + ax1.set_title(mod + "_" + str(width)) squarify(f) xvals = np.array(ax1.get_xlim()) - frac = (min(flatten(delaysL))-xvals[0])/(xvals[1]-xvals[0]) - areaLowerLim = min(flatten(areasL))-100 - areaUpperLim = max(flatten(areasL))/frac + areaLowerLim + frac = (min(flatten(delaysL)) - xvals[0]) / (xvals[1] - xvals[0]) + areaLowerLim = min(flatten(areasL)) - 100 + areaUpperLim = max(flatten(areasL)) / frac + areaLowerLim ax2.set_ylim([areaLowerLim, areaUpperLim]) 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() + def squarify(fig): - ''' helper function for squareAreaDelay() - forces matplotlib figure to be a square - ''' + """helper function for squareAreaDelay() + forces matplotlib figure to be a square + """ w, h = fig.get_size_inches() if w > h: t = fig.subplotpars.top b = fig.subplotpars.bottom - axs = h*(t-b) - l = (1.-axs/w)/2 - fig.subplots_adjust(left=l, right=1-l) + axs = h * (t - b) + l = (1.0 - axs / w) / 2 + fig.subplots_adjust(left=l, right=1 - l) else: t = fig.subplotpars.right b = fig.subplotpars.left - axs = w*(t-b) - l = (1.-axs/h)/2 - fig.subplots_adjust(bottom=l, top=1-l) + axs = w * (t - b) + l = (1.0 - axs / h) / 2 + 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 - if no freq specified, uses the synthesis with best achievable delay for each width - overlays data from both techs - ''' - with mpl.rc_context({"figure.figsize": (7,3.46)}): + +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 + overlays data from both techs + """ + with mpl.rc_context({"figure.figsize": (7, 3.46)}): fig, axs = plt.subplots(2, 2) - arr = [['delay', 'area'], ['lpower', 'denergy']] + arr = [["delay", "area"], ["lpower", "denergy"]] freqs = [freq] - if aleOpt: freqs += [10] + if aleOpt: + freqs += [10] for i in [0, 1]: for j in [0, 1]: leg = [] for f in freqs: - if (arr[i][j]=='delay') and (f==10): + if (arr[i][j] == "delay") and (f == 10): pass else: - r2 = oneMetricPlot(mod, widths, arr[i][j], ax=axs[i, j], freq=f, norm=norm) - ls = '--' if f else '-' - leg += [lines.Line2D([0], [0], color='red', label='$R^2$='+str(round(r2, 4)), linestyle=ls)] + # print(f"Pasing in widths {widths}") + r2 = oneMetricPlot( + 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) 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) else: axs[i, j].legend(handles=leg, handlelength=1.5) - - titleStr = " (target " + str(freq)+ "MHz)" if freq != None else "" - plt.suptitle(mod + titleStr) - plt.tight_layout(pad=0.05, w_pad=1, h_pad=0.5, rect=(0,0,1,0.97)) - if freq != 10: - n = 'normalized' if norm else 'unnormalized' - saveStr = './plots/'+ n + '/' + mod + '.png' + titleStr = " (target " + str(freq) + "MHz)" if freq != None else "" + plt.suptitle(mod + titleStr) + plt.tight_layout(pad=0.05, w_pad=1, h_pad=0.5, rect=(0, 0, 1, 0.97)) + + if freq != 10: + n = "normalized" if norm else "unnormalized" + saveStr = "./plots/" + n + "/" + mod + "_" + ".png" + print(f"Saving to {saveStr}") plt.savefig(saveStr) # plt.show() + def makeLineLegend(): - ''' generates legend to accompany normalized plots - ''' - plt.rcParams["figure.figsize"] = (5.5,0.3) + """generates legend to accompany normalized plots""" + plt.rcParams["figure.figsize"] = (5.5, 0.3) fig = plt.figure() - 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='blue', label='tsmc28', marker='^')] - 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='sky130', marker='+')] - fullLeg += [lines.Line2D([0], [0], color='red', label='combined', marker='_')] - fig.legend(handles=fullLeg, ncol=5, handlelength=1.4, loc='center') - saveStr = './plots/legend.png' + 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="blue", label="tsmc28", marker="^")] + 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="purple", label="sky130", marker="+")] + fullLeg += [lines.Line2D([0], [0], color="orange", label="combined", marker="_")] + fig.legend(handles=fullLeg, ncol=5, handlelength=1.4, loc="center") + saveStr = "./plots/legend.png" plt.savefig(saveStr) -def muxPlot(fits='clsgn', norm=True): - ''' module: string module name - freq: int freq (MHz) - var: string delay, area, lpower, or denergy - fits: constant, linear, square, log2, Nlog2 - plots given variable vs width for all matching syntheses with regression - ''' + +def muxPlot(fits="clsgn", norm=True): + """module: string module name + freq: int freq (MHz) + var: string delay, area, lpower, or denergy + fits: constant, linear, square, log2, Nlog2 + plots given variable vs width for all matching syntheses with regression + """ ax = plt.gca() inputs = [2, 4, 8] - allInputs = inputs*2 + allInputs = inputs * 2 fullLeg = [] - for crit in ['data', 'control']: + for crit in ["data", "control"]: allMetrics = [] - muxes = ['mux2', 'mux4', 'mux8'] + muxes = ["mux2", "mux4", "mux8"] - if crit == 'data': - ls = '--' - muxes = [m + 'd' for m in muxes] - elif crit == 'control': - ls = '-' + if crit == "data": + ls = "--" + muxes = [m + "d" for m in muxes] + elif crit == "control": + ls = "-" for spec in techSpecs: metric = [] for module in muxes: - metric += getVals(spec.tech, module, 'delay', width=[1]) - + metric += getVals(spec.tech, module, "delay", width=[1]) + if norm: techdict = spec._asdict() - norm = techdict['delay'] - metric = [m/norm for m in metric] + norm = techdict["delay"] + metric = [m / norm for m in 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) ax.scatter(inputs, metric, color=spec.color, marker=spec.shape) ax.plot(xp, pred, color=spec.color, linestyle=ls) allMetrics += metric xp, pred, coefs, r2 = regress(allInputs, allMetrics, fits) - ax.plot(xp, pred, color='red', linestyle=ls) - fullLeg += [lines.Line2D([0], [0], color='red', label=crit, linestyle=ls)] - - ax.set_ylabel('Delay (FO4)') + ax.plot(xp, pred, color="orange", linestyle=ls) + fullLeg += [lines.Line2D([0], [0], color="orange", label=crit, linestyle=ls)] + + ax.set_ylabel("Delay (FO4)") ax.set_xticks(inputs) ax.set_xlabel("Number of inputs") - ax.set_title('mux timing') - - ax.legend(handles = fullLeg) - plt.savefig('./plots/mux.png') + ax.set_title("mux timing") + + ax.legend(handles=fullLeg) + plt.savefig("./plots/mux.png") + def stdDevError(): - ''' calculates std deviation and error for paper-writing purposes - ''' - for var in ['delay', 'area', 'lpower', 'denergy']: + """calculates std deviation and error for paper-writing purposes""" + for var in ["delay", "area", "lpower", "denergy"]: errlist = [] for module in modules: - ale = (var != 'delay') + ale = var != "delay" metL = [] modFit = fitDict[module] fits = modFit[ale] @@ -643,20 +819,20 @@ def stdDevError(): metric = getVals(spec.tech, module, var) techdict = spec._asdict() norm = techdict[var] - metL += [m/norm for m in metric] + metL += [m / norm for m in metric] if ale: - ws = [w/normAddWidth for w in widths] + ws = [w / normAddWidth for w in widths] else: ws = widths - ws = ws*2 + ws = ws * 2 mat = [] for w in ws: row = [] for func in funcArr: row += [func(w)] mat += [row] - + y = np.array(metL, dtype=np.float) coefs = opt.nnls(mat, y)[0] @@ -665,68 +841,84 @@ def stdDevError(): n = [func(w) for func in funcArr] yp += [sum(np.multiply(coefs, n))] - if (var == 'delay') & (module == 'flop'): + if (var == "delay") & (module == "flop"): pass - elif (module == 'mult') & ale: + elif (module == "mult") & ale: pass else: for i in range(len(y)): - errlist += [abs(y[i]/yp[i]-1)] + errlist += [abs(y[i] / yp[i] - 1)] # print(module, ' ', var, ' ', np.mean(errlist[-10:])) - + avgErr = np.mean(errlist) stdv = np.std(errlist) - print(var, ' ', avgErr, ' ', stdv) + print(var, " ", avgErr, " ", stdv) + 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() - final_directory = os.path.join(current_directory, 'plots') + final_directory = os.path.join(current_directory, "plots") if not os.path.exists(final_directory): os.makedirs(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) if not os.path.exists(new_directory): os.makedirs(new_directory) os.chdir(new_directory) - if 'freq' in folder: - for tech in ['sky90', 'sky130', 'tsmc28', 'tsmc28psyn']: + if "freq" in folder: + for tech in ["sky90", "sky130", "tsmc28", "tsmc28psyn"]: for mod in modules: tech_directory = os.path.join(new_directory, tech) mod_directory = os.path.join(tech_directory, mod) if not os.path.exists(mod_directory): os.makedirs(mod_directory) - os.chdir('..') - + os.chdir("..") + os.chdir(current_directory) - -if __name__ == '__main__': + + +if __name__ == "__main__": ############################## # set up stuff, global variables - widths = [64, 128] - modules = ['adder', 'comparator'] + widths = [8, 16, 32, 64, 128] + modules = ["adder", "comparator"] - 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.update(dict.fromkeys(['mux2', 'mux4', 'mux8'], ['cg', 'l', 'l'])) + 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.update(dict.fromkeys(["mux2", "mux4", "mux8"], ["cg", "l", "l"])) - 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]] - techSpecs = [TechSpec(*t) for t in techSpecs] - combined = TechSpec('combined fit', 'red', '_', 0, 0, 0, 0) + TechSpec = namedtuple("TechSpec", "tech color shape delay area lpower denergy") + # 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] + combined = TechSpec("combined fit", "orange", "_", 0, 0, 0, 0) ############################## # cleanup() # run to remove garbage synth runs - synthsintocsv() # slow, run only when new synth runs to add to csv - - allSynths = synthsfromcsv('ppaData.csv') # your csv here! - bestSynths = csvOfBest('bestSynths.csv') - makePlotDirectory() + synthsintocsv() # slow, run only when new synth runs to add to csv + + allSynths = synthsfromcsv("ppaData.csv") # your csv here! + bestSynths = csvOfBest("bestSynths.csv") + makePlotDirectory() # ### other functions # makeCoefTable() @@ -734,12 +926,12 @@ if __name__ == '__main__': # muxPlot() # stdDevError() - for mod in modules: - for w in widths: - #freqPlot('sky90', mod, w) - freqPlot('sky130', mod, w) - #freqPlot('tsmc28', mod, w) - #freqPlot('tsmc28psyn', mod, w) - #plotPPA(mod, widths, norm=False) - #plotPPA(mod, aleOpt=True) - plt.close('all') + for mod in modules: + for w in widths: + # freqPlot('sky90', mod, w) + # freqPlot("sky130", mod, w) + # freqPlot('tsmc28', mod, w) + # freqPlot('tsmc28psyn', mod, w) + plotPPA(mod, norm=False) + # plotPPA(mod, aleOpt=True) + plt.close("all") From 9dce08a743060ceae695a544f9e7b038041a33e5 Mon Sep 17 00:00:00 2001 From: "James E. Stine" Date: Tue, 14 Nov 2023 02:41:44 -0600 Subject: [PATCH 3/3] minor typo on ppaSynth and ppaAnalyze --- synthDC/ppa/ppaAnalyze.py | 31 ++++++++++++++----------------- synthDC/ppa/ppaSynth.py | 2 +- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/synthDC/ppa/ppaAnalyze.py b/synthDC/ppa/ppaAnalyze.py index 9af15fd80..bd98e79be 100755 --- a/synthDC/ppa/ppaAnalyze.py +++ b/synthDC/ppa/ppaAnalyze.py @@ -82,11 +82,9 @@ def synthsintocsv(): delay = 1000 / int(freq) - metrics[0] area = metrics[1] lpower = metrics[4] - # switching, internal power in mW and leakage in nW - tpower = metrics[2] + metrics[3] + metrics[4]*0.000001 - # EDP (fJ/GHz) + tpower = (metrics[2] + metrics[3] + metrics[4]*.000001) denergy = ( - (metrics[2] + metrics[3] + metrics[4]*0.000001) / int(freq) + (tpower) / int(freq) * 1000 ) # (switching + internal powers)*delay, more practical units for regression coefs if "flop" in module: # since two flops in each module @@ -304,7 +302,6 @@ def oneMetricPlot( allMetrics += metric # print(f"Widths passed into regress : {allWidths}") - # Not sure why this works (jes) - if allWidths doesn't have data widths does if len(allWidths) > 0: xp, pred, coefs, r2 = regress(allWidths, allMetrics, fits) ax.plot(xp, pred, color="orange", linestyle=ls) @@ -322,7 +319,7 @@ def oneMetricPlot( else: ylabeldic = { "lpower": "Leakage Power (nW)", - "denergy": "EDP (fJ/GHz)", + "denergy": "Dynamic Energy (nJ)", "area": "Area (sq microns)", "delay": "Delay (ns)", } @@ -355,9 +352,9 @@ def regress(widths, var, fits="clsgn", ale=False): 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" - ) + # 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) @@ -792,8 +789,8 @@ def muxPlot(fits="clsgn", norm=True): allMetrics += metric xp, pred, coefs, r2 = regress(allInputs, allMetrics, fits) - ax.plot(xp, pred, color="orange", linestyle=ls) - fullLeg += [lines.Line2D([0], [0], color="orange", label=crit, linestyle=ls)] + ax.plot(xp, pred, color="red", linestyle=ls) + fullLeg += [lines.Line2D([0], [0], color="red", label=crit, linestyle=ls)] ax.set_ylabel("Delay (FO4)") ax.set_xticks(inputs) @@ -885,7 +882,7 @@ if __name__ == "__main__": ############################## # set up stuff, global variables widths = [8, 16, 32, 64, 128] - modules = ["adder", "comparator"] + modules = ["adder"] normAddWidth = 32 # divisor to use with N since normalizing to add_32 @@ -903,14 +900,14 @@ if __name__ == "__main__": TechSpec = namedtuple("TechSpec", "tech color shape delay area lpower denergy") # FO4 delay information information techSpecs = [ - # ["sky90", "green", "o", 43.2e-3, 1440.600027, 714.057, 0.658022690438], + #["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] - combined = TechSpec("combined fit", "orange", "_", 0, 0, 0, 0) + combined = TechSpec("combined fit", "red", "_", 0, 0, 0, 0) ############################## # cleanup() # run to remove garbage synth runs @@ -928,10 +925,10 @@ if __name__ == "__main__": for mod in modules: for w in widths: - # freqPlot('sky90', mod, w) - # freqPlot("sky130", mod, w) + #freqPlot('sky90', mod, w) + freqPlot("sky130", mod, w) # freqPlot('tsmc28', mod, w) # freqPlot('tsmc28psyn', mod, w) plotPPA(mod, norm=False) - # plotPPA(mod, aleOpt=True) + plotPPA(mod, aleOpt=True) plt.close("all") diff --git a/synthDC/ppa/ppaSynth.py b/synthDC/ppa/ppaSynth.py index 07a342e26..30fe1254f 100755 --- a/synthDC/ppa/ppaSynth.py +++ b/synthDC/ppa/ppaSynth.py @@ -84,7 +84,7 @@ if __name__ == '__main__': synthsToRun = freqSweep(module, width, tech) ##### Run a sweep for multiple modules/widths based on best delay found in existing syntheses - modules = ['adder', "comparator"] + modules = ['adder'] widths = [8, 16, 32, 64, 128] tech = 'sky130' synthsToRun = freqModuleSweep(widths, modules, tech)