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
69 changes: 35 additions & 34 deletions easybuild/framework/easyblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -4439,48 +4439,49 @@ def xs2str(xs):
else:
self._sanity_check_step_extensions()

linked_shared_lib_fails = self.sanity_check_linked_shared_libs()
if linked_shared_lib_fails:
self.log.warning("Check for required/banned linked shared libraries failed!")
self.sanity_check_fail_msgs.append(linked_shared_lib_fails)

# software installed with GCCcore toolchain should not have Fortran module files (.mod),
# unless that's explicitly allowed
if self.toolchain.name in ('GCCcore',) and not self.cfg['skip_mod_files_sanity_check']:
mod_files_found_msg = self.sanity_check_mod_files()
if mod_files_found_msg:
if build_option('fail_on_mod_files_gcccore'):
self.sanity_check_fail_msgs.append(mod_files_found_msg)
# Do not do those checks for extensions, only in the main easyconfig
linked_shared_lib_fails = self.sanity_check_linked_shared_libs()
if linked_shared_lib_fails:
self.log.warning("Check for required/banned linked shared libraries failed!")
self.sanity_check_fail_msgs.append(linked_shared_lib_fails)

# software installed with GCCcore toolchain should not have Fortran module files (.mod),
# unless that's explicitly allowed
if self.toolchain.name in ('GCCcore',) and not self.cfg['skip_mod_files_sanity_check']:
mod_files_found_msg = self.sanity_check_mod_files()
if mod_files_found_msg:
if build_option('fail_on_mod_files_gcccore'):
self.sanity_check_fail_msgs.append(mod_files_found_msg)
else:
print_warning(mod_files_found_msg)

if self.toolchain.use_rpath:
rpath_fails = self.sanity_check_rpath()
if rpath_fails:
self.log.warning("RPATH sanity check failed!")
self.sanity_check_fail_msgs.extend(rpath_fails)
else:
self.log.debug("Skipping RPATH sanity check")

if 'CUDA' in [dep['name'] for dep in self.cfg.dependencies()]:
if shutil.which('cuobjdump'):
cuda_fails = self.sanity_check_cuda()
if cuda_fails:
self.log.warning("CUDA device code sanity check failed!")
self.sanity_check_fail_msgs.extend(cuda_fails)
else:
print_warning(mod_files_found_msg)
msg = "Failed to execute CUDA sanity check: cuobjdump not found\n"
msg += "CUDA module must be loaded for sanity check (or cuobjdump available in PATH)"
raise EasyBuildError(msg)
else:
self.log.debug("Skipping CUDA sanity check: CUDA is not in dependencies")

# cleanup
if self.fake_mod_data:
self.clean_up_fake_module(self.fake_mod_data)
self.sanity_check_module_loaded = False
self.fake_mod_data = None

if self.toolchain.use_rpath:
rpath_fails = self.sanity_check_rpath()
if rpath_fails:
self.log.warning("RPATH sanity check failed!")
self.sanity_check_fail_msgs.extend(rpath_fails)
else:
self.log.debug("Skipping RPATH sanity check")

if 'CUDA' in [dep['name'] for dep in self.cfg.dependencies()]:
if shutil.which('cuobjdump'):
cuda_fails = self.sanity_check_cuda()
if cuda_fails:
self.log.warning("CUDA device code sanity check failed!")
self.sanity_check_fail_msgs.extend(cuda_fails)
else:
msg = "Failed to execute CUDA sanity check: cuobjdump not found\n"
msg += "CUDA module must be loaded for sanity check (or cuobjdump available in PATH)"
raise EasyBuildError(msg)
else:
self.log.debug("Skipping CUDA sanity check: CUDA is not in dependencies")

# pass or fail
if self.sanity_check_fail_msgs:
raise EasyBuildError(
Expand Down
26 changes: 15 additions & 11 deletions test/framework/toy_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -3087,6 +3087,8 @@ def test_toy_cuda_sanity_check(self):
" 'cp %s %s/pytoy-cuda.cpython-39-x86_64-linux-gnu.%s'," % (toy_bin, py_site_pkgs, shlib_ext),
" 'cp %s %s/plugins/libpytoy_cuda.%s'," % (toy_bin, py_site_pkgs, shlib_ext),
"]",
"exts_list = [('bar', '0.0')]",
"exts_defaultclass = 'DummyExtension'",
])
write_file(toy_ec_cuda, toy_ec_txt)

Expand Down Expand Up @@ -3235,7 +3237,9 @@ def assert_in_log_and_stdout(s):
with self.mocked_stdout_stderr():
outtxt = self._test_toy_build(ec_file=toy_ec_cuda, extra_args=args, raise_error=True)
stdout = self.get_stdout()
assert_cuda_report(missing_cc=0, additional_cc=0, missing_ptx=3, log=outtxt, stdout=stdout)
assert_cuda_report(missing_cc=0, additional_cc=0, missing_ptx=4, log=outtxt, stdout=stdout)
self.assertEqual(outtxt.count("CUDA sanity check summary report"), 1,
"CUDA sanity check should be done exactly once")

# Test case 1b: test with default options, --cuda-compute-capabilities=8.0 and a binary that contains
# 7.0 and 9.0 device code and 8.0 PTX code.
Expand All @@ -3256,21 +3260,21 @@ def assert_in_log_and_stdout(s):
stdout = self.get_stdout()
self.assertIn(device_additional_70_90_code_msg, outtxt)
self.assertIn(device_missing_80_code_msg, outtxt)
assert_cuda_report(missing_cc=3, additional_cc=3, missing_ptx=0, log=outtxt, stdout=stdout)
assert_cuda_report(missing_cc=4, additional_cc=4, missing_ptx=0, log=outtxt, stdout=stdout)

# Test case 2: same as Test case 1, but add --cuda-sanity-check-error-on-failed-checks
# This is expected to fail since there is missing device code for CC80
args = ['--cuda-compute-capabilities=8.0', '--cuda-sanity-check-error-on-failed-checks']
# We expect this to fail, so first check error, then run again to check output
error_pattern = r"Files missing CUDA device code: 3."
error_pattern = r"Files missing CUDA device code: 4."
with self.mocked_stdout_stderr():
self.assertErrorRegex(EasyBuildError, error_pattern, self._test_toy_build, ec_file=toy_ec_cuda,
extra_args=args, raise_error=True)
outtxt = self._test_toy_build(ec_file=toy_ec_cuda, extra_args=args, raise_error=False, verify=False)
stdout = self.get_stdout()
self.assertIn(device_additional_70_90_code_msg, outtxt)
self.assertIn(device_missing_80_code_msg, outtxt)
assert_cuda_report(missing_cc=3, additional_cc=3, missing_ptx=0, log=outtxt, stdout=stdout)
assert_cuda_report(missing_cc=4, additional_cc=4, missing_ptx=0, log=outtxt, stdout=stdout)

# Test case 3: same as Test case 2, but add --cuda-sanity-check-accept-ptx-as-devcode
# This is expected to succeed, since now the PTX code for CC80 will be accepted as
Expand All @@ -3284,22 +3288,22 @@ def assert_in_log_and_stdout(s):
stdout = self.get_stdout()
self.assertIn(device_additional_70_90_code_msg, outtxt)
self.assertIn(device_missing_80_code_msg, outtxt)
assert_cuda_report(missing_cc=0, additional_cc=3, missing_ptx=0, log=outtxt, stdout=stdout,
missing_cc_but_ptx=3)
assert_cuda_report(missing_cc=0, additional_cc=4, missing_ptx=0, log=outtxt, stdout=stdout,
missing_cc_but_ptx=4)

# Test case 4: same as Test case 2, but run with --cuda-compute-capabilities=9.0
# This is expected to fail: device code is present, but PTX code for the highest CC (9.0) is missing
args = ['--cuda-compute-capabilities=9.0', '--cuda-sanity-check-error-on-failed-checks']
# We expect this to fail, so first check error, then run again to check output
error_pattern = r"Files missing CUDA PTX code: 3"
error_pattern = r"Files missing CUDA PTX code: 4"
with self.mocked_stdout_stderr():
self.assertErrorRegex(EasyBuildError, error_pattern, self._test_toy_build, ec_file=toy_ec_cuda,
extra_args=args, raise_error=True)
outtxt = self._test_toy_build(ec_file=toy_ec_cuda, extra_args=args, raise_error=False, verify=False)
stdout = self.get_stdout()
self.assertIn(device_additional_70_code_msg, outtxt)

assert_cuda_report(missing_cc=0, additional_cc=3, missing_ptx=3, log=outtxt, stdout=stdout)
assert_cuda_report(missing_cc=0, additional_cc=4, missing_ptx=4, log=outtxt, stdout=stdout)

# Test case 5: same as Test case 4, but add --cuda-sanity-check-accept-missing-ptx
# This is expected to succeed: device code is present, PTX code is missing, but that's accepted
Expand All @@ -3314,22 +3318,22 @@ def assert_in_log_and_stdout(s):
stdout = self.get_stdout()
self.assertIn(device_additional_70_code_msg, outtxt)
self.assertRegex(outtxt, warning_pattern)
assert_cuda_report(missing_cc=0, additional_cc=3, missing_ptx=3, log=outtxt, stdout=stdout)
assert_cuda_report(missing_cc=0, additional_cc=4, missing_ptx=4, log=outtxt, stdout=stdout)

# Test case 6: same as Test case 5, but add --cuda-sanity-check-strict
# This is expected to fail: device code is present, PTX code is missing (but accepted due to option)
# but additional device code is present, which is not allowed by --cuda-sanity-check-strict
args = ['--cuda-compute-capabilities=9.0', '--cuda-sanity-check-error-on-failed-checks',
'--cuda-sanity-check-accept-missing-ptx', '--cuda-sanity-check-strict']
# We expect this to fail, so first check error, then run again to check output
error_pattern = r"Files with additional CUDA device code: 3"
error_pattern = r"Files with additional CUDA device code: 4"
with self.mocked_stdout_stderr():
self.assertErrorRegex(EasyBuildError, error_pattern, self._test_toy_build, ec_file=toy_ec_cuda,
extra_args=args, raise_error=True)
outtxt = self._test_toy_build(ec_file=toy_ec_cuda, extra_args=args, raise_error=False, verify=False)
stdout = self.get_stdout()
self.assertIn(device_additional_70_code_msg, outtxt)
assert_cuda_report(missing_cc=0, additional_cc=3, missing_ptx=3, log=outtxt, stdout=stdout)
assert_cuda_report(missing_cc=0, additional_cc=4, missing_ptx=4, log=outtxt, stdout=stdout)

# Test case 7: same as Test case 6, but add the failing file to the cuda_sanity_ignore_files
# This is expected to succeed: the individual file which _would_ cause the sanity check to fail is
Expand Down
Loading