From fd6518236d02ef110910ecd7281fae8c0b351051 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 5 Jun 2018 21:32:56 -0500 Subject: [PATCH 01/10] Fix broken access to columns_in_use in draw_dependencies_as_unicode_arrows --- loopy/kernel/tools.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/loopy/kernel/tools.py b/loopy/kernel/tools.py index ec26916f3..c5341ce47 100644 --- a/loopy/kernel/tools.py +++ b/loopy/kernel/tools.py @@ -1258,8 +1258,10 @@ def draw_dependencies_as_unicode_arrows( rdeps = reverse_deps.get(insn.id, set()).copy() - processed_ids assert insn.id not in rdeps - if insn.id in dep_to_column: - columns_in_use[insn.id][0].update(rdeps) + col = dep_to_column.get(insn.id) + if col is not None: + columns_in_use[col][0].update(rdeps) + del col # }}} -- GitLab From 099a5e20702745e9ab5090d01df6f4ef6dfe5198 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 11 Jun 2018 17:11:02 -0500 Subject: [PATCH 02/10] Fix stringification of instructions in the presence of predicates --- loopy/kernel/instruction.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/loopy/kernel/instruction.py b/loopy/kernel/instruction.py index 067e3de13..5c238ec28 100644 --- a/loopy/kernel/instruction.py +++ b/loopy/kernel/instruction.py @@ -872,7 +872,8 @@ class Assignment(MultiAssignmentBase): result += " {%s}" % (": ".join(options)) if self.predicates: - result += "\n" + 10*" " + "if (%s)" % " && ".join(self.predicates) + result += "\n" + 10*" " + "if (%s)" % " and ".join( + str(p) for p in self.predicates) return result # {{{ for interface uniformity with CallInstruction -- GitLab From 813142da7863b8855f17756d42667b7c1dd65869 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 11 Jun 2018 17:11:37 -0500 Subject: [PATCH 03/10] Fix docs on draw_dependencies_as_unicode_arrows --- loopy/kernel/tools.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/loopy/kernel/tools.py b/loopy/kernel/tools.py index c5341ce47..a5db3b2e1 100644 --- a/loopy/kernel/tools.py +++ b/loopy/kernel/tools.py @@ -1205,9 +1205,11 @@ def draw_dependencies_as_unicode_arrows( instances :arg fore: if given, will be used like a :mod:`colorama` ``Fore`` object to color-code dependencies. (E.g. red for downward edges) - :returns: A list of tuples (arrows, extender) with Unicode-drawn dependency - arrows, one per entry of *instructions*. *extender* can be used to - extend arrows below the line of an instruction. + :returns: A tuple ``(uniform_length, rows)``, where *rows* is a list of + tuples (arrows, extender) with Unicode-drawn dependency arrows, one per + entry of *instructions*. *extender* can be used to extend arrows below the + line of an instruction. *uniform_length* is the length of the *arrows* and + *extender* strings. """ reverse_deps = {} -- GitLab From 96152a8b21570eb87446cf36ac6acb4ee0ec333a Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 11 Jun 2018 17:19:06 -0500 Subject: [PATCH 04/10] Fix unicode dep arrow drawing in the presence of cyclic depdencies (drawn red) --- loopy/kernel/tools.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/loopy/kernel/tools.py b/loopy/kernel/tools.py index a5db3b2e1..6c0343781 100644 --- a/loopy/kernel/tools.py +++ b/loopy/kernel/tools.py @@ -1344,12 +1344,27 @@ def draw_dependencies_as_unicode_arrows( added_ellipsis = [False] + def len_without_color_escapes(s): + s = (s + .replace(fore.RED, "") + .replace(style.RESET_ALL, "")) + return len(s) + + def truncate_without_color_escapes(s, l): + s = (s + .replace(fore.RED, "") + .replace(style.RESET_ALL, "")) + + return s[:l] + u"…" + def conform_to_uniform_length(s): - if len(s) <= uniform_length: - return s + " "*(uniform_length-len(s)) + len_s = len_without_color_escapes(s) + + if len_s <= uniform_length: + return s + " "*(uniform_length-len_s) else: added_ellipsis[0] = True - return s[:uniform_length] + u"…" + return truncate_without_color_escapes(s, uniform_length) rows = [ (conform_to_uniform_length(row), -- GitLab From e6af7583ddfc9f3e15b89d55b288fc834cc15c25 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 11 Jun 2018 17:19:58 -0500 Subject: [PATCH 05/10] draw_dependencies_as_unicode_arrows: Only redo length-conforming if needed --- loopy/kernel/tools.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/loopy/kernel/tools.py b/loopy/kernel/tools.py index 6c0343781..b2b13bad1 100644 --- a/loopy/kernel/tools.py +++ b/loopy/kernel/tools.py @@ -1374,10 +1374,10 @@ def draw_dependencies_as_unicode_arrows( if added_ellipsis[0]: uniform_length += 1 - rows = [ - (conform_to_uniform_length(row), - conform_to_uniform_length(extender)) - for row, extender in rows] + rows = [ + (conform_to_uniform_length(row), + conform_to_uniform_length(extender)) + for row, extender in rows] return uniform_length, rows -- GitLab From 64b1500668914c467023a3d9e67c464f3c9b346b Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 11 Jun 2018 17:33:39 -0500 Subject: [PATCH 06/10] draw_dependencies_as_unicode_arrows: Fix (never-ending) drawing of downward arrows, indicating cyclic deps --- loopy/kernel/tools.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/loopy/kernel/tools.py b/loopy/kernel/tools.py index b2b13bad1..d8dc70096 100644 --- a/loopy/kernel/tools.py +++ b/loopy/kernel/tools.py @@ -1319,7 +1319,11 @@ def draw_dependencies_as_unicode_arrows( dep_key = dep if dep_key not in dep_to_column: col = dep_to_column[dep_key] = find_free_column() - columns_in_use[col] = (set([insn.id]), dep) + + # No need to add current instruction to end_insn_ids set, as + # we're currently handling it. + columns_in_use[col] = (set(), dep) + row[col] = do_flag_downward(u"┌", dep) # }}} -- GitLab From 720390baaf47e08e7cb8434f139d53d093f3a634 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 11 Jun 2018 17:33:59 -0500 Subject: [PATCH 07/10] draw_dependencies_as_unicode_arrows: add comments/fixmes --- loopy/kernel/tools.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/loopy/kernel/tools.py b/loopy/kernel/tools.py index d8dc70096..371758b3c 100644 --- a/loopy/kernel/tools.py +++ b/loopy/kernel/tools.py @@ -1223,6 +1223,8 @@ def draw_dependencies_as_unicode_arrows( # {{{ find column assignments # mapping from column indices to (end_insn_ids, pointed_at_insn_id) + # end_insn_ids is a set that gets modified in-place to remove 'ends' + # (arrow origins) as they are being passed. columns_in_use = {} n_columns = [0] @@ -1355,6 +1357,9 @@ def draw_dependencies_as_unicode_arrows( return len(s) def truncate_without_color_escapes(s, l): + # FIXME: This is a bit dumb--it removes color escapes when truncation + # is needed. + s = (s .replace(fore.RED, "") .replace(style.RESET_ALL, "")) -- GitLab From 63ea78919a460e2b3c36e96cb49782fdc0d42082 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 11 Jun 2018 17:52:41 -0500 Subject: [PATCH 08/10] Check for dependency cycles in check_variable_access_ordered --- loopy/check.py | 12 +++++++++++- loopy/diagnostic.py | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/loopy/check.py b/loopy/check.py index 146391bf2..bfb7b362a 100644 --- a/loopy/check.py +++ b/loopy/check.py @@ -400,9 +400,18 @@ class IndirectDependencyEdgeFinder(object): cache_key = (depender_id, dependee_id) try: - return self.dep_edge_cache[cache_key] + result = self.dep_edge_cache[cache_key] except KeyError: pass + else: + if result is not None: + from loopy.diagnostic import DependencyCycleFound + raise DependencyCycleFound("when " + "checking for dependency edge between " + "depender '%s' and dependee '%s'" + % (depender_id, dependee_id)) + else: + return result depender = self.kernel.id_to_insn[depender_id] @@ -410,6 +419,7 @@ class IndirectDependencyEdgeFinder(object): self.dep_edge_cache[cache_key] = True return True + self.dep_edge_cache[cache_key] = None for dep in depender.depends_on: if self(dep, dependee_id): self.dep_edge_cache[cache_key] = True diff --git a/loopy/diagnostic.py b/loopy/diagnostic.py index 410b89d78..561bbc7cc 100644 --- a/loopy/diagnostic.py +++ b/loopy/diagnostic.py @@ -123,6 +123,10 @@ class ExpressionToAffineConversionError(LoopyError): class VariableAccessNotOrdered(LoopyError): pass + +class DependencyCycleFound(LoopyError): + pass + # }}} -- GitLab From 1131b1759170f5d00d4c81a9f9474dc9dccbda74 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 11 Jun 2018 17:54:28 -0500 Subject: [PATCH 09/10] Add test for kernel with dep cycles --- test/test_loopy.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/test_loopy.py b/test/test_loopy.py index 7a6b8c8a6..07179ae14 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -2869,6 +2869,42 @@ def test_half_complex_conditional(ctx_factory): knl(queue) +def test_dep_cycle_printing_and_error(): + # https://gitlab.tiker.net/inducer/loopy/issues/140 + # This kernel has two dep cycles. + + knl = lp.make_kernel('{[i,j,k]: 0 <= i,j,k < 12}', + """ + for j + for i + <> nu = i - 4 + if nu > 0 + <> P_val = a[i, j] {id=pset0} + else + P_val = 0.1 * a[i, j] {id=pset1} + end + <> B_sum = 0 + for k + B_sum = B_sum + k * P_val {id=bset, dep=pset*} + end + # here, we are testing that Kc is properly promoted to a vector dtype + <> Kc = P_val * B_sum {id=kset, dep=bset} + a[i, j] = Kc {dep=kset} + end + end + """, + [lp.GlobalArg('a', shape=(12, 12), dtype=np.int32)]) + + knl = lp.split_iname(knl, 'j', 4, inner_tag='vec') + knl = lp.split_array_axis(knl, 'a', 1, 4) + knl = lp.tag_array_axes(knl, 'a', 'N1,N0,vec') + knl = lp.preprocess_kernel(knl) + + from loopy.diagnostic import DependencyCycleFound + with pytest.raises(DependencyCycleFound): + print(lp.generate_code(knl)[0]) + + if __name__ == "__main__": if len(sys.argv) > 1: exec(sys.argv[1]) -- GitLab From 274409d55918eea6affa4c07e2229fe64688f238 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Mon, 11 Jun 2018 18:35:08 -0500 Subject: [PATCH 10/10] Fix dep cycle check in check_variable_access_ordered --- loopy/check.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/check.py b/loopy/check.py index bfb7b362a..7a4139b4e 100644 --- a/loopy/check.py +++ b/loopy/check.py @@ -404,7 +404,7 @@ class IndirectDependencyEdgeFinder(object): except KeyError: pass else: - if result is not None: + if result is None: from loopy.diagnostic import DependencyCycleFound raise DependencyCycleFound("when " "checking for dependency edge between " -- GitLab