From 7f68fcccf533d33e300057d131b5f55ae62c2ad5 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Thu, 25 Aug 2022 02:32:10 -0700 Subject: [PATCH] allow crtl tests to run in parallel --- .gitignore | 3 +- src/openpower/decoder/test/_pyrtl.py | 5 ++- src/openpower/decoder/test/crtl_path.py | 47 +++++++++++++++++++++++++ src/openpower/decoder/test/pysim.py | 28 +++++++-------- 4 files changed, 66 insertions(+), 17 deletions(-) create mode 100644 src/openpower/decoder/test/crtl_path.py diff --git a/.gitignore b/.gitignore index ea10fbc5..ee28534d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ dist *.il /jit_test /jit_test.o -/crtl +/crtl*/ +/crtl* diff --git a/src/openpower/decoder/test/_pyrtl.py b/src/openpower/decoder/test/_pyrtl.py index f7f33a9c..ed3039c8 100644 --- a/src/openpower/decoder/test/_pyrtl.py +++ b/src/openpower/decoder/test/_pyrtl.py @@ -4,6 +4,7 @@ from contextlib import contextmanager from nmigen.hdl.ast import SignalSet from nmigen.hdl.xfrm import ValueVisitor, StatementVisitor, LHSGroupFilter from nmigen.sim._base import BaseProcess +from openpower.decoder.test.crtl_path import get_crtl_path __all__ = ["PyRTLProcess"] @@ -462,7 +463,9 @@ class _FragmentCompiler: code += "#include \"common.h\"\n" code += emitter.flush() - file = open(f"crtl/{domain_process.name}.c", "w") + crtl = get_crtl_path() + + file = open(os.path.join(crtl, f"{domain_process.name}.c"), "w") file.write(code) file.close() diff --git a/src/openpower/decoder/test/crtl_path.py b/src/openpower/decoder/test/crtl_path.py new file mode 100644 index 00000000..27829963 --- /dev/null +++ b/src/openpower/decoder/test/crtl_path.py @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: LGPL-3-or-later +# Copyright 2022 Jacob Lifshay + + +from contextlib import contextmanager +from itertools import count +import os +from pathlib import Path +import shutil +from tempfile import NamedTemporaryFile +from threading import local + +__ctrl_path = local() + + +@contextmanager +def __try_lock_file(path): + path = Path(path) + try: + file = path.open("xb") + except FileExistsError: + yield False + return + try: + yield True + finally: + file.close() + path.unlink() + + +def get_crtl_path(): + # type: () -> str + path = getattr(__ctrl_path, "path", None) + if path is not None: + assert isinstance(path, str), "invalid state" + return path + for i in range(10000): + path = f"crtl{i}" + with __try_lock_file(f"crtl{i}.lock") as locked: + if locked and next(Path(path).glob(".lock_*"), None) is None: + shutil.rmtree(path, ignore_errors=True) + Path(path).mkdir(parents=True, exist_ok=True) + tmpfile = NamedTemporaryFile(prefix=".lock_", dir=path) + __ctrl_path.tmpfile = tmpfile + __ctrl_path.path = path + return path + assert False, "can't create crtl* path" diff --git a/src/openpower/decoder/test/pysim.py b/src/openpower/decoder/test/pysim.py index 0edf785e..7201de17 100644 --- a/src/openpower/decoder/test/pysim.py +++ b/src/openpower/decoder/test/pysim.py @@ -20,6 +20,7 @@ from cffi import FFI from os.path import dirname, join from collections import namedtuple +from openpower.decoder.test.crtl_path import get_crtl_path __all__ = ["PySimEngine"] @@ -316,14 +317,8 @@ class PySimEngine(BaseEngine): self._fragment = fragment - # blow away and recreate crtl subdirectory. (hope like hell - # nobody is using this in their current working directory) - if PySimEngine._crtl_counter == 0: - shutil.rmtree("crtl", True) - try: - os.mkdir("crtl") - except FileExistsError: - pass + # create crtl directory + crtl = get_crtl_path() # "Processes" are the compiled modules. Each module ends up # with its own run() function @@ -353,7 +348,7 @@ class PySimEngine(BaseEngine): cdef += f"void run_{process.name}(void);\n" # write out the header file - with open("crtl/common.h", "w") as cdef_file : + with open(os.path.join(crtl, "common.h"), "w") as cdef_file: cdef_file.write(cdef) # same with c template: read template first @@ -365,20 +360,23 @@ class PySimEngine(BaseEngine): src = template % (len(self._state.slots), len(self._state.slots)) # write it out - with open("crtl/common.c", "w") as src_file: + with open(os.path.join(crtl, "common.c"), "w") as src_file: src_file.write(src) # build module named crtlNNN in crtl subdirectory - modulename = "crtl.crtl%d" % PySimEngine._crtl_counter - sources = ["crtl/common.c"] - sources += [f"crtl/{process.name}.c" for process in self._processes] + modulename = f"{crtl}.crtl{PySimEngine._crtl_counter}" + sources = [os.path.join(crtl, "common.c")] + for process in self._processes: + sources.append(os.path.join(crtl, f"{process.name}.c")) ffibuilder = FFI() ffibuilder.cdef(cdef) ffibuilder.set_source(modulename, cdef, sources=sources) ffibuilder.compile(verbose=True) - + # append search path of crtl directory before attempting import - sys.path.append(os.path.join(os.getcwd())) + cwd = os.path.join(os.getcwd()) + if cwd not in sys.path: + sys.path.append(cwd) self._state.crtl = importlib.import_module(modulename).lib # Use a counter to generate unique names for modules, because Python -- 2.30.2