diff --git a/src/bashi/filter_software_dependency.py b/src/bashi/filter_software_dependency.py index 6244a7e..df65e82 100644 --- a/src/bashi/filter_software_dependency.py +++ b/src/bashi/filter_software_dependency.py @@ -117,3 +117,38 @@ def software_dependency_filter( ) return False return True + + # Rule: d4 + # Ubuntu 20.04 and newer is not available with CUDA older than 10.2 + + """ + if UBUNTU in row and row[UBUNTU].version >= pkv.parse("20.04"): + if ALPAKA_ACC_GPU_CUDA_ENABLE in row and row[ALPAKA_ACC_GPU_CUDA_ENABLE].version != OFF_VER: + if row[ALPAKA_ACC_GPU_CUDA_ENABLE].version < pkv.parse("10.2"): + reason( + output, + f"CUDA {row[ALPAKA_ACC_GPU_CUDA_ENABLE].version} " + "is not available in Ubuntu " + f"{__ubuntu_version_to_string(row[UBUNTU].version)}", + ) + return False + + """ + + if UBUNTU in row and row[UBUNTU].version >= pkv.parse("20.04"): + if ALPAKA_ACC_GPU_CUDA_ENABLE in row and row[ALPAKA_ACC_GPU_CUDA_ENABLE].version != OFF_VER: + if row[ALPAKA_ACC_GPU_CUDA_ENABLE].version < pkv.parse("11"): + reason( + output, + f"CUDA {row[ALPAKA_ACC_GPU_CUDA_ENABLE].version} " + "is not available in Ubuntu " + f"{__ubuntu_version_to_string(row[UBUNTU].version)}", + ) + return False + if DEVICE_COMPILER in row and row[DEVICE_COMPILER].name == NVCC: + if row[DEVICE_COMPILER].version < pkv.parse("11"): + return False + for compiler in (HOST_COMPILER, DEVICE_COMPILER): + if compiler in row and row[compiler].name == CLANG_CUDA: + if row[compiler].version < get_max_supported_clang_cuda_ver("11.0"): + return False diff --git a/src/bashi/results.py b/src/bashi/results.py index bff2586..a26fd59 100644 --- a/src/bashi/results.py +++ b/src/bashi/results.py @@ -4,7 +4,12 @@ from typeguard import typechecked from packaging.specifiers import SpecifierSet from bashi.types import ParameterValuePair, ParameterValueMatrix -from bashi.utils import get_expected_parameter_value_pairs, remove_parameter_value_pairs, bi_filter +from bashi.utils import ( + remove_parameter_value_pairs_ranges, + get_expected_parameter_value_pairs, + remove_parameter_value_pairs, + bi_filter, +) from bashi.globals import * # pylint: disable=wildcard-import,unused-wildcard-import from bashi.versions import ( COMPILERS, @@ -84,6 +89,7 @@ def get_expected_bashi_parameter_value_pairs( _remove_all_rocm_images_older_than_ubuntu2004_based( param_val_pair_list, removed_param_val_pair_list ) + _remove_unsupported_cuda_versions_for_ubuntu(param_val_pair_list, removed_param_val_pair_list) return (param_val_pair_list, removed_param_val_pair_list) @@ -827,3 +833,56 @@ def _remove_all_rocm_images_older_than_ubuntu2004_based( value_name2=HIPCC, value_version2=ANY_VERSION, ) + + +def _remove_unsupported_cuda_versions_for_ubuntu( + parameter_value_pairs: List[ParameterValuePair], + removed_parameter_value_pairs: List[ParameterValuePair], +): + remove_parameter_value_pairs_ranges( + parameter_value_pairs, + removed_parameter_value_pairs, + parameter1=UBUNTU, + value_name1=UBUNTU, + value_min_version1=20.04, + value_min_version1_inclusive=True, + value_max_version1=9999, + parameter2=ALPAKA_ACC_GPU_CUDA_ENABLE, + value_name2=ALPAKA_ACC_GPU_CUDA_ENABLE, + value_min_version2=OFF, + value_min_version2_inclusive=False, + value_max_version2=11, + value_max_version2_inclusive=True, + ) + + remove_parameter_value_pairs_ranges( + parameter_value_pairs, + removed_parameter_value_pairs, + parameter1=UBUNTU, + value_name1=UBUNTU, + value_min_version1=20.04, + value_min_version1_inclusive=True, + value_max_version1=9999, + parameter2=DEVICE_COMPILER, + value_name2=NVCC, + value_min_version2=OFF, + value_min_version2_inclusive=True, + value_max_version2=11, + value_max_version2_inclusive=False, + ) + for compiler_type in (HOST_COMPILER, DEVICE_COMPILER): + remove_parameter_value_pairs_ranges( + parameter_value_pairs, + removed_parameter_value_pairs, + parameter1=UBUNTU, + value_name1=UBUNTU, + value_min_version1=20.04, + value_min_version1_inclusive=True, + value_max_version1=9999, + parameter2=compiler_type, + value_name2=CLANG_CUDA, + value_min_version2=OFF, + value_min_version2_inclusive=True, + value_max_version2=12, + value_max_version2_inclusive=False, + ) diff --git a/src/bashi/utils.py b/src/bashi/utils.py index b868a2a..1eea828 100644 --- a/src/bashi/utils.py +++ b/src/bashi/utils.py @@ -484,3 +484,176 @@ def print_row_nice( f"{nice_version.get(val.version, str(val.version))} " ) print(s) + + +def _create_version_range( + min_version: Union[int, float, str], + min_version_inclusive: bool, + max_version: Union[int, float, str], + max_version_inclusive: bool, +) -> SpecifierSet: + """Creates Version SpecifierSet depending on the input. + Args: + min_version (Union[int, float, str]): Minimum version of the version range. Must be able + to be parsed into a `packaging.version.Version`. Use `ANY_VERSION` if the minimum range + should be open and every check for minimum version should return true. + min_version_inclusive (bool): If True, the minimum version is within the range and a check + for minimum version results in True. If False, the check for the minimum version results + in False. + max_version (Union[int, float, str]): Maximum version of the version range. Must be able + to be parsed into a `packaging.version.Version`. Use `ANY_VERSION` if the maximum range + should be open and every check for maximum version should return true. + max_version_inclusive (bool): If True, the maximum version is within the range and a check + for maximum version results in True. If False, the check for the maximum version results + in False. + Returns: + SpecifierSet: A SpecifierSet which can be used to check if version is inside the created + range. + """ + # if empty, it matches all versions + min_range = SpecifierSet() + max_range = SpecifierSet() + + if min_version != ANY_VERSION: + # check if valid version number + packaging.version.parse(str(min_version)) + min_range = SpecifierSet( + ">=" + str(min_version) if min_version_inclusive else ">" + str(min_version) + ) + + if max_version != ANY_VERSION: + # check if valid version number + packaging.version.parse(str(max_version)) + max_range = SpecifierSet( + "<=" + str(max_version) if max_version_inclusive else "<" + str(max_version) + ) + + return min_range & max_range + + +@typechecked +def remove_parameter_value_pairs_ranges( # pylint: disable=too-many-arguments + parameter_value_pairs: List[ParameterValuePair], + removed_parameter_value_pairs: List[ParameterValuePair], + parameter1: Parameter = ANY_PARAM, + value_name1: ValueName = ANY_NAME, + value_min_version1: Union[int, float, str] = ANY_VERSION, + value_min_version1_inclusive: bool = True, + value_max_version1: Union[int, float, str] = ANY_VERSION, + value_max_version1_inclusive: bool = True, + parameter2: Parameter = ANY_PARAM, + value_name2: ValueName = ANY_NAME, + value_min_version2: Union[int, float, str] = ANY_VERSION, + value_min_version2_inclusive: bool = True, + value_max_version2: Union[int, float, str] = ANY_VERSION, + value_max_version2_inclusive: bool = True, + symmetric: bool = True, +) -> bool: + """Removes all elements from `parameter_value_pairs` and moves them to + `removed_parameter_value_pairs` if certain filter requirements are met. The filter properties + are defined for the first and/or second parameter-value in a parameter-value-pair. All entries + that meet all requirements are removed from “parameter_value_pairs”. + The default values `ANY_PARAM`, `ANY_NAME` and `ANY_VERSION` match all values of each property, + which means if each argument is set to default, all elements of `parameter_value_pairs` are + removed.c + Parameter and value-name are checked for equality. + value_min_version and value_max_version allow you to define a version range that is to be + removed. By default, the version range is open in both directions (minimum and maximum version) + and can be restricted. If the version range is defined for both parameter values, the pair must + match both version ranges for it to be removed. + Args: + parameter_value_pairs (List[ParameterValuePair]): list where parameter-value-pairs will be + removed + removed_parameter_value_pairs (List[ParameterValuePair]): list where removed + parameter-value-pairs will be stored + parameter1 (Parameter, optional): Name of the first parameter. Defaults to ANY_PARAM. + value_name1 (ValueName, optional): Name of the first value-name. Defaults to ANY_NAME. + value_min_version1 (Union[int, float, str], optional): Minimum version of the version range + of the first value-version. All versions that are greater than this version are removed. + Defaults to ANY_VERSION. + value_min_version1_inclusive (bool, optional): If True, `value_min_version1` is removed. + Otherwise, all versions greater than `value_min_version1` are removed. Defaults to True. + value_max_version1 (Union[int, float, str], optional): Maximum version of the version range + of the first value-version. All versions that are smaller than this version are removed. + Defaults to ANY_VERSION. + value_max_version1_inclusive (bool, optional): If True, `value_max_version1` is removed. + Otherwise, all versions smaller than `value_max_version1` are removed. Defaults to True. + parameter2 (Parameter, optional): _description_. Defaults to ANY_PARAM. + value_name2 (ValueName, optional): _description_. Defaults to ANY_NAME. + value_min_version2 (Union[int, float, str], optional): Minimum version of the version range + of the second value-version. All versions that are greater than this version are + removed. Defaults to ANY_VERSION. + value_min_version2_inclusive (bool, optional): If True, `value_min_version2` is removed. + Otherwise, all versions greater than `value_min_version2` are removed. Defaults to True. + value_max_version2 (Union[int, float, str], optional): Maximum version of the version range + of the second value-version. All versions that are smaller than this version are + removed. Defaults to ANY_VERSION. + value_max_version2_inclusive (bool, optional): If True, `value_max_version2` is removed. + Otherwise, all versions smaller than `value_max_version2` are removed. Defaults to True. + symmetric (bool, optional): If symmetric is true, it does not matter whether a group of + parameters, value-name and value-version was found in the first or second + parameter-value. If false, it is taken into account whether the search criterion was + found in the first or second parameter value. Defaults to True. + Returns: + bool: Return True, if parameter-value-pair was removed. + """ + filter_list: List[Callable[[ParameterValuePair], bool]] = [] + if parameter1 != ANY_PARAM: + filter_list.append(lambda param_val: param_val.first.parameter == parameter1) + + if value_name1 != ANY_NAME: + filter_list.append(lambda param_val: param_val.first.parameterValue.name == value_name1) + + if parameter2 != ANY_PARAM: + filter_list.append(lambda param_val: param_val.second.parameter == parameter2) + + if value_name2 != ANY_NAME: + filter_list.append(lambda param_val: param_val.second.parameterValue.name == value_name2) + + range_ver1 = _create_version_range( + value_min_version1, + value_min_version1_inclusive, + value_max_version1, + value_max_version1_inclusive, + ) + filter_list.append(lambda param_val: param_val.first.parameterValue.version in range_ver1) + + range_ver2 = _create_version_range( + value_min_version2, + value_min_version2_inclusive, + value_max_version2, + value_max_version2_inclusive, + ) + filter_list.append(lambda param_val: param_val.second.parameterValue.version in range_ver2) + + def filter_func(param_value_pair: ParameterValuePair) -> bool: + return_value = True + + for f in filter_list: + return_value = return_value and f(param_value_pair) + + return not return_value + + len_before = len(parameter_value_pairs) + bi_filter(parameter_value_pairs, removed_parameter_value_pairs, filter_func) + + if symmetric: + remove_parameter_value_pairs_ranges( + parameter_value_pairs, + removed_parameter_value_pairs, + parameter2, + value_name2, + value_min_version2, + value_min_version2_inclusive, + value_max_version2, + value_max_version2_inclusive, + parameter1, + value_name1, + value_min_version1, + value_min_version1_inclusive, + value_max_version1, + value_max_version1_inclusive, + symmetric=False, + ) + + return len_before != len(parameter_value_pairs) diff --git a/src/bashi/versions.py b/src/bashi/versions.py index 80c83bf..afea9aa 100644 --- a/src/bashi/versions.py +++ b/src/bashi/versions.py @@ -232,3 +232,13 @@ def is_supported_version(name: ValueName, version: ValueVersion) -> bool: return True return False + + +def get_max_supported_clang_cuda_ver(cuda_version: str) -> str: + """Returns the latest supported Clang-CUDA version for a given CUDA version.""" + parsed_cuda_ver = pkv.parse(cuda_version) + + for sdk_support in CLANG_CUDA_MAX_CUDA_VERSION: + if pkv.parse(sdk_support.cuda) == parsed_cuda_ver: + max_clang_cuda_ver = pkv.parse(sdk_support.clang_cuda) + return max_clang_cuda_ver diff --git a/tests/test_filter_software_dependency.py b/tests/test_filter_software_dependency.py index 20419f1..3cf098c 100644 --- a/tests/test_filter_software_dependency.py +++ b/tests/test_filter_software_dependency.py @@ -302,3 +302,125 @@ def test_non_valid_ROCm_images_Ubuntu2004_based_d4(self): error_msg, f"{test_row}", ) + + def test_valid_cuda_versions_for_ubuntu_d3(self): + for CUDA_version in [10.2, 11.4, 15]: + self.assertTrue( + software_dependency_filter_typechecked( + OD( + { + ALPAKA_ACC_GPU_CUDA_ENABLE: ppv( + (ALPAKA_ACC_GPU_CUDA_ENABLE, CUDA_version) + ), + UBUNTU: ppv((UBUNTU, "22.04")), + } + ), + ) + ) + + self.assertTrue( + software_dependency_filter_typechecked( + OD( + { + ALPAKA_ACC_GPU_CUDA_ENABLE: ppv( + (ALPAKA_ACC_GPU_CUDA_ENABLE, CUDA_version) + ), + UBUNTU: ppv((UBUNTU, "22.04")), + } + ), + ) + ) + for CUDA_version in [10.2, 11.4, 15]: + self.assertTrue( + software_dependency_filter_typechecked( + OD( + { + ALPAKA_ACC_GPU_CUDA_ENABLE: ppv( + (ALPAKA_ACC_GPU_CUDA_ENABLE, CUDA_version) + ), + UBUNTU: ppv((UBUNTU, "20.04")), + } + ), + ) + ) + + self.assertTrue( + software_dependency_filter_typechecked( + OD( + { + ALPAKA_ACC_GPU_CUDA_ENABLE: ppv( + (ALPAKA_ACC_GPU_CUDA_ENABLE, CUDA_version) + ), + UBUNTU: ppv((UBUNTU, "20.04")), + } + ), + ) + ) + for CUDA_version in [2, 6, 10.1, 10.2, 11.4, 15]: + self.assertTrue( + software_dependency_filter_typechecked( + OD( + { + ALPAKA_ACC_GPU_CUDA_ENABLE: ppv( + (ALPAKA_ACC_GPU_CUDA_ENABLE, CUDA_version) + ), + UBUNTU: ppv((UBUNTU, "18.04")), + } + ), + ) + ) + + self.assertTrue( + software_dependency_filter_typechecked( + OD( + { + ALPAKA_ACC_GPU_CUDA_ENABLE: ppv( + (ALPAKA_ACC_GPU_CUDA_ENABLE, CUDA_version) + ), + UBUNTU: ppv((UBUNTU, "18.04")), + } + ), + ) + ) + + def test_not_valid_cuda_versions_for_ubuntu_d3(self): + for CUDA_version in [1, 6, 10.1]: + reason_msg = io.StringIO() + self.assertFalse( + software_dependency_filter_typechecked( + OD( + { + ALPAKA_ACC_GPU_CUDA_ENABLE: ppv( + (ALPAKA_ACC_GPU_CUDA_ENABLE, CUDA_version) + ), + UBUNTU: ppv((UBUNTU, "20.04")), + } + ), + reason_msg, + ), + f"CUDA {CUDA_version} is not available in Ubuntu 20.04", + ) + self.assertEqual( + reason_msg.getvalue(), + f"CUDA {CUDA_version} is not available in Ubuntu 20.04", + ) + for gcc_version in [1, 6, 10.1]: + reason_msg = io.StringIO() + self.assertFalse( + software_dependency_filter_typechecked( + OD( + { + ALPAKA_ACC_GPU_CUDA_ENABLE: ppv( + (ALPAKA_ACC_GPU_CUDA_ENABLE, CUDA_version) + ), + UBUNTU: ppv((UBUNTU, "22.04")), + } + ), + reason_msg, + ), + f"CUDA {CUDA_version} is not available in Ubuntu 22.04", + ) + self.assertEqual( + reason_msg.getvalue(), + f"CUDA {CUDA_version} is not available in Ubuntu 22.04", + ) diff --git a/tests/test_results.py b/tests/test_results.py index 4702fa8..229c74b 100644 --- a/tests/test_results.py +++ b/tests/test_results.py @@ -45,6 +45,7 @@ _remove_unsupported_gcc_versions_for_ubuntu2004, _remove_unsupported_cmake_versions_for_clangcuda, _remove_all_rocm_images_older_than_ubuntu2004_based, + _remove_unsupported_cuda_versions_for_ubuntu, ) from bashi.versions import NvccHostSupport, NVCC_GCC_MAX_VERSION @@ -2492,3 +2493,220 @@ def test_remove_all_rocm_images_older_than_ubuntu2004_based(self): expected_results, create_diff_parameter_value_pairs(test_param_value_pairs, expected_results), ) + + def test_remove_unsupported_cuda_versions_for_ubuntu(self): + test_param_value_pairs: List[ParameterValuePair] = parse_expected_val_pairs( + [ + OD({HOST_COMPILER: (GCC, 12), UBUNTU: (UBUNTU, 22.04)}), + OD({HOST_COMPILER: (CLANG_CUDA, 14), CMAKE: (CMAKE, "3.19")}), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "10.1"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "22.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "10.1"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "22.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "12"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "18.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "10.1"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "10.2"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "11.1"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "14.1"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "7.4"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, OFF), + } + ), + OD( + { + UBUNTU: (UBUNTU, "18.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, OFF), + } + ), + OD( + { + UBUNTU: (UBUNTU, "18.04"), + DEVICE_COMPILER: (NVCC, "11.2"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + DEVICE_COMPILER: (NVCC, "12"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + DEVICE_COMPILER: (NVCC, "10.1"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "22.04"), + DEVICE_COMPILER: (NVCC, "10"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + DEVICE_COMPILER: (CLANG_CUDA, "10"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + DEVICE_COMPILER: (CLANG_CUDA, "10.2"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "18.04"), + DEVICE_COMPILER: (CLANG_CUDA, "11"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "22.04"), + DEVICE_COMPILER: (CLANG_CUDA, "12"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + DEVICE_COMPILER: (CLANG_CUDA, "13"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "18.04"), + DEVICE_COMPILER: (NVCC, "10.2"), + } + ), + ] + ) + expected_results = parse_expected_val_pairs( + [ + OD( + { + UBUNTU: (UBUNTU, "18.04"), + DEVICE_COMPILER: (CLANG_CUDA, "11"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "22.04"), + DEVICE_COMPILER: (CLANG_CUDA, "12"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + DEVICE_COMPILER: (CLANG_CUDA, "13"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "18.04"), + DEVICE_COMPILER: (NVCC, "10.2"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "18.04"), + DEVICE_COMPILER: (NVCC, "11.2"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + DEVICE_COMPILER: (NVCC, "12"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "22.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "12"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, OFF), + } + ), + OD( + { + UBUNTU: (UBUNTU, "18.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, OFF), + } + ), + OD( + { + UBUNTU: (UBUNTU, "18.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "10.1"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "14.1"), + } + ), + OD( + { + UBUNTU: (UBUNTU, "20.04"), + ALPAKA_ACC_GPU_CUDA_ENABLE: (ALPAKA_ACC_GPU_CUDA_ENABLE, "11.1"), + } + ), + OD({HOST_COMPILER: (GCC, 12), UBUNTU: (UBUNTU, 22.04)}), + OD({HOST_COMPILER: (CLANG_CUDA, 14), CMAKE: (CMAKE, "3.19")}), + ] + ) + default_remove_test( + _remove_unsupported_cuda_versions_for_ubuntu, + test_param_value_pairs, + expected_results, + self, + ) + self.assertEqual( + test_param_value_pairs, + expected_results, + create_diff_parameter_value_pairs(test_param_value_pairs, expected_results), + )