Skip to content

Commit 72814ba

Browse files
committed
Run different simulator threads in different directories.
This avoids interference between different runner.cfg files.
1 parent 5e6ade4 commit 72814ba

12 files changed

Lines changed: 195 additions & 146 deletions

tests/unit/test_incisive_interface.py

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -503,9 +503,9 @@ def test_simulate_vhdl(self, run_command, find_cds_root_irun, find_cds_root_virt
503503
simif.compile_project(project)
504504

505505
config = make_config()
506-
self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config))
507-
elaborate_args_file = str(Path("suite_output_path") / simif.name / "irun_elaborate.args")
508-
simulate_args_file = str(Path("suite_output_path") / simif.name / "irun_simulate.args")
506+
self.assertTrue(simif.simulate("suite_output_path", "simulator_output_path", "test_suite_name", config))
507+
elaborate_args_file = str(Path("simulator_output_path") / "irun_elaborate.args")
508+
simulate_args_file = str(Path("simulator_output_path") / "irun_simulate.args")
509509
run_command.assert_has_calls(
510510
[
511511
mock.call(
@@ -541,7 +541,7 @@ def test_simulate_vhdl(self, run_command, find_cds_root_irun, find_cds_root_virt
541541
"-work work",
542542
'-nclibdirname "%s"' % str(Path(self.output_path) / "libraries"),
543543
'-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"),
544-
'-log "%s"' % str(Path("suite_output_path") / simif.name / "irun_elaborate.log"),
544+
'-log "%s"' % str(Path("simulator_output_path") / "irun_elaborate.log"),
545545
"-quiet",
546546
'-reflib "lib_path"',
547547
"-access +r",
@@ -565,7 +565,7 @@ def test_simulate_vhdl(self, run_command, find_cds_root_irun, find_cds_root_virt
565565
"-work work",
566566
'-nclibdirname "%s"' % str(Path(self.output_path) / "libraries"),
567567
'-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"),
568-
'-log "%s"' % str(Path("suite_output_path") / simif.name / "irun_simulate.log"),
568+
'-log "%s"' % str(Path("simulator_output_path") / "irun_simulate.log"),
569569
"-quiet",
570570
'-reflib "lib_path"',
571571
"-access +r",
@@ -591,9 +591,9 @@ def test_simulate_verilog(self, run_command, find_cds_root_irun, find_cds_root_v
591591
simif.compile_project(project)
592592

593593
config = make_config(verilog=True)
594-
self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config))
595-
elaborate_args_file = str(Path("suite_output_path") / simif.name / "irun_elaborate.args")
596-
simulate_args_file = str(Path("suite_output_path") / simif.name / "irun_simulate.args")
594+
self.assertTrue(simif.simulate("suite_output_path", "simulator_output_path", "test_suite_name", config))
595+
elaborate_args_file = str(Path("simulator_output_path") / "irun_elaborate.args")
596+
simulate_args_file = str(Path("simulator_output_path") / "irun_simulate.args")
597597
run_command.assert_has_calls(
598598
[
599599
mock.call(
@@ -629,7 +629,7 @@ def test_simulate_verilog(self, run_command, find_cds_root_irun, find_cds_root_v
629629
"-work work",
630630
'-nclibdirname "%s"' % str(Path(self.output_path) / "libraries"),
631631
'-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"),
632-
'-log "%s"' % str(Path("suite_output_path") / simif.name / "irun_elaborate.log"),
632+
'-log "%s"' % str(Path("simulator_output_path") / "irun_elaborate.log"),
633633
"-quiet",
634634
'-reflib "lib_path"',
635635
"-access +r",
@@ -653,7 +653,7 @@ def test_simulate_verilog(self, run_command, find_cds_root_irun, find_cds_root_v
653653
"-work work",
654654
'-nclibdirname "%s"' % str(Path(self.output_path) / "libraries"),
655655
'-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"),
656-
'-log "%s"' % str(Path("suite_output_path") / simif.name / "irun_simulate.log"),
656+
'-log "%s"' % str(Path("simulator_output_path") / "irun_simulate.log"),
657657
"-quiet",
658658
'-reflib "lib_path"',
659659
"-access +r",
@@ -670,9 +670,9 @@ def test_simulate_extra_flags(self, run_command, find_cds_root_irun, find_cds_ro
670670
find_cds_root_virtuoso.return_value = None
671671
simif = IncisiveInterface(prefix="prefix", output_path=self.output_path)
672672
config = make_config(sim_options={"incisive.irun_sim_flags": ["custom", "flags"]})
673-
self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config))
674-
elaborate_args_file = str(Path("suite_output_path") / simif.name / "irun_elaborate.args")
675-
simulate_args_file = str(Path("suite_output_path") / simif.name / "irun_simulate.args")
673+
self.assertTrue(simif.simulate("suite_output_path", "simulator_output_path", "test_suite_name", config))
674+
elaborate_args_file = str(Path("simulator_output_path") / "irun_elaborate.args")
675+
simulate_args_file = str(Path("simulator_output_path") / "irun_simulate.args")
676676
run_command.assert_has_calls(
677677
[
678678
mock.call(
@@ -708,9 +708,9 @@ def test_simulate_generics_and_parameters(self, run_command, find_cds_root_irun,
708708
find_cds_root_virtuoso.return_value = None
709709
simif = IncisiveInterface(prefix="prefix", output_path=self.output_path)
710710
config = make_config(verilog=True, generics={"genstr": "genval", "genint": 1, "genbool": True})
711-
self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config))
712-
elaborate_args_file = str(Path("suite_output_path") / simif.name / "irun_elaborate.args")
713-
simulate_args_file = str(Path("suite_output_path") / simif.name / "irun_simulate.args")
711+
self.assertTrue(simif.simulate("suite_output_path", "simulator_output_path", "test_suite_name", config))
712+
elaborate_args_file = str(Path("simulator_output_path") / "irun_elaborate.args")
713+
simulate_args_file = str(Path("simulator_output_path") / "irun_simulate.args")
714714
run_command.assert_has_calls(
715715
[
716716
mock.call(
@@ -744,9 +744,9 @@ def test_simulate_hdlvar(self, run_command, find_cds_root_irun, find_cds_root_vi
744744
find_cds_root_virtuoso.return_value = None
745745
simif = IncisiveInterface(prefix="prefix", output_path=self.output_path, hdlvar="custom_hdlvar")
746746
config = make_config()
747-
self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config))
748-
elaborate_args_file = str(Path("suite_output_path") / simif.name / "irun_elaborate.args")
749-
simulate_args_file = str(Path("suite_output_path") / simif.name / "irun_simulate.args")
747+
self.assertTrue(simif.simulate("suite_output_path", "simulator_output_path", "test_suite_name", config))
748+
elaborate_args_file = str(Path("simulator_output_path") / "irun_elaborate.args")
749+
simulate_args_file = str(Path("simulator_output_path") / "irun_simulate.args")
750750
run_command.assert_has_calls(
751751
[
752752
mock.call(
@@ -778,8 +778,10 @@ def test_elaborate(self, run_command, find_cds_root_irun, find_cds_root_virtuoso
778778
find_cds_root_virtuoso.return_value = None
779779
simif = IncisiveInterface(prefix="prefix", output_path=self.output_path)
780780
config = make_config(verilog=True)
781-
self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config, elaborate_only=True))
782-
elaborate_args_file = str(Path("suite_output_path") / simif.name / "irun_elaborate.args")
781+
self.assertTrue(
782+
simif.simulate("suite_output_path", "simulator_output_path", "test_suite_name", config, elaborate_only=True)
783+
)
784+
elaborate_args_file = str(Path("simulator_output_path") / "irun_elaborate.args")
783785
run_command.assert_has_calls(
784786
[
785787
mock.call(
@@ -810,7 +812,7 @@ def test_elaborate(self, run_command, find_cds_root_irun, find_cds_root_virtuoso
810812
"-work work",
811813
'-nclibdirname "%s"' % str(Path(self.output_path) / "libraries"),
812814
'-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"),
813-
'-log "%s"' % str(Path("suite_output_path") / simif.name / "irun_elaborate.log"),
815+
'-log "%s"' % str(Path("simulator_output_path") / "irun_elaborate.log"),
814816
"-quiet",
815817
"-access +r",
816818
'-input "@run"',
@@ -826,8 +828,8 @@ def test_elaborate_fail(self, run_command, find_cds_root_irun, find_cds_root_vir
826828
find_cds_root_virtuoso.return_value = None
827829
simif = IncisiveInterface(prefix="prefix", output_path=self.output_path)
828830
config = make_config()
829-
self.assertFalse(simif.simulate("suite_output_path", "test_suite_name", config))
830-
elaborate_args_file = str(Path("suite_output_path") / simif.name / "irun_elaborate.args")
831+
self.assertFalse(simif.simulate("suite_output_path", "simulator_output_path", "test_suite_name", config))
832+
elaborate_args_file = str(Path("simulator_output_path") / "irun_elaborate.args")
831833
run_command.assert_has_calls(
832834
[
833835
mock.call(
@@ -850,9 +852,9 @@ def test_simulate_fail(self, run_command, find_cds_root_irun, find_cds_root_virt
850852
find_cds_root_virtuoso.return_value = None
851853
simif = IncisiveInterface(prefix="prefix", output_path=self.output_path)
852854
config = make_config()
853-
self.assertFalse(simif.simulate("suite_output_path", "test_suite_name", config))
854-
elaborate_args_file = str(Path("suite_output_path") / simif.name / "irun_elaborate.args")
855-
simulate_args_file = str(Path("suite_output_path") / simif.name / "irun_simulate.args")
855+
self.assertFalse(simif.simulate("suite_output_path", "simulator_output_path", "test_suite_name", config))
856+
elaborate_args_file = str(Path("simulator_output_path") / "irun_elaborate.args")
857+
simulate_args_file = str(Path("simulator_output_path") / "irun_simulate.args")
856858
run_command.assert_has_calls(
857859
[
858860
mock.call(
@@ -888,9 +890,9 @@ def test_simulate_gui(self, run_command, find_cds_root_irun, find_cds_root_virtu
888890
with mock.patch("vunit.sim_if.check_output", autospec=True, return_value="") as dummy:
889891
simif.compile_project(project)
890892
config = make_config()
891-
self.assertTrue(simif.simulate("suite_output_path", "test_suite_name", config))
892-
elaborate_args_file = str(Path("suite_output_path") / simif.name / "irun_elaborate.args")
893-
simulate_args_file = str(Path("suite_output_path") / simif.name / "irun_simulate.args")
893+
self.assertTrue(simif.simulate("suite_output_path", "simulator_output_path", "test_suite_name", config))
894+
elaborate_args_file = str(Path("simulator_output_path") / "irun_elaborate.args")
895+
simulate_args_file = str(Path("simulator_output_path") / "irun_simulate.args")
894896
run_command.assert_has_calls(
895897
[
896898
mock.call(
@@ -925,7 +927,7 @@ def test_simulate_gui(self, run_command, find_cds_root_irun, find_cds_root_virtu
925927
"-work work",
926928
'-nclibdirname "%s"' % str(Path(self.output_path) / "libraries"),
927929
'-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"),
928-
'-log "%s"' % str(Path("suite_output_path") / simif.name / "irun_elaborate.log"),
930+
'-log "%s"' % str(Path("simulator_output_path") / "irun_elaborate.log"),
929931
"-quiet",
930932
'-reflib "lib_path"',
931933
"-access +rwc",
@@ -949,7 +951,7 @@ def test_simulate_gui(self, run_command, find_cds_root_irun, find_cds_root_virtu
949951
"-work work",
950952
'-nclibdirname "%s"' % str(Path(self.output_path) / "libraries"),
951953
'-cdslib "%s"' % str(Path(self.output_path) / "cds.lib"),
952-
'-log "%s"' % str(Path("suite_output_path") / simif.name / "irun_simulate.log"),
954+
'-log "%s"' % str(Path("simulator_output_path") / "irun_simulate.log"),
953955
"-quiet",
954956
'-reflib "lib_path"',
955957
"-access +rwc",

tests/unit/test_test_runner.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from pathlib import Path
1212
import unittest
1313
from unittest import mock
14+
from time import sleep
1415
from tests.common import with_tempdir
1516
from vunit.hashing import hash_string
1617
from vunit.test.runner import TestRunner
@@ -44,6 +45,35 @@ def test_runs_testcases_in_order(self, tempdir):
4445
self.assertTrue(report.result_of("test1").passed)
4546
self.assertTrue(report.result_of("test2").failed)
4647
self.assertTrue(report.result_of("test3").passed)
48+
self.assertEqual(test_case1.thread_id, 0)
49+
self.assertEqual(test_case2.thread_id, 0)
50+
self.assertEqual(test_case3.thread_id, 0)
51+
52+
@with_tempdir
53+
def test_runs_testcases_in_multiple_threads(self, tempdir):
54+
report = TestReport()
55+
runner = TestRunner(report, tempdir, num_threads=3)
56+
57+
test_cases = [self.create_test(f"test{n}", True) for n in range(1, 6)]
58+
test_list = TestList()
59+
for test_case in test_cases:
60+
test_list.add_test(test_case)
61+
62+
runner.run(test_list)
63+
64+
all_threads_called = False
65+
while not all_threads_called:
66+
all_threads_called = True
67+
for test_case in test_cases:
68+
if not test_case.called:
69+
all_threads_called = False
70+
sleep(0.1)
71+
72+
self.assertSetEqual(
73+
set([test_case.thread_id for test_case in test_cases]),
74+
set([0, 1, 2]),
75+
str([(test_case.name, test_case.thread_id) for test_case in test_cases]),
76+
)
4777

4878
@with_tempdir
4979
def test_fail_fast(self, tempdir):
@@ -68,6 +98,9 @@ def test_fail_fast(self, tempdir):
6898
self.assertEqual(order, ["test1", "test2"])
6999
self.assertTrue(report.result_of("test1").passed)
70100
self.assertTrue(report.result_of("test2").failed)
101+
self.assertEqual(test_case1.thread_id, 0)
102+
self.assertEqual(test_case2.thread_id, 0)
103+
self.assertEqual(test_case3.thread_id, None)
71104

72105
@with_tempdir
73106
def test_handles_python_exeception(self, tempdir):
@@ -223,15 +256,17 @@ def __init__(self, name, run_side_effect):
223256
self.name = name
224257
self.output_path = None
225258
self.read_output = None
259+
self.thread_id = None
226260
self.called = False
227261
self.run_side_effect = run_side_effect
228262

229-
def run(self, output_path, read_output):
263+
def run(self, output_path, read_output, thread_id):
230264
"""
231265
Mock run method that just records the arguments
232266
"""
233267
assert not self.called
234268
self.called = True
235269
self.output_path = output_path
236270
self.read_output = read_output
271+
self.thread_id = thread_id
237272
return self.run_side_effect(output_path=output_path, read_output=read_output)

tests/unit/test_test_suites.py

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -194,37 +194,47 @@ def test_runner_cfg_location(self):
194194
with create_tempdir() as tempdir:
195195
design_unit = Entity("tb_entity", file_name=str(Path(tempdir) / "file.vhd"))
196196
design_unit.generic_names = ["runner_cfg"]
197-
output_path = str(Path(__file__).parent / "sim_out")
198-
renew_path(output_path)
197+
vunit_output_path = str(Path(tempdir) / "vunit_out")
198+
renew_path(vunit_output_path)
199+
test_output_path = str(Path(vunit_output_path) / "test_out")
200+
simulator_root = str(Path(vunit_output_path) / "my_simulator")
199201

200202
class TestSimIf(SimulatorInterface):
201-
def __init__(self, output_path, gui, expect_runner_cfg_generic):
203+
def __init__(self, output_path, gui, expect_runner_cfg_generic, thread_id):
202204
super().__init__(output_path, gui)
203205
self._expect_runner_cfg_generic = expect_runner_cfg_generic
206+
self._thread_id = thread_id
204207

205-
def simulate(self, output_path, test_suite_name, config, elaborate_only):
208+
def simulate(self, output_path, simulator_output_path, test_suite_name, config, elaborate_only):
206209
tc = TestCase()
210+
tc.assertEqual(Path(output_path), Path(test_output_path))
211+
tc.assertEqual(Path(simulator_output_path), Path(simulator_root) / str(self._thread_id))
207212
if self._expect_runner_cfg_generic:
208213
tc.assertIn("runner_cfg", config.generics)
209-
tc.assertFalse((Path(output_path) / "test_sim" / "runner.cfg").exists())
214+
tc.assertFalse((Path(simulator_output_path) / "runner.cfg").exists())
210215
else:
211216
tc.assertNotIn("runner_cfg", config.generics)
212-
tc.assertTrue((Path(output_path) / "test_sim" / "runner.cfg").exists())
213-
214-
def get_simulator_output_path(self, output_path):
215-
return Path(output_path) / "test_sim"
217+
tc.assertTrue((Path(simulator_output_path) / "runner.cfg").exists())
216218

217219
for expect_runner_cfg_generic in [False, True]:
218-
config = Configuration(
219-
"name", design_unit, vhdl_config_name=None if expect_runner_cfg_generic else "cfg"
220-
)
221-
sim_if = TestSimIf(output_path, gui=False, expect_runner_cfg_generic=expect_runner_cfg_generic)
222-
223-
run = TestRun(
224-
simulator_if=sim_if,
225-
config=config,
226-
elaborate_only=False,
227-
test_suite_name=None,
228-
test_cases=["foo"],
229-
)
230-
run._simulate(output_path) # pylint: disable=protected-access
220+
for thread_id in range(2):
221+
renew_path(test_output_path)
222+
renew_path(simulator_root)
223+
config = Configuration(
224+
"name", design_unit, vhdl_config_name=None if expect_runner_cfg_generic else "cfg"
225+
)
226+
sim_if = TestSimIf(
227+
simulator_root,
228+
gui=False,
229+
expect_runner_cfg_generic=expect_runner_cfg_generic,
230+
thread_id=thread_id,
231+
)
232+
233+
test_run = TestRun(
234+
simulator_if=sim_if,
235+
config=config,
236+
elaborate_only=False,
237+
test_suite_name=None,
238+
test_cases=["foo"],
239+
)
240+
test_run.run(test_output_path, thread_id=thread_id, read_output=None)

vunit/persistent_tcl_shell.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def __init__(self, create_process):
2525
self._lock = threading.Lock()
2626
self._create_process = create_process
2727

28-
def _process(self):
28+
def _process(self, simulator_output_path):
2929
"""
3030
Create the vsim process
3131
"""
@@ -39,7 +39,7 @@ def _process(self):
3939
except KeyError:
4040
pass
4141

42-
process = self._create_process(ident)
42+
process = self._create_process(ident, simulator_output_path)
4343
self._processes[ident] = process
4444

4545
process.writeline("puts #VUNIT_RETURN")
@@ -53,27 +53,27 @@ def _process(self):
5353
raise
5454
return process
5555

56-
def execute(self, cmd):
56+
def execute(self, cmd, simulator_output_path):
5757
"""
5858
Execute a command to the persistent TCL shell
5959
"""
60-
process = self._process()
60+
process = self._process(simulator_output_path)
6161
process.writeline(cmd)
6262
process.writeline("puts #VUNIT_RETURN")
6363
process.consume_output(output_consumer)
6464

65-
def read_var(self, varname):
65+
def read_var(self, varname, simulator_output_path):
6666
"""
6767
Read a variable from the persistent TCL shell
6868
"""
69-
process = self._process()
69+
process = self._process(simulator_output_path)
7070
process.writeline(f"puts #VUNIT_READVAR=${varname!s}")
7171
consumer = ReadVarOutputConsumer()
7272
process.consume_output(consumer)
7373
return consumer.var
7474

75-
def read_bool(self, varname):
76-
result = self.read_var(varname)
75+
def read_bool(self, varname, simulator_output_path):
76+
result = self.read_var(varname, simulator_output_path)
7777
assert result in ("true", "false")
7878
return result == "true"
7979

0 commit comments

Comments
 (0)