From 50dd460dbca33e39c97952f174c1b3cafb8b5285 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Fri, 5 Jul 2013 14:32:35 -0400 Subject: [PATCH] Creation/write race fixes --- loopy/check.py | 9 ++++----- loopy/diagnostic.py | 22 ++++++++++++++++++---- loopy/kernel/__init__.py | 5 +++++ loopy/kernel/creation.py | 19 +++++++++++++------ loopy/kernel/data.py | 3 +-- loopy/preprocess.py | 16 +++++++++------- test/test_linalg.py | 13 +++++++++---- test/test_loopy.py | 13 +++++++++---- 8 files changed, 68 insertions(+), 32 deletions(-) diff --git a/loopy/check.py b/loopy/check.py index a871508b9..8022d91ee 100644 --- a/loopy/check.py +++ b/loopy/check.py @@ -26,13 +26,11 @@ THE SOFTWARE. from islpy import dim_type import islpy as isl from loopy.symbolic import WalkMapper -from loopy.diagnostic import LoopyError, LoopyWarning +from loopy.diagnostic import LoopyError, WriteRaceConditionWarning, warn import logging logger = logging.getLogger(__name__) -from loopy.diagnostic import WriteRaceConditionError - # {{{ sanity checks run during scheduling @@ -167,11 +165,12 @@ def check_for_write_races(kernel): raceable_parallel_insn_inames - assignee_inames if race_inames: - raise WriteRaceConditionError( + warn(kernel, "write_race(%s)" % insn.id, "instruction '%s' contains a write race: " "instruction will be run across parallel iname(s) " "'%s', which is/are not referenced in the lhs index" - % (insn.id, ",".join(race_inames))) + % (insn.id, ",".join(race_inames)), + WriteRaceConditionWarning) def check_for_orphaned_user_hardware_axes(kernel): diff --git a/loopy/diagnostic.py b/loopy/diagnostic.py index dd2860a0e..e305038b8 100644 --- a/loopy/diagnostic.py +++ b/loopy/diagnostic.py @@ -40,9 +40,24 @@ class LoopyAdvisory(LoopyWarningBase): class ParameterFinderWarning(LoopyWarningBase): pass + +class WriteRaceConditionWarning(LoopyWarningBase): + pass + # }}} +def warn(kernel, id, text, type=LoopyWarning): + if id in kernel.silenced_warnings: + return + + text += (" (add '%s' to silenced_warnings kernel argument to disable)" + % id) + + from warnings import warn + warn(text, type) + + # {{{ errors class LoopyError(RuntimeError): @@ -53,10 +68,6 @@ class CannotBranchDomainTree(LoopyError): pass -class WriteRaceConditionError(LoopyError): - pass - - class TypeInferenceFailure(LoopyError): pass @@ -66,4 +77,7 @@ class DependencyTypeInferenceFailure(TypeInferenceFailure): # }}} + + + # vim: foldmethod=marker diff --git a/loopy/kernel/__init__.py b/loopy/kernel/__init__.py index 8a7c53f84..423dba4e6 100644 --- a/loopy/kernel/__init__.py +++ b/loopy/kernel/__init__.py @@ -124,6 +124,8 @@ class LoopKernel(Record): it will be scheduled. (This applies to inames with non-parallel implementation tags.) + .. attribute:: silenced_warnings + .. attribute:: applied_iname_rewrites A list of past substitution dictionaries that @@ -154,6 +156,8 @@ class LoopKernel(Record): iname_slab_increments={}, loop_priority=[], + silenced_warnings=[], + applied_iname_rewrites=[], cache_manager=None, index_dtype=np.int32, @@ -250,6 +254,7 @@ class LoopKernel(Record): assumptions=assumptions, iname_slab_increments=iname_slab_increments, loop_priority=loop_priority, + silenced_warnings=silenced_warnings, temporary_variables=temporary_variables, local_sizes=local_sizes, iname_to_tag=iname_to_tag, diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index 157b7cbf3..91a654c37 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -401,9 +401,10 @@ def guess_kernel_args_if_requested(domains, instructions, temporary_variables, temp_var_names = set(temporary_variables.iterkeys()) for insn in instructions: - if insn.temp_var_type is not None: - (assignee_var_name, _), = insn.assignees_and_indices() - temp_var_names.add(assignee_var_name) + if isinstance(insn, ExpressionInstruction): + if insn.temp_var_type is not None: + (assignee_var_name, _), = insn.assignees_and_indices() + temp_var_names.add(assignee_var_name) # }}} @@ -430,7 +431,7 @@ def guess_kernel_args_if_requested(domains, instructions, temporary_variables, all_params.update(dom.get_var_names(dim_type.param)) all_params = all_params - all_inames - new_arg_names = (all_names - not_new_arg_names) | all_params + new_arg_names = (all_names | all_params) - not_new_arg_names # }}} @@ -438,8 +439,8 @@ def guess_kernel_args_if_requested(domains, instructions, temporary_variables, irf = IndexRankFinder(name) for insn in instructions: - irf(submap(insn.expression, insn.id)) - irf(submap(insn.assignee, insn.id)) + insn.with_transformed_expressions( + lambda expr: irf(submap(expr, insn.id))) if not irf.index_ranks: return 0 @@ -880,11 +881,17 @@ def make_kernel(device, domains, instructions, kernel_data=["..."], **kwargs): :arg local_sizes: A dictionary from integers to integers, mapping workgroup axes to their sizes, e.g. *{0: 16}* forces axis 0 to be length 16. + :arg silenced_warnings: a list (or semicolon-separated string) or warnings + to silence """ defines = kwargs.pop("defines", {}) default_order = kwargs.pop("default_order", "C") default_offset = kwargs.pop("default_offset", 0) + silenced_warnings = kwargs.pop("silenced_warnings", []) + + if isinstance(silenced_warnings, str): + silenced_warnings = silenced_warnings.split(";") # {{{ separate temporary variables and arguments diff --git a/loopy/kernel/data.py b/loopy/kernel/data.py index c844995d6..832096a32 100644 --- a/loopy/kernel/data.py +++ b/loopy/kernel/data.py @@ -556,8 +556,7 @@ def _remove_common_indentation(code): code = code.lstrip("//CL//") if not code.startswith("\n"): - raise ValueError("expected newline as first character " - "in literal lines") + return code lines = code.split("\n") while lines[0].strip() == "": diff --git a/loopy/preprocess.py b/loopy/preprocess.py index d41a36405..c9adbf0c9 100644 --- a/loopy/preprocess.py +++ b/loopy/preprocess.py @@ -25,7 +25,9 @@ THE SOFTWARE. import pyopencl as cl import pyopencl.characterize as cl_char -from loopy.diagnostic import LoopyError, LoopyWarning +from loopy.diagnostic import ( + LoopyError, LoopyWarning, WriteRaceConditionWarning, warn, + LoopyAdvisory) import logging logger = logging.getLogger(__name__) @@ -250,15 +252,16 @@ def mark_local_temporaries(kernel): if (locparallel_assignee_inames != locparallel_compute_inames and bool(locparallel_assignee_inames)): - from loopy.check import WriteRaceConditionError - raise WriteRaceConditionError("instruction '%s' looks invalid: " + warn(kernel, "write_race_local(%s)" % insn_id, + "instruction '%s' looks invalid: " "it assigns to indices based on local IDs, but " "its temporary '%s' cannot be made local because " "a write race across the iname(s) '%s' would emerge. " "(Do you need to add an extra iname to your prefetch?)" % (insn_id, temp_var.name, ", ".join( locparallel_compute_inames - - locparallel_assignee_inames))) + - locparallel_assignee_inames)), + WriteRaceConditionWarning) wants_to_be_local_per_insn.append( locparallel_assignee_inames == locparallel_compute_inames @@ -268,9 +271,8 @@ def mark_local_temporaries(kernel): and bool(locparallel_compute_inames)) if not wants_to_be_local_per_insn: - from warnings import warn - from loopy.diagnostic import LoopyAdvisory - warn("temporary variable '%s' never written, eliminating" + warn(kernel, "temp_to_write(%s)" % temp_var.name, + "temporary variable '%s' never written, eliminating" % temp_var.name, LoopyAdvisory) is_local = wants_to_be_local_per_insn[0] diff --git a/test/test_linalg.py b/test/test_linalg.py index 374b43e6f..6cbc81d46 100644 --- a/test/test_linalg.py +++ b/test/test_linalg.py @@ -23,6 +23,8 @@ THE SOFTWARE. """ +import pytest +import sys import numpy as np import pyopencl as cl import pyopencl.array as cl_array @@ -490,6 +492,7 @@ def test_image_matrix_mul_ilp(ctx_factory): parameters={}) +@pytest.mark.skipif("sys.version_info < (2,6)") def test_ilp_race_matmul(ctx_factory): dtype = np.float32 ctx = ctx_factory() @@ -513,11 +516,14 @@ def test_ilp_race_matmul(ctx_factory): knl = lp.split_iname(knl, "k", 2) knl = lp.add_prefetch(knl, 'b', ["k_inner"]) - from loopy.check import WriteRaceConditionError - import pytest - with pytest.raises(WriteRaceConditionError): + from loopy.diagnostic import WriteRaceConditionWarning + from warnings import catch_warnings + with catch_warnings(record=True) as warn_list: list(lp.generate_loop_schedules(knl)) + assert any(isinstance(w.message, WriteRaceConditionWarning) + for w in warn_list) + def test_fancy_matrix_mul(ctx_factory): dtype = np.float32 @@ -587,7 +593,6 @@ def test_small_batched_matvec(ctx_factory): if __name__ == "__main__": - import sys if len(sys.argv) > 1: exec(sys.argv[1]) else: diff --git a/test/test_loopy.py b/test/test_loopy.py index e6d8a61ad..111c59686 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -23,10 +23,12 @@ THE SOFTWARE. """ +import sys import numpy as np import loopy as lp import pyopencl as cl import pyopencl.clrandom # noqa +import pytest import logging logger = logging.getLogger(__name__) @@ -895,6 +897,7 @@ def test_double_sum(ctx_factory): # {{{ test race detection +@pytest.mark.skipif("sys.version_info < (2,6)") def test_ilp_write_race_detection_global(ctx_factory): ctx = ctx_factory() @@ -912,11 +915,14 @@ def test_ilp_write_race_detection_global(ctx_factory): knl = lp.tag_inames(knl, dict(j="ilp")) - from loopy.check import WriteRaceConditionError - import pytest - with pytest.raises(WriteRaceConditionError): + from loopy.diagnostic import WriteRaceConditionWarning + from warnings import catch_warnings + with catch_warnings(record=True) as warn_list: list(lp.generate_loop_schedules(knl)) + assert any(isinstance(w.message, WriteRaceConditionWarning) + for w in warn_list) + def test_ilp_write_race_avoidance_local(ctx_factory): ctx = ctx_factory() @@ -1192,7 +1198,6 @@ def test_c_instruction(ctx_factory): if __name__ == "__main__": - import sys if len(sys.argv) > 1: exec(sys.argv[1]) else: -- GitLab