ppaAnalyze: docstrings and tsmc28 plotting

This commit is contained in:
Madeleine Masser-Frye 2022-05-25 13:52:20 +00:00
parent dd4997bd1b
commit 81a869c921
3 changed files with 180 additions and 142 deletions

View File

@ -276,51 +276,6 @@ module ppa_shiftleft_128 #(parameter WIDTH=128) (
assign y = a << amt; assign y = a << amt;
endmodule endmodule
module ppa_shifter_8 #(parameter WIDTH=8) (
input logic [WIDTH-1:0] A,
input logic [$clog2(WIDTH)-1:0] Amt,
input logic Right, Arith, W64,
output logic [WIDTH-1:0] Y);
ppa_shifter #(WIDTH) sh (.*);
endmodule
module ppa_shifter_16 #(parameter WIDTH=16) (
input logic [WIDTH-1:0] A,
input logic [$clog2(WIDTH)-1:0] Amt,
input logic Right, Arith, W64,
output logic [WIDTH-1:0] Y);
ppa_shifter #(WIDTH) sh (.*);
endmodule
module ppa_shifter_32 #(parameter WIDTH=32) (
input logic [WIDTH-1:0] A,
input logic [$clog2(WIDTH)-1:0] Amt,
input logic Right, Arith, W64,
output logic [WIDTH-1:0] Y);
ppa_shifter #(WIDTH) sh (.*);
endmodule
module ppa_shifter_64 #(parameter WIDTH=64) (
input logic [WIDTH-1:0] A,
input logic [$clog2(WIDTH)-1:0] Amt,
input logic Right, Arith, W64,
output logic [WIDTH-1:0] Y);
ppa_shifter #(WIDTH) sh (.*);
endmodule
module ppa_shifter_128 #(parameter WIDTH=128) (
input logic [WIDTH-1:0] A,
input logic [$clog2(WIDTH)-1:0] Amt,
input logic Right, Arith, W64,
output logic [WIDTH-1:0] Y);
ppa_shifter #(WIDTH) sh (.*);
endmodule
module ppa_shifter #(parameter WIDTH=32) ( module ppa_shifter #(parameter WIDTH=32) (
input logic [WIDTH-1:0] A, input logic [WIDTH-1:0] A,
input logic [$clog2(WIDTH)-1:0] Amt, input logic [$clog2(WIDTH)-1:0] Amt,
@ -373,7 +328,51 @@ module ppa_shifter #(parameter WIDTH=32) (
assign Y = zshift[WIDTH-1:0]; assign Y = zshift[WIDTH-1:0];
endmodule endmodule
// just report one hot // module ppa_shifter_8 #(parameter WIDTH=8) (
// input logic [WIDTH-1:0] A,
// input logic [$clog2(WIDTH)-1:0] Amt,
// input logic Right, Arith, W64,
// output logic [WIDTH-1:0] Y);
// ppa_shifter #(WIDTH) sh (.*);
// endmodule
// module ppa_shifter_16 #(parameter WIDTH=16) (
// input logic [WIDTH-1:0] A,
// input logic [$clog2(WIDTH)-1:0] Amt,
// input logic Right, Arith, W64,
// output logic [WIDTH-1:0] Y);
// ppa_shifter #(WIDTH) sh (.*);
// endmodule
// module ppa_shifter_32 #(parameter WIDTH=32) (
// input logic [WIDTH-1:0] A,
// input logic [$clog2(WIDTH)-1:0] Amt,
// input logic Right, Arith, W64,
// output logic [WIDTH-1:0] Y);
// ppa_shifter #(WIDTH) sh (.*);
// endmodule
// module ppa_shifter_64 #(parameter WIDTH=64) (
// input logic [WIDTH-1:0] A,
// input logic [$clog2(WIDTH)-1:0] Amt,
// input logic Right, Arith, W64,
// output logic [WIDTH-1:0] Y);
// ppa_shifter #(WIDTH) sh (.*);
// endmodule
// module ppa_shifter_128 #(parameter WIDTH=128) (
// input logic [WIDTH-1:0] A,
// input logic [$clog2(WIDTH)-1:0] Amt,
// input logic Right, Arith, W64,
// output logic [WIDTH-1:0] Y);
// ppa_shifter #(WIDTH) sh (.*);
// endmodule
module ppa_prioritythermometer #(parameter N = 8) ( module ppa_prioritythermometer #(parameter N = 8) (
input logic [N-1:0] a, input logic [N-1:0] a,
output logic [N-1:0] y); output logic [N-1:0] y);

View File

@ -2,6 +2,7 @@
# Madeleine Masser-Frye mmasserfrye@hmc.edu 5/22 # Madeleine Masser-Frye mmasserfrye@hmc.edu 5/22
from distutils.log import error from distutils.log import error
from operator import index
from statistics import median from statistics import median
import subprocess import subprocess
import statistics import statistics
@ -12,13 +13,16 @@ import matplotlib.lines as lines
import numpy as np import numpy as np
def getData(mod=None, width=None): def getData(tech, mod=None, width=None):
''' returns a list of lists
each list contains results of one synthesis that matches the input specs
'''
specStr = '' specStr = ''
if mod != None: if mod != None:
specStr = mod specStr = mod
if width != None: if width != None:
specStr += ('_'+str(width)) specStr += ('_'+str(width))
specStr += '*' specStr += '*{}*'.format(tech)
bashCommand = "grep 'Critical Path Length' runs/ppa_{}/reports/*qor*".format(specStr) bashCommand = "grep 'Critical Path Length' runs/ppa_{}/reports/*qor*".format(specStr)
outputCPL = subprocess.check_output(['bash','-c', bashCommand]) outputCPL = subprocess.check_output(['bash','-c', bashCommand])
@ -57,8 +61,13 @@ def getData(mod=None, width=None):
return allSynths return allSynths
def getVals(module, var, freq=None): def getVals(tech, module, var, freq=None):
allSynths = getData(mod=module) ''' for a specified tech, module, and variable/metric
returns a list of widths and the corresponding values for that metric with the appropriate units
works at a specified target frequency or if none is given, uses the synthesis with the min delay for each width
'''
allSynths = getData(tech, mod=module)
if (var == 'delay'): if (var == 'delay'):
ind = 3 ind = 3
@ -96,10 +105,14 @@ def getVals(module, var, freq=None):
if ('flop' in module) & (var == 'area'): if ('flop' in module) & (var == 'area'):
metric = [m/2 for m in metric] # since two flops in each module metric = [m/2 for m in metric] # since two flops in each module
return widths, metric, units return widths, metric, units
def writeCSV(): def writeCSV(tech):
allSynths = getData() ''' writes a CSV with one line for every available synthesis for a specified tech
each line contains the module, width, target freq, and resulting metrics
'''
allSynths = getData(tech)
file = open("ppaData.csv", "w") file = open("ppaData.csv", "w")
writer = csv.writer(file) writer = csv.writer(file)
writer.writerow(['Module', 'Width', 'Target Freq', 'Delay', 'Area', 'L Power (nW)', 'D energy (mJ)']) writer.writerow(['Module', 'Width', 'Target Freq', 'Delay', 'Area', 'L Power (nW)', 'D energy (mJ)'])
@ -109,7 +122,10 @@ def writeCSV():
file.close() file.close()
def genLegend(fits, coefs, module, r2): def genLegend(fits, coefs, r2, tech):
''' generates a list of two legend elements
labels line with fit equation and dots with tech and r squared of the fit
'''
coefsr = [str(round(c, 3)) for c in coefs] coefsr = [str(round(c, 3)) for c in coefs]
@ -131,26 +147,18 @@ def genLegend(fits, coefs, module, r2):
eq += " + " + coefsr[ind] + "*Nlog2(N)" eq += " + " + coefsr[ind] + "*Nlog2(N)"
ind += 1 ind += 1
legend_elements = [lines.Line2D([0], [0], color='orange', label=eq), c = 'blue' if (tech == 'sky90') else 'green'
lines.Line2D([0], [0], color='steelblue', ls='', marker='o', label=' R^2='+ str(round(r2, 4)))] legend_elements = [lines.Line2D([0], [0], color=c, label=eq),
lines.Line2D([0], [0], color=c, ls='', marker='o', label=tech +' $R^2$='+ str(round(r2, 4)))]
return legend_elements return legend_elements
def oneMetricPlot(module, var, freq=None, ax=None, fits='clsgn'): def oneMetricPlot(module, var, freq=None, ax=None, fits='clsgn'):
''' 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
''' '''
module: string module name
freq: int freq (MHz)
var: string delay, area, lpower, or denergy
fits: constant, linear, square, log2, Nlog2
plots chosen variable vs width for all matching syntheses with regression
'''
widths, metric, units = getVals(module, var, freq=freq)
coefs, r2, funcArr = regress(widths, metric, fits)
xp = np.linspace(8, 140, 200)
pred = []
for x in xp:
y = [func(x) for func in funcArr]
pred += [sum(np.multiply(coefs, y))]
if ax is None: if ax is None:
singlePlot = True singlePlot = True
@ -158,11 +166,17 @@ def oneMetricPlot(module, var, freq=None, ax=None, fits='clsgn'):
else: else:
singlePlot = False singlePlot = False
ax.scatter(widths, metric) fullLeg = []
ax.plot(xp, pred, color='orange') for tech in ['sky90', 'tsmc28']:
c = 'blue' if (tech == 'sky90') else 'green'
widths, metric, units = getVals(tech, module, var, freq=freq)
xp, pred, leg = regress(widths, metric, tech, fits)
fullLeg += leg
legend_elements = genLegend(fits, coefs, module, r2) ax.scatter(widths, metric, color=c)
ax.legend(handles=legend_elements) ax.plot(xp, pred, color=c)
ax.legend(handles=fullLeg)
ax.set_xticks(widths) ax.set_xticks(widths)
ax.set_xlabel("Width (bits)") ax.set_xlabel("Width (bits)")
@ -172,7 +186,10 @@ def oneMetricPlot(module, var, freq=None, ax=None, fits='clsgn'):
ax.set_title(module + " (target " + str(freq) + "MHz)") ax.set_title(module + " (target " + str(freq) + "MHz)")
plt.show() plt.show()
def regress(widths, var, fits='clsgn'): def regress(widths, var, tech, fits='clsgn'):
''' fits a curve to the given points
returns lists of x and y values to plot that curve and legend elements with the equation
'''
funcArr = genFuncs(fits) funcArr = genFuncs(fits)
@ -191,9 +208,21 @@ def regress(widths, var, fits='clsgn'):
except: except:
resid = 0 resid = 0
r2 = 1 - resid / (y.size * y.var()) r2 = 1 - resid / (y.size * y.var())
return coefs, r2, funcArr
def makeCoefTable(): xp = np.linspace(8, 140, 200)
pred = []
for x in xp:
n = [func(x) for func in funcArr]
pred += [sum(np.multiply(coefs, n))]
leg = genLegend(fits, coefs, r2, tech)
return xp, pred, leg
def makeCoefTable(tech):
''' writes CSV with each line containing the coefficients for a regression fit
to a particular combination of module, metric, and target frequency
'''
file = open("ppaFitting.csv", "w") file = open("ppaFitting.csv", "w")
writer = csv.writer(file) writer = csv.writer(file)
writer.writerow(['Module', 'Metric', 'Freq', '1', 'N', 'N^2', 'log2(N)', 'Nlog2(N)', 'R^2']) writer.writerow(['Module', 'Metric', 'Freq', '1', 'N', 'N^2', 'log2(N)', 'Nlog2(N)', 'R^2'])
@ -202,7 +231,7 @@ def makeCoefTable():
for comb in [['delay', 5000], ['area', 5000], ['area', 10]]: for comb in [['delay', 5000], ['area', 5000], ['area', 10]]:
var = comb[0] var = comb[0]
freq = comb[1] freq = comb[1]
widths, metric, units = getVals(mod, freq, var) widths, metric, units = getVals(tech, mod, freq, var)
coefs, r2, funcArr = regress(widths, metric) coefs, r2, funcArr = regress(widths, metric)
row = [mod] + comb + np.ndarray.tolist(coefs) + [r2] row = [mod] + comb + np.ndarray.tolist(coefs) + [r2]
writer.writerow(row) writer.writerow(row)
@ -210,6 +239,9 @@ def makeCoefTable():
file.close() file.close()
def genFuncs(fits='clsgn'): def genFuncs(fits='clsgn'):
''' helper function for regress()
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]
@ -224,11 +256,17 @@ def genFuncs(fits='clsgn'):
return funcArr return funcArr
def noOutliers(freqs, delays, areas): def noOutliers(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=[] f=[]
d=[] d=[]
a=[] a=[]
try: try:
med = statistics.median(freqs) ind = delays.index(min(delays))
med = freqs[ind]
for i in range(len(freqs)): for i in range(len(freqs)):
norm = freqs[i]/med norm = freqs[i]/med
if (norm > 0.25) & (norm<1.75): if (norm > 0.25) & (norm<1.75):
@ -239,65 +277,67 @@ def noOutliers(freqs, delays, areas):
return f, d, a return f, d, a
def freqPlot(mod, width): def freqPlot(tech, mod, width):
allSynths = getData(mod=mod, width=width) ''' plots delay, area, area*delay, and area*delay^2 for syntheses with specified tech, module, width
'''
allSynths = getData(tech, mod=mod, width=width)
freqsV, delaysV, areasV, freqsA, delaysA, areasA = ([] for i in range(6)) freqsL, delaysL, areasL = ([[], []] for i in range(3))
for oneSynth in allSynths: for oneSynth in allSynths:
if (mod == oneSynth[0]) & (width == oneSynth[1]): if (mod == oneSynth[0]) & (width == oneSynth[1]):
if (1000/oneSynth[3] < oneSynth[2]): ind = (1000/oneSynth[3] < oneSynth[2]) # when delay is within target clock period
freqsV += [oneSynth[2]] freqsL[ind] += [oneSynth[2]]
delaysV += [oneSynth[3]] delaysL[ind] += [oneSynth[3]]
areasV += [oneSynth[4]] areasL[ind] += [oneSynth[4]]
else:
freqsA += [oneSynth[2]]
delaysA += [oneSynth[3]]
areasA += [oneSynth[4]]
if ('flop' in mod): # since two flops in each module f, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, 1, sharex=True)
areasA = [m/2 for m in areasA]
areasV = [m/2 for m in areasV]
freqsA, delaysA, areasA = noOutliers(freqsA, delaysA, areasA) for ind in [0,1]:
freqsV, delaysV, areasV = noOutliers(freqsV, delaysV, areasV) areas = areasL[ind]
delays = delaysL[ind]
freqs = freqsL[ind]
adprodA, adprodV = adprodpow(areasA, delaysA, areasV, delaysV, 1) if ('flop' in mod): areas = [m/2 for m in areas] # since two flops in each module
adpowA, adpowV = adprodpow(areasA, delaysA, areasV, delaysV, 2) freqs, delays, areas = noOutliers(freqs, delays, areas)
c = 'blue' if ind else 'green'
adprod = adprodpow(areas, delays, 2)
adpow = adprodpow(areas, delays, 3)
adpow2 = adprodpow(areas, delays, 4)
ax1.scatter(freqs, delays, color=c)
ax2.scatter(freqs, areas, color=c)
ax3.scatter(freqs, adprod, color=c)
ax4.scatter(freqs, adpow, color=c)
ax5.scatter(freqs, adpow2, color=c)
legend_elements = [lines.Line2D([0], [0], color='green', ls='', marker='o', label='timing achieved'), 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')] lines.Line2D([0], [0], color='blue', ls='', marker='o', label='slack violated')]
f, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, sharex=True)
ax1.scatter(freqsA, delaysA, color='green')
ax1.scatter(freqsV, delaysV, color='blue')
ax2.scatter(freqsA, areasA, color='green')
ax2.scatter(freqsV, areasV, color='blue')
ax3.scatter(freqsA, adprodA, color='green')
ax3.scatter(freqsV, adprodV, color='blue')
ax4.scatter(freqsA, adpowA, color='green')
ax4.scatter(freqsV, adpowV, color='blue')
ax1.legend(handles=legend_elements) ax1.legend(handles=legend_elements)
ax4.set_xlabel("Target Freq (MHz)") ax4.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)')
ax3.set_ylabel('Area * Delay') ax3.set_ylabel('Area * Delay')
ax4.set_ylabel('Area * Delay^2') ax4.set_ylabel('Area * $Delay^2$')
ax1.set_title(mod + '_' + str(width)) ax1.set_title(mod + '_' + str(width))
plt.show() plt.show()
def adprodpow(areasA, delaysA, areasV, delaysV, pow): def adprodpow(areas, delays, pow):
resultA = [] ''' for each value in [areas] returns area*delay^pow
resultV = [] helper function for freqPlot'''
result = []
for i in range(len(areasA)): for i in range(len(areas)):
resultA += [(areasA[i])*(delaysA[i])**pow] result += [(areas[i])*(delays[i])**pow]
for i in range(len(areasV)):
resultV += [(areasV[i])*(delaysV[i])**pow]
return resultA, resultV return result
def plotPPA(mod, freq=None): def plotPPA(mod, freq=None):
''' for the module specified, plots width vs delay, area, leakage power, and dynamic energy with fits
if no freq specified, uses the synthesis with min delay for each width
overlays data from both techs
'''
fig, axs = plt.subplots(2, 2) fig, axs = plt.subplots(2, 2)
oneMetricPlot(mod, 'delay', ax=axs[0,0], fits='clg', freq=freq) oneMetricPlot(mod, 'delay', ax=axs[0,0], fits='clg', freq=freq)
oneMetricPlot(mod, 'area', ax=axs[0,1], fits='s', freq=freq) oneMetricPlot(mod, 'area', ax=axs[0,1], fits='s', freq=freq)
@ -308,13 +348,12 @@ def plotPPA(mod, freq=None):
plt.show() plt.show()
# plotPPA('alu')
# writeCSV() # writeCSV()
# look at comparaotro 32 # look at comparaotro 32
# for x in ['add', 'mult', 'comparator']:
# for y in [16, 32, 64, 128]:
# freqPlot(x, y)
freqPlot('flop', 8) # for x in ['add', 'mult', 'comparator', 'alu', 'csa']:
# for y in [8, 16, 32, 64, 128]:
# freqPlot('sky90', x, y)
# plotPPA('alu') freqPlot('sky90', 'mult', 32)

View File

@ -42,34 +42,34 @@ def getData():
return allSynths return allSynths
allSynths = getData() allSynths = getData()
arr = [-40, -20, -8, -6, -4, -2, 0, 2, 4, 6, 8, 10, 14, 20, 40] arr = [-40, -20, -8, -6, -4, -2, 0, 2, 4, 6, 8, 12, 20, 40]
widths = [32, 64] widths = [8, 16, 32, 64, 128]
modules = ['flop', 'flopr'] modules = ['add']
tech = 'sky90' tech = 'tsmc28'
LoT = [] LoT = []
# # # # initial sweep to get estimate of min delay # # # initial sweep to get estimate of min delay
# freqs = ['10000', '15000', '20000'] freqs = [10000, 15000, 20000]
# for module in modules: for module in modules:
# for width in widths: for width in widths:
# for freq in freqs: for freq in freqs:
# LoT += [[module, width, tech, freq]] LoT += [[module, width, tech, freq]]
# thorough sweep based on estimate of min delay
for m in modules: # # thorough sweep based on estimate of min delay
for w in widths: # for m in modules:
delays = [] # for w in widths:
for oneSynth in allSynths: # delays = []
if (oneSynth[0] == m) & (oneSynth[1] == w): # for oneSynth in allSynths:
delays += [oneSynth[3]] # if (oneSynth[0] == m) & (oneSynth[1] == w):
try: f = 1000/min(delays) # delays += [oneSynth[3]]
except: print(m) # try: f = 1000/min(delays)
for freq in [str(round(f+f*x/100)) for x in arr]: # except: print(m)
LoT += [[m, w, tech, freq]] # for freq in [str(round(f+f*x/100)) for x in arr]:
# LoT += [[m, w, tech, freq]]
deleteRedundant(LoT) deleteRedundant(LoT)
pool = Pool() pool = Pool()
pool.starmap(runCommand, LoT) pool.starmap(runCommand, LoT)
pool.close() pool.close()