From d0b22df0321f01c28b83f8f4c3aed4727fbb7550 Mon Sep 17 00:00:00 2001 From: Simeon Ehrig Date: Wed, 14 Feb 2024 16:30:51 +0100 Subject: [PATCH 1/2] add rule which disallow clang-cuda 13 and older --- bashi/filter_compiler_version.py | 13 ++++ bashi/generator.py | 5 ++ bashi/versions.py | 8 ++- tests/test_clang_cuda_filter.py | 78 +++++++++++++++++++++ tests/test_filter_compiler_version.py | 4 +- tests/test_params_value_matrix_generator.py | 11 ++- 6 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 tests/test_clang_cuda_filter.py diff --git a/bashi/filter_compiler_version.py b/bashi/filter_compiler_version.py index 78f445d..cd1dd80 100644 --- a/bashi/filter_compiler_version.py +++ b/bashi/filter_compiler_version.py @@ -116,4 +116,17 @@ def compiler_version_filter( return False break + # Rule: v5 + # clang-cuda 13 and older is not supported + # this rule will be never used, because of an implementation detail of the covertable library + # it is not possible to add the clang-cuda versions and filter it out afterwards + # this rule is only used by bashi-verify + if ( + DEVICE_COMPILER in row + and row[DEVICE_COMPILER].name == CLANG_CUDA + and row[DEVICE_COMPILER].version < pkv.parse("14") + ): + reason(output, "all clang versions older than 14 are disabled as CUDA Compiler") + return False + return True diff --git a/bashi/generator.py b/bashi/generator.py index 42a68bf..9b55763 100644 --- a/bashi/generator.py +++ b/bashi/generator.py @@ -33,6 +33,11 @@ def generate_combination_list( """ filter_chain = get_default_filter_chain(custom_filter) + # TODO(SimeonEhrig): add filter function here, which remove NVCC as host compiler and + # CLANG-CUDA 13 and older as compiler + # the covertable throws an error, if the filter rule removes to much possibilities in an early + # filter + comb_list: CombinationList = [] all_pairs: List[Dict[Parameter, ParameterValue]] = make( diff --git a/bashi/versions.py b/bashi/versions.py index 304e248..4ac9d35 100644 --- a/bashi/versions.py +++ b/bashi/versions.py @@ -111,6 +111,7 @@ def __str__(self) -> str: NVCC_CLANG_MAX_VERSION.sort(reverse=True) +# pylint: disable=too-many-branches def get_parameter_value_matrix() -> ParameterValueMatrix: """Generates a parameter-value-matrix from all supported compilers, softwares and compilation configuration. @@ -133,9 +134,10 @@ def get_parameter_value_matrix() -> ParameterValueMatrix: continue if sw_name in COMPILERS: for sw_version in sw_versions: - param_val_matrix[compiler_type].append( - ParameterValue(sw_name, pkv.parse(str(sw_version))) - ) + if not (sw_name == CLANG_CUDA and pkv.parse(str(sw_version)) < pkv.parse("14")): + param_val_matrix[compiler_type].append( + ParameterValue(sw_name, pkv.parse(str(sw_version))) + ) for backend in BACKENDS: if backend == ALPAKA_ACC_GPU_CUDA_ENABLE: diff --git a/tests/test_clang_cuda_filter.py b/tests/test_clang_cuda_filter.py new file mode 100644 index 0000000..5e3adf4 --- /dev/null +++ b/tests/test_clang_cuda_filter.py @@ -0,0 +1,78 @@ +# pylint: disable=missing-docstring +import unittest +import io + +from collections import OrderedDict as OD +from utils_test import parse_param_val as ppv +from bashi.globals import * # pylint: disable=wildcard-import,unused-wildcard-import +from bashi.filter_compiler_version import compiler_version_filter_typechecked + + +class TestClangCudaOldVersions(unittest.TestCase): + def test_valid_clang_cuda_versions_rule_v5(self): + for clang_cuda_version in [14, 16, 18, 78]: + self.assertTrue( + compiler_version_filter_typechecked( + OD( + { + HOST_COMPILER: ppv((CLANG_CUDA, clang_cuda_version)), + DEVICE_COMPILER: ppv((CLANG_CUDA, clang_cuda_version)), + } + ) + ) + ) + + def test_valid_clang_cuda_versions_multi_row_rule_v5(self): + for clang_cuda_version in [14, 16, 18, 78]: + self.assertTrue( + compiler_version_filter_typechecked( + OD( + { + HOST_COMPILER: ppv((CLANG_CUDA, clang_cuda_version)), + ALPAKA_ACC_GPU_CUDA_ENABLE: ppv((ALPAKA_ACC_GPU_CUDA_ENABLE, 11.2)), + DEVICE_COMPILER: ppv((CLANG_CUDA, clang_cuda_version)), + CMAKE: ppv((CMAKE, 3.22)), + } + ), + ) + ) + + def test_invalid_clang_cuda_versions_rule_v5(self): + for clang_cuda_version in [13, 7, 1]: + reason_msg = io.StringIO() + self.assertFalse( + compiler_version_filter_typechecked( + OD( + { + HOST_COMPILER: ppv((CLANG_CUDA, clang_cuda_version)), + DEVICE_COMPILER: ppv((CLANG_CUDA, clang_cuda_version)), + } + ), + reason_msg, + ) + ) + self.assertEqual( + reason_msg.getvalue(), + "all clang versions older than 14 are disabled as CUDA Compiler", + ) + + def test_invalid_clang_cuda_versions_multi_row_rule_v5(self): + for clang_cuda_version in [13, 7, 1]: + reason_msg = io.StringIO() + self.assertFalse( + compiler_version_filter_typechecked( + OD( + { + HOST_COMPILER: ppv((CLANG_CUDA, clang_cuda_version)), + ALPAKA_ACC_GPU_CUDA_ENABLE: ppv((ALPAKA_ACC_GPU_CUDA_ENABLE, 11.2)), + DEVICE_COMPILER: ppv((CLANG_CUDA, clang_cuda_version)), + CMAKE: ppv((CMAKE, 3.22)), + } + ), + reason_msg, + ) + ) + self.assertEqual( + reason_msg.getvalue(), + "all clang versions older than 14 are disabled as CUDA Compiler", + ) diff --git a/tests/test_filter_compiler_version.py b/tests/test_filter_compiler_version.py index 25742a4..1d44f89 100644 --- a/tests/test_filter_compiler_version.py +++ b/tests/test_filter_compiler_version.py @@ -33,9 +33,9 @@ def test_valid_combination_rule_v1(self): compiler_version_filter_typechecked( OD( { - HOST_COMPILER: ppv((CLANG_CUDA, 10)), + HOST_COMPILER: ppv((CLANG_CUDA, 14)), ALPAKA_ACC_GPU_CUDA_ENABLE: ppv((ALPAKA_ACC_GPU_CUDA_ENABLE, 11.2)), - DEVICE_COMPILER: ppv((CLANG_CUDA, 10)), + DEVICE_COMPILER: ppv((CLANG_CUDA, 14)), CMAKE: ppv((CMAKE, 3.18)), } ) diff --git a/tests/test_params_value_matrix_generator.py b/tests/test_params_value_matrix_generator.py index 97db279..27d3527 100644 --- a/tests/test_params_value_matrix_generator.py +++ b/tests/test_params_value_matrix_generator.py @@ -1,5 +1,6 @@ # pylint: disable=missing-docstring import unittest +import packaging.version as pkv from bashi.versions import VERSIONS, get_parameter_value_matrix from bashi.globals import * # pylint: disable=wildcard-import,unused-wildcard-import @@ -25,7 +26,15 @@ def test_all_params_in(self): def test_number_host_device_compiler(self): extended_versions = VERSIONS.copy() - extended_versions[CLANG_CUDA] = extended_versions[CLANG] + # filter clang-cuda 13 and older because the pair-wise generator cannot filter it out + # afterwards + extended_versions[CLANG_CUDA] = list( + filter( + lambda clang_version: pkv.parse(str(clang_version)) >= pkv.parse("14"), + extended_versions[CLANG], + ) + ) + number_of_host_compilers = 0 for compiler in COMPILERS: if compiler != NVCC: From 5d025ad7b5bb3a27621807da43a84c2904c9c9f6 Mon Sep 17 00:00:00 2001 From: Simeon Ehrig Date: Thu, 15 Feb 2024 10:56:33 +0100 Subject: [PATCH 2/2] generate_combination_list() filters now the parameter-value-matrix - it is not necessary to avoid specific parameter-values such like nvcc as host-compiler anymore - filters also clang-cuda 13 and older - replace .copy() with deepcopy() solve some memory problems --- bashi/generator.py | 42 ++++++++++-- bashi/utils.py | 42 ++++++++++-- bashi/versions.py | 17 ++--- tests/test_expected_parameter_value_pairs.py | 3 +- tests/test_generate_combination_list.py | 69 +++++++++++++++++++- tests/test_params_value_matrix_generator.py | 16 ++--- 6 files changed, 152 insertions(+), 37 deletions(-) diff --git a/bashi/generator.py b/bashi/generator.py index 9b55763..35c4702 100644 --- a/bashi/generator.py +++ b/bashi/generator.py @@ -2,6 +2,8 @@ from typing import Dict, List from collections import OrderedDict +import copy +import packaging.version as pkv from covertable import make # type: ignore @@ -13,6 +15,7 @@ Combination, CombinationList, ) +from bashi.globals import * # pylint: disable=wildcard-import,unused-wildcard-import from bashi.filter_chain import get_default_filter_chain @@ -31,17 +34,44 @@ def generate_combination_list( Returns: CombinationList: combination-list """ + # use local version to do not modify parameter_value_matrix + local_param_val_mat = copy.deepcopy(parameter_value_matrix) + filter_chain = get_default_filter_chain(custom_filter) - # TODO(SimeonEhrig): add filter function here, which remove NVCC as host compiler and - # CLANG-CUDA 13 and older as compiler - # the covertable throws an error, if the filter rule removes to much possibilities in an early - # filter + def host_compiler_filter(param_val: ParameterValue) -> bool: + # Rule: n1 + # remove nvcc as host compiler + if param_val.name == NVCC: + return False + # Rule: v5 + # remove clang-cuda older than 14 + if param_val.name == CLANG_CUDA and param_val.version < pkv.parse("14"): + return False + + return True + + def device_compiler_filter(param_val: ParameterValue) -> bool: + # Rule: v5 + # remove clang-cuda older than 14 + if param_val.name == CLANG_CUDA and param_val.version < pkv.parse("14"): + return False + + return True + + pre_filters = {HOST_COMPILER: host_compiler_filter, DEVICE_COMPILER: device_compiler_filter} + + # some filter rules requires that specific parameter-values are already removed from the + # parameter-value-matrix + # otherwise the covertable library throws an error + for param, filter_func in pre_filters.items(): + if param in local_param_val_mat: + local_param_val_mat[param] = list(filter(filter_func, local_param_val_mat[param])) comb_list: CombinationList = [] all_pairs: List[Dict[Parameter, ParameterValue]] = make( - factors=parameter_value_matrix, + factors=local_param_val_mat, length=2, pre_filter=filter_chain, ) # type: ignore @@ -51,7 +81,7 @@ def generate_combination_list( tmp_comb: Combination = OrderedDict({}) # covertable does not keep the ordering of the parameters # therefore we sort it - for param in parameter_value_matrix.keys(): + for param in local_param_val_mat.keys(): tmp_comb[param] = all_pair[param] comb_list.append(tmp_comb) diff --git a/bashi/utils.py b/bashi/utils.py index 231b7a2..90afef4 100644 --- a/bashi/utils.py +++ b/bashi/utils.py @@ -2,6 +2,7 @@ import dataclasses import sys +import copy from collections import OrderedDict from typing import IO, Dict, List, Optional, Union @@ -316,7 +317,9 @@ def reason(output: Optional[IO[str]], msg: str): ) +# TODO(SimeonEhrig) modularize the function # pylint: disable=too-many-branches +# pylint: disable=too-many-locals @typechecked def get_expected_bashi_parameter_value_pairs( parameter_matrix: ParameterValueMatrix, @@ -331,9 +334,34 @@ def get_expected_bashi_parameter_value_pairs( Returns: List[ParameterValuePair]: list of all parameter-value-pairs supported by bashi """ - param_val_pair_list = get_expected_parameter_value_pairs(parameter_matrix) + local_parameter_matrix = copy.deepcopy(parameter_matrix) - extend_versions = VERSIONS.copy() + def remove_host_compiler_nvcc(param_val: ParameterValue) -> bool: + if param_val.name == NVCC: + return False + return True + + # remove nvcc as host compiler + local_parameter_matrix[HOST_COMPILER] = list( + filter(remove_host_compiler_nvcc, local_parameter_matrix[HOST_COMPILER]) + ) + + # remove clang-cuda 13 and older + def remove_unsupported_clang_cuda_version(param_val: ParameterValue) -> bool: + if param_val.name == CLANG_CUDA and param_val.version < packaging.version.parse("14"): + return False + return True + + local_parameter_matrix[HOST_COMPILER] = list( + filter(remove_unsupported_clang_cuda_version, local_parameter_matrix[HOST_COMPILER]) + ) + local_parameter_matrix[DEVICE_COMPILER] = list( + filter(remove_unsupported_clang_cuda_version, local_parameter_matrix[DEVICE_COMPILER]) + ) + + param_val_pair_list = get_expected_parameter_value_pairs(local_parameter_matrix) + + extend_versions = copy.deepcopy(VERSIONS) extend_versions[CLANG_CUDA] = extend_versions[CLANG] # remove all combinations where nvcc is device compiler and the host compiler is not gcc or @@ -390,15 +418,15 @@ def get_expected_bashi_parameter_value_pairs( gcc_versions = [packaging.version.parse(str(v)) for v in VERSIONS[GCC]] gcc_versions.sort() for nvcc_version in nvcc_versions: - for max_nvcc_clang_version in NVCC_GCC_MAX_VERSION: - if nvcc_version >= max_nvcc_clang_version.nvcc: - for clang_version in gcc_versions: - if clang_version > max_nvcc_clang_version.host: + for max_nvcc_gcc_version in NVCC_GCC_MAX_VERSION: + if nvcc_version >= max_nvcc_gcc_version.nvcc: + for gcc_version in gcc_versions: + if gcc_version > max_nvcc_gcc_version.host: remove_parameter_value_pair( to_remove=create_parameter_value_pair( HOST_COMPILER, GCC, - clang_version, + gcc_version, DEVICE_COMPILER, NVCC, nvcc_version, diff --git a/bashi/versions.py b/bashi/versions.py index 4ac9d35..ce4ee1a 100644 --- a/bashi/versions.py +++ b/bashi/versions.py @@ -1,5 +1,6 @@ """Provides all supported software versions""" +import copy from typing import Dict, List, Union from collections import OrderedDict from typeguard import typechecked @@ -121,23 +122,17 @@ def get_parameter_value_matrix() -> ParameterValueMatrix: """ param_val_matrix: ParameterValueMatrix = OrderedDict() - extended_version = VERSIONS.copy() + extended_version = copy.deepcopy(VERSIONS) extended_version[CLANG_CUDA] = extended_version[CLANG] for compiler_type in [HOST_COMPILER, DEVICE_COMPILER]: param_val_matrix[compiler_type] = [] for sw_name, sw_versions in extended_version.items(): - # do not add NVCC as HOST_COMPILER - # filtering out all NVCC as HOST_COMPILER later does not work with the covertable - # library - if compiler_type == HOST_COMPILER and sw_name == NVCC: - continue if sw_name in COMPILERS: for sw_version in sw_versions: - if not (sw_name == CLANG_CUDA and pkv.parse(str(sw_version)) < pkv.parse("14")): - param_val_matrix[compiler_type].append( - ParameterValue(sw_name, pkv.parse(str(sw_version))) - ) + param_val_matrix[compiler_type].append( + ParameterValue(sw_name, pkv.parse(str(sw_version))) + ) for backend in BACKENDS: if backend == ALPAKA_ACC_GPU_CUDA_ENABLE: @@ -180,7 +175,7 @@ def is_supported_version(name: ValueName, version: ValueVersion) -> bool: if name not in known_names: raise ValueError(f"Unknown software name: {name}") - local_versions = VERSIONS.copy() + local_versions = copy.deepcopy(VERSIONS) local_versions[CLANG_CUDA] = local_versions[CLANG] local_versions[ALPAKA_ACC_GPU_CUDA_ENABLE] = [OFF] diff --git a/tests/test_expected_parameter_value_pairs.py b/tests/test_expected_parameter_value_pairs.py index ec3cd29..555cce0 100644 --- a/tests/test_expected_parameter_value_pairs.py +++ b/tests/test_expected_parameter_value_pairs.py @@ -1,5 +1,6 @@ # pylint: disable=missing-docstring import unittest +import copy from typing import List, Dict from collections import OrderedDict import io @@ -635,7 +636,7 @@ def test_remove_parameter_value_pair_all_versions(self): expected_number_of_reduced_pairs = len(reduced_param_value_pairs) - expected_reduced_param_value_pairs = reduced_param_value_pairs.copy() + expected_reduced_param_value_pairs = copy.deepcopy(reduced_param_value_pairs) # remove single value to verify that default flag is working example_single_pair = create_parameter_value_pair( diff --git a/tests/test_generate_combination_list.py b/tests/test_generate_combination_list.py index ba2c3ef..67c39cf 100644 --- a/tests/test_generate_combination_list.py +++ b/tests/test_generate_combination_list.py @@ -2,6 +2,7 @@ import unittest import os import io +import copy from collections import OrderedDict import packaging.version as pkv from utils_test import parse_param_vals @@ -145,7 +146,7 @@ def custom_filter(row: ParameterValueTuple) -> bool: parameter_value_matrix=self.param_matrix, custom_filter=custom_filter ) - reduced_expected_param_val_pairs = self.generated_parameter_value_pairs.copy() + reduced_expected_param_val_pairs = copy.deepcopy(self.generated_parameter_value_pairs) for device_compiler in self.param_matrix[DEVICE_COMPILER]: if device_compiler.name == NVCC: self.assertTrue( @@ -241,3 +242,69 @@ def custom_filter(row: ParameterValueTuple) -> bool: number_of_combs = len(missing_combinations_str.split("\n")) print(f"\nnumber of missing combinations: {number_of_combs}") raise e + + +class TestParameterMatrixFilter(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.param_base_matrix: ParameterValueMatrix = OrderedDict() + + cls.param_base_matrix[HOST_COMPILER] = parse_param_vals( + [(GCC, 10), (GCC, 11), (GCC, 12), (CLANG, 16), (CLANG, 17)] + ) + cls.param_base_matrix[DEVICE_COMPILER] = parse_param_vals( + [ + (GCC, 10), + (GCC, 11), + (GCC, 12), + (CLANG, 16), + (CLANG, 17), + ] + ) + cls.param_base_matrix[CMAKE] = parse_param_vals([(CMAKE, 3.22), (CMAKE, 3.23)]) + cls.param_base_matrix[BOOST] = parse_param_vals( + [(BOOST, 1.81), (BOOST, 1.82), (BOOST, 1.83)] + ) + + def test_nvcc_host_compiler_rule_n1(self): + # test if generate_combination_list() correctly handles nvcc as host compiler + param_matrix = copy.deepcopy(self.param_base_matrix) + for nvcc_version in [11.2, 11.3, 11.8, 12.0]: + param_matrix[HOST_COMPILER].append(ParameterValue(NVCC, pkv.parse(str(nvcc_version)))) + param_matrix[DEVICE_COMPILER].append(ParameterValue(NVCC, pkv.parse(str(nvcc_version)))) + param_matrix_before = copy.deepcopy(param_matrix) + + comb_list = generate_combination_list(param_matrix) + + # generate_combination_list should not modify the param_matrix + self.assertEqual(param_matrix_before, param_matrix) + + self.assertTrue( + check_parameter_value_pair_in_combination_list( + comb_list, get_expected_bashi_parameter_value_pairs(param_matrix) + ) + ) + + def test_clang_cuda_old_versions_rule_v5(self): + # test if generate_combination_list() correctly clang-cuda version 13 and older + + param_matrix = copy.deepcopy(self.param_base_matrix) + for clang_cuda_version in [8, 13, 14, 17]: + param_matrix[HOST_COMPILER].append( + ParameterValue(CLANG_CUDA, pkv.parse(str(clang_cuda_version))) + ) + param_matrix[DEVICE_COMPILER].append( + ParameterValue(CLANG_CUDA, pkv.parse(str(clang_cuda_version))) + ) + param_matrix_before = copy.deepcopy(param_matrix) + + comb_list = generate_combination_list(parameter_value_matrix=param_matrix) + + # generate_combination_list should not modify the param_matrix + self.assertEqual(param_matrix_before, param_matrix) + + self.assertTrue( + check_parameter_value_pair_in_combination_list( + comb_list, get_expected_bashi_parameter_value_pairs(param_matrix) + ) + ) diff --git a/tests/test_params_value_matrix_generator.py b/tests/test_params_value_matrix_generator.py index 27d3527..fc1de63 100644 --- a/tests/test_params_value_matrix_generator.py +++ b/tests/test_params_value_matrix_generator.py @@ -1,6 +1,6 @@ # pylint: disable=missing-docstring import unittest -import packaging.version as pkv +import copy from bashi.versions import VERSIONS, get_parameter_value_matrix from bashi.globals import * # pylint: disable=wildcard-import,unused-wildcard-import @@ -25,23 +25,17 @@ def test_all_params_in(self): ) def test_number_host_device_compiler(self): - extended_versions = VERSIONS.copy() + extended_versions = copy.deepcopy(VERSIONS) # filter clang-cuda 13 and older because the pair-wise generator cannot filter it out # afterwards - extended_versions[CLANG_CUDA] = list( - filter( - lambda clang_version: pkv.parse(str(clang_version)) >= pkv.parse("14"), - extended_versions[CLANG], - ) - ) + extended_versions[CLANG_CUDA] = extended_versions[CLANG] number_of_host_compilers = 0 for compiler in COMPILERS: - if compiler != NVCC: - number_of_host_compilers += len(extended_versions[compiler]) + number_of_host_compilers += len(extended_versions[compiler]) # NVCC is only as device compiler added - number_of_device_compilers = number_of_host_compilers + len(extended_versions[NVCC]) + number_of_device_compilers = number_of_host_compilers self.assertEqual(len(self.param_val_matrix[HOST_COMPILER]), number_of_host_compilers) self.assertEqual(len(self.param_val_matrix[DEVICE_COMPILER]), number_of_device_compilers)