explanations and modifications for general ppa use

This commit is contained in:
Madeleine Masser-Frye 2022-07-09 03:24:47 +00:00
parent 19db618b7f
commit b196b6b504
3 changed files with 112 additions and 37 deletions

32
synthDC/ppa/README Normal file
View File

@ -0,0 +1,32 @@
Wally PPA Study
July 8, 2022
Madeleine Masser-Frye
mmasserfrye@hmc.edu
___________________
Apologies for issues in this folder, code was written originally for individual use and documentation was compiled in haste. Please feel free to contact the author with questions.
-------------------
ppaSynth.py
Run to synthesize datapath modules from src/ppa.
To run a specific combination of widths, modules, techs, and freqs,
modify those lists and use allCombos() to generate synthsToRun (comment out freqSweep).
To run a sweep of frequencies around the best delay found in existing syntheses (according to bestSynths.csv), modify the parameters and use freqSweep to generate synthsToRun.
To remove synths to be run that already exist in /runs from synthsToRun, use filterRedundant().
Syntheses run in parallel but you may encounter issues doing more than a dozen or so at once.
-------------------
ppaAnalyze.py
Run to plot results of PPA syntheses. See docstrings for individual function info.
-------------------
bestSynths.csv
Results of the synthesis for each combination of module, width, and tech with the best achievable delay. Generated by csvOfBest() in ppaAnalyze.py
-------------------
ppaFitting.csv & ppaEquations.csv
Representations of the regression fit for each module and metric. Generated in ppaAnalyze.py by makeCoefTable() and makeEqTable().
-------------------
ppaData.csv
Results from all synthesis runs. Generated by synthsintocsv() and used by synthsfromcsv in ppaAnalyze.py.

View File

@ -8,9 +8,11 @@ import re
from matplotlib.cbook import flatten
import matplotlib.pyplot as plt
import matplotlib.lines as lines
import matplotlib as mpl
import numpy as np
from collections import namedtuple
import sklearn.metrics as skm
import os
def synthsfromcsv(filename):
Synth = namedtuple("Synth", "module tech width freq delay area lpower denergy")
@ -518,8 +520,8 @@ def plotPPA(mod, freq=None, norm=True, aleOpt=False):
if no freq specified, uses the synthesis with best achievable delay for each width
overlays data from both techs
'''
plt.rcParams["figure.figsize"] = (7,3.46)
fig, axs = plt.subplots(2, 2)
with mpl.rc_context({"figure.figsize": (7,3.46)}):
fig, axs = plt.subplots(2, 2)
arr = [['delay', 'area'], ['lpower', 'denergy']]
@ -555,6 +557,8 @@ def plotPPA(mod, freq=None, norm=True, aleOpt=False):
# plt.show()
def makeLineLegend():
''' 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='-')]
@ -619,6 +623,8 @@ def muxPlot(fits='clsgn', norm=True):
plt.savefig('./plots/mux.png')
def stdDevError():
''' calculates std deviation and error for paper-writing purposes
'''
for var in ['delay', 'area', 'lpower', 'denergy']:
errlist = []
for module in modules:
@ -668,6 +674,30 @@ def stdDevError():
print(var, ' ', avgErr, ' ', stdv)
def makePlotDirectory():
''' 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')
if not os.path.exists(final_directory):
os.makedirs(final_directory)
os.chdir(final_directory)
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', 'tsmc28']:
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(current_directory)
if __name__ == '__main__':
##############################
@ -686,26 +716,22 @@ if __name__ == '__main__':
##############################
# cleanup() # run to remove garbage synth runs
# synthsintocsv() # slow, run only when new synth runs to add to csv
synthsintocsv() # slow, run only when new synth runs to add to csv
allSynths = synthsfromcsv('ppaData.csv') # your csv here!
bestSynths = csvOfBest('bestSynths.csv')
makePlotDirectory()
# ### function examples
# squareAreaDelay('sky90', 'add', 32)
# oneMetricPlot('mult', 'lpower')
# freqPlot('sky90', 'mux4', 16)
# plotBestAreas('add')
# ### other functions
# makeCoefTable()
# makeEqTable()
# makeLineLegend()
# muxPlot()
# stdDevError()
for mod in modules:
plotPPA(mod, norm=False)
plotPPA(mod, aleOpt=True)
for w in widths:
freqPlot('sky90', mod, w)
freqPlot('tsmc28', mod, w)
plotPPA(mod, norm=False)
plotPPA(mod, aleOpt=True)
plt.close('all')

View File

@ -10,47 +10,64 @@ def runCommand(module, width, tech, freq):
command = "make synth DESIGN=ppa_{}_{} TECH={} DRIVE=INV FREQ={} MAXOPT=1 MAXCORES=1".format(module, width, tech, freq)
subprocess.Popen(command, shell=True)
def deleteRedundant(LoT):
def deleteRedundant(synthsToRun):
'''removes any previous runs for the current synthesis specifications'''
synthStr = "rm -rf runs/ppa_{}_{}_rv32e_{}nm_{}_*"
for synth in LoT:
for synth in synthsToRun:
bashCommand = synthStr.format(*synth)
outputCPL = subprocess.check_output(['bash','-c', bashCommand])
if __name__ == '__main__':
LoT = []
def freqSweep(module, width, tech):
synthsToRun = []
##### Run specific syntheses
# widths = [8]
# modules = ['mult', 'add', 'shiftleft', 'flop', 'comparator', 'priorityencoder', 'add', 'csa', 'mux2', 'mux4', 'mux8']
# techs = ['sky90']
# freqs = [5000]
# for w in widths:
# for module in modules:
# for tech in techs:
# for freq in freqs:
# LoT += [[module, str(w), tech, str(freq)]]
##### Run a sweep based on best delay found in existing syntheses
arr = [-8, -6, -4, -2, 0, 2, 4, 6, 8]
allSynths = synthsfromcsv('bestSynths.csv')
for synth in allSynths:
f = 1000/synth.delay
for freq in [round(f+f*x/100) for x in arr]:
LoT += [[synth.module, str(synth.width), synth.tech, str(freq)]]
##### Only do syntheses for which a run doesn't already exist
if (synth.module == module) & (synth.tech == tech) & (synth.width == width):
f = 1000/synth.delay
for freq in [round(f+f*x/100) for x in arr]:
synthsToRun += [[synth.module, str(synth.width), synth.tech, str(freq)]]
return synthsToRun
def filterRedundant(synthsToRun):
bashCommand = "find . -path '*runs/ppa*rv32e*' -prune"
output = subprocess.check_output(['bash','-c', bashCommand])
specReg = re.compile('[a-zA-Z0-9]+')
allSynths = output.decode("utf-8").split('\n')[:-1]
allSynths = [specReg.findall(oneSynth)[2:7] for oneSynth in allSynths]
allSynths = [oneSynth[0:2] + [oneSynth[3][:-2]] + [oneSynth[4]] for oneSynth in allSynths]
for synth in LoT:
output = []
for synth in synthsToRun:
if (synth not in allSynths):
synthsToRun += [synth]
output += [synth]
return output
def allCombos(widths, modules, techs, freqs):
synthsToRun = []
for w in widths:
for module in modules:
for tech in techs:
for freq in freqs:
synthsToRun += [[module, str(w), tech, str(freq)]]
return synthsToRun
if __name__ == '__main__':
##### Run specific syntheses
widths = [8, 16, 32, 64, 128]
modules = ['mult', 'add', 'shiftleft', 'flop', 'comparator', 'priorityencoder', 'add', 'csa', 'mux2', 'mux4', 'mux8']
techs = ['sky90', 'tsmc28']
freqs = [5000]
synthsToRun = allCombos(widths, modules, techs, freqs)
##### Run a sweep based on best delay found in existing syntheses
module = 'add'
width = 32
tech = 'sky90'
synthsToRun = freqSweep(module, width, tech)
##### Only do syntheses for which a run doesn't already exist
synthsToRun = filterRedundant(synthsToRun)
pool = Pool(processes=25)
pool.starmap(runCommand, synthsToRun)
pool.starmap(print, synthsToRun)