diff --git a/util/sim/Simulation.py b/util/sim/Simulation.py index 5b3f218184..3fd024639e 100644 --- a/util/sim/Simulation.py +++ b/util/sim/Simulation.py @@ -71,6 +71,13 @@ def launch(self, dry_run=None): self.process = subprocess.Popen(self.cmd, stdout=f, stderr=subprocess.STDOUT, cwd=self.run_dir, universal_newlines=True) + def launched(self): + """Return whether the simulation was launched.""" + if self.process: + return True + else: + return False + def completed(self): """Return whether the simulation completed.""" if self.dry_run: @@ -96,6 +103,14 @@ def successful(self): else: return False + def get_simulation_time(self): + """Return the execution time [ns] of the binary in simulation.""" + return None + + def get_elapsed_time(self): + """Return the actual time [s] taken to run the simulation.""" + return None + def print_log(self): """Print a log of the simulation to stdout.""" with open(self.log, 'r') as f: @@ -112,8 +127,10 @@ def print_status(self): cprint(f'{self.elf} test passed', 'green', attrs=['bold'], flush=True) else: cprint(f'{self.elf} test failed', 'red', attrs=['bold'], flush=True) - else: + elif self.launched(): cprint(f'{self.elf} test running', 'yellow', attrs=['bold'], flush=True) + else: + cprint(f'{self.elf} test not launched', 'yellow', attrs=['bold'], flush=True) class RTLSimulation(Simulation): @@ -183,6 +200,27 @@ def __init__(self, **kwargs): super().__init__(**kwargs) self.cmd += ['', '-batch'] + def get_simulation_time(self): + # Extract the simulation time from the simulation log + with open(self.log, 'r') as f: + for line in f.readlines(): + regex = r'Time: (\d+) ns' + match = re.search(regex, line) + if match: + return int(match.group(1)) + + def get_elapsed_time(self): + # Extract the simulation time from the simulation log + with open(self.log, 'r') as f: + for line in f.readlines(): + regex = r'Elapsed time: (\d+):(\d+):(\d+)' + match = re.search(regex, line) + if match: + hours = int(match.group(1)) + minutes = int(match.group(2)) + seconds = int(match.group(3)) + return hours*3600 + minutes*60 + seconds + class VCSSimulation(QuestaVCSSimulation): """An RTL simulation running on VCS.""" diff --git a/util/sim/sim_utils.py b/util/sim/sim_utils.py index 830c856664..ac5f67b2e3 100755 --- a/util/sim/sim_utils.py +++ b/util/sim/sim_utils.py @@ -55,8 +55,10 @@ import yaml import signal import psutil +import pandas as pd POLL_PERIOD = 0.2 +REPORT_FILE = 'sim_report.csv' def parser(default_simulator='vsim', simulator_choices=['vsim']): @@ -200,6 +202,23 @@ def print_summary(sims, early_exit=False, dry_run=False): print(f'{colored("All tests terminated and passed!", "green")}') +def dump_report(sims): + """Print a detailed report on the simulation suite's execution. + + Args: + sims: A list of simulations from the simulation suite. + """ + data = [{'elf': sim.elf, + 'launched': sim.launched(), + 'completed': sim.completed(), + 'passed': sim.successful(), + 'elapsed time [s]': sim.get_elapsed_time(), + 'simulation time [ns]': sim.get_simulation_time()} for sim in sims] + df = pd.DataFrame(data) + df = df.set_index('elf') + df.to_csv(REPORT_FILE) + + def terminate_processes(): print('Terminate processes') # Get PID and PGID of parent process (current Python script) @@ -250,6 +269,7 @@ def run_simulations(simulations, n_procs=1, dry_run=None, early_exit=False, # Spawn a process for every test, wait for all running tests to terminate and check results running_sims = [] failed_sims = [] + successful_sims = [] early_exit_requested = False try: while (len(simulations) or len(running_sims)) and not early_exit_requested: @@ -264,6 +284,7 @@ def run_simulations(simulations, n_procs=1, dry_run=None, early_exit=False, # Check completed sims and report status for sim in completed_sims: if sim.successful(): + successful_sims.append(sim) sim.print_status() else: failed_sims.append(sim) @@ -281,6 +302,9 @@ def run_simulations(simulations, n_procs=1, dry_run=None, early_exit=False, # Print summary print_summary(running_sims + failed_sims, early_exit_requested) + # Dump report + dump_report(simulations + running_sims + successful_sims + failed_sims) + # Clean up after early exit if early_exit_requested: terminate_processes()