mirror of
https://github.com/openhwgroup/cvw
synced 2025-02-11 06:05:49 +00:00
major revisions to ppaAnalyze
synths as namedtuples, plotting pulls from csv, support for multiple techs
This commit is contained in:
parent
c8892f2847
commit
309f85bb38
@ -1,28 +1,39 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
# Madeleine Masser-Frye mmasserfrye@hmc.edu 5/22
|
# Madeleine Masser-Frye mmasserfrye@hmc.edu 5/22
|
||||||
|
|
||||||
from distutils.log import error
|
|
||||||
from operator import index
|
from operator import index
|
||||||
from statistics import median
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import statistics
|
|
||||||
import csv
|
import csv
|
||||||
import re
|
import re
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
import matplotlib.lines as lines
|
import matplotlib.lines as lines
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
|
|
||||||
def getData(tech, mod=None, width=None):
|
def synthsfromcsv(filename):
|
||||||
''' returns a list of lists
|
with open(filename, newline='') as csvfile:
|
||||||
each list contains results of one synthesis that matches the input specs
|
csvreader = csv.reader(csvfile)
|
||||||
|
global allSynths
|
||||||
|
allSynths = list(csvreader)
|
||||||
|
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
|
||||||
|
allSynths[i] = Synth(*allSynths[i])
|
||||||
|
|
||||||
|
def synthsintocsv(mod=None, width=None):
|
||||||
|
''' writes a CSV with one line for every available synthesis
|
||||||
|
each line contains the module, tech, width, target freq, and resulting metrics
|
||||||
'''
|
'''
|
||||||
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 += '*{}*'.format(tech)
|
specStr += '*'
|
||||||
|
|
||||||
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])
|
||||||
@ -41,8 +52,12 @@ def getData(tech, mod=None, width=None):
|
|||||||
wm = re.compile('ppa_\w*_\d*_qor')
|
wm = re.compile('ppa_\w*_\d*_qor')
|
||||||
da = re.compile('\d*\.\d{6}')
|
da = re.compile('\d*\.\d{6}')
|
||||||
p = re.compile('\d+\.\d+[e-]*\d+')
|
p = re.compile('\d+\.\d+[e-]*\d+')
|
||||||
|
t = re.compile('[a-zA-Z0-9]+nm')
|
||||||
|
|
||||||
|
file = open("ppaData.csv", "w")
|
||||||
|
writer = csv.writer(file)
|
||||||
|
writer.writerow(['Module', 'Tech', 'Width', 'Target Freq', 'Delay', 'Area', 'L Power (nW)', 'D energy (mJ)'])
|
||||||
|
|
||||||
allSynths = []
|
|
||||||
for i in range(len(linesCPL)):
|
for i in range(len(linesCPL)):
|
||||||
line = linesCPL[i]
|
line = linesCPL[i]
|
||||||
mwm = wm.findall(line)[0][4:-4].split('_')
|
mwm = wm.findall(line)[0][4:-4].split('_')
|
||||||
@ -51,78 +66,60 @@ def getData(tech, mod=None, width=None):
|
|||||||
area = float(da.findall(linesDA[i])[0])
|
area = float(da.findall(linesDA[i])[0])
|
||||||
mod = mwm[0]
|
mod = mwm[0]
|
||||||
width = int(mwm[1])
|
width = int(mwm[1])
|
||||||
|
tech = t.findall(line)[0][:-2]
|
||||||
|
try: #fix
|
||||||
power = p.findall(linesP[i])
|
power = p.findall(linesP[i])
|
||||||
lpower = float(power[2])
|
lpower = float(power[2])
|
||||||
denergy = float(power[1])*delay
|
denergy = float(power[1])*delay
|
||||||
|
except:
|
||||||
|
lpower = 0
|
||||||
|
denergy = 0
|
||||||
|
|
||||||
oneSynth = [mod, width, freq, delay, area, lpower, denergy]
|
writer.writerow([mod, tech, width, freq, delay, area, lpower, denergy])
|
||||||
allSynths += [oneSynth]
|
file.close()
|
||||||
|
|
||||||
return allSynths
|
|
||||||
|
|
||||||
def getVals(tech, module, var, freq=None):
|
def getVals(tech, module, var, freq=None):
|
||||||
''' for a specified tech, module, and variable/metric
|
''' for a specified tech, module, and variable/metric
|
||||||
returns a list of widths and the corresponding values for that metric with the appropriate units
|
returns a list of values for that metric in ascending width order 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
|
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
|
|
||||||
units = " (ns)"
|
units = " (ns)"
|
||||||
elif (var == 'area'):
|
elif (var == 'area'):
|
||||||
ind = 4
|
|
||||||
units = " (sq microns)"
|
units = " (sq microns)"
|
||||||
scale = 2
|
|
||||||
elif (var == 'lpower'):
|
elif (var == 'lpower'):
|
||||||
ind = 5
|
|
||||||
units = " (nW)"
|
units = " (nW)"
|
||||||
elif (var == 'denergy'):
|
elif (var == 'denergy'):
|
||||||
ind = 6
|
|
||||||
units = " (pJ)"
|
units = " (pJ)"
|
||||||
else:
|
|
||||||
error
|
|
||||||
|
|
||||||
widths = []
|
global widths
|
||||||
metric = []
|
metric = []
|
||||||
|
widthL = []
|
||||||
if (freq != None):
|
if (freq != None):
|
||||||
for oneSynth in allSynths:
|
for oneSynth in allSynths:
|
||||||
if (oneSynth[2] == freq):
|
if (oneSynth.freq == freq) & (oneSynth.tech == tech) & (oneSynth.module == module):
|
||||||
widths += [oneSynth[1]]
|
widthL += [oneSynth.width]
|
||||||
metric += [oneSynth[ind]]
|
osdict = oneSynth._asdict()
|
||||||
|
metric += [osdict[var]]
|
||||||
|
metric = [x for _, x in sorted(zip(widthL, metric))] # ordering
|
||||||
else:
|
else:
|
||||||
widths = [8, 16, 32, 64, 128]
|
|
||||||
for w in widths:
|
for w in widths:
|
||||||
m = 10000 # large number to start
|
m = 100000 # large number to start
|
||||||
for oneSynth in allSynths:
|
for oneSynth in allSynths:
|
||||||
if (oneSynth[1] == w):
|
if (oneSynth.width == w) & (oneSynth.tech == tech) & (oneSynth.module == module):
|
||||||
if (oneSynth[3] < m):
|
if (oneSynth.delay < m):
|
||||||
m = oneSynth[3]
|
m = oneSynth.delay
|
||||||
met = oneSynth[ind]
|
osdict = oneSynth._asdict()
|
||||||
|
met = osdict[var]
|
||||||
metric += [met]
|
metric += [met]
|
||||||
|
|
||||||
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 metric, units
|
||||||
|
|
||||||
def writeCSV(tech):
|
def genLegend(fits, coefs, r2, techcolor):
|
||||||
''' 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)'])
|
|
||||||
|
|
||||||
for one in allSynths:
|
|
||||||
writer.writerow(one)
|
|
||||||
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
def genLegend(fits, coefs, r2, tech):
|
|
||||||
''' generates a list of two legend elements
|
''' generates a list of two legend elements
|
||||||
labels line with fit equation and dots with tech and r squared of the fit
|
labels line with fit equation and dots with tech and r squared of the fit
|
||||||
'''
|
'''
|
||||||
@ -147,7 +144,7 @@ def genLegend(fits, coefs, r2, tech):
|
|||||||
eq += " + " + coefsr[ind] + "*Nlog2(N)"
|
eq += " + " + coefsr[ind] + "*Nlog2(N)"
|
||||||
ind += 1
|
ind += 1
|
||||||
|
|
||||||
c = 'blue' if (tech == 'sky90') else 'green'
|
tech, c = techcolor
|
||||||
legend_elements = [lines.Line2D([0], [0], color=c, label=eq),
|
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)))]
|
lines.Line2D([0], [0], color=c, ls='', marker='o', label=tech +' $R^2$='+ str(round(r2, 4)))]
|
||||||
return legend_elements
|
return legend_elements
|
||||||
@ -167,10 +164,13 @@ def oneMetricPlot(module, var, freq=None, ax=None, fits='clsgn'):
|
|||||||
singlePlot = False
|
singlePlot = False
|
||||||
|
|
||||||
fullLeg = []
|
fullLeg = []
|
||||||
for tech in ['sky90', 'tsmc28']:
|
global techcolors
|
||||||
c = 'blue' if (tech == 'sky90') else 'green'
|
global widths
|
||||||
widths, metric, units = getVals(tech, module, var, freq=freq)
|
for combo in techcolors:
|
||||||
xp, pred, leg = regress(widths, metric, tech, fits)
|
tech, c = combo
|
||||||
|
metric, units = getVals(tech, module, var, freq=freq)
|
||||||
|
if len(metric) == 5:
|
||||||
|
xp, pred, leg = regress(widths, metric, combo, fits)
|
||||||
fullLeg += leg
|
fullLeg += leg
|
||||||
|
|
||||||
ax.scatter(widths, metric, color=c)
|
ax.scatter(widths, metric, color=c)
|
||||||
@ -183,10 +183,11 @@ def oneMetricPlot(module, var, freq=None, ax=None, fits='clsgn'):
|
|||||||
ax.set_ylabel(str.title(var) + units)
|
ax.set_ylabel(str.title(var) + units)
|
||||||
|
|
||||||
if singlePlot:
|
if singlePlot:
|
||||||
ax.set_title(module + " (target " + str(freq) + "MHz)")
|
titleStr = " (target " + str(freq)+ "MHz)" if freq != None else " (min delay)"
|
||||||
|
ax.set_title(module + titleStr)
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
def regress(widths, var, tech, fits='clsgn'):
|
def regress(widths, var, techcolor, fits='clsgn'):
|
||||||
''' fits a curve to the given points
|
''' fits a curve to the given points
|
||||||
returns lists of x and y values to plot that curve and legend elements with the equation
|
returns lists of x and y values to plot that curve and legend elements with the equation
|
||||||
'''
|
'''
|
||||||
@ -215,12 +216,13 @@ def regress(widths, var, tech, fits='clsgn'):
|
|||||||
n = [func(x) for func in funcArr]
|
n = [func(x) for func in funcArr]
|
||||||
pred += [sum(np.multiply(coefs, n))]
|
pred += [sum(np.multiply(coefs, n))]
|
||||||
|
|
||||||
leg = genLegend(fits, coefs, r2, tech)
|
leg = genLegend(fits, coefs, r2, techcolor)
|
||||||
|
|
||||||
return xp, pred, leg
|
return xp, pred, leg
|
||||||
|
|
||||||
def makeCoefTable(tech):
|
def makeCoefTable(tech):
|
||||||
''' writes CSV with each line containing the coefficients for a regression fit
|
''' not currently in use, may salvage later
|
||||||
|
writes CSV with each line containing the coefficients for a regression fit
|
||||||
to a particular combination of module, metric, and target frequency
|
to a particular combination of module, metric, and target frequency
|
||||||
'''
|
'''
|
||||||
file = open("ppaFitting.csv", "w")
|
file = open("ppaFitting.csv", "w")
|
||||||
@ -231,7 +233,8 @@ def makeCoefTable(tech):
|
|||||||
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(tech, mod, freq, var)
|
metric, units = getVals(tech, mod, freq, var)
|
||||||
|
global widths
|
||||||
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)
|
||||||
@ -280,15 +283,14 @@ def noOutliers(freqs, delays, areas):
|
|||||||
def freqPlot(tech, mod, width):
|
def freqPlot(tech, mod, width):
|
||||||
''' plots delay, area, area*delay, and area*delay^2 for syntheses with specified tech, module, width
|
''' plots delay, area, area*delay, and area*delay^2 for syntheses with specified tech, module, width
|
||||||
'''
|
'''
|
||||||
allSynths = getData(tech, mod=mod, width=width)
|
global allSynths
|
||||||
|
|
||||||
freqsL, delaysL, areasL = ([[], []] for i in range(3))
|
freqsL, delaysL, areasL = ([[], []] for i in range(3))
|
||||||
for oneSynth in allSynths:
|
for oneSynth in allSynths:
|
||||||
if (mod == oneSynth[0]) & (width == oneSynth[1]):
|
if (mod == oneSynth.module) & (width == oneSynth.width) & (tech == oneSynth.tech):
|
||||||
ind = (1000/oneSynth[3] < oneSynth[2]) # when delay is within target clock period
|
ind = (1000/oneSynth.delay < oneSynth.freq) # when delay is within target clock period
|
||||||
freqsL[ind] += [oneSynth[2]]
|
freqsL[ind] += [oneSynth.freq]
|
||||||
delaysL[ind] += [oneSynth[3]]
|
delaysL[ind] += [oneSynth.delay]
|
||||||
areasL[ind] += [oneSynth[4]]
|
areasL[ind] += [oneSynth.area]
|
||||||
|
|
||||||
f, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, 1, sharex=True)
|
f, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, 1, sharex=True)
|
||||||
|
|
||||||
@ -347,13 +349,14 @@ def plotPPA(mod, freq=None):
|
|||||||
plt.suptitle(mod + titleStr)
|
plt.suptitle(mod + titleStr)
|
||||||
plt.show()
|
plt.show()
|
||||||
|
|
||||||
|
Synth = namedtuple("Synth", "module tech width freq delay area lpower denergy")
|
||||||
|
techcolors = [['sky90', 'green'], ['tsmc28', 'blue']]
|
||||||
|
widths = [8, 16, 32, 64, 128]
|
||||||
|
synthsintocsv()
|
||||||
|
|
||||||
# writeCSV()
|
synthsfromcsv('ppaData.csv') # your csv here!
|
||||||
|
|
||||||
# look at comparaotro 32
|
### examples
|
||||||
|
# oneMetricPlot('add', 'delay')
|
||||||
# for x in ['add', 'mult', 'comparator', 'alu', 'csa']:
|
#freqPlot('sky90', 'add', 8)
|
||||||
# for y in [8, 16, 32, 64, 128]:
|
#plotPPA('add')
|
||||||
# freqPlot('sky90', x, y)
|
|
||||||
|
|
||||||
freqPlot('sky90', 'mult', 32)
|
|
2024
synthDC/ppaData.csv
2024
synthDC/ppaData.csv
File diff suppressed because it is too large
Load Diff
@ -44,30 +44,30 @@ def getData():
|
|||||||
allSynths = getData()
|
allSynths = getData()
|
||||||
arr = [-40, -20, -8, -6, -4, -2, 0, 2, 4, 6, 8, 12, 20, 40]
|
arr = [-40, -20, -8, -6, -4, -2, 0, 2, 4, 6, 8, 12, 20, 40]
|
||||||
|
|
||||||
widths = [8, 16, 32, 64, 128]
|
widths = [16, 8, 32, 64, 128]
|
||||||
modules = ['add']
|
modules = ['add']
|
||||||
tech = 'tsmc28'
|
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 = [25000, 35000]
|
||||||
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
|
# # thorough sweep based on estimate of min delay
|
||||||
# for m in modules:
|
for m in modules:
|
||||||
# for w in widths:
|
for w in widths:
|
||||||
# delays = []
|
delays = []
|
||||||
# for oneSynth in allSynths:
|
for oneSynth in allSynths:
|
||||||
# if (oneSynth[0] == m) & (oneSynth[1] == w):
|
if (oneSynth[0] == m) & (oneSynth[1] == w):
|
||||||
# delays += [oneSynth[3]]
|
delays += [oneSynth[3]]
|
||||||
# try: f = 1000/min(delays)
|
try: f = 1000/min(delays)
|
||||||
# except: print(m)
|
except: print(m)
|
||||||
# for freq in [str(round(f+f*x/100)) for x in arr]:
|
for freq in [str(round(f+f*x/100)) for x in arr]:
|
||||||
# LoT += [[m, w, tech, freq]]
|
LoT += [[m, w, tech, freq]]
|
||||||
|
|
||||||
deleteRedundant(LoT)
|
deleteRedundant(LoT)
|
||||||
pool = Pool()
|
pool = Pool()
|
||||||
|
Loading…
Reference in New Issue
Block a user