diff --git a/fuzzers/007-timing/projects/corner.mk b/fuzzers/007-timing/projects/corner.mk new file mode 100644 index 00000000..c4ac2d23 --- /dev/null +++ b/fuzzers/007-timing/projects/corner.mk @@ -0,0 +1,42 @@ +# Run corner specific calculations + +TIMFUZ_DIR=$(XRAY_DIR)/fuzzers/007-timing +CORNER=slow_max + +all: build/$(CORNER)/tilea.json + +run: + $(MAKE) clean + $(MAKE) all + touch run.ok + +clean: + rm -rf specimen_[0-9][0-9][0-9]/ seg_clblx.segbits __pycache__ run.ok + rm -rf vivado*.log vivado_*.str vivado*.jou design *.bits *.dcp *.bit + rm -rf build + +.PHONY: all run clean + +build/$(CORNER): + mkdir build/$(CORNER) + +build/$(CORNER)/leastsq.csv: build/sub.json build/grouped.csv build/checksub build/$(CORNER) + # Create a rough timing model that approximately fits the given paths + python3 $(TIMFUZ_DIR)/solve_leastsq.py --sub-json build/sub.json build/grouped.csv --corner $(CORNER) --out build/$(CORNER)/leastsq.csv.tmp + mv build/$(CORNER)/leastsq.csv.tmp build/$(CORNER)/leastsq.csv + +build/$(CORNER)/linprog.csv: build/$(CORNER)/leastsq.csv build/grouped.csv + # Tweak rough timing model, making sure all constraints are satisfied + python3 $(TIMFUZ_DIR)/solve_linprog.py --sub-json build/sub.json --sub-csv build/$(CORNER)/leastsq.csv --massage build/grouped.csv --corner $(CORNER) --out build/$(CORNER)/linprog.csv.tmp + mv build/$(CORNER)/linprog.csv.tmp build/$(CORNER)/linprog.csv + +build/$(CORNER)/flat.csv: build/$(CORNER)/linprog.csv + # Take separated variables and back-annotate them to the original timing variables + python3 $(TIMFUZ_DIR)/csv_group2flat.py --sub-json build/sub.json --corner $(CORNER) --sort build/$(CORNER)/linprog.csv build/$(CORNER)/flat.csv.tmp + mv build/$(CORNER)/flat.csv.tmp build/$(CORNER)/flat.csv + +build/$(CORNER)/tilea.json: build/$(CORNER)/flat.csv + # Final processing + # Insert timing delays into actual tile layouts + python3 $(TIMFUZ_DIR)/tile_annotate.py --tile-json $(TIMFUZ_DIR)/timgrid/build/timgrid.json build/$(CORNER)/flat.csv build/$(CORNER)/tilea.json + diff --git a/fuzzers/007-timing/projects/project.mk b/fuzzers/007-timing/projects/project.mk index 45a6165c..c0b3d1a3 100644 --- a/fuzzers/007-timing/projects/project.mk +++ b/fuzzers/007-timing/projects/project.mk @@ -1,11 +1,30 @@ +# project.mk: build specimens (run vivado), compute rref +# corner.mk: run corner specific calculations + N := 1 SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N))) SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS)) CSVS := $(addsuffix /timing3.csv,$(SPECIMENS)) TIMFUZ_DIR=$(XRAY_DIR)/fuzzers/007-timing -CORNER=slow_max +RREF_CORNER=slow_max -all: build/tilea.json +TILEA_JSONS=build/fast_max/tilea.json build/fast_min/tilea.json build/slow_max/tilea.json build/slow_min/tilea.json + +all: $(TILEA_JSONS) + +# make build/checksub first +build/fast_max/tilea.json: build/checksub + $(MAKE) -f $(TIMFUZ_DIR)/projects/corner.mk CORNER=fast_max +build/fast_min/tilea.json: build/checksub + $(MAKE) -f $(TIMFUZ_DIR)/projects/corner.mk CORNER=fast_min +build/slow_max/tilea.json: build/checksub + $(MAKE) -f $(TIMFUZ_DIR)/projects/corner.mk CORNER=slow_max +build/slow_min/tilea.json: build/checksub + $(MAKE) -f $(TIMFUZ_DIR)/projects/corner.mk CORNER=slow_min +fast_max: build/fast_max/tilea.json +fast_min: build/fast_min/tilea.json +slow_max: build/slow_max/tilea.json +slow_min: build/slow_min/tilea.json $(SPECIMENS_OK): bash generate.sh $(subst /OK,,$@) @@ -21,13 +40,15 @@ clean: rm -rf vivado*.log vivado_*.str vivado*.jou design *.bits *.dcp *.bit rm -rf build -.PHONY: database pushdb run clean +.PHONY: all run clean + +# rref should be the same regardless of corner build/sub.json: $(SPECIMENS_OK) mkdir -p build # Discover which variables can be separated # This is typically the longest running operation - python3 $(TIMFUZ_DIR)/rref.py --corner $(CORNER) --simplify --out build/sub.json.tmp $(CSVS) + python3 $(TIMFUZ_DIR)/rref.py --corner $(RREF_CORNER) --simplify --out build/sub.json.tmp $(CSVS) mv build/sub.json.tmp build/sub.json build/grouped.csv: $(SPECIMENS_OK) build/sub.json @@ -40,23 +61,3 @@ build/checksub: build/grouped.csv build/sub.json python3 $(TIMFUZ_DIR)/checksub.py --sub-json build/sub.json build/grouped.csv touch build/checksub -build/leastsq.csv: build/sub.json build/grouped.csv build/checksub - # Create a rough timing model that approximately fits the given paths - python3 $(TIMFUZ_DIR)/solve_leastsq.py --sub-json build/sub.json build/grouped.csv --corner $(CORNER) --out build/leastsq.csv.tmp - mv build/leastsq.csv.tmp build/leastsq.csv - -build/linprog.csv: build/leastsq.csv build/grouped.csv - # Tweak rough timing model, making sure all constraints are satisfied - python3 $(TIMFUZ_DIR)/solve_linprog.py --sub-json build/sub.json --sub-csv build/leastsq.csv --massage build/grouped.csv --corner $(CORNER) --out build/linprog.csv.tmp - mv build/linprog.csv.tmp build/linprog.csv - -build/flat.csv: build/linprog.csv - # Take separated variables and back-annotate them to the original timing variables - python3 $(TIMFUZ_DIR)/csv_group2flat.py --sub-json build/sub.json --corner $(CORNER) --sort build/linprog.csv build/flat.csv.tmp - mv build/flat.csv.tmp build/flat.csv - -build/tilea.json: build/flat.csv - # Final processing - # Insert timing delays into actual tile layouts - python3 $(TIMFUZ_DIR)/tile_annotate.py --tile-json $(TIMFUZ_DIR)/timgrid/build/timgrid.json build/flat.csv build/tilea.json - diff --git a/fuzzers/007-timing/solve_linprog.py b/fuzzers/007-timing/solve_linprog.py index 037cafe2..9c943ecb 100644 --- a/fuzzers/007-timing/solve_linprog.py +++ b/fuzzers/007-timing/solve_linprog.py @@ -12,7 +12,7 @@ import os import time import timfuz_solve -def save(outfn, res, names, corner): +def save(outfn, xvals, names, corner): # ballpark minimum actual observed delay is around 7 (carry chain) # anything less than one is probably a solver artifact delta = 0.5 @@ -24,7 +24,7 @@ def save(outfn, res, names, corner): # write as one variable per line # this natively forms a bound if fed into linprog solver fout.write('ico,fast_max fast_min slow_max slow_min,rows...\n') - for xval, name in zip(res.x, names): + for xval, name in zip(xvals, names): row_ico = 1 # FIXME: only report for the given corner? @@ -40,6 +40,12 @@ def save(outfn, res, names, corner): print('Wrote: zeros %u => %u / %u constrained delays' % (zeros, len(names) - zeros, len(names))) def run_corner(Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=None): + if len(Anp) == 0: + print('WARNING: zero equations') + if outfn: + save(outfn, [], [], corner) + return + # Given timing scores for above delays (-ps) assert type(Anp[0]) is np.ndarray, type(Anp[0]) assert type(b) is np.ndarray, type(b) @@ -126,7 +132,7 @@ def run_corner(Anp, b, names, corner, verbose=False, opts={}, meta={}, outfn=Non print('Delay on %d / %d' % (nonzeros, len(res.x))) if outfn: - save(outfn, res, names, corner) + save(outfn, res.x, names, corner) def main(): import argparse diff --git a/fuzzers/007-timing/timfuz.py b/fuzzers/007-timing/timfuz.py index c20a1b57..c0d0aad2 100644 --- a/fuzzers/007-timing/timfuz.py +++ b/fuzzers/007-timing/timfuz.py @@ -37,6 +37,10 @@ corner_s2i = OrderedDict([ ('slow_min', 3), ]) +# Equations are filtered out until nothing is left +class SimplifiedToZero(Exception): + pass + def print_eqns(A_ubd, b_ub, verbose=0, lim=3, label=''): rows = len(b_ub) @@ -172,6 +176,8 @@ def simplify_rows(Ads, b_ub, remove_zd=False, corner=None): eqns[rowt] = minmax(eqns.get(rowt, 0), b) print(' done') + if len(eqns) == 0: + raise SimplifiedToZero() #A_ub_ret = eqns.keys() A_ubd_ret, b_ub_ret = Ab_ub_dt2d(eqns) diff --git a/fuzzers/007-timing/timfuz_solve.py b/fuzzers/007-timing/timfuz_solve.py index dd08c5e0..47373411 100644 --- a/fuzzers/007-timing/timfuz_solve.py +++ b/fuzzers/007-timing/timfuz_solve.py @@ -2,7 +2,7 @@ # https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.optimize.linprog.html from scipy.optimize import linprog -from timfuz import Benchmark, Ar_di2np, Ar_ds2t, A_di2ds, A_ds2di, simplify_rows, loadc_Ads_b, index_names, A_ds2np, load_sub, run_sub_json, A_ub_np2d, print_eqns, print_eqns_np, Ads2bounds, instances +from timfuz import Benchmark, simplify_rows, loadc_Ads_b, index_names, A_ds2np, run_sub_json, print_eqns, Ads2bounds, instances, SimplifiedToZero from timfuz_massage import massage_equations import numpy as np import glob @@ -139,7 +139,12 @@ def run(fns_in, corner, run_corner, sub_json=None, sub_csv=None, dedup=True, mas This creates derived constraints to provide more realistic results ''' if massage: - Ads, b = massage_equations(Ads, b, corner=corner) + try: + Ads, b = massage_equations(Ads, b, corner=corner) + except SimplifiedToZero: + print('WARNING: simplified to zero equations') + Ads = [] + b = [] print('Converting to numpy...') names, Anp = A_ds2np(Ads)