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;
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) (
input logic [WIDTH-1:0] A,
input logic [$clog2(WIDTH)-1:0] Amt,
@ -373,7 +328,51 @@ module ppa_shifter #(parameter WIDTH=32) (
assign Y = zshift[WIDTH-1:0];
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) (
input logic [N-1:0] a,
output logic [N-1:0] y);

View File

@ -2,6 +2,7 @@
# Madeleine Masser-Frye mmasserfrye@hmc.edu 5/22
from distutils.log import error
from operator import index
from statistics import median
import subprocess
import statistics
@ -12,13 +13,16 @@ import matplotlib.lines as lines
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 = ''
if mod != None:
specStr = mod
if width != None:
specStr += ('_'+str(width))
specStr += '*'
specStr += '*{}*'.format(tech)
bashCommand = "grep 'Critical Path Length' runs/ppa_{}/reports/*qor*".format(specStr)
outputCPL = subprocess.check_output(['bash','-c', bashCommand])
@ -57,8 +61,13 @@ def getData(mod=None, width=None):
return allSynths
def getVals(module, var, freq=None):
allSynths = getData(mod=module)
def getVals(tech, module, var, freq=None):
''' 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'):
ind = 3
@ -96,10 +105,14 @@ def getVals(module, var, freq=None):
if ('flop' in module) & (var == 'area'):
metric = [m/2 for m in metric] # since two flops in each module
return widths, metric, units
def writeCSV():
allSynths = getData()
def writeCSV(tech):
''' 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")
writer = csv.writer(file)
writer.writerow(['Module', 'Width', 'Target Freq', 'Delay', 'Area', 'L Power (nW)', 'D energy (mJ)'])
@ -109,7 +122,10 @@ def writeCSV():
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]
@ -131,26 +147,18 @@ def genLegend(fits, coefs, module, r2):
eq += " + " + coefsr[ind] + "*Nlog2(N)"
ind += 1
legend_elements = [lines.Line2D([0], [0], color='orange', label=eq),
lines.Line2D([0], [0], color='steelblue', ls='', marker='o', label=' R^2='+ str(round(r2, 4)))]
c = 'blue' if (tech == 'sky90') else 'green'
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
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:
singlePlot = True
@ -158,11 +166,17 @@ def oneMetricPlot(module, var, freq=None, ax=None, fits='clsgn'):
else:
singlePlot = False
ax.scatter(widths, metric)
ax.plot(xp, pred, color='orange')
fullLeg = []
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.legend(handles=legend_elements)
ax.scatter(widths, metric, color=c)
ax.plot(xp, pred, color=c)
ax.legend(handles=fullLeg)
ax.set_xticks(widths)
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)")
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)
@ -191,9 +208,21 @@ def regress(widths, var, fits='clsgn'):
except:
resid = 0
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")
writer = csv.writer(file)
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]]:
var = comb[0]
freq = comb[1]
widths, metric, units = getVals(mod, freq, var)
widths, metric, units = getVals(tech, mod, freq, var)
coefs, r2, funcArr = regress(widths, metric)
row = [mod] + comb + np.ndarray.tolist(coefs) + [r2]
writer.writerow(row)
@ -210,6 +239,9 @@ def makeCoefTable():
file.close()
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:
funcArr += [lambda x: 1]
@ -224,11 +256,17 @@ def genFuncs(fits='clsgn'):
return funcArr
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=[]
d=[]
a=[]
try:
med = statistics.median(freqs)
ind = delays.index(min(delays))
med = freqs[ind]
for i in range(len(freqs)):
norm = freqs[i]/med
if (norm > 0.25) & (norm<1.75):
@ -239,65 +277,67 @@ def noOutliers(freqs, delays, areas):
return f, d, a
def freqPlot(mod, width):
allSynths = getData(mod=mod, width=width)
def freqPlot(tech, mod, 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:
if (mod == oneSynth[0]) & (width == oneSynth[1]):
if (1000/oneSynth[3] < oneSynth[2]):
freqsV += [oneSynth[2]]
delaysV += [oneSynth[3]]
areasV += [oneSynth[4]]
else:
freqsA += [oneSynth[2]]
delaysA += [oneSynth[3]]
areasA += [oneSynth[4]]
ind = (1000/oneSynth[3] < oneSynth[2]) # when delay is within target clock period
freqsL[ind] += [oneSynth[2]]
delaysL[ind] += [oneSynth[3]]
areasL[ind] += [oneSynth[4]]
if ('flop' in mod): # since two flops in each module
areasA = [m/2 for m in areasA]
areasV = [m/2 for m in areasV]
f, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, 1, sharex=True)
freqsA, delaysA, areasA = noOutliers(freqsA, delaysA, areasA)
freqsV, delaysV, areasV = noOutliers(freqsV, delaysV, areasV)
for ind in [0,1]:
areas = areasL[ind]
delays = delaysL[ind]
freqs = freqsL[ind]
adprodA, adprodV = adprodpow(areasA, delaysA, areasV, delaysV, 1)
adpowA, adpowV = adprodpow(areasA, delaysA, areasV, delaysV, 2)
if ('flop' in mod): areas = [m/2 for m in areas] # since two flops in each module
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'),
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)
ax4.set_xlabel("Target Freq (MHz)")
ax1.set_ylabel('Delay (ns)')
ax2.set_ylabel('Area (sq microns)')
ax3.set_ylabel('Area * Delay')
ax4.set_ylabel('Area * Delay^2')
ax4.set_ylabel('Area * $Delay^2$')
ax1.set_title(mod + '_' + str(width))
plt.show()
def adprodpow(areasA, delaysA, areasV, delaysV, pow):
resultA = []
resultV = []
def adprodpow(areas, delays, pow):
''' for each value in [areas] returns area*delay^pow
helper function for freqPlot'''
result = []
for i in range(len(areasA)):
resultA += [(areasA[i])*(delaysA[i])**pow]
for i in range(len(areasV)):
resultV += [(areasV[i])*(delaysV[i])**pow]
for i in range(len(areas)):
result += [(areas[i])*(delays[i])**pow]
return resultA, resultV
return result
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)
oneMetricPlot(mod, 'delay', ax=axs[0,0], fits='clg', freq=freq)
oneMetricPlot(mod, 'area', ax=axs[0,1], fits='s', freq=freq)
@ -308,13 +348,12 @@ def plotPPA(mod, freq=None):
plt.show()
# plotPPA('alu')
# writeCSV()
# 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
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]
modules = ['flop', 'flopr']
tech = 'sky90'
widths = [8, 16, 32, 64, 128]
modules = ['add']
tech = 'tsmc28'
LoT = []
# # # # initial sweep to get estimate of min delay
# freqs = ['10000', '15000', '20000']
# for module in modules:
# for width in widths:
# for freq in freqs:
# LoT += [[module, width, tech, freq]]
# # # initial sweep to get estimate of min delay
freqs = [10000, 15000, 20000]
for module in modules:
for width in widths:
for freq in freqs:
LoT += [[module, width, tech, freq]]
# thorough sweep based on estimate of min delay
for m in modules:
for w in widths:
delays = []
for oneSynth in allSynths:
if (oneSynth[0] == m) & (oneSynth[1] == w):
delays += [oneSynth[3]]
try: f = 1000/min(delays)
except: print(m)
for freq in [str(round(f+f*x/100)) for x in arr]:
LoT += [[m, w, tech, freq]]
# # thorough sweep based on estimate of min delay
# for m in modules:
# for w in widths:
# delays = []
# for oneSynth in allSynths:
# if (oneSynth[0] == m) & (oneSynth[1] == w):
# delays += [oneSynth[3]]
# try: f = 1000/min(delays)
# except: print(m)
# for freq in [str(round(f+f*x/100)) for x in arr]:
# LoT += [[m, w, tech, freq]]
deleteRedundant(LoT)
pool = Pool()
pool.starmap(runCommand, LoT)
pool.close()