diff --git a/README.md b/README.md index 676ffa9..e0235bc 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Choose `uv-env` as kernel in Jupyter Lab. Numbers are given in `gfs/s` = `gates * faults * patterns / second`. -Stuck-at fault sim on 1024 patterns, baseline: +`SAFSimSimple` on 1024 patterns (baseline): | OS, CPU, RAM | `tests/c6288.bench` | `polito-itc99-b15-sky130` | |--------------|---------------------|---------------------------| diff --git a/kyupy b/kyupy index c90bc89..53309f9 160000 --- a/kyupy +++ b/kyupy @@ -1 +1 @@ -Subproject commit c90bc89522bd0ba39ac0786dd43f19a8502c4224 +Subproject commit 53309f9e597c91bf630886f7e125995bf48c6f53 diff --git a/main.py b/main.py index 9883fa5..355016a 100755 --- a/main.py +++ b/main.py @@ -10,7 +10,8 @@ from kyupy import verilog, bench, log, logic, batchrange, atalanta, stil from kyupy.techlib import techlib_by_name, KYUPY from fsim.static import LineRoles, FaultSet -from fsim.baseline import SAFSimSimple +from fsim.simple import SAFSimSimple +from fsim.incremental import SAFSimIncremental def main(): @@ -80,8 +81,8 @@ def main(): fclasses = safsim.classify_faults(saf_collapsed, patterns) - log.info(f'fsim time: {safsim.sim_time:.2f}s') - sim_performance = stats['comb'] * len(saf_collapsed) * patterns.shape[1] / safsim.sim_time + log.info(f'{safsim.timers=}') + sim_performance = stats['comb'] * len(saf_collapsed) * patterns.shape[1] / safsim.timers['sim'].s log.info(f'fsim performance: {sim_performance:.2e} gfp/s') log.info(f'detected by simulation (collapsed): {len(fclasses["DS"])}/{len(saf_collapsed)} - {len(fclasses["DS"])/len(saf_collapsed)*100:.2f}%') diff --git a/src/fsim/baseline.py b/src/fsim/baseline.py deleted file mode 100644 index 9f9e24f..0000000 --- a/src/fsim/baseline.py +++ /dev/null @@ -1,47 +0,0 @@ -import time -from collections.abc import Collection - -import numpy as np - -from kyupy import log, batchrange -from kyupy.circuit import Circuit -from kyupy.logic_sim import LogicSim2V - -class SAFSimSimple: - - def __init__(self, circuit_resolved: Circuit, batch_size: int): - self.sim = LogicSim2V(circuit_resolved, sims=batch_size) - self.sim_time = 0 - pass - - def classify_faults(self, faults: Collection[int], patterns: np.ndarray): - - golden = np.zeros_like(patterns) - self.sim.simulate(patterns, golden) - log.info(f'golden sim finished.') - - syndrome = np.zeros_like(patterns) - - fclass_NO = set() - fclass_DS = set() - - start_time = time.perf_counter() - - with log.progress() as p: - for fidx, fault in enumerate(faults): - fault_site = fault//2 - fault_polarity = fault&1 - p.update((fidx+1) / len(faults), f'DS:{len(fclass_DS)} NO:{len(fclass_NO)}') - for bo, bs in batchrange(patterns.shape[1], self.sim.sims): - self.sim.s_assign[:, :bs] = patterns[:, bo:bo+bs] - self.sim.s_to_c() - self.sim.c_prop(fault_line=fault_site, fault_model=fault_polarity) - self.sim.c_to_s() - syndrome[:, bo:bo+bs] = self.sim.s_result[:,:bs] - if np.allclose(golden, syndrome): - fclass_NO.add(fault) - else: - fclass_DS.add(fault) - - self.sim_time += time.perf_counter() - start_time - return {'DS': fclass_DS, 'NO': fclass_NO} \ No newline at end of file diff --git a/src/fsim/incremental.py b/src/fsim/incremental.py new file mode 100644 index 0000000..18667d9 --- /dev/null +++ b/src/fsim/incremental.py @@ -0,0 +1,47 @@ +import time +from collections.abc import Collection + +import numpy as np + +from kyupy import log, batchrange, cdiv, Timers +from kyupy.circuit import Circuit +from kyupy.logic_sim import LogicSim2V + +class SAFSimIncremental: + + def __init__(self, circuit_resolved: Circuit, batch_size: int): + self.sim = LogicSim2V(circuit_resolved, sims=batch_size) + self.timers = Timers() + + def classify_faults(self, faults: Collection[int], patterns: np.ndarray): + + with self.timers['startup']: + self.sim.c_prop() # trigger jit + c_golden = np.zeros_like(self.sim.c) + fclass_DS = set() + nbatches = cdiv(patterns.shape[1], self.sim.sims) + nfaults = len(faults) + + with self.timers['sim'], log.progress() as p: + for bidx, (bo, bs) in enumerate(batchrange(patterns.shape[1], self.sim.sims)): + self.sim.s_assign[:, :bs] = patterns[:, bo:bo+bs] + self.sim.s_to_c() + self.sim.c_dirty[...] = 1 + with self.timers['sim_full_prop']: + self.sim.c_prop() + c_golden[...] = self.sim.c + c_golden_poppo = c_golden[self.sim.poppo_c_locs] + for fidx, fault in enumerate(faults): + fault_site = fault//2 + fault_polarity = fault&1 + self.sim.c_dirty[...] = 0 + with self.timers['sim_incr_prop']: + self.sim.c_prop(fault_line=fault_site, fault_model=fault_polarity) + with self.timers['sim_incr_eval']: + if not np.all(c_golden_poppo == self.sim.c[self.sim.poppo_c_locs]): + fclass_DS.add(fault) + with self.timers['sim_incr_reset']: + self.sim.c[...] = c_golden # clear fault + p.update(((fidx+1) / nfaults) * ((bidx+1) / nbatches)) + + return {'DS': fclass_DS, 'NO': set(faults) - fclass_DS} \ No newline at end of file diff --git a/src/fsim/simple.py b/src/fsim/simple.py new file mode 100644 index 0000000..4866f4d --- /dev/null +++ b/src/fsim/simple.py @@ -0,0 +1,44 @@ +import time +from collections.abc import Collection + +import numpy as np + +from kyupy import log, batchrange, Timers +from kyupy.circuit import Circuit +from kyupy.logic_sim import LogicSim2V + +class SAFSimSimple: + + def __init__(self, circuit_resolved: Circuit, batch_size: int): + self.sim = LogicSim2V(circuit_resolved, sims=batch_size) + self.timers = Timers() + + def classify_faults(self, faults: Collection[int], patterns: np.ndarray): + + with self.timers['startup']: + golden = np.zeros_like(patterns) + self.sim.simulate(patterns, golden) + syndrome = np.zeros_like(patterns) + fclass_NO = set() + fclass_DS = set() + + with self.timers['sim'], log.progress() as p: + for fidx, fault in enumerate(faults): + fault_site = fault//2 + fault_polarity = fault&1 + p.update((fidx+1) / len(faults), f'DS:{len(fclass_DS)} NO:{len(fclass_NO)}') + for bo, bs in batchrange(patterns.shape[1], self.sim.sims): + self.sim.s_assign[:, :bs] = patterns[:, bo:bo+bs] + self.sim.s_to_c() + with self.timers['sim_prop']: + self.sim.c_prop(fault_line=fault_site, fault_model=fault_polarity) + with self.timers['sim_eval']: + self.sim.c_to_s() + syndrome[:, bo:bo+bs] = self.sim.s_result[:,:bs] + with self.timers['sim_eval2']: + if np.allclose(golden, syndrome): + fclass_NO.add(fault) + else: + fclass_DS.add(fault) + + return {'DS': fclass_DS, 'NO': fclass_NO} \ No newline at end of file