mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
ppaAnalyze: docstrings and tsmc28 plotting
This commit is contained in:
parent
dd4997bd1b
commit
81a869c921
@ -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);
|
||||
|
@ -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)
|
@ -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()
|
Loading…
Reference in New Issue
Block a user