Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 24 additions & 14 deletions dace/codegen/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -656,25 +656,29 @@ def get_folder_mode(object_folder: Union[pathlib.Path, str], probe: bool = False
folder_mode = F.readline().strip()
return folder_mode
else:
# This is to check an old style folder, i.e. a cache folder that was generated before
# the `FOLDER_MODE` file was introduced. We do some small sanity checks.
# This is to check an old style folder, i.e. a cache folder that was generated
# before the `FOLDER_MODE` file was introduced. We do some small sanity checks.
# TODO: Investigate if we should check for `program.sdfgz` and if it is not
# pressent assume that we just have some random folder.
# TODO: Phase out this feature, after there are no old style caches.
found_sub_folder = False
for sub_folder in ["build", "map", "src", "include", "sample"]:
if (object_folder / sub_folder).is_dir():
found_sub_folder = True
elif found_sub_folder:
raise NotADirectoryError(f'Expected that folder ``{object_folder}`` contains ``{sub_folder}``')

if found_sub_folder:
maybe_an_old_style_folder = (object_folder / "build").is_dir()
for sub_folder in ["map", "src", "include", "sample"]:
if (object_folder / sub_folder).is_dir() != maybe_an_old_style_folder:
if probe:
# TODO: This is an inconsistent folder, currently it is not an error
# but should it be one?
return None
raise NotADirectoryError(f'The old-style folder ``{object_folder}`` is inconsistent.')

if maybe_an_old_style_folder:
# All expected folders where found, so expect that this is a 'development' format folder.
return "development"
elif probe:
# None of the files where found. Thus this is probably an empty folder that just exist.
# None of the files where found and this is probe, so it is probably just an "empty" folder.
return None
else:
# Up for discussion what to do here.
raise NotADirectoryError(f'``{object_folder}`` does not appear to be a valid build folder.')
raise NotADirectoryError(f'``{object_folder}`` does not appear to be a valid old-style build folder.')


def get_binary_name(
Expand All @@ -685,15 +689,21 @@ def get_binary_name(
) -> pathlib.Path:
"""Returns the supposed location of the compiled library given the boundary conditions.

If folder mode is not explicitly given, then the function will use `get_folder_mode()`,
if this fails, then the `compiler.build_folder_mode` key is consulted.

:param object_folder: The build folder of the SDFG, i.e. `sdfg.build_folder`.
:param sdfg_name: The name of the SDFG, i.e. `sdfg.name`.
:param lib_extension: The extension of the library, i.e. file extension.
If not given the config option `compiler.library_extension` is used.
:param folder_mode: The save mode for the build folder. If not given the config
option `compiler.build_folder_mode` is used.
:param folder_mode: The mode of the build folder.
"""
if lib_extension is None:
lib_extension = Config.get('compiler', 'library_extension')

# First try `get_folder_mode()` if that failed, consult the configuration.
if folder_mode is None:
folder_mode = get_folder_mode(object_folder, probe=True)
if folder_mode is None:
folder_mode = Config.get('compiler', 'build_folder_mode')

Expand Down
84 changes: 83 additions & 1 deletion tests/compile_folder_mode_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def test_production_folder_mode():
assert not version_file.exists()

with pytest.raises(NotADirectoryError,
match=re.escape(f'``{build_folder}`` does not appear to be a valid build folder.')):
match=re.escape(f'``{build_folder}`` does not appear to be a valid old-style build folder.')):
sdfg_compiler.get_folder_mode(build_folder)

assert sdfg_compiler.get_folder_mode(build_folder, probe=True) is None
Expand Down Expand Up @@ -222,6 +222,83 @@ def test_build_with_scheme_one_and_then_switch():
)


def _expected_binary_path(
build_folder: pathlib.Path,
sdfg_name: str,
folder_mode: str,
lib_extension: str,
) -> pathlib.Path:
if folder_mode == "development":
return build_folder / "build" / f"lib{sdfg_name}.{lib_extension}"
assert folder_mode == "production"
return build_folder / f"lib{sdfg_name}.{lib_extension}"


def _test_get_binary_name_detects_folder_mode_switch_impl(
build_folder: pathlib.Path,
version1: str,
version2: str,
) -> None:
sdfg_name = "some_sdfg"
lib_extension = "so"
build_folder.mkdir()

with dace.config.temporary_config() as conf:
# The configuration keeps naming `version1`; after the switch only the
# `FOLDER_MODE` file knows about `version2`, so `get_binary_name()` must
# take the mode from the folder and not from the configuration.
conf.set('compiler', 'build_folder_mode', value=version1)

sdfg_compiler.generate_program_folder(None, [], str(build_folder), folder_mode=version1)
assert sdfg_compiler.get_folder_mode(build_folder) == version1

lib1_path = sdfg_compiler.get_binary_name(build_folder, sdfg_name=sdfg_name, lib_extension=lib_extension)
assert lib1_path == _expected_binary_path(build_folder, sdfg_name, version1, lib_extension)

# Now switch the folder to the second mode; the configuration still says `version1`.
sdfg_compiler.generate_program_folder(None, [], str(build_folder), folder_mode=version2)
assert sdfg_compiler.get_folder_mode(build_folder) == version2

lib2_path = sdfg_compiler.get_binary_name(build_folder, sdfg_name=sdfg_name, lib_extension=lib_extension)
assert lib2_path == _expected_binary_path(build_folder, sdfg_name, version2, lib_extension)
assert lib1_path != lib2_path


def test_get_binary_name_detects_folder_mode_switch(tmp_path):
_test_get_binary_name_detects_folder_mode_switch_impl(
build_folder=tmp_path / "dev_to_prod",
version1="development",
version2="production",
)
_test_get_binary_name_detects_folder_mode_switch_impl(
build_folder=tmp_path / "prod_to_dev",
version1="production",
version2="development",
)


def test_get_folder_mode_probes_inconsistent_old_style_folder(tmp_path):
# An old-style development folder that was generated but never compiled, i.e.
# there is no `FOLDER_MODE` file and no `build` folder. Such a folder is
# inconsistent, thus probing must return `None` and `get_binary_name()` must
# fall back to the configuration instead of raising.
build_folder = tmp_path / "old_style_never_compiled"
build_folder.mkdir()
for sub_folder in ["map", "src", "include", "sample"]:
(build_folder / sub_folder).mkdir()

assert sdfg_compiler.get_folder_mode(build_folder, probe=True) is None
with pytest.raises(NotADirectoryError,
match=re.escape(f'The old-style folder ``{build_folder}`` is inconsistent.')):
sdfg_compiler.get_folder_mode(build_folder)

for folder_mode in ["development", "production"]:
with dace.config.temporary_config() as conf:
conf.set('compiler', 'build_folder_mode', value=folder_mode)
lib_path = sdfg_compiler.get_binary_name(build_folder, sdfg_name="some_sdfg", lib_extension="so")
assert lib_path == _expected_binary_path(build_folder, "some_sdfg", folder_mode, "so")


def test_already_loaded_and_comple_again():
_test_build_with_scheme_one_and_then_switch_impl(
version1="development",
Expand All @@ -234,7 +311,12 @@ def test_already_loaded_and_comple_again():


if __name__ == '__main__':
import tempfile
test_development_folder_mode()
test_production_folder_mode()
test_already_loaded_and_comple_again()
test_build_with_scheme_one_and_then_switch()
with tempfile.TemporaryDirectory() as tmp_dir:
test_get_binary_name_detects_folder_mode_switch(pathlib.Path(tmp_dir))
with tempfile.TemporaryDirectory() as tmp_dir:
test_get_folder_mode_probes_inconsistent_old_style_folder(pathlib.Path(tmp_dir))
2 changes: 1 addition & 1 deletion tests/wcr_cudatest.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def create_zero_initialization(init_state: dace.SDFGState, array_name):


def create_test_sdfg():
sdfg = dace.SDFG('test_sdfg')
sdfg = dace.SDFG('test_sdfg_super_random_string')

sdfg.add_array('BETA', shape=[10], dtype=dace.float32)
sdfg.add_array('BETA_MAX', shape=[1], dtype=dace.float32)
Expand Down