From afe70c954c4648120b633ead1317aafcc6584a7c Mon Sep 17 00:00:00 2001 From: Ben van Werkhoven Date: Thu, 3 Jul 2025 17:00:32 +0200 Subject: [PATCH 1/6] fix support for 1D problem_size in caches --- kernel_tuner/util.py | 20 +++++++------------- test/test_util_functions.py | 6 +++--- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/kernel_tuner/util.py b/kernel_tuner/util.py index 4b204a45..ec4cbf49 100644 --- a/kernel_tuner/util.py +++ b/kernel_tuner/util.py @@ -520,7 +520,9 @@ def get_kernel_string(kernel_source, params=None): kernel_string = read_file(kernel_source) elif isinstance(kernel_source, str): if looks_like_a_filename(kernel_source): - kernel_string = read_file(kernel_source) or kernel_source + kernel_string = read_file(kernel_source) + if kernel_string is None: + raise ValueError(f"{kernel_source} looks like a filename, but cannot open file") else: kernel_string = kernel_source else: @@ -1115,6 +1117,9 @@ def compile_restrictions( noncompiled_restrictions.append((r, [], r)) return noncompiled_restrictions + compiled_restrictions +def check_matching_problem_size(cached_problem_size, problem_size): + if not all(np.array(cached_problem_size) == np.array(problem_size)): + ValueError(f"Cannot load cache which contains results for different problem_size, cache: {cached_data['problem_size']}, requested: {kernel_options.problem_size}") def process_cache(cache, kernel_options, tuning_options, runner): """Cache file for storing tuned configurations. @@ -1185,18 +1190,7 @@ def process_cache(cache, kernel_options, tuning_options, runner): f"Cannot load cache which contains results for different kernel (cache: {cached_data['kernel_name']}, actual: {kernel_options.kernel_name})" ) if "problem_size" in cached_data and not callable(kernel_options.problem_size): - # if it's a single value, convert to an array - if isinstance(cached_data["problem_size"], int): - cached_data["problem_size"] = [cached_data["problem_size"]] - # if problem_size is not iterable, compare directly - if not hasattr(kernel_options.problem_size, "__iter__"): - if cached_data["problem_size"] != kernel_options.problem_size: - raise ValueError("Cannot load cache which contains results for different problem_size") - # else (problem_size is iterable) - # cache returns list, problem_size is likely a tuple. Therefore, the next check - # checks the equality of all items in the list/tuples individually - elif not all([i == j for i, j in zip(cached_data["problem_size"], kernel_options.problem_size)]): - raise ValueError("Cannot load cache which contains results for different problem_size") + check_matching_problem_size(cached_data["problem_size"], kernel_options.problem_size) if cached_data["tune_params_keys"] != list(tuning_options.tune_params.keys()): if all(key in tuning_options.tune_params for key in cached_data["tune_params_keys"]): raise ValueError( diff --git a/test/test_util_functions.py b/test/test_util_functions.py index 5892a028..77bab66a 100644 --- a/test/test_util_functions.py +++ b/test/test_util_functions.py @@ -525,10 +525,10 @@ def gen_kernel(params): def test_get_kernel_string_filename_not_found(): # when the string looks like a filename, but the file does not exist - # assume the string is not a filename after all + # check if throws an exception bogus_filename = "filename_3456789.cu" - answer = get_kernel_string(bogus_filename) - assert answer == bogus_filename + with pytest.raises(ValueError): + get_kernel_string(bogus_filename) def test_looks_like_a_filename1(): From 149f169fcc81bf3d5e730940eabc12d2686d945f Mon Sep 17 00:00:00 2001 From: Ben van Werkhoven Date: Thu, 3 Jul 2025 17:03:10 +0200 Subject: [PATCH 2/6] bugfix the bugfix --- kernel_tuner/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel_tuner/util.py b/kernel_tuner/util.py index ec4cbf49..8811c2cb 100644 --- a/kernel_tuner/util.py +++ b/kernel_tuner/util.py @@ -1118,7 +1118,7 @@ def compile_restrictions( return noncompiled_restrictions + compiled_restrictions def check_matching_problem_size(cached_problem_size, problem_size): - if not all(np.array(cached_problem_size) == np.array(problem_size)): + if not (np.array(cached_problem_size) == np.array(problem_size)).all(): ValueError(f"Cannot load cache which contains results for different problem_size, cache: {cached_data['problem_size']}, requested: {kernel_options.problem_size}") def process_cache(cache, kernel_options, tuning_options, runner): From a093cfd6110f77b939e0147526dd1ad20d98cf48 Mon Sep 17 00:00:00 2001 From: Ben van Werkhoven Date: Thu, 3 Jul 2025 17:16:13 +0200 Subject: [PATCH 3/6] change ValueError to FileNotFoundError --- kernel_tuner/util.py | 5 ++--- test/test_util_functions.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel_tuner/util.py b/kernel_tuner/util.py index 8811c2cb..a1ce0fb7 100644 --- a/kernel_tuner/util.py +++ b/kernel_tuner/util.py @@ -520,9 +520,8 @@ def get_kernel_string(kernel_source, params=None): kernel_string = read_file(kernel_source) elif isinstance(kernel_source, str): if looks_like_a_filename(kernel_source): - kernel_string = read_file(kernel_source) - if kernel_string is None: - raise ValueError(f"{kernel_source} looks like a filename, but cannot open file") + with open(kernel_source, "r") as f: + kernel_string = f.read() else: kernel_string = kernel_source else: diff --git a/test/test_util_functions.py b/test/test_util_functions.py index 77bab66a..f3bdc21e 100644 --- a/test/test_util_functions.py +++ b/test/test_util_functions.py @@ -527,7 +527,7 @@ def test_get_kernel_string_filename_not_found(): # when the string looks like a filename, but the file does not exist # check if throws an exception bogus_filename = "filename_3456789.cu" - with pytest.raises(ValueError): + with pytest.raises(FileNotFoundError): get_kernel_string(bogus_filename) From cd554d2b4408b4b57a0ddc8907f745340fd3af3a Mon Sep 17 00:00:00 2001 From: Ben van Werkhoven Date: Thu, 3 Jul 2025 18:50:00 +0200 Subject: [PATCH 4/6] raise the exception --- kernel_tuner/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel_tuner/util.py b/kernel_tuner/util.py index a1ce0fb7..7e01c27a 100644 --- a/kernel_tuner/util.py +++ b/kernel_tuner/util.py @@ -1118,7 +1118,7 @@ def compile_restrictions( def check_matching_problem_size(cached_problem_size, problem_size): if not (np.array(cached_problem_size) == np.array(problem_size)).all(): - ValueError(f"Cannot load cache which contains results for different problem_size, cache: {cached_data['problem_size']}, requested: {kernel_options.problem_size}") + raise ValueError(f"Cannot load cache which contains results for different problem_size, cache: {cached_data['problem_size']}, requested: {kernel_options.problem_size}") def process_cache(cache, kernel_options, tuning_options, runner): """Cache file for storing tuned configurations. From 9c8613e3c0dc4bf158185cfb707590aecd9789e4 Mon Sep 17 00:00:00 2001 From: Ben van Werkhoven Date: Thu, 3 Jul 2025 19:03:58 +0200 Subject: [PATCH 5/6] add test --- kernel_tuner/util.py | 3 ++- test/test_util_functions.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/kernel_tuner/util.py b/kernel_tuner/util.py index 7e01c27a..b2f95c32 100644 --- a/kernel_tuner/util.py +++ b/kernel_tuner/util.py @@ -1117,8 +1117,9 @@ def compile_restrictions( return noncompiled_restrictions + compiled_restrictions def check_matching_problem_size(cached_problem_size, problem_size): + """ check if requested problem size matches the problem size in the cache""" if not (np.array(cached_problem_size) == np.array(problem_size)).all(): - raise ValueError(f"Cannot load cache which contains results for different problem_size, cache: {cached_data['problem_size']}, requested: {kernel_options.problem_size}") + raise ValueError(f"Cannot load cache which contains results for different problem_size, cache: {cached_problem_size}, requested: {problem_size}") def process_cache(cache, kernel_options, tuning_options, runner): """Cache file for storing tuned configurations. diff --git a/test/test_util_functions.py b/test/test_util_functions.py index f3bdc21e..7dc5cb9f 100644 --- a/test/test_util_functions.py +++ b/test/test_util_functions.py @@ -726,6 +726,19 @@ def test_parse_restrictions(): assert all(param in tune_params for param in params) +def test_check_matching_problem_size(): + # these should error + with pytest.raises(ValueError): + check_matching_problem_size(42, 1000) + with pytest.raises(ValueError): + check_matching_problem_size([42,1], 42) + # these should not error + check_matching_problem_size(1000, (1000,)) + check_matching_problem_size([1000], 1000) + check_matching_problem_size(1000, 1000) + check_matching_problem_size(1000, [1000]) + + def test_convert_constraint_lambdas(): restrictions = [lambda p: 32 <= p["block_size_x"]*p["block_size_y"] <= 1024, From 0353c40a22378a32c8e7c17071f4df75c7479e50 Mon Sep 17 00:00:00 2001 From: fjwillemsen Date: Mon, 7 Jul 2025 17:56:31 +0200 Subject: [PATCH 6/6] Extended test_check_matching_problem_size with edge cases, made docstring conform to linting rules --- kernel_tuner/util.py | 2 +- test/test_util_functions.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/kernel_tuner/util.py b/kernel_tuner/util.py index b2f95c32..f34deb03 100644 --- a/kernel_tuner/util.py +++ b/kernel_tuner/util.py @@ -1117,7 +1117,7 @@ def compile_restrictions( return noncompiled_restrictions + compiled_restrictions def check_matching_problem_size(cached_problem_size, problem_size): - """ check if requested problem size matches the problem size in the cache""" + """Check the if requested problem size matches the problem size in the cache.""" if not (np.array(cached_problem_size) == np.array(problem_size)).all(): raise ValueError(f"Cannot load cache which contains results for different problem_size, cache: {cached_problem_size}, requested: {problem_size}") diff --git a/test/test_util_functions.py b/test/test_util_functions.py index 7dc5cb9f..9d682d31 100644 --- a/test/test_util_functions.py +++ b/test/test_util_functions.py @@ -732,11 +732,16 @@ def test_check_matching_problem_size(): check_matching_problem_size(42, 1000) with pytest.raises(ValueError): check_matching_problem_size([42,1], 42) + with pytest.raises(ValueError): + check_matching_problem_size([42,0], 42) + with pytest.raises(ValueError): + check_matching_problem_size(None, 42) # these should not error check_matching_problem_size(1000, (1000,)) check_matching_problem_size([1000], 1000) check_matching_problem_size(1000, 1000) check_matching_problem_size(1000, [1000]) + check_matching_problem_size([1000,], 1000) def test_convert_constraint_lambdas():