From 45b29f7a3c97760ccba104e6e189522b1587b552 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Apr 2020 20:34:04 -0500 Subject: [PATCH 001/220] adding lexicographic_order_map.py (creates isl maps defining lex orderings and statement instance orderings) --- .../checker/lexicographic_order_map.py | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 loopy/schedule/checker/lexicographic_order_map.py diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py new file mode 100644 index 000000000..2e063e7d7 --- /dev/null +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -0,0 +1,159 @@ +__copyright__ = "Copyright (C) 2019 James Stevens" + +__license__ = """ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import islpy as isl + + +def get_statement_ordering_map( + sched_map_before, sched_map_after, lex_map, before_marker="'"): + """Return a mapping that maps each statement instance to + all statement instances occuring later. + + :arg sched_map_before: An :class:`islpy.Map` representing instruction + instance order for the dependee as a mapping from each statement + instance to a point in the lexicographic ordering. + + :arg sched_map_after: An :class:`islpy.Map` representing instruction + instance order for the depender as a mapping from each statement + instance to a point in the lexicographic ordering. + + :arg lex_map: An :class:`islpy.Map` representing a lexicographic + ordering as a mapping from each point in lexicographic time + to every point that occurs later in lexicographic time. E.g.:: + + {[i0', i1', i2', ...] -> [i0, i1, i2, ...] : + i0' < i0 or (i0' = i0 and i1' < i1) + or (i0' = i0 and i1' = i1 and i2' < i2) ...} + + :returns: An :class:`islpy.Map` representing the lex schedule as + a mapping from each statement instance to all statement instances + occuring later. I.e., we compose B -> L -> A^-1, where B + is sched_map_before, A is sched_map_after, and L is the + lexicographic ordering map. + + """ + + sio = sched_map_before.apply_range( + lex_map).apply_range(sched_map_after.reverse()) + # append marker to in names + for i in range(sio.dim(isl.dim_type.in_)): + sio = sio.set_dim_name(isl.dim_type.in_, i, sio.get_dim_name( + isl.dim_type.in_, i)+before_marker) + return sio + + +def get_lex_order_constraint(islvars, before_names, after_names): + """Return a constraint represented as an :class:`islpy.Set` + defining a 'happens before' relationship in a lexicographic + ordering. + + :arg islvars: A dictionary from variable names to :class:`islpy.PwAff` + instances that represent each of the variables + (islvars may be produced by `islpy.make_zero_and_vars`). The key + '0' is also include and represents a :class:`islpy.PwAff` zero constant. + This dictionary defines the space to be used for the set. + + :arg before_names: A list of :class:`str` variable names representing + the lexicographic space dimensions for a point in lexicographic + time that occurs before. (see example below) + + :arg after_names: A list of :class:`str` variable names representing + the lexicographic space dimensions for a point in lexicographic + time that occurs after. (see example below) + + :returns: An :class:`islpy.Set` representing a constraint that enforces a + lexicographic ordering. E.g., if ``before_names = [i0', i1', i2']`` and + ``after_names = [i0, i1, i2]``, return the set:: + + {[i0', i1', i2', i0, i1, i2] : + i0' < i0 or (i0' = i0 and i1' < i1) + or (i0' = i0 and i1' = i1 and i2' < i2)} + + """ + + lex_order_constraint = islvars[before_names[0]].lt_set(islvars[after_names[0]]) + for i in range(1, len(before_names)): + lex_order_constraint_conj = islvars[before_names[i]].lt_set( + islvars[after_names[i]]) + for j in range(i): + lex_order_constraint_conj = lex_order_constraint_conj & \ + islvars[before_names[j]].eq_set(islvars[after_names[j]]) + lex_order_constraint = lex_order_constraint | lex_order_constraint_conj + return lex_order_constraint + + +def create_lex_order_map( + n_dims, + before_names=None, + after_names=None, + ): + """Return a mapping that maps each point in a lexicographic + ordering to every point that occurs later in lexicographic + time. + + :arg n_dims: An :class:`int` representing the number of dimensions + in the lexicographic ordering. + + :arg before_names: A list of :class:`str` variable names representing + the lexicographic space dimensions for a point in lexicographic + time that occurs before. (see example below) + + :arg after_names: A list of :class:`str` variable names representing + the lexicographic space dimensions for a point in lexicographic + time that occurs after. (see example below) + + :returns: An :class:`islpy.Map` representing a lexicographic + ordering as a mapping from each point in lexicographic time + to every point that occurs later in lexicographic time. + E.g., if ``before_names = [i0', i1', i2']`` and + ``after_names = [i0, i1, i2]``, return the map:: + + {[i0', i1', i2'] -> [i0, i1, i2] : + i0' < i0 or (i0' = i0 and i1' < i1) + or (i0' = i0 and i1' = i1 and i2' < i2)} + + """ + + if before_names is None: + before_names = ["i%s" % (i) for i in range(n_dims)] + if after_names is None: + from loopy.schedule.checker.utils import ( + append_marker_to_strings, + ) + after_names = append_marker_to_strings(before_names, marker="_") + + assert len(before_names) == len(after_names) == n_dims + dim_type = isl.dim_type + + islvars = isl.make_zero_and_vars( + before_names+after_names, + []) + + lex_order_constraint = get_lex_order_constraint( + islvars, before_names, after_names) + + lex_map = isl.Map.from_domain(lex_order_constraint) + lex_map = lex_map.move_dims( + dim_type.out, 0, dim_type.in_, + len(before_names), len(after_names)) + + return lex_map From 782dde2330328a0716bda113efc1526257c3fcbe Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Apr 2020 20:35:41 -0500 Subject: [PATCH 002/220] add get_lex_order_map_for_sched_space() to schedule (gets an isl map defining the lexicographic ordering) --- loopy/schedule/checker/schedule.py | 13 +++++++++++++ loopy/schedule/checker/utils.py | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 0aca588c3..305d1f74f 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -405,6 +405,19 @@ def get_lex_var_names(self): return [self.lex_var_prefix+str(i) for i in range(self.max_lex_dims())] + def get_lex_order_map_for_sched_space(self): + """Return an :class:`islpy.BasicMap` that maps each point in a + lexicographic ordering to every point that is + lexocigraphically greater. + """ + + from loopy.schedule.checker.lexicographic_order_map import ( + create_lex_order_map, + ) + n_dims = self.max_lex_dims() + return create_lex_order_map( + n_dims, before_names=self.get_lex_var_names()) + def __str__(self): def stringify_sched_stmt_instance(stmt_inst): diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index cb933de6f..8757406b7 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -143,6 +143,13 @@ def align_isl_maps_by_var_names(input_map, target_map): return aligned_input_map +def append_marker_to_strings(strings, marker="'"): + if not isinstance(strings, list): + raise ValueError("append_marker_to_strings did not receive a list") + else: + return [s+marker for s in strings] + + def _union_of_isl_sets_or_maps(set_list): union = set_list[0] for s in set_list[1:]: From 0e664550837299ff697d5f6947fed9d90d2cc095 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Apr 2020 22:13:50 -0500 Subject: [PATCH 003/220] add function append_marker_to_in_dim_names(islmap) --- loopy/schedule/checker/lexicographic_order_map.py | 8 ++++---- loopy/schedule/checker/utils.py | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 2e063e7d7..61f191247 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -55,10 +55,10 @@ def get_statement_ordering_map( sio = sched_map_before.apply_range( lex_map).apply_range(sched_map_after.reverse()) # append marker to in names - for i in range(sio.dim(isl.dim_type.in_)): - sio = sio.set_dim_name(isl.dim_type.in_, i, sio.get_dim_name( - isl.dim_type.in_, i)+before_marker) - return sio + from loopy.schedule.checker.utils import ( + append_marker_to_in_dim_names, + ) + return append_marker_to_in_dim_names(sio, before_marker) def get_lex_order_constraint(islvars, before_names, after_names): diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 8757406b7..96aa007c7 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -150,6 +150,14 @@ def append_marker_to_strings(strings, marker="'"): return [s+marker for s in strings] +def append_marker_to_in_dim_names(islmap, marker="'"): + # append marker to in names + for i in range(islmap.dim(isl.dim_type.in_)): + islmap = islmap.set_dim_name(isl.dim_type.in_, i, islmap.get_dim_name( + isl.dim_type.in_, i)+marker) + return islmap + + def _union_of_isl_sets_or_maps(set_list): union = set_list[0] for s in set_list[1:]: From ceb9015a1a18d16f0615c8f3deb9cf35f0cb9ca2 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Apr 2020 22:14:38 -0500 Subject: [PATCH 004/220] test lexicographic order map creation and statement instance order creation --- test/test_linearization_checker.py | 203 +++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index c112b40ae..5a05bdd8e 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -46,6 +46,8 @@ faulthandler.enable() +# {{{ test LexSchedule and isl map creation + def test_lexschedule_and_islmap_creation(): import islpy as isl from loopy.schedule.checker import ( @@ -362,6 +364,207 @@ def perform_insn_cd_checks_with(sid_c, sid_d): else: perform_insn_cd_checks_with(1, 0) +# }}} + + +# {{{ test statement instance ordering creation + +def test_statement_instance_ordering_creation(): + import islpy as isl + from loopy.schedule.checker import ( + get_schedule_for_statement_pair, + get_isl_maps_for_LexSchedule, + ) + from loopy.schedule.checker.utils import ( + align_isl_maps_by_var_names, + append_marker_to_in_dim_names, + ) + from loopy.schedule.checker.lexicographic_order_map import ( + get_statement_ordering_map, + ) + + # example kernel (add deps to fix loop order) + knl = lp.make_kernel( + [ + "{[i]: 0<=itemp = b[i,k] {id=insn_a} + end + for j + a[i,j] = temp + 1 {id=insn_b,dep=insn_a} + c[i,j] = d[i,j] {id=insn_c,dep=insn_b} + end + end + for t + e[t] = f[t] {id=insn_d, dep=insn_c} + end + """, + name="example", + assumptions="pi,pj,pk,pt >= 1", + lang_version=(2018, 2) + ) + knl = lp.add_and_infer_dtypes( + knl, + {"b": np.float32, "d": np.float32, "f": np.float32}) + knl = lp.prioritize_loops(knl, "i,k") + knl = lp.prioritize_loops(knl, "i,j") + + # get a linearization + knl = preprocess_kernel(knl) + knl = get_one_linearized_kernel(knl) + linearization_items = knl.linearization + + def check_sio_for_insn_pair( + insn_id_before, + insn_id_after, + expected_lex_order_map, + expected_sio, + ): + + lex_sched = get_schedule_for_statement_pair( + knl, + linearization_items, + insn_id_before, + insn_id_after, + ) + + # Get two isl maps representing the LexSchedule + isl_sched_map_before, isl_sched_map_after = \ + get_isl_maps_for_LexSchedule(lex_sched, knl, insn_id_before, insn_id_after) + + # get map representing lexicographic ordering + sched_lex_order_map = lex_sched.get_lex_order_map_for_sched_space() + + assert sched_lex_order_map == expected_lex_order_map + + # create statement instance ordering, + # maps each statement instance to all statement instances occuring later + sio = get_statement_ordering_map( + isl_sched_map_before, + isl_sched_map_after, + sched_lex_order_map, + ) + + print(sio) + print(expected_sio) + + sio_aligned = align_isl_maps_by_var_names(sio, expected_sio) + + print(sio_aligned) + print(expected_sio) + + assert sio_aligned == expected_sio + + expected_lex_order_map = isl.Map( + "{ " + "[l0, l1, l2, l3, l4] -> [l0_, l1_, l2_, l3_, l4_] : l0_ > l0; " + "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_, l2_, l3_, l4_] : l1_ > l1; " + "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_, l3_, l4_] : l2_ > l2; " + "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_= l2, l3_, l4_] : l3_ > l3; " + "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_= l2, l3_= l3, l4_] : l4_ > l4 " + "}" + ) + + # Relationship between insn_a and insn_b --------------------------------------- + + expected_sio = isl.Map( + "[pi, pj, pk] -> { " + "[statement' = 0, i', k'] -> [statement = 1, i, j] : " + "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i'; " + "[statement' = 0, i', k'] -> [statement = 1, i = i', j] : " + "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " + "}" + ) + # isl ignores these apostrophes, so explicitly add them + expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + + check_sio_for_insn_pair( + "insn_a", "insn_b", expected_lex_order_map, expected_sio) + + # Relationship between insn_a and insn_c --------------------------------------- + + expected_sio = isl.Map( + "[pi, pj, pk] -> { " + "[statement' = 0, i', k'] -> [statement = 1, i, j] : " + "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i'; " + "[statement' = 0, i', k'] -> [statement = 1, i = i', j] : " + "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " + "}" + ) + # isl ignores these apostrophes, so explicitly add them + expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + + check_sio_for_insn_pair( + "insn_a", "insn_c", expected_lex_order_map, expected_sio) + + # Relationship between insn_a and insn_d --------------------------------------- + + expected_sio = isl.Map( + "[pt, pi, pk] -> { " + "[statement' = 0, i', k'] -> [statement = 1, t] : " + "0 <= i' < pi and 0 <= k' < pk and 0 <= t < pt " + "}" + ) + # isl ignores these apostrophes, so explicitly add them + expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + + check_sio_for_insn_pair( + "insn_a", "insn_d", expected_lex_order_map, expected_sio) + + # Relationship between insn_b and insn_c --------------------------------------- + + expected_sio = isl.Map( + "[pi, pj] -> { " + "[statement' = 0, i', j'] -> [statement = 1, i, j] : " + "0 <= i' < pi and 0 <= j' < pj and i > i' and 0 <= i < pi and 0 <= j < pj; " + "[statement' = 0, i', j'] -> [statement = 1, i = i', j] : " + "0 <= i' < pi and 0 <= j' < pj and j > j' and 0 <= j < pj; " + "[statement' = 0, i', j'] -> [statement = 1, i = i', j = j'] : " + "0 <= i' < pi and 0 <= j' < pj " + "}" + ) + # isl ignores these apostrophes, so explicitly add them + expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + + check_sio_for_insn_pair( + "insn_b", "insn_c", expected_lex_order_map, expected_sio) + + # Relationship between insn_b and insn_d --------------------------------------- + + expected_sio = isl.Map( + "[pt, pi, pj] -> { " + "[statement' = 0, i', j'] -> [statement = 1, t] : " + "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " + "}" + ) + # isl ignores these apostrophes, so explicitly add them + expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + + check_sio_for_insn_pair( + "insn_b", "insn_d", expected_lex_order_map, expected_sio) + + # Relationship between insn_c and insn_d --------------------------------------- + + expected_sio = isl.Map( + "[pt, pi, pj] -> { " + "[statement' = 0, i', j'] -> [statement = 1, t] : " + "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " + "}" + ) + # isl ignores these apostrophes, so explicitly add them + expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + + check_sio_for_insn_pair( + "insn_c", "insn_d", expected_lex_order_map, expected_sio) + +# }}} + if __name__ == "__main__": if len(sys.argv) > 1: From 6f109f979f39a4ab2cc7839ea582b1457c538ac6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Apr 2020 22:28:38 -0500 Subject: [PATCH 005/220] fixing flake8 issues --- test/test_linearization_checker.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 5a05bdd8e..52145915d 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -435,8 +435,8 @@ def check_sio_for_insn_pair( ) # Get two isl maps representing the LexSchedule - isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched, knl, insn_id_before, insn_id_after) + isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( + lex_sched, knl, insn_id_before, insn_id_after) # get map representing lexicographic ordering sched_lex_order_map = lex_sched.get_lex_order_map_for_sched_space() @@ -463,11 +463,11 @@ def check_sio_for_insn_pair( expected_lex_order_map = isl.Map( "{ " - "[l0, l1, l2, l3, l4] -> [l0_, l1_, l2_, l3_, l4_] : l0_ > l0; " - "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_, l2_, l3_, l4_] : l1_ > l1; " - "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_, l3_, l4_] : l2_ > l2; " - "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_= l2, l3_, l4_] : l3_ > l3; " - "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_= l2, l3_= l3, l4_] : l4_ > l4 " + "[l0, l1, l2, l3, l4] -> [l0_, l1_, l2_, l3_, l4_]: l0_ > l0; " + "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_, l2_, l3_, l4_]: l1_ > l1; " + "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_, l3_, l4_]: l2_ > l2; " + "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_= l2, l3_, l4_]: l3_ > l3; " + "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_= l2, l3_= l3, l4_]: l4_ > l4" "}" ) From ae7f906a83159796f0ae21929f7dd8d08d518279 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 21 Apr 2020 03:57:15 -0500 Subject: [PATCH 006/220] replace append_marker_to_in_dim_names() with more generic append_marker_to_isl_map_var_names() that allows dim specification --- .../checker/lexicographic_order_map.py | 5 ++-- loopy/schedule/checker/utils.py | 29 ++++++++++++++----- test/test_linearization_checker.py | 20 ++++++++----- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 61f191247..ddc320ed9 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -56,9 +56,10 @@ def get_statement_ordering_map( lex_map).apply_range(sched_map_after.reverse()) # append marker to in names from loopy.schedule.checker.utils import ( - append_marker_to_in_dim_names, + append_marker_to_isl_map_var_names, ) - return append_marker_to_in_dim_names(sio, before_marker) + return append_marker_to_isl_map_var_names( + sio, isl.dim_type.in_, before_marker) def get_lex_order_constraint(islvars, before_names, after_names): diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 96aa007c7..46c33ed3b 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -143,6 +143,27 @@ def align_isl_maps_by_var_names(input_map, target_map): return aligned_input_map +def append_marker_to_isl_map_var_names(old_isl_map, dim_type, marker="'"): + """Return an isl_map with marker appended to + dim_type dimension names. + + :arg old_isl_map: A :class:`islpy.Map`. + + :arg dim_type: A :class:`islpy.dim_type`, i.e., an :class:`int`, + specifying the dimension to be marked. + + :returns: A :class:`islpy.Map` matching `old_isl_map` with + apostrophes appended to dim_type dimension names. + + """ + + new_map = old_isl_map.copy() + for i in range(len(old_isl_map.get_var_names(dim_type))): + new_map = new_map.set_dim_name(dim_type, i, old_isl_map.get_dim_name( + dim_type, i)+marker) + return new_map + + def append_marker_to_strings(strings, marker="'"): if not isinstance(strings, list): raise ValueError("append_marker_to_strings did not receive a list") @@ -150,14 +171,6 @@ def append_marker_to_strings(strings, marker="'"): return [s+marker for s in strings] -def append_marker_to_in_dim_names(islmap, marker="'"): - # append marker to in names - for i in range(islmap.dim(isl.dim_type.in_)): - islmap = islmap.set_dim_name(isl.dim_type.in_, i, islmap.get_dim_name( - isl.dim_type.in_, i)+marker) - return islmap - - def _union_of_isl_sets_or_maps(set_list): union = set_list[0] for s in set_list[1:]: diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 52145915d..a15d48d1c 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -377,7 +377,7 @@ def test_statement_instance_ordering_creation(): ) from loopy.schedule.checker.utils import ( align_isl_maps_by_var_names, - append_marker_to_in_dim_names, + append_marker_to_isl_map_var_names, ) from loopy.schedule.checker.lexicographic_order_map import ( get_statement_ordering_map, @@ -482,7 +482,8 @@ def check_sio_for_insn_pair( "}" ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + expected_sio = append_marker_to_isl_map_var_names( + expected_sio, isl.dim_type.in_, "'") check_sio_for_insn_pair( "insn_a", "insn_b", expected_lex_order_map, expected_sio) @@ -498,7 +499,8 @@ def check_sio_for_insn_pair( "}" ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + expected_sio = append_marker_to_isl_map_var_names( + expected_sio, isl.dim_type.in_, "'") check_sio_for_insn_pair( "insn_a", "insn_c", expected_lex_order_map, expected_sio) @@ -512,7 +514,8 @@ def check_sio_for_insn_pair( "}" ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + expected_sio = append_marker_to_isl_map_var_names( + expected_sio, isl.dim_type.in_, "'") check_sio_for_insn_pair( "insn_a", "insn_d", expected_lex_order_map, expected_sio) @@ -530,7 +533,8 @@ def check_sio_for_insn_pair( "}" ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + expected_sio = append_marker_to_isl_map_var_names( + expected_sio, isl.dim_type.in_, "'") check_sio_for_insn_pair( "insn_b", "insn_c", expected_lex_order_map, expected_sio) @@ -544,7 +548,8 @@ def check_sio_for_insn_pair( "}" ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + expected_sio = append_marker_to_isl_map_var_names( + expected_sio, isl.dim_type.in_, "'") check_sio_for_insn_pair( "insn_b", "insn_d", expected_lex_order_map, expected_sio) @@ -558,7 +563,8 @@ def check_sio_for_insn_pair( "}" ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_in_dim_names(expected_sio, "'") + expected_sio = append_marker_to_isl_map_var_names( + expected_sio, isl.dim_type.in_, "'") check_sio_for_insn_pair( "insn_c", "insn_d", expected_lex_order_map, expected_sio) From 2556e7590f6724b1a49c8370925dc9701aab6097 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 27 Apr 2020 18:16:23 -0500 Subject: [PATCH 007/220] remove extra args from get_isl_maps_for_LexSchedule() --- test/test_linearization_checker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index c6f8d56dc..f51b050ac 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -436,7 +436,7 @@ def check_sio_for_insn_pair( # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - lex_sched, knl, insn_id_before, insn_id_after) + lex_sched, knl) # get map representing lexicographic ordering sched_lex_order_map = lex_sched.get_lex_order_map_for_sched_space() From f38f3027c1b575c6cbce1849b80a37292accbb85 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 12 May 2020 00:47:46 -0500 Subject: [PATCH 008/220] add new reserved prefix to map vars --- test/test_linearization_checker.py | 55 +++++++++++++++++++----------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 9ce2f981e..1e5457b94 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -485,23 +485,40 @@ def check_sio_for_insn_pair( assert sio_aligned == expected_sio - expected_lex_order_map = isl.Map( - "{ " - "[l0, l1, l2, l3, l4] -> [l0_, l1_, l2_, l3_, l4_]: l0_ > l0; " - "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_, l2_, l3_, l4_]: l1_ > l1; " - "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_, l3_, l4_]: l2_ > l2; " - "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_= l2, l3_, l4_]: l3_ > l3; " - "[l0, l1, l2, l3, l4] -> [l0_= l0, l1_= l1, l2_= l2, l3_= l3, l4_]: l4_ > l4" - "}" - ) + expected_lex_order_map = isl.Map("{ " + "[_lp_sched_l0, _lp_sched_l1, _lp_sched_l2, _lp_sched_l3, _lp_sched_l4] -> " + "[_lp_sched_l0_, _lp_sched_l1_, _lp_sched_l2_, _lp_sched_l3_, _lp_sched_l4_]" + ":" + "(" + "_lp_sched_l0_ > _lp_sched_l0 " + ") or (" + "_lp_sched_l0_= _lp_sched_l0 and " + "_lp_sched_l1_ > _lp_sched_l1 " + ") or (" + "_lp_sched_l0_= _lp_sched_l0 and " + "_lp_sched_l1_= _lp_sched_l1 and " + "_lp_sched_l2_ > _lp_sched_l2 " + ") or (" + "_lp_sched_l0_= _lp_sched_l0 and " + "_lp_sched_l1_= _lp_sched_l1 and " + "_lp_sched_l2_= _lp_sched_l2 and " + "_lp_sched_l3_ > _lp_sched_l3 " + ") or (" + "_lp_sched_l0_= _lp_sched_l0 and " + "_lp_sched_l1_= _lp_sched_l1 and " + "_lp_sched_l2_= _lp_sched_l2 and " + "_lp_sched_l3_= _lp_sched_l3 and " + "_lp_sched_l4_ > _lp_sched_l4" + ")" + "}") # Relationship between insn_a and insn_b --------------------------------------- expected_sio = isl.Map( "[pi, pj, pk] -> { " - "[statement' = 0, i', k'] -> [statement = 1, i, j] : " + "[_lp_sched_statement'=0, i', k'] -> [_lp_sched_statement=1, i, j]:" "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i'; " - "[statement' = 0, i', k'] -> [statement = 1, i = i', j] : " + "[_lp_sched_statement'=0, i', k'] -> [_lp_sched_statement=1, i=i', j]:" "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " "}" ) @@ -516,9 +533,9 @@ def check_sio_for_insn_pair( expected_sio = isl.Map( "[pi, pj, pk] -> { " - "[statement' = 0, i', k'] -> [statement = 1, i, j] : " + "[_lp_sched_statement'=0, i', k'] -> [_lp_sched_statement=1, i, j]:" "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i'; " - "[statement' = 0, i', k'] -> [statement = 1, i = i', j] : " + "[_lp_sched_statement'=0, i', k'] -> [_lp_sched_statement=1, i=i', j]:" "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " "}" ) @@ -533,7 +550,7 @@ def check_sio_for_insn_pair( expected_sio = isl.Map( "[pt, pi, pk] -> { " - "[statement' = 0, i', k'] -> [statement = 1, t] : " + "[_lp_sched_statement'=0, i', k'] -> [_lp_sched_statement=1, t]:" "0 <= i' < pi and 0 <= k' < pk and 0 <= t < pt " "}" ) @@ -548,11 +565,11 @@ def check_sio_for_insn_pair( expected_sio = isl.Map( "[pi, pj] -> { " - "[statement' = 0, i', j'] -> [statement = 1, i, j] : " + "[_lp_sched_statement'=0, i', j'] -> [_lp_sched_statement=1, i, j]:" "0 <= i' < pi and 0 <= j' < pj and i > i' and 0 <= i < pi and 0 <= j < pj; " - "[statement' = 0, i', j'] -> [statement = 1, i = i', j] : " + "[_lp_sched_statement'=0, i', j'] -> [_lp_sched_statement=1, i=i', j]:" "0 <= i' < pi and 0 <= j' < pj and j > j' and 0 <= j < pj; " - "[statement' = 0, i', j'] -> [statement = 1, i = i', j = j'] : " + "[_lp_sched_statement'=0, i', j'] -> [_lp_sched_statement=1, i=i', j=j']:" "0 <= i' < pi and 0 <= j' < pj " "}" ) @@ -567,7 +584,7 @@ def check_sio_for_insn_pair( expected_sio = isl.Map( "[pt, pi, pj] -> { " - "[statement' = 0, i', j'] -> [statement = 1, t] : " + "[_lp_sched_statement'=0, i', j'] -> [_lp_sched_statement=1, t]:" "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}" ) @@ -582,7 +599,7 @@ def check_sio_for_insn_pair( expected_sio = isl.Map( "[pt, pi, pj] -> { " - "[statement' = 0, i', j'] -> [statement = 1, t] : " + "[_lp_sched_statement'=0, i', j'] -> [_lp_sched_statement=1, t]:" "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}" ) From d4506a0ef3d0f8bf3adf3efbe231f4be6d1cbc09 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 12 May 2020 01:08:24 -0500 Subject: [PATCH 009/220] =?UTF-8?q?use=20composition=20symbol=20=E2=97=A6?= =?UTF-8?q?=20in=20docstring=20for=20get=5Fstatement=5Fordering=5Fmap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- loopy/schedule/checker/lexicographic_order_map.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index ddc320ed9..f42e8e610 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -46,7 +46,7 @@ def get_statement_ordering_map( :returns: An :class:`islpy.Map` representing the lex schedule as a mapping from each statement instance to all statement instances - occuring later. I.e., we compose B -> L -> A^-1, where B + occuring later. I.e., we compose B ◦ L ◦ A^-1, where B is sched_map_before, A is sched_map_after, and L is the lexicographic ordering map. From 1568d79dd0d36a33e77efb6ad94d997e6fa2e217 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 12 May 2020 01:12:18 -0500 Subject: [PATCH 010/220] in docstring for get_statement_ordering_map(), clarify that we are composing relations --- loopy/schedule/checker/lexicographic_order_map.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index f42e8e610..ce8808119 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -46,9 +46,9 @@ def get_statement_ordering_map( :returns: An :class:`islpy.Map` representing the lex schedule as a mapping from each statement instance to all statement instances - occuring later. I.e., we compose B ◦ L ◦ A^-1, where B - is sched_map_before, A is sched_map_after, and L is the - lexicographic ordering map. + occuring later. I.e., we compose relations B, L, and A as + B ◦ L ◦ A^-1, where B is sched_map_before, A is sched_map_after, + and L is the lexicographic ordering map. """ From a2c007b2f6908d72ccbd1c125347ee1e0f5e1c7a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 19 May 2020 00:04:56 -0500 Subject: [PATCH 011/220] try a slightlyl different function composition symbol (to address 'Non-ASCII character' syntax error) --- loopy/schedule/checker/lexicographic_order_map.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index ce8808119..9807d293f 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -47,7 +47,7 @@ def get_statement_ordering_map( :returns: An :class:`islpy.Map` representing the lex schedule as a mapping from each statement instance to all statement instances occuring later. I.e., we compose relations B, L, and A as - B ◦ L ◦ A^-1, where B is sched_map_before, A is sched_map_after, + B ∘ L ∘ A^-1, where B is sched_map_before, A is sched_map_after, and L is the lexicographic ordering map. """ From 11f8edd708ada13db5f81aa6b2d87638978155ca Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 19 May 2020 00:11:31 -0500 Subject: [PATCH 012/220] add 'coding: utf-8' at top of file to allow composition character --- loopy/schedule/checker/lexicographic_order_map.py | 1 + 1 file changed, 1 insertion(+) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 9807d293f..5ce2bb4a5 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -1,3 +1,4 @@ +# coding: utf-8 __copyright__ = "Copyright (C) 2019 James Stevens" __license__ = """ From db5fefe4c803947855484b96ce3132a3dc0a4a45 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 19 May 2020 01:57:43 -0500 Subject: [PATCH 013/220] improve time complexity of get_lex_order_constraint() --- .../checker/lexicographic_order_map.py | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 5ce2bb4a5..d783bac76 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -92,14 +92,32 @@ def get_lex_order_constraint(islvars, before_names, after_names): """ + # Initialize constraint with i0' < i0 lex_order_constraint = islvars[before_names[0]].lt_set(islvars[after_names[0]]) + + # Initialize conjunction constraint with True. + # For each dim d, starting with d=1, this conjunction will have d equalities, + # e.g., (i0' = i0 and i1' = i1 and ... i(d-1)' = i(d-1)) + equality_constraint_conj = islvars[0].eq_set(islvars[0]) + for i in range(1, len(before_names)): - lex_order_constraint_conj = islvars[before_names[i]].lt_set( - islvars[after_names[i]]) - for j in range(i): - lex_order_constraint_conj = lex_order_constraint_conj & \ - islvars[before_names[j]].eq_set(islvars[after_names[j]]) - lex_order_constraint = lex_order_constraint | lex_order_constraint_conj + + # Add the next equality constraint to equality_constraint_conj + equality_constraint_conj = equality_constraint_conj & \ + islvars[before_names[i-1]].eq_set(islvars[after_names[i-1]]) + + # Create a conjunction constraint by combining a less-than + # constraint for this dim, e.g., (i1' < i1), with the current + # equality constraint conjunction. + # For each dim d, starting with d=1, this conjunction will have d equalities, + # and one inequality, + # e.g., (i0' = i0 and i1' = i1 and ... i(d-1)' = i(d-1) and id' < id) + full_conj_constraint = islvars[before_names[i]].lt_set( + islvars[after_names[i]]) & equality_constraint_conj + + # Union this new constraint with the current lex_order_constraint + lex_order_constraint = lex_order_constraint | full_conj_constraint + return lex_order_constraint From 97e90820c5c232b845bf5063bfe2a71bd3bee01b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 19 May 2020 02:22:12 -0500 Subject: [PATCH 014/220] have create_lex_order_map() put apostrophes on 'before' vars for consistency with other logic --- .../checker/lexicographic_order_map.py | 6 +-- loopy/schedule/checker/schedule.py | 2 +- test/test_linearization_checker.py | 40 +++++++++++-------- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index d783bac76..17b6616ca 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -153,13 +153,13 @@ def create_lex_order_map( """ - if before_names is None: - before_names = ["i%s" % (i) for i in range(n_dims)] if after_names is None: + after_names = ["i%s" % (i) for i in range(n_dims)] + if before_names is None: from loopy.schedule.checker.utils import ( append_marker_to_strings, ) - after_names = append_marker_to_strings(before_names, marker="_") + before_names = append_marker_to_strings(after_names, marker="'") assert len(before_names) == len(after_names) == n_dims dim_type = isl.dim_type diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index ea0829199..a87723480 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -409,7 +409,7 @@ def get_lex_order_map_for_sched_space(self): ) n_dims = self.max_lex_dims() return create_lex_order_map( - n_dims, before_names=self.get_lex_var_names()) + n_dims, after_names=self.get_lex_var_names()) def __str__(self): diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 1e5457b94..e57df9ac8 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -486,32 +486,38 @@ def check_sio_for_insn_pair( assert sio_aligned == expected_sio expected_lex_order_map = isl.Map("{ " - "[_lp_sched_l0, _lp_sched_l1, _lp_sched_l2, _lp_sched_l3, _lp_sched_l4] -> " - "[_lp_sched_l0_, _lp_sched_l1_, _lp_sched_l2_, _lp_sched_l3_, _lp_sched_l4_]" + "[_lp_sched_l0', _lp_sched_l1', _lp_sched_l2', _lp_sched_l3', _lp_sched_l4']" + " -> [_lp_sched_l0, _lp_sched_l1, _lp_sched_l2, _lp_sched_l3, _lp_sched_l4]" ":" "(" - "_lp_sched_l0_ > _lp_sched_l0 " + "_lp_sched_l0' < _lp_sched_l0 " ") or (" - "_lp_sched_l0_= _lp_sched_l0 and " - "_lp_sched_l1_ > _lp_sched_l1 " + "_lp_sched_l0'= _lp_sched_l0 and " + "_lp_sched_l1' < _lp_sched_l1 " ") or (" - "_lp_sched_l0_= _lp_sched_l0 and " - "_lp_sched_l1_= _lp_sched_l1 and " - "_lp_sched_l2_ > _lp_sched_l2 " + "_lp_sched_l0'= _lp_sched_l0 and " + "_lp_sched_l1'= _lp_sched_l1 and " + "_lp_sched_l2' < _lp_sched_l2 " ") or (" - "_lp_sched_l0_= _lp_sched_l0 and " - "_lp_sched_l1_= _lp_sched_l1 and " - "_lp_sched_l2_= _lp_sched_l2 and " - "_lp_sched_l3_ > _lp_sched_l3 " + "_lp_sched_l0'= _lp_sched_l0 and " + "_lp_sched_l1'= _lp_sched_l1 and " + "_lp_sched_l2'= _lp_sched_l2 and " + "_lp_sched_l3' < _lp_sched_l3 " ") or (" - "_lp_sched_l0_= _lp_sched_l0 and " - "_lp_sched_l1_= _lp_sched_l1 and " - "_lp_sched_l2_= _lp_sched_l2 and " - "_lp_sched_l3_= _lp_sched_l3 and " - "_lp_sched_l4_ > _lp_sched_l4" + "_lp_sched_l0'= _lp_sched_l0 and " + "_lp_sched_l1'= _lp_sched_l1 and " + "_lp_sched_l2'= _lp_sched_l2 and " + "_lp_sched_l3'= _lp_sched_l3 and " + "_lp_sched_l4' < _lp_sched_l4" ")" "}") + # Isl ignores these apostrophes, but test would still pass since it ignores + # variable names when checking for equality. Even so, explicitly add apostrophes + # for sanity. + expected_lex_order_map = append_marker_to_isl_map_var_names( + expected_lex_order_map, isl.dim_type.in_, "'") + # Relationship between insn_a and insn_b --------------------------------------- expected_sio = isl.Map( From 3b5d4caa5a5f1e272172370f949bcd19a54d9b0a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 26 May 2020 10:27:36 -0500 Subject: [PATCH 015/220] rename LexScheduleStatement->PairwiseScheduleStatement, get_isl_maps_for_LexSchedule->get_isl_maps_from_PairwiseScheduleBuilder, LexSchedule->PairwiseScheduleBuilder; also rename other variables for consistency --- test/test_linearization_checker.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index df40c1dd5..255d2b0a6 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -46,9 +46,9 @@ faulthandler.enable() -# {{{ test LexSchedule and isl map creation +# {{{ test PairwiseScheduleBuilder and isl map creation -def test_lexschedule_and_islmap_creation(): +def test_pairwise_schedule_and_islmap_creation(): import islpy as isl from loopy.schedule.checker import ( get_schedule_for_statement_pair, @@ -397,7 +397,7 @@ def test_statement_instance_ordering_creation(): import islpy as isl from loopy.schedule.checker import ( get_schedule_for_statement_pair, - get_isl_maps_for_LexSchedule, + get_isl_maps_from_PairwiseScheduleBuilder, ) from loopy.schedule.checker.utils import ( align_isl_maps_by_var_names, @@ -451,19 +451,19 @@ def check_sio_for_insn_pair( expected_sio, ): - lex_sched = get_schedule_for_statement_pair( + sched_builder = get_schedule_for_statement_pair( knl, linearization_items, insn_id_before, insn_id_after, ) - # Get two isl maps representing the LexSchedule - isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - lex_sched, knl) + # Get two isl maps from the PairwiseScheduleBuilder + isl_sched_map_before, isl_sched_map_after = \ + get_isl_maps_from_PairwiseScheduleBuilder(sched_builder, knl) # get map representing lexicographic ordering - sched_lex_order_map = lex_sched.get_lex_order_map_for_sched_space() + sched_lex_order_map = sched_builder.get_lex_order_map_for_sched_space() assert sched_lex_order_map == expected_lex_order_map From ba46ade4f5b002e72451d593162cac22cfa10553 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 1 Jun 2020 22:30:23 -0500 Subject: [PATCH 016/220] update identifier prefix for loopy.schedule.checker from _lp_sched_->_lp_linchk_ --- test/test_linearization_checker.py | 57 ++++++++++++++++-------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 6841072ff..01e28f24a 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -486,29 +486,32 @@ def check_sio_for_insn_pair( assert sio_aligned == expected_sio expected_lex_order_map = isl.Map("{ " - "[_lp_sched_l0', _lp_sched_l1', _lp_sched_l2', _lp_sched_l3', _lp_sched_l4']" - " -> [_lp_sched_l0, _lp_sched_l1, _lp_sched_l2, _lp_sched_l3, _lp_sched_l4]" + "[_lp_linchk_l0', _lp_linchk_l1', _lp_linchk_l2', _lp_linchk_l3', " + "_lp_linchk_l4']" + " -> " + "[_lp_linchk_l0, _lp_linchk_l1, _lp_linchk_l2, _lp_linchk_l3, " + "_lp_linchk_l4]" ":" "(" - "_lp_sched_l0' < _lp_sched_l0 " + "_lp_linchk_l0' < _lp_linchk_l0 " ") or (" - "_lp_sched_l0'= _lp_sched_l0 and " - "_lp_sched_l1' < _lp_sched_l1 " + "_lp_linchk_l0'= _lp_linchk_l0 and " + "_lp_linchk_l1' < _lp_linchk_l1 " ") or (" - "_lp_sched_l0'= _lp_sched_l0 and " - "_lp_sched_l1'= _lp_sched_l1 and " - "_lp_sched_l2' < _lp_sched_l2 " + "_lp_linchk_l0'= _lp_linchk_l0 and " + "_lp_linchk_l1'= _lp_linchk_l1 and " + "_lp_linchk_l2' < _lp_linchk_l2 " ") or (" - "_lp_sched_l0'= _lp_sched_l0 and " - "_lp_sched_l1'= _lp_sched_l1 and " - "_lp_sched_l2'= _lp_sched_l2 and " - "_lp_sched_l3' < _lp_sched_l3 " + "_lp_linchk_l0'= _lp_linchk_l0 and " + "_lp_linchk_l1'= _lp_linchk_l1 and " + "_lp_linchk_l2'= _lp_linchk_l2 and " + "_lp_linchk_l3' < _lp_linchk_l3 " ") or (" - "_lp_sched_l0'= _lp_sched_l0 and " - "_lp_sched_l1'= _lp_sched_l1 and " - "_lp_sched_l2'= _lp_sched_l2 and " - "_lp_sched_l3'= _lp_sched_l3 and " - "_lp_sched_l4' < _lp_sched_l4" + "_lp_linchk_l0'= _lp_linchk_l0 and " + "_lp_linchk_l1'= _lp_linchk_l1 and " + "_lp_linchk_l2'= _lp_linchk_l2 and " + "_lp_linchk_l3'= _lp_linchk_l3 and " + "_lp_linchk_l4' < _lp_linchk_l4" ")" "}") @@ -522,9 +525,9 @@ def check_sio_for_insn_pair( expected_sio = isl.Map( "[pi, pj, pk] -> { " - "[_lp_sched_statement'=0, i', k'] -> [_lp_sched_statement=1, i, j]:" + "[_lp_linchk_statement'=0, i', k'] -> [_lp_linchk_statement=1, i, j]:" "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i'; " - "[_lp_sched_statement'=0, i', k'] -> [_lp_sched_statement=1, i=i', j]:" + "[_lp_linchk_statement'=0, i', k'] -> [_lp_linchk_statement=1, i=i', j]:" "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " "}" ) @@ -539,9 +542,9 @@ def check_sio_for_insn_pair( expected_sio = isl.Map( "[pi, pj, pk] -> { " - "[_lp_sched_statement'=0, i', k'] -> [_lp_sched_statement=1, i, j]:" + "[_lp_linchk_statement'=0, i', k'] -> [_lp_linchk_statement=1, i, j]:" "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i'; " - "[_lp_sched_statement'=0, i', k'] -> [_lp_sched_statement=1, i=i', j]:" + "[_lp_linchk_statement'=0, i', k'] -> [_lp_linchk_statement=1, i=i', j]:" "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " "}" ) @@ -556,7 +559,7 @@ def check_sio_for_insn_pair( expected_sio = isl.Map( "[pt, pi, pk] -> { " - "[_lp_sched_statement'=0, i', k'] -> [_lp_sched_statement=1, t]:" + "[_lp_linchk_statement'=0, i', k'] -> [_lp_linchk_statement=1, t]:" "0 <= i' < pi and 0 <= k' < pk and 0 <= t < pt " "}" ) @@ -571,11 +574,11 @@ def check_sio_for_insn_pair( expected_sio = isl.Map( "[pi, pj] -> { " - "[_lp_sched_statement'=0, i', j'] -> [_lp_sched_statement=1, i, j]:" + "[_lp_linchk_statement'=0, i', j'] -> [_lp_linchk_statement=1, i, j]:" "0 <= i' < pi and 0 <= j' < pj and i > i' and 0 <= i < pi and 0 <= j < pj; " - "[_lp_sched_statement'=0, i', j'] -> [_lp_sched_statement=1, i=i', j]:" + "[_lp_linchk_statement'=0, i', j'] -> [_lp_linchk_statement=1, i=i', j]:" "0 <= i' < pi and 0 <= j' < pj and j > j' and 0 <= j < pj; " - "[_lp_sched_statement'=0, i', j'] -> [_lp_sched_statement=1, i=i', j=j']:" + "[_lp_linchk_statement'=0, i', j'] -> [_lp_linchk_statement=1, i=i', j=j']:" "0 <= i' < pi and 0 <= j' < pj " "}" ) @@ -590,7 +593,7 @@ def check_sio_for_insn_pair( expected_sio = isl.Map( "[pt, pi, pj] -> { " - "[_lp_sched_statement'=0, i', j'] -> [_lp_sched_statement=1, t]:" + "[_lp_linchk_statement'=0, i', j'] -> [_lp_linchk_statement=1, t]:" "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}" ) @@ -605,7 +608,7 @@ def check_sio_for_insn_pair( expected_sio = isl.Map( "[pt, pi, pj] -> { " - "[_lp_sched_statement'=0, i', j'] -> [_lp_sched_statement=1, t]:" + "[_lp_linchk_statement'=0, i', j'] -> [_lp_linchk_statement=1, t]:" "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}" ) From a4c97513effa690b7c3a66f67caf54ed565490ad Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 2 Jun 2020 03:30:13 -0500 Subject: [PATCH 017/220] don't require islvars be passed to get_lex_order_constraint(); islvars default: create islvars from before_names+after_names --- .../checker/lexicographic_order_map.py | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 17b6616ca..b547e1d94 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -63,17 +63,11 @@ def get_statement_ordering_map( sio, isl.dim_type.in_, before_marker) -def get_lex_order_constraint(islvars, before_names, after_names): +def get_lex_order_constraint(before_names, after_names, islvars=None): """Return a constraint represented as an :class:`islpy.Set` defining a 'happens before' relationship in a lexicographic ordering. - :arg islvars: A dictionary from variable names to :class:`islpy.PwAff` - instances that represent each of the variables - (islvars may be produced by `islpy.make_zero_and_vars`). The key - '0' is also include and represents a :class:`islpy.PwAff` zero constant. - This dictionary defines the space to be used for the set. - :arg before_names: A list of :class:`str` variable names representing the lexicographic space dimensions for a point in lexicographic time that occurs before. (see example below) @@ -82,6 +76,14 @@ def get_lex_order_constraint(islvars, before_names, after_names): the lexicographic space dimensions for a point in lexicographic time that occurs after. (see example below) + :arg islvars: A dictionary from variable names to :class:`islpy.PwAff` + instances that represent each of the variables + (islvars may be produced by `islpy.make_zero_and_vars`). The key + '0' is also include and represents a :class:`islpy.PwAff` zero constant. + This dictionary defines the space to be used for the set. If no + value is passed, the dictionary will be made using ``before_names`` + and ``after_names``. + :returns: An :class:`islpy.Set` representing a constraint that enforces a lexicographic ordering. E.g., if ``before_names = [i0', i1', i2']`` and ``after_names = [i0, i1, i2]``, return the set:: @@ -92,6 +94,10 @@ def get_lex_order_constraint(islvars, before_names, after_names): """ + # If no islvars passed, make them using the names provided + if islvars is None: + islvars = isl.make_zero_and_vars(before_names+after_names, []) + # Initialize constraint with i0' < i0 lex_order_constraint = islvars[before_names[0]].lt_set(islvars[after_names[0]]) @@ -164,12 +170,7 @@ def create_lex_order_map( assert len(before_names) == len(after_names) == n_dims dim_type = isl.dim_type - islvars = isl.make_zero_and_vars( - before_names+after_names, - []) - - lex_order_constraint = get_lex_order_constraint( - islvars, before_names, after_names) + lex_order_constraint = get_lex_order_constraint(before_names, after_names) lex_map = isl.Map.from_domain(lex_order_constraint) lex_map = lex_map.move_dims( From ed8c8fa252fc895c3e7ce254111227d981d1b94c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 2 Jun 2020 04:16:23 -0500 Subject: [PATCH 018/220] delete stray print statements in test_statement_instance_ordering_creation() --- test/test_linearization_checker.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 01e28f24a..58884b443 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -475,14 +475,8 @@ def check_sio_for_insn_pair( sched_lex_order_map, ) - print(sio) - print(expected_sio) - sio_aligned = align_isl_maps_by_var_names(sio, expected_sio) - print(sio_aligned) - print(expected_sio) - assert sio_aligned == expected_sio expected_lex_order_map = isl.Map("{ " From d345c21fc0b6cc4c6c4de3b403c1565f4f35ec17 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 7 Jun 2020 16:00:32 -0500 Subject: [PATCH 019/220] update basedon func change: get_isl_maps_from_PairwiseScheduleBuilder(sched_builder, knl)->sched_builder.build_maps(knl) --- test/test_linearization_checker.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 9511da729..15d022144 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -390,7 +390,6 @@ def test_statement_instance_ordering_creation(): import islpy as isl from loopy.schedule.checker import ( get_schedule_for_statement_pair, - get_isl_maps_from_PairwiseScheduleBuilder, ) from loopy.schedule.checker.utils import ( align_isl_maps_by_var_names, @@ -452,8 +451,7 @@ def check_sio_for_insn_pair( ) # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_from_PairwiseScheduleBuilder(sched_builder, knl) + isl_sched_map_before, isl_sched_map_after = sched_builder.build_maps(knl) # get map representing lexicographic ordering sched_lex_order_map = sched_builder.get_lex_order_map_for_sched_space() From 7c2309ab23db59413b5fb3dbdf3cb58325087941 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 8 Jun 2020 14:42:59 -0500 Subject: [PATCH 020/220] rename local vars isl_sched_map_*->sched_map_* --- test/test_linearization_checker.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 3745564d2..5f7329ba1 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -451,7 +451,7 @@ def check_sio_for_insn_pair( ) # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_map_before, isl_sched_map_after = sched_builder.build_maps(knl) + sched_map_before, sched_map_after = sched_builder.build_maps(knl) # get map representing lexicographic ordering sched_lex_order_map = sched_builder.get_lex_order_map_for_sched_space() @@ -461,8 +461,8 @@ def check_sio_for_insn_pair( # create statement instance ordering, # maps each statement instance to all statement instances occuring later sio = get_statement_ordering_map( - isl_sched_map_before, - isl_sched_map_after, + sched_map_before, + sched_map_after, sched_lex_order_map, ) From 0f4269b86ae1d7b1863184b731d007bb8463324f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 8 Jun 2020 16:50:25 -0500 Subject: [PATCH 021/220] update after renaming of align_isl_maps_by_var_names()->ensure_dim_names_match_and_align() --- test/test_linearization_checker.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 84decedca..5640da8b8 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -392,7 +392,7 @@ def test_statement_instance_ordering_creation(): get_schedule_for_statement_pair, ) from loopy.schedule.checker.utils import ( - align_isl_maps_by_var_names, + ensure_dim_names_match_and_align, append_marker_to_isl_map_var_names, ) from loopy.schedule.checker.lexicographic_order_map import ( @@ -466,7 +466,7 @@ def check_sio_for_insn_pair( sched_lex_order_map, ) - sio_aligned = align_isl_maps_by_var_names(sio, expected_sio) + sio_aligned = ensure_dim_names_match_and_align(sio, expected_sio) assert sio_aligned == expected_sio From c549f652e739af191d0297e5b2621bdbe33d44a2 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 10 Jul 2020 07:33:43 -0500 Subject: [PATCH 022/220] use STATEMENT_VAR_NAME and LEX_VAR_PREFIX constants when building test maps --- test/test_linearization_checker.py | 76 ++++++++++++------------------ 1 file changed, 31 insertions(+), 45 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 2dc12b451..208d9350e 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -494,35 +494,21 @@ def check_sio_for_insn_pair( assert sio_aligned == expected_sio - expected_lex_order_map = isl.Map("{ " - "[_lp_linchk_l0', _lp_linchk_l1', _lp_linchk_l2', _lp_linchk_l3', " - "_lp_linchk_l4']" - " -> " - "[_lp_linchk_l0, _lp_linchk_l1, _lp_linchk_l2, _lp_linchk_l3, " - "_lp_linchk_l4]" - ":" + expected_lex_order_map = isl.Map( + "{{ " + "[{0}0', {0}1', {0}2', {0}3', {0}4'] -> [{0}0, {0}1, {0}2, {0}3, {0}4] :" "(" - "_lp_linchk_l0' < _lp_linchk_l0 " + "{0}0' < {0}0 " ") or (" - "_lp_linchk_l0'= _lp_linchk_l0 and " - "_lp_linchk_l1' < _lp_linchk_l1 " + "{0}0'={0}0 and {0}1' < {0}1 " ") or (" - "_lp_linchk_l0'= _lp_linchk_l0 and " - "_lp_linchk_l1'= _lp_linchk_l1 and " - "_lp_linchk_l2' < _lp_linchk_l2 " + "{0}0'={0}0 and {0}1'={0}1 and {0}2' < {0}2 " ") or (" - "_lp_linchk_l0'= _lp_linchk_l0 and " - "_lp_linchk_l1'= _lp_linchk_l1 and " - "_lp_linchk_l2'= _lp_linchk_l2 and " - "_lp_linchk_l3' < _lp_linchk_l3 " + "{0}0'={0}0 and {0}1'={0}1 and {0}2'={0}2 and {0}3' < {0}3 " ") or (" - "_lp_linchk_l0'= _lp_linchk_l0 and " - "_lp_linchk_l1'= _lp_linchk_l1 and " - "_lp_linchk_l2'= _lp_linchk_l2 and " - "_lp_linchk_l3'= _lp_linchk_l3 and " - "_lp_linchk_l4' < _lp_linchk_l4" + "{0}0'={0}0 and {0}1'={0}1 and {0}2'={0}2 and {0}3'={0}3 and {0}4' < {0}4" ")" - "}") + "}}".format(LEX_VAR_PREFIX)) # Isl ignores these apostrophes, but test would still pass since it ignores # variable names when checking for equality. Even so, explicitly add apostrophes @@ -533,12 +519,12 @@ def check_sio_for_insn_pair( # Relationship between insn_a and insn_b --------------------------------------- expected_sio = isl.Map( - "[pi, pj, pk] -> { " - "[_lp_linchk_statement'=0, i', k'] -> [_lp_linchk_statement=1, i, j]:" + "[pi, pj, pk] -> {{ " + "[{0}'=0, i', k'] -> [{0}=1, i, j] : " "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i'; " - "[_lp_linchk_statement'=0, i', k'] -> [_lp_linchk_statement=1, i=i', j]:" + "[{0}'=0, i', k'] -> [{0}=1, i=i', j] : " "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " - "}" + "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them expected_sio = append_marker_to_isl_map_var_names( @@ -550,12 +536,12 @@ def check_sio_for_insn_pair( # Relationship between insn_a and insn_c --------------------------------------- expected_sio = isl.Map( - "[pi, pj, pk] -> { " - "[_lp_linchk_statement'=0, i', k'] -> [_lp_linchk_statement=1, i, j]:" + "[pi, pj, pk] -> {{ " + "[{0}'=0, i', k'] -> [{0}=1, i, j] : " "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i'; " - "[_lp_linchk_statement'=0, i', k'] -> [_lp_linchk_statement=1, i=i', j]:" + "[{0}'=0, i', k'] -> [{0}=1, i=i', j] : " "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " - "}" + "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them expected_sio = append_marker_to_isl_map_var_names( @@ -567,10 +553,10 @@ def check_sio_for_insn_pair( # Relationship between insn_a and insn_d --------------------------------------- expected_sio = isl.Map( - "[pt, pi, pk] -> { " - "[_lp_linchk_statement'=0, i', k'] -> [_lp_linchk_statement=1, t]:" + "[pt, pi, pk] -> {{ " + "[{0}'=0, i', k'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= k' < pk and 0 <= t < pt " - "}" + "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them expected_sio = append_marker_to_isl_map_var_names( @@ -582,14 +568,14 @@ def check_sio_for_insn_pair( # Relationship between insn_b and insn_c --------------------------------------- expected_sio = isl.Map( - "[pi, pj] -> { " - "[_lp_linchk_statement'=0, i', j'] -> [_lp_linchk_statement=1, i, j]:" + "[pi, pj] -> {{ " + "[{0}'=0, i', j'] -> [{0}=1, i, j] : " "0 <= i' < pi and 0 <= j' < pj and i > i' and 0 <= i < pi and 0 <= j < pj; " - "[_lp_linchk_statement'=0, i', j'] -> [_lp_linchk_statement=1, i=i', j]:" + "[{0}'=0, i', j'] -> [{0}=1, i=i', j] : " "0 <= i' < pi and 0 <= j' < pj and j > j' and 0 <= j < pj; " - "[_lp_linchk_statement'=0, i', j'] -> [_lp_linchk_statement=1, i=i', j=j']:" + "[{0}'=0, i', j'] -> [{0}=1, i=i', j=j'] : " "0 <= i' < pi and 0 <= j' < pj " - "}" + "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them expected_sio = append_marker_to_isl_map_var_names( @@ -601,10 +587,10 @@ def check_sio_for_insn_pair( # Relationship between insn_b and insn_d --------------------------------------- expected_sio = isl.Map( - "[pt, pi, pj] -> { " - "[_lp_linchk_statement'=0, i', j'] -> [_lp_linchk_statement=1, t]:" + "[pt, pi, pj] -> {{ " + "[{0}'=0, i', j'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " - "}" + "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them expected_sio = append_marker_to_isl_map_var_names( @@ -616,10 +602,10 @@ def check_sio_for_insn_pair( # Relationship between insn_c and insn_d --------------------------------------- expected_sio = isl.Map( - "[pt, pi, pj] -> { " - "[_lp_linchk_statement'=0, i', j'] -> [_lp_linchk_statement=1, t]:" + "[pt, pi, pj] -> {{ " + "[{0}'=0, i', j'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " - "}" + "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them expected_sio = append_marker_to_isl_map_var_names( From 200eed41de56f90bec1a8c3f85d6a3ef9ddc05bc Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Jul 2020 09:07:08 -0500 Subject: [PATCH 023/220] update tests after removeal of PairwiseScheduleBuilder class --- test/test_linearization_checker.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 82658bc01..9ad268edb 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -50,7 +50,7 @@ faulthandler.enable() -# {{{ test PairwiseScheduleBuilder and map creation +# {{{ test pairwise schedule map creation def test_pairwise_schedule_and_map_creation(): import islpy as isl @@ -379,6 +379,9 @@ def test_statement_instance_ordering_creation(): from loopy.schedule.checker import ( get_schedule_for_statement_pair, ) + from loopy.schedule.checker.schedule import ( + get_lex_order_map_for_sched_space, + ) from loopy.schedule.checker.utils import ( ensure_dim_names_match_and_align, append_marker_to_isl_map_var_names, @@ -431,18 +434,16 @@ def check_sio_for_insn_pair( expected_sio, ): - sched_builder = get_schedule_for_statement_pair( + # Get pairwise schedule + sched_map_before, sched_map_after = get_schedule_for_statement_pair( knl, linearization_items, insn_id_before, insn_id_after, ) - # Get two isl maps from the PairwiseScheduleBuilder - sched_map_before, sched_map_after = sched_builder.build_maps(knl) - # get map representing lexicographic ordering - sched_lex_order_map = sched_builder.get_lex_order_map_for_sched_space() + sched_lex_order_map = get_lex_order_map_for_sched_space(sched_map_before) assert sched_lex_order_map == expected_lex_order_map From cd1c1310b88d4f22157e6f9b5b79774f0e5f397f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Jul 2020 09:07:49 -0500 Subject: [PATCH 024/220] in create_lex_order_map(), make n_dims arg optional --- loopy/schedule/checker/lexicographic_order_map.py | 4 +++- loopy/schedule/checker/schedule.py | 3 +-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index b547e1d94..0966cba99 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -128,7 +128,7 @@ def get_lex_order_constraint(before_names, after_names, islvars=None): def create_lex_order_map( - n_dims, + n_dims=None, before_names=None, after_names=None, ): @@ -166,6 +166,8 @@ def create_lex_order_map( append_marker_to_strings, ) before_names = append_marker_to_strings(after_names, marker="'") + if n_dims is None: + n_dims = len(after_names) assert len(before_names) == len(after_names) == n_dims dim_type = isl.dim_type diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index ad2ecefc6..a73c72cb2 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -341,5 +341,4 @@ def get_lex_order_map_for_sched_space(schedule): ) lex_dim_names = schedule.space.get_var_names(isl.dim_type.out) - return create_lex_order_map( - len(lex_dim_names), after_names=lex_dim_names) + return create_lex_order_map(after_names=lex_dim_names) From 67887d36ed9eb1b1a229833b4590cac030f7d2b1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 Jul 2020 21:02:18 -0500 Subject: [PATCH 025/220] update sio test to deal with new output from get_schedules_for_statement_pairs(); don't hardcode expected lex order maps, instead create them to match expected dim size --- test/test_linearization_checker.py | 79 ++++++++++++++---------------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 7a1723d47..f081e2184 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -360,7 +360,7 @@ def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): def test_statement_instance_ordering_creation(): import islpy as isl from loopy.schedule.checker import ( - get_schedule_for_statement_pair, + get_schedules_for_statement_pairs, ) from loopy.schedule.checker.schedule import ( get_lex_order_map_for_sched_space, @@ -371,6 +371,7 @@ def test_statement_instance_ordering_creation(): ) from loopy.schedule.checker.lexicographic_order_map import ( get_statement_ordering_map, + create_lex_order_map, ) # example kernel (add deps to fix loop order) @@ -410,24 +411,44 @@ def test_statement_instance_ordering_creation(): knl = get_one_linearized_kernel(knl) linearization_items = knl.linearization + # Get pairwise schedules + insn_id_pairs = [ + ("insn_a", "insn_b"), + ("insn_a", "insn_c"), + ("insn_a", "insn_d"), + ("insn_b", "insn_c"), + ("insn_b", "insn_d"), + ("insn_c", "insn_d"), + ] + sched_maps = get_schedules_for_statement_pairs( + knl, + linearization_items, + insn_id_pairs, + ) + def check_sio_for_insn_pair( insn_id_before, insn_id_after, - expected_lex_order_map, + expected_lex_dims, expected_sio, ): # Get pairwise schedule - sched_map_before, sched_map_after = get_schedule_for_statement_pair( - knl, - linearization_items, - insn_id_before, - insn_id_after, - ) + sched_map_before, sched_map_after = sched_maps[ + (insn_id_before, insn_id_after)] - # get map representing lexicographic ordering + # Get map representing lexicographic ordering sched_lex_order_map = get_lex_order_map_for_sched_space(sched_map_before) + # Get expected lex order map + expected_lex_order_map = create_lex_order_map( + n_dims=expected_lex_dims, + before_names=["%s%d'" % (LEX_VAR_PREFIX, i) + for i in range(expected_lex_dims)], + after_names=["%s%d" % (LEX_VAR_PREFIX, i) + for i in range(expected_lex_dims)], + ) + assert sched_lex_order_map == expected_lex_order_map # create statement instance ordering, @@ -442,28 +463,6 @@ def check_sio_for_insn_pair( assert sio_aligned == expected_sio - expected_lex_order_map = isl.Map( - "{{ " - "[{0}0', {0}1', {0}2', {0}3', {0}4'] -> [{0}0, {0}1, {0}2, {0}3, {0}4] :" - "(" - "{0}0' < {0}0 " - ") or (" - "{0}0'={0}0 and {0}1' < {0}1 " - ") or (" - "{0}0'={0}0 and {0}1'={0}1 and {0}2' < {0}2 " - ") or (" - "{0}0'={0}0 and {0}1'={0}1 and {0}2'={0}2 and {0}3' < {0}3 " - ") or (" - "{0}0'={0}0 and {0}1'={0}1 and {0}2'={0}2 and {0}3'={0}3 and {0}4' < {0}4" - ")" - "}}".format(LEX_VAR_PREFIX)) - - # Isl ignores these apostrophes, but test would still pass since it ignores - # variable names when checking for equality. Even so, explicitly add apostrophes - # for sanity. - expected_lex_order_map = append_marker_to_isl_map_var_names( - expected_lex_order_map, isl.dim_type.in_, "'") - # Relationship between insn_a and insn_b --------------------------------------- expected_sio = isl.Map( @@ -478,8 +477,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair( - "insn_a", "insn_b", expected_lex_order_map, expected_sio) + check_sio_for_insn_pair("insn_a", "insn_b", 3, expected_sio) # Relationship between insn_a and insn_c --------------------------------------- @@ -495,8 +493,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair( - "insn_a", "insn_c", expected_lex_order_map, expected_sio) + check_sio_for_insn_pair("insn_a", "insn_c", 3, expected_sio) # Relationship between insn_a and insn_d --------------------------------------- @@ -510,8 +507,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair( - "insn_a", "insn_d", expected_lex_order_map, expected_sio) + check_sio_for_insn_pair("insn_a", "insn_d", 3, expected_sio) # Relationship between insn_b and insn_c --------------------------------------- @@ -529,8 +525,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair( - "insn_b", "insn_c", expected_lex_order_map, expected_sio) + check_sio_for_insn_pair("insn_b", "insn_c", 3, expected_sio) # Relationship between insn_b and insn_d --------------------------------------- @@ -544,8 +539,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair( - "insn_b", "insn_d", expected_lex_order_map, expected_sio) + check_sio_for_insn_pair("insn_b", "insn_d", 3, expected_sio) # Relationship between insn_c and insn_d --------------------------------------- @@ -559,8 +553,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair( - "insn_c", "insn_d", expected_lex_order_map, expected_sio) + check_sio_for_insn_pair("insn_c", "insn_d", 3, expected_sio) # }}} From 81dd0eee59b577edc58c41be83e425f110a2e1b3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 Jul 2020 21:14:55 -0500 Subject: [PATCH 026/220] add independent test for lex order map creation --- test/test_linearization_checker.py | 61 ++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index f081e2184..6070909c5 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -355,6 +355,67 @@ def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): # }}} +# {{{ test lex order map creation + +def test_lex_order_map_creation(): + import islpy as isl + from loopy.schedule.checker.lexicographic_order_map import ( + create_lex_order_map, + ) + from loopy.schedule.checker.utils import ( + append_marker_to_isl_map_var_names, + ) + + def _check_lex_map(expected_lex_order_map, n_dims): + # Isl ignores the apostrophes, so explicitly add them + expected_lex_order_map = append_marker_to_isl_map_var_names( + expected_lex_order_map, isl.dim_type.in_, "'") + + lex_order_map = create_lex_order_map( + n_dims=n_dims, + before_names=["%s%d'" % (LEX_VAR_PREFIX, i) for i in range(n_dims)], + after_names=["%s%d" % (LEX_VAR_PREFIX, i) for i in range(n_dims)], + ) + + assert lex_order_map == expected_lex_order_map + assert ( + lex_order_map.get_var_names(isl.dim_type.in_) == + expected_lex_order_map.get_var_names(isl.dim_type.in_)) + assert ( + lex_order_map.get_var_names(isl.dim_type.out) == + expected_lex_order_map.get_var_names(isl.dim_type.out)) + + expected_lex_order_map = isl.Map( + "{{ " + "[{0}0', {0}1', {0}2', {0}3', {0}4'] -> [{0}0, {0}1, {0}2, {0}3, {0}4] :" + "(" + "{0}0' < {0}0 " + ") or (" + "{0}0'={0}0 and {0}1' < {0}1 " + ") or (" + "{0}0'={0}0 and {0}1'={0}1 and {0}2' < {0}2 " + ") or (" + "{0}0'={0}0 and {0}1'={0}1 and {0}2'={0}2 and {0}3' < {0}3 " + ") or (" + "{0}0'={0}0 and {0}1'={0}1 and {0}2'={0}2 and {0}3'={0}3 and {0}4' < {0}4" + ")" + "}}".format(LEX_VAR_PREFIX)) + + _check_lex_map(expected_lex_order_map, 5) + + expected_lex_order_map = isl.Map( + "{{ " + "[{0}0'] -> [{0}0] :" + "(" + "{0}0' < {0}0 " + ")" + "}}".format(LEX_VAR_PREFIX)) + + _check_lex_map(expected_lex_order_map, 1) + +# }}} + + # {{{ test statement instance ordering creation def test_statement_instance_ordering_creation(): From 5f060a84d96cf960c50a528b0b37b18ec355c170 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 2 Aug 2020 21:32:55 -0500 Subject: [PATCH 027/220] reduce the number of dims expected in lex maps after update that simplified lex maps --- test/test_linearization_checker.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index a3a95b624..bf33bebb2 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -538,7 +538,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair("insn_a", "insn_b", 3, expected_sio) + check_sio_for_insn_pair("insn_a", "insn_b", 2, expected_sio) # Relationship between insn_a and insn_c --------------------------------------- @@ -554,7 +554,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair("insn_a", "insn_c", 3, expected_sio) + check_sio_for_insn_pair("insn_a", "insn_c", 2, expected_sio) # Relationship between insn_a and insn_d --------------------------------------- @@ -568,7 +568,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair("insn_a", "insn_d", 3, expected_sio) + check_sio_for_insn_pair("insn_a", "insn_d", 1, expected_sio) # Relationship between insn_b and insn_c --------------------------------------- @@ -600,7 +600,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair("insn_b", "insn_d", 3, expected_sio) + check_sio_for_insn_pair("insn_b", "insn_d", 1, expected_sio) # Relationship between insn_c and insn_d --------------------------------------- @@ -614,7 +614,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair("insn_c", "insn_d", 3, expected_sio) + check_sio_for_insn_pair("insn_c", "insn_d", 1, expected_sio) # }}} From 9ab0a22d1232f8dabeb0ae7bb3b2e880f808c225 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 27 Sep 2020 21:24:01 -0500 Subject: [PATCH 028/220] rename get_lex_order_constraint->get_lex_order_set; lots of documenation/naming/comment improvements for clarity --- .../checker/lexicographic_order_map.py | 168 ++++++++++-------- loopy/schedule/checker/schedule.py | 12 +- loopy/schedule/checker/utils.py | 21 +-- 3 files changed, 109 insertions(+), 92 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 0966cba99..d9066030f 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -25,17 +25,19 @@ def get_statement_ordering_map( - sched_map_before, sched_map_after, lex_map, before_marker="'"): - """Return a mapping that maps each statement instance to - all statement instances occuring later. + sched_before, sched_after, lex_map, before_marker="'"): + """Return a statement ordering represented as a map from each statement + instance to all statement instances occurring later. - :arg sched_map_before: An :class:`islpy.Map` representing instruction - instance order for the dependee as a mapping from each statement - instance to a point in the lexicographic ordering. + :arg sched_before: An :class:`islpy.Map` representing a schedule + as a mapping from statement instances (for one particular statement) + to lexicographic time. The statement represented will typically + be the dependee in a dependency relationship. - :arg sched_map_after: An :class:`islpy.Map` representing instruction - instance order for the depender as a mapping from each statement - instance to a point in the lexicographic ordering. + :arg sched_after: An :class:`islpy.Map` representing a schedule + as a mapping from statement instances (for one particular statement) + to lexicographic time. The statement represented will typically + be the depender in a dependency relationship. :arg lex_map: An :class:`islpy.Map` representing a lexicographic ordering as a mapping from each point in lexicographic time @@ -45,17 +47,23 @@ def get_statement_ordering_map( i0' < i0 or (i0' = i0 and i1' < i1) or (i0' = i0 and i1' = i1 and i2' < i2) ...} - :returns: An :class:`islpy.Map` representing the lex schedule as + :arg before_marker: A :class:`str` to be appended to the names of the + map dimensions representing the 'before' statement in the + 'happens before' relationship. + + :returns: An :class:`islpy.Map` representing the statement odering as a mapping from each statement instance to all statement instances - occuring later. I.e., we compose relations B, L, and A as - B ∘ L ∘ A^-1, where B is sched_map_before, A is sched_map_after, - and L is the lexicographic ordering map. + occurring later. I.e., we compose relations B, L, and A as + B ∘ L ∘ A^-1, where B is `sched_before`, A is `sched_after`, + and L is `lex_map`. """ - sio = sched_map_before.apply_range( - lex_map).apply_range(sched_map_after.reverse()) - # append marker to in names + # Perform the composition of relations + sio = sched_before.apply_range( + lex_map).apply_range(sched_after.reverse()) + + # Append marker to in_ dims from loopy.schedule.checker.utils import ( append_marker_to_isl_map_var_names, ) @@ -63,30 +71,38 @@ def get_statement_ordering_map( sio, isl.dim_type.in_, before_marker) -def get_lex_order_constraint(before_names, after_names, islvars=None): - """Return a constraint represented as an :class:`islpy.Set` - defining a 'happens before' relationship in a lexicographic - ordering. - - :arg before_names: A list of :class:`str` variable names representing - the lexicographic space dimensions for a point in lexicographic - time that occurs before. (see example below) - - :arg after_names: A list of :class:`str` variable names representing - the lexicographic space dimensions for a point in lexicographic - time that occurs after. (see example below) - - :arg islvars: A dictionary from variable names to :class:`islpy.PwAff` - instances that represent each of the variables - (islvars may be produced by `islpy.make_zero_and_vars`). The key - '0' is also include and represents a :class:`islpy.PwAff` zero constant. - This dictionary defines the space to be used for the set. If no - value is passed, the dictionary will be made using ``before_names`` - and ``after_names``. - - :returns: An :class:`islpy.Set` representing a constraint that enforces a - lexicographic ordering. E.g., if ``before_names = [i0', i1', i2']`` and - ``after_names = [i0, i1, i2]``, return the set:: +def get_lex_order_set(before_names, after_names, islvars=None): + """Return an :class:`islpy.Set` representing a lexicographic ordering + with the number of dimensions provided in `before_names` + (equal to the number of dimensions in `after_names`). + + :arg before_names: A list of :class:`str` variable names to be used + to describe lexicographic space dimensions for a point in a lexicographic + ordering that occurs before another point, which will be represented using + `after_names`. (see example below) + + :arg after_names: A list of :class:`str` variable names to be used + to describe lexicographic space dimensions for a point in a lexicographic + ordering that occurs after another point, which will be represented using + `before_names`. (see example below) + + :arg islvars: A dictionary mapping variable names in `before_names` and + `after_names` to :class:`islpy.PwAff` instances that represent each + of the variables (islvars may be produced by `islpy.make_zero_and_vars`). + The key '0' is also include and represents a :class:`islpy.PwAff` zero + constant. This dictionary defines the space to be used for the set. If no + value is passed, the dictionary will be made using `before_names` + and `after_names`. + + :returns: An :class:`islpy.Set` representing a big-endian lexicographic ordering + with the number of dimensions provided in `before_names`. The set + has one dimension for each name in *both* `before_names` and + `after_names`, and contains all points which meet a 'happens before' + constraint defining the lexicographic ordering. E.g., if + `before_names = [i0', i1', i2']` and `after_names = [i0, i1, i2]`, + return the set containing all points in a 3-dimensional, big-endian + lexicographic ordering such that point + `[i0', i1', i2']` happens before `[i0, i1, i2]`. I.e., return:: {[i0', i1', i2', i0, i1, i2] : i0' < i0 or (i0' = i0 and i1' < i1) @@ -98,33 +114,31 @@ def get_lex_order_constraint(before_names, after_names, islvars=None): if islvars is None: islvars = isl.make_zero_and_vars(before_names+after_names, []) - # Initialize constraint with i0' < i0 - lex_order_constraint = islvars[before_names[0]].lt_set(islvars[after_names[0]]) + # Initialize set with constraint i0' < i0 + lex_order_set = islvars[before_names[0]].lt_set(islvars[after_names[0]]) - # Initialize conjunction constraint with True. - # For each dim d, starting with d=1, this conjunction will have d equalities, - # e.g., (i0' = i0 and i1' = i1 and ... i(d-1)' = i(d-1)) - equality_constraint_conj = islvars[0].eq_set(islvars[0]) + # For each dim d, starting with d=1, equality_conj_set will be constrained + # by d equalities, e.g., (i0' = i0 and i1' = i1 and ... i(d-1)' = i(d-1)). + equality_conj_set = islvars[0].eq_set(islvars[0]) # initialize to 'true' for i in range(1, len(before_names)): - # Add the next equality constraint to equality_constraint_conj - equality_constraint_conj = equality_constraint_conj & \ + # Add the next equality constraint to equality_conj_set + equality_conj_set = equality_conj_set & \ islvars[before_names[i-1]].eq_set(islvars[after_names[i-1]]) - # Create a conjunction constraint by combining a less-than - # constraint for this dim, e.g., (i1' < i1), with the current - # equality constraint conjunction. - # For each dim d, starting with d=1, this conjunction will have d equalities, - # and one inequality, - # e.g., (i0' = i0 and i1' = i1 and ... i(d-1)' = i(d-1) and id' < id) - full_conj_constraint = islvars[before_names[i]].lt_set( - islvars[after_names[i]]) & equality_constraint_conj + # Create a set constrained by adding a less-than constraint for this dim, + # e.g., (i1' < i1), to the current equality conjunction set. + # For each dim d, starting with d=1, this full conjunction will have + # d equalities and one inequality, e.g., + # (i0' = i0 and i1' = i1 and ... i(d-1)' = i(d-1) and id' < id) + full_conj_set = islvars[before_names[i]].lt_set( + islvars[after_names[i]]) & equality_conj_set - # Union this new constraint with the current lex_order_constraint - lex_order_constraint = lex_order_constraint | full_conj_constraint + # Union this new constraint with the current lex_order_set + lex_order_set = lex_order_set | full_conj_set - return lex_order_constraint + return lex_order_set def create_lex_order_map( @@ -132,26 +146,28 @@ def create_lex_order_map( before_names=None, after_names=None, ): - """Return a mapping that maps each point in a lexicographic - ordering to every point that occurs later in lexicographic - time. + """Return a map from each point in a lexicographic ordering to every + point that occurs later in the lexicographic ordering. :arg n_dims: An :class:`int` representing the number of dimensions - in the lexicographic ordering. + in the lexicographic ordering. If not provided, `n_dims` will be + set to length of `after_names`. - :arg before_names: A list of :class:`str` variable names representing - the lexicographic space dimensions for a point in lexicographic - time that occurs before. (see example below) + :arg before_names: A list of :class:`str` variable names to be used + to describe lexicographic space dimensions for a point in a lexicographic + ordering that occurs before another point, which will be represented using + `after_names`. (see example below) - :arg after_names: A list of :class:`str` variable names representing - the lexicographic space dimensions for a point in lexicographic - time that occurs after. (see example below) + :arg after_names: A list of :class:`str` variable names to be used + to describe lexicographic space dimensions for a point in a lexicographic + ordering that occurs after another point, which will be represented using + `before_names`. (see example below) :returns: An :class:`islpy.Map` representing a lexicographic ordering as a mapping from each point in lexicographic time to every point that occurs later in lexicographic time. - E.g., if ``before_names = [i0', i1', i2']`` and - ``after_names = [i0, i1, i2]``, return the map:: + E.g., if `before_names = [i0', i1', i2']` and + `after_names = [i0, i1, i2]`, return the map:: {[i0', i1', i2'] -> [i0, i1, i2] : i0' < i0 or (i0' = i0 and i1' < i1) @@ -172,11 +188,11 @@ def create_lex_order_map( assert len(before_names) == len(after_names) == n_dims dim_type = isl.dim_type - lex_order_constraint = get_lex_order_constraint(before_names, after_names) + # First, get a set representing the lexicographic ordering. + lex_order_set = get_lex_order_set(before_names, after_names) - lex_map = isl.Map.from_domain(lex_order_constraint) - lex_map = lex_map.move_dims( + # Now convert that set to a map. + lex_map = isl.Map.from_domain(lex_order_set) + return lex_map.move_dims( dim_type.out, 0, dim_type.in_, len(before_names), len(after_names)) - - return lex_map diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 97764a5e2..a947da3ac 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -317,17 +317,17 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): def get_lex_order_map_for_sched_space(schedule): """Return an :class:`islpy.BasicMap` that maps each point in a - lexicographic ordering to every point that is - lexocigraphically greater. + lexicographic ordering to every point that occurs later. :arg schedule: A :class:`islpy.Map` representing the ordering of statement instances as a mapping from statement instances to lexicographic time. - :returns: An :class:`islpy.BasicMap` that maps each point in a - lexicographic ordering to every point that is - lexocigraphically greater with the dimension number and names - matching the output dimension of `schedule`. + :returns: An :class:`islpy.BasicMap` representing a lexicographic + ordering as a mapping from each point in lexicographic time + to every point that occurs later in lexicographic time, with + the dimension count and names matching the output dimension + of `schedule`. """ diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 959c2116d..db1d861c8 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -88,16 +88,19 @@ def ensure_dim_names_match_and_align(obj_map, tgt_map): def append_marker_to_isl_map_var_names(old_isl_map, dim_type, marker="'"): - """Return an isl_map with marker appended to - dim_type dimension names. + """Return an :class:`islpy.Map` with a marker appended to the specified + dimension names. - :arg old_isl_map: A :class:`islpy.Map`. + :arg old_isl_map: An :class:`islpy.Map`. - :arg dim_type: A :class:`islpy.dim_type`, i.e., an :class:`int`, + :arg dim_type: An :class:`islpy.dim_type`, i.e., an :class:`int`, specifying the dimension to be marked. - :returns: A :class:`islpy.Map` matching `old_isl_map` with - apostrophes appended to dim_type dimension names. + :arg marker: A :class:`str` to be appended to the specified dimension + names. If not provided, `marker` defaults to an apostrophe. + + :returns: An :class:`islpy.Map` matching `old_isl_map` with + `marker` appended to the `dim_type` dimension names. """ @@ -109,10 +112,8 @@ def append_marker_to_isl_map_var_names(old_isl_map, dim_type, marker="'"): def append_marker_to_strings(strings, marker="'"): - if not isinstance(strings, list): - raise ValueError("append_marker_to_strings did not receive a list") - else: - return [s+marker for s in strings] + assert isinstance(strings, list) + return [s+marker for s in strings] def sorted_union_of_names_in_isl_sets( From 9cd492d409045473c97f62a78d814a3c62ad3790 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 25 Feb 2021 16:18:35 -0600 Subject: [PATCH 029/220] moved lex order map creation into schedule generation func to avoid duplicating logic when we start dealing with parallel loops and map dims for LID/GID tags --- loopy/schedule/checker/schedule.py | 37 ++++++++++-------------------- test/test_linearization_checker.py | 26 ++++++++++----------- 2 files changed, 25 insertions(+), 38 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index a947da3ac..5221eecb3 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -277,6 +277,10 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): # Second, create pairwise schedules for each individual pair of insns + from loopy.schedule.checker.lexicographic_order_map import ( + create_lex_order_map, + ) + pairwise_schedules = {} for insn_ids in insn_id_pairs: lex_tuples = [stmt_instances[insn_id] for insn_id in insn_ids] @@ -310,30 +314,13 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): in zip(insn_ids, lex_tuples_simplified, int_sids) ] - pairwise_schedules[tuple(insn_ids)] = tuple(sched_maps) - - return pairwise_schedules - - -def get_lex_order_map_for_sched_space(schedule): - """Return an :class:`islpy.BasicMap` that maps each point in a - lexicographic ordering to every point that occurs later. + # TODO (moved func below up here to avoid passing extra info around) + # Benefit (e.g.): don't want to examine the schedule tuple in separate func + # below to re-determine which parallel + # dims are used. (could simplify everything by always using all dims, which + # would make maps more complex than necessary) + lex_order_map = create_lex_order_map(after_names=out_names_sched) - :arg schedule: A :class:`islpy.Map` representing the ordering of - statement instances as a mapping from statement instances to - lexicographic time. + pairwise_schedules[tuple(insn_ids)] = (tuple(sched_maps), lex_order_map) - :returns: An :class:`islpy.BasicMap` representing a lexicographic - ordering as a mapping from each point in lexicographic time - to every point that occurs later in lexicographic time, with - the dimension count and names matching the output dimension - of `schedule`. - - """ - - from loopy.schedule.checker.lexicographic_order_map import ( - create_lex_order_map, - ) - - lex_dim_names = schedule.space.get_var_names(isl.dim_type.out) - return create_lex_order_map(after_names=lex_dim_names) + return pairwise_schedules diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 56882416b..c7683cb27 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -116,7 +116,8 @@ def _lex_space_string(dim_vals): # Relationship between insn_a and insn_b --------------------------------------- # Get two maps - sched_map_before, sched_map_after = sched_maps[("insn_a", "insn_b")] + (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + ("insn_a", "insn_b")] # Create expected maps, align, compare @@ -147,7 +148,8 @@ def _lex_space_string(dim_vals): # Relationship between insn_a and insn_c --------------------------------------- # Get two maps - sched_map_before, sched_map_after = sched_maps[("insn_a", "insn_c")] + (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + ("insn_a", "insn_c")] # Create expected maps, align, compare @@ -178,7 +180,8 @@ def _lex_space_string(dim_vals): # Relationship between insn_a and insn_d --------------------------------------- # Get two maps - sched_map_before, sched_map_after = sched_maps[("insn_a", "insn_d")] + (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + ("insn_a", "insn_d")] # Create expected maps, align, compare @@ -209,7 +212,8 @@ def _lex_space_string(dim_vals): # Relationship between insn_b and insn_c --------------------------------------- # Get two maps - sched_map_before, sched_map_after = sched_maps[("insn_b", "insn_c")] + (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + ("insn_b", "insn_c")] # Create expected maps, align, compare @@ -240,7 +244,8 @@ def _lex_space_string(dim_vals): # Relationship between insn_b and insn_d --------------------------------------- # Get two maps - sched_map_before, sched_map_after = sched_maps[("insn_b", "insn_d")] + (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + ("insn_b", "insn_d")] # Create expected maps, align, compare @@ -271,7 +276,8 @@ def _lex_space_string(dim_vals): # Relationship between insn_c and insn_d --------------------------------------- # Get two maps - sched_map_before, sched_map_after = sched_maps[("insn_c", "insn_d")] + (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + ("insn_c", "insn_d")] # Create expected maps, align, compare @@ -369,9 +375,6 @@ def test_statement_instance_ordering_creation(): from loopy.schedule.checker import ( get_schedules_for_statement_pairs, ) - from loopy.schedule.checker.schedule import ( - get_lex_order_map_for_sched_space, - ) from loopy.schedule.checker.utils import ( ensure_dim_names_match_and_align, append_marker_to_isl_map_var_names, @@ -441,12 +444,9 @@ def check_sio_for_insn_pair( ): # Get pairwise schedule - sched_map_before, sched_map_after = sched_maps[ + (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ (insn_id_before, insn_id_after)] - # Get map representing lexicographic ordering - sched_lex_order_map = get_lex_order_map_for_sched_space(sched_map_before) - # Get expected lex order map expected_lex_order_map = create_lex_order_map( n_dims=expected_lex_dims, From bc748a171d19ffcbaa0c8dce4f63122ce2574344 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 25 Feb 2021 19:52:56 -0600 Subject: [PATCH 030/220] add create_elementwise_comparison_conjunction_set() function from child merge request; don't extract initial iteration in add_dims_to_isl_set() (why did I do this before??) --- loopy/schedule/checker/utils.py | 40 ++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index db1d861c8..4c42be861 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -31,9 +31,10 @@ def prettier_map_string(map_obj): def add_dims_to_isl_set(isl_set, dim_type, names, new_idx_start): new_set = isl_set.insert_dims( dim_type, new_idx_start, len(names) - ).set_dim_name(dim_type, new_idx_start, names[0]) - for i, name in enumerate(names[1:]): - new_set = new_set.set_dim_name(dim_type, new_idx_start+1+i, name) + ) + #.set_dim_name(dim_type, new_idx_start, names[0]) + for i, name in enumerate(names): + new_set = new_set.set_dim_name(dim_type, new_idx_start+i, name) return new_set @@ -250,3 +251,36 @@ def get_EnterLoop_inames(linearization_items): [item.iname, ] for item in linearization_items if isinstance(item, EnterLoop) ]) + + +def create_elementwise_comparison_conjunction_set( + names0, names1, islvars, op="eq"): + """Create a set constrained by the conjunction of conditions comparing + `names0` to `names1`. + + :arg names0: A list of :class:`str` representing variable names. + + :arg names1: A list of :class:`str` representing variable names. + + :arg islvars: A dictionary from variable names to :class:`islpy.PwAff` + instances that represent each of the variables + (islvars may be produced by `islpy.make_zero_and_vars`). The key + '0' is also include and represents a :class:`islpy.PwAff` zero constant. + + :arg op: A :class:`str` describing the operator to use when creating + the set constraints. Options: `eq` for `=`, `lt` for `<` + + :returns: A set involving `islvars` cosntrained by the constraints + `{names0[0] names1[0] and names0[1] names1[1] and ...}`. + + """ + + # initialize set with constraint that is always true + conj_set = islvars[0].eq_set(islvars[0]) + for n0, n1 in zip(names0, names1): + if op == "eq": + conj_set = conj_set & islvars[n0].eq_set(islvars[n1]) + elif op == "lt": + conj_set = conj_set & islvars[n0].lt_set(islvars[n1]) + + return conj_set From 24c8b68d530b1f94c1af5ffe8d682bdaf8daeab5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 25 Feb 2021 19:57:12 -0600 Subject: [PATCH 031/220] add dims to lex space for parallel (gid/lid) loops; in lex order map, require that corresponding parallel dims be equal; changed function signatures for get_lex_order_set() and create_lex_order_map() --- .../checker/lexicographic_order_map.py | 39 +++++- loopy/schedule/checker/schedule.py | 60 +++++++-- test/test_linearization_checker.py | 122 ++++++++++++++++-- 3 files changed, 191 insertions(+), 30 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index d9066030f..144c20a8b 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -71,7 +71,12 @@ def get_statement_ordering_map( sio, isl.dim_type.in_, before_marker) -def get_lex_order_set(before_names, after_names, islvars=None): +def get_lex_order_set( + before_names, after_names, + before_names_concurrent=[], + after_names_concurrent=[], + islvars=None, + ): """Return an :class:`islpy.Set` representing a lexicographic ordering with the number of dimensions provided in `before_names` (equal to the number of dimensions in `after_names`). @@ -109,10 +114,17 @@ def get_lex_order_set(before_names, after_names, islvars=None): or (i0' = i0 and i1' = i1 and i2' < i2)} """ + # TODO update doc + + from loopy.schedule.checker.utils import ( + create_elementwise_comparison_conjunction_set, + ) # If no islvars passed, make them using the names provided if islvars is None: - islvars = isl.make_zero_and_vars(before_names+after_names, []) + islvars = isl.make_zero_and_vars( + before_names+after_names+before_names_concurrent+after_names_concurrent, + []) # Initialize set with constraint i0' < i0 lex_order_set = islvars[before_names[0]].lt_set(islvars[after_names[0]]) @@ -138,6 +150,12 @@ def get_lex_order_set(before_names, after_names, islvars=None): # Union this new constraint with the current lex_order_set lex_order_set = lex_order_set | full_conj_set + lex_order_set = lex_order_set & \ + create_elementwise_comparison_conjunction_set( + before_names_concurrent, after_names_concurrent, + islvars, op="eq", + ) + return lex_order_set @@ -145,6 +163,7 @@ def create_lex_order_map( n_dims=None, before_names=None, after_names=None, + after_names_concurrent=[], ): """Return a map from each point in a lexicographic ordering to every point that occurs later in the lexicographic ordering. @@ -174,25 +193,31 @@ def create_lex_order_map( or (i0' = i0 and i1' = i1 and i2' < i2)} """ + # TODO update doc + + from loopy.schedule.checker.utils import append_marker_to_strings if after_names is None: after_names = ["i%s" % (i) for i in range(n_dims)] if before_names is None: - from loopy.schedule.checker.utils import ( - append_marker_to_strings, - ) before_names = append_marker_to_strings(after_names, marker="'") if n_dims is None: n_dims = len(after_names) + before_names_concurrent = append_marker_to_strings( + after_names_concurrent, marker="'") assert len(before_names) == len(after_names) == n_dims dim_type = isl.dim_type # First, get a set representing the lexicographic ordering. - lex_order_set = get_lex_order_set(before_names, after_names) + lex_order_set = get_lex_order_set( + before_names, after_names, + before_names_concurrent, after_names_concurrent, + ) # Now convert that set to a map. lex_map = isl.Map.from_domain(lex_order_set) return lex_map.move_dims( dim_type.out, 0, dim_type.in_, - len(before_names), len(after_names)) + len(before_names) + len(before_names_concurrent), + len(after_names) + len(after_names_concurrent)) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 5221eecb3..5d3e0fa96 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -43,8 +43,14 @@ """ LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" -LEX_VAR_PREFIX = "%sl" % (LIN_CHECK_IDENTIFIER_PREFIX) +LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) +# TODO document: +GTAG_VAR_NAMES = [] +LTAG_VAR_NAMES = [] +for par_level in [0, 1, 2]: + GTAG_VAR_NAMES.append("%sgid%d" % (LIN_CHECK_IDENTIFIER_PREFIX, par_level)) + LTAG_VAR_NAMES.append("%slid%d" % (LIN_CHECK_IDENTIFIER_PREFIX, par_level)) def _pad_tuple_with_zeros(tup, desired_length): @@ -142,8 +148,10 @@ def generate_pairwise_schedules( mappings from statement instances to lexicographic time, one for each of the two statements. """ + # TODO update doc from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) + from loopy.kernel.data import (LocalIndexTag, GroupIndexTag) all_insn_ids = set().union(*insn_id_pairs) @@ -233,13 +241,16 @@ def generate_pairwise_schedules( if len(stmt_instances.keys()) == len(all_insn_ids): break + # Second, create pairwise schedules for each individual pair of insns + from loopy.schedule.checker.utils import ( sorted_union_of_names_in_isl_sets, create_symbolic_map_from_tuples, add_dims_to_isl_set, ) - def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): + def _get_map_for_stmt( + insn_id, lex_points, int_sid, seq_lex_dim_names, conc_lex_dim_names): # Get inames domain for statement instance (a BasicSet) dom = knl.get_inames_domain( @@ -253,13 +264,15 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): in_names_sched = [STATEMENT_VAR_NAME] + dom_inames_ordered[:] sched_space = isl.Space.create_from_names( isl.DEFAULT_CONTEXT, - in_=in_names_sched, out=out_names_sched, params=[]) + in_=in_names_sched, + out=seq_lex_dim_names+conc_lex_dim_names, + params=[], + ) # Insert 'statement' dim into domain so that its space allows # for intersection with sched map later - dom_to_intersect = [ - add_dims_to_isl_set( - dom, isl.dim_type.set, [STATEMENT_VAR_NAME], 0), ] + dom_to_intersect = add_dims_to_isl_set( + dom, isl.dim_type.set, [STATEMENT_VAR_NAME], 0) # Each map will map statement instances -> lex time. # Right now, statement instance tuples consist of single int. @@ -271,11 +284,30 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): # Create map return create_symbolic_map_from_tuples( - tuple_pairs_with_domains=zip(tuple_pair, dom_to_intersect), + tuple_pairs_with_domains=zip(tuple_pair, [dom_to_intersect,]), space=sched_space, ) - # Second, create pairwise schedules for each individual pair of insns + # Get local/group axes for this kernel + l_axes_used = set() + g_axes_used = set() + for iname in knl.all_inames(): + ltag = knl.iname_tags_of_type(iname, LocalIndexTag) + if ltag: + assert len(ltag) == 1 # TODO always true? remove? + l_axes_used.add(ltag.pop().axis) + continue + gtag = knl.iname_tags_of_type(iname, GroupIndexTag) + if gtag: + assert len(gtag) == 1 # TODO always true? remove? + g_axes_used.add(gtag.pop().axis) + continue + conc_lex_dim_names = ( + [LTAG_VAR_NAMES[i] for i in sorted(l_axes_used)] + + [GTAG_VAR_NAMES[i] for i in sorted(g_axes_used)] + ) + # TODO (For now, using same loc/glob axes for for all pairwise + # schedules in this knl.) from loopy.schedule.checker.lexicographic_order_map import ( create_lex_order_map, @@ -299,8 +331,8 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): # Now generate maps from the blueprint -------------------------------------- - # Create names for the output dimensions - out_names_sched = [ + # Create names for the output dimensions for sequential loops + seq_lex_dim_names = [ LEX_VAR_PREFIX+str(i) for i in range(len(lex_tuples_simplified[0]))] # Determine integer IDs that will represent each statement in mapping @@ -309,7 +341,8 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): int_sids = [0, 0] if insn_ids[0] == insn_ids[1] else [0, 1] sched_maps = [ - _get_map_for_stmt_inst(insn_id, lex_tuple, int_sid, out_names_sched) + _get_map_for_stmt( + insn_id, lex_tuple, int_sid, seq_lex_dim_names, conc_lex_dim_names) for insn_id, lex_tuple, int_sid in zip(insn_ids, lex_tuples_simplified, int_sids) ] @@ -319,7 +352,10 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): # below to re-determine which parallel # dims are used. (could simplify everything by always using all dims, which # would make maps more complex than necessary) - lex_order_map = create_lex_order_map(after_names=out_names_sched) + lex_order_map = create_lex_order_map( + after_names=seq_lex_dim_names, + after_names_concurrent=conc_lex_dim_names, + ) pairwise_schedules[tuple(insn_ids)] = (tuple(sched_maps), lex_order_map) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index c7683cb27..99bd39394 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -38,6 +38,8 @@ from loopy.schedule.checker.schedule import ( LEX_VAR_PREFIX, STATEMENT_VAR_NAME, + LTAG_VAR_NAMES, + GTAG_VAR_NAMES, ) logger = logging.getLogger(__name__) @@ -45,6 +47,18 @@ # {{{ test pairwise schedule creation +def _lex_space_string(dim_vals, lid_axes=[], gid_axes=[]): + # Return a string describing lex space dimension assignments + # (used to create maps below) + + lid_names = [LTAG_VAR_NAMES[i] for i in lid_axes] + gid_names = [GTAG_VAR_NAMES[i] for i in gid_axes] + + return ", ".join( + ["%s%d=%s" % (LEX_VAR_PREFIX, idx, str(val)) + for idx, val in enumerate(dim_vals)] + lid_names + gid_names) + + def test_pairwise_schedule_creation(): import islpy as isl from loopy.schedule.checker import ( @@ -88,16 +102,9 @@ def test_pairwise_schedule_creation(): knl = lp.prioritize_loops(knl, "i,j") # get a linearization - knl = preprocess_kernel(knl) - knl = get_one_linearized_kernel(knl) - linearization_items = knl.linearization - - def _lex_space_string(dim_vals): - # Return a string describing lex space dimension assignments - # (used to create maps below) - return ", ".join( - ["%s%d=%s" % (LEX_VAR_PREFIX, idx, str(val)) - for idx, val in enumerate(dim_vals)]) + proc_knl = preprocess_kernel(knl) + lin_knl = get_one_linearized_kernel(proc_knl) + linearization_items = lin_knl.linearization insn_id_pairs = [ ("insn_a", "insn_b"), @@ -108,7 +115,7 @@ def _lex_space_string(dim_vals): ("insn_c", "insn_d"), ] sched_maps = get_schedules_for_statement_pairs( - knl, + proc_knl, linearization_items, insn_id_pairs, ) @@ -304,6 +311,99 @@ def _lex_space_string(dim_vals): assert sched_map_before == sched_map_before_expected assert sched_map_after == sched_map_after_expected + +def test_pairwise_schedule_creation_parallel(): + import islpy as isl + from loopy.schedule.checker import ( + get_schedules_for_statement_pairs, + ) + from loopy.schedule.checker.utils import ( + ensure_dim_names_match_and_align, + ) + + # example kernel + knl = lp.make_kernel( + [ + "{[i]: 0<=itemp = b[i,k] {id=insn_a} + end + for j + for jj + a[i,j,jj] = temp + 1 {id=insn_b,dep=insn_a} + c[i,j,jj] = d[i,j,jj] {id=insn_c,dep=insn_b} + end + end + end + for t + e[t] = f[t] {id=insn_d, dep=insn_c} + end + """, + name="example", + assumptions="pi,pj,pk,pt >= 1", + ) + knl = lp.add_and_infer_dtypes( + knl, + {"b": np.float32, "d": np.float32, "f": np.float32}) + knl = lp.prioritize_loops(knl, "i,k") + knl = lp.tag_inames(knl, {"j": "l.1", "jj": "l.0", "t": "g.0"}) + + # get a linearization + proc_knl = preprocess_kernel(knl) + lin_knl = get_one_linearized_kernel(proc_knl) + linearization_items = lin_knl.linearization + + insn_id_pairs = [ + ("insn_a", "insn_b"), + ("insn_a", "insn_c"), + ("insn_a", "insn_d"), + ("insn_b", "insn_c"), + ("insn_b", "insn_d"), + ("insn_c", "insn_d"), + ] + sched_maps = get_schedules_for_statement_pairs( + proc_knl, + linearization_items, + insn_id_pairs, + ) + + # Relationship between insn_a and insn_b --------------------------------------- + + # Get two maps + (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + ("insn_a", "insn_b")] + + # Create expected maps, align, compare + + sched_map_before_expected = isl.Map( + "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string(["i", "0"], lid_axes=[0, 1], gid_axes=[0]), + ) + ) + sched_map_before_expected = ensure_dim_names_match_and_align( + sched_map_before_expected, sched_map_before) + + sched_map_after_expected = isl.Map( + "[pi, pj] -> { [%s=1, i, j, jj] -> [%s] : 0 <= i < pi and 0 <= j,jj < pj }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string(["i", "1"], lid_axes=[0, 1], gid_axes=[0]), + ) + ) + sched_map_after_expected = ensure_dim_names_match_and_align( + sched_map_after_expected, sched_map_after) + + assert sched_map_before == sched_map_before_expected + assert sched_map_after == sched_map_after_expected + # }}} From ac6aec9bd634e69fac22bebf6286c547def25be2 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 25 Feb 2021 20:02:19 -0600 Subject: [PATCH 032/220] fix flake8 issue --- loopy/schedule/checker/schedule.py | 2 +- test/test_linearization_checker.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 5d3e0fa96..734d568c3 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -284,7 +284,7 @@ def _get_map_for_stmt( # Create map return create_symbolic_map_from_tuples( - tuple_pairs_with_domains=zip(tuple_pair, [dom_to_intersect,]), + tuple_pairs_with_domains=zip(tuple_pair, [dom_to_intersect, ]), space=sched_space, ) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 99bd39394..5787e8bcb 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -662,6 +662,8 @@ def check_sio_for_insn_pair( check_sio_for_insn_pair("insn_c", "insn_d", 1, expected_sio) +# TODO test SIO creation with parallel loops + # }}} From 41232897684b42a3877a8eac1767b39fb0b4dccf Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 27 Feb 2021 19:45:49 -0600 Subject: [PATCH 033/220] correct order of var names passed to isl.make_zero_and_vars() --- loopy/schedule/checker/lexicographic_order_map.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 144c20a8b..fb912cb7b 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -121,9 +121,10 @@ def get_lex_order_set( ) # If no islvars passed, make them using the names provided + # (make sure to pass var names in desired order of space dims) if islvars is None: islvars = isl.make_zero_and_vars( - before_names+after_names+before_names_concurrent+after_names_concurrent, + before_names+before_names_concurrent+after_names+after_names_concurrent, []) # Initialize set with constraint i0' < i0 From 35968a1f5ef3e5b1a48a1755b2c455241b9966f5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 27 Feb 2021 19:49:08 -0600 Subject: [PATCH 034/220] reduce duplicated code by adding/improving helper functions; test lex map creation with parallel hw tags; more tests for schedule creation with parallel hw tags; improve variable naming a bit --- test/test_linearization_checker.py | 394 ++++++++++++++++++----------- 1 file changed, 243 insertions(+), 151 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 5787e8bcb..3d8e7203f 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -45,10 +45,22 @@ logger = logging.getLogger(__name__) -# {{{ test pairwise schedule creation +# {{{ helper functions for map creation/handling + +def _align_and_compare_maps(maps1, maps2): + from loopy.schedule.checker.utils import ( + ensure_dim_names_match_and_align, + ) -def _lex_space_string(dim_vals, lid_axes=[], gid_axes=[]): - # Return a string describing lex space dimension assignments + for map1, map2 in zip(maps1, maps2): + # Align maps and compare + map1_aligned = ensure_dim_names_match_and_align(map1, map2) + assert map1_aligned == map2 + + +def _lex_point_string(dim_vals, lid_axes=[], gid_axes=[]): + # Return a string describing a point in a lex space + # by assigning values to lex dimension variables # (used to create maps below) lid_names = [LTAG_VAR_NAMES[i] for i in lid_axes] @@ -58,17 +70,18 @@ def _lex_space_string(dim_vals, lid_axes=[], gid_axes=[]): ["%s%d=%s" % (LEX_VAR_PREFIX, idx, str(val)) for idx, val in enumerate(dim_vals)] + lid_names + gid_names) +# }}} + + +# {{{ test pairwise schedule creation def test_pairwise_schedule_creation(): import islpy as isl from loopy.schedule.checker import ( get_schedules_for_statement_pairs, ) - from loopy.schedule.checker.utils import ( - ensure_dim_names_match_and_align, - ) - # example kernel + # Example kernel # insn_c depends on insn_b only to create deterministic order # insn_d depends on insn_c only to create deterministic order knl = lp.make_kernel( @@ -101,7 +114,7 @@ def test_pairwise_schedule_creation(): knl = lp.prioritize_loops(knl, "i,k") knl = lp.prioritize_loops(knl, "i,j") - # get a linearization + # Get a linearization proc_knl = preprocess_kernel(knl) lin_knl = get_one_linearized_kernel(proc_knl) linearization_items = lin_knl.linearization @@ -126,30 +139,28 @@ def test_pairwise_schedule_creation(): (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ ("insn_a", "insn_b")] - # Create expected maps, align, compare + # Create expected maps and compare sched_map_before_expected = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "0"]), + _lex_point_string(["i", "0"]), ) ) - sched_map_before_expected = ensure_dim_names_match_and_align( - sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "1"]), + _lex_point_string(["i", "1"]), ) ) - sched_map_after_expected = ensure_dim_names_match_and_align( - sched_map_after_expected, sched_map_after) - assert sched_map_before == sched_map_before_expected - assert sched_map_after == sched_map_after_expected + _align_and_compare_maps( + [sched_map_before_expected, sched_map_after_expected], + [sched_map_before, sched_map_after], + ) # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_c --------------------------------------- @@ -158,30 +169,28 @@ def test_pairwise_schedule_creation(): (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ ("insn_a", "insn_c")] - # Create expected maps, align, compare + # Create expected maps and compare sched_map_before_expected = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "0"]), + _lex_point_string(["i", "0"]), ) ) - sched_map_before_expected = ensure_dim_names_match_and_align( - sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "1"]), + _lex_point_string(["i", "1"]), ) ) - sched_map_after_expected = ensure_dim_names_match_and_align( - sched_map_after_expected, sched_map_after) - assert sched_map_before == sched_map_before_expected - assert sched_map_after == sched_map_after_expected + _align_and_compare_maps( + [sched_map_before_expected, sched_map_after_expected], + [sched_map_before, sched_map_after], + ) # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_d --------------------------------------- @@ -190,30 +199,28 @@ def test_pairwise_schedule_creation(): (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ ("insn_a", "insn_d")] - # Create expected maps, align, compare + # Create expected maps and compare sched_map_before_expected = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, - _lex_space_string([0, ]), + _lex_point_string([0, ]), ) ) - sched_map_before_expected = ensure_dim_names_match_and_align( - sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, - _lex_space_string([1, ]), + _lex_point_string([1, ]), ) ) - sched_map_after_expected = ensure_dim_names_match_and_align( - sched_map_after_expected, sched_map_after) - assert sched_map_before == sched_map_before_expected - assert sched_map_after == sched_map_after_expected + _align_and_compare_maps( + [sched_map_before_expected, sched_map_after_expected], + [sched_map_before, sched_map_after], + ) # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_c --------------------------------------- @@ -222,30 +229,28 @@ def test_pairwise_schedule_creation(): (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ ("insn_b", "insn_c")] - # Create expected maps, align, compare + # Create expected maps and compare sched_map_before_expected = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "j", 0]), + _lex_point_string(["i", "j", 0]), ) ) - sched_map_before_expected = ensure_dim_names_match_and_align( - sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "j", 1]), + _lex_point_string(["i", "j", 1]), ) ) - sched_map_after_expected = ensure_dim_names_match_and_align( - sched_map_after_expected, sched_map_after) - assert sched_map_before == sched_map_before_expected - assert sched_map_after == sched_map_after_expected + _align_and_compare_maps( + [sched_map_before_expected, sched_map_after_expected], + [sched_map_before, sched_map_after], + ) # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_d --------------------------------------- @@ -254,30 +259,28 @@ def test_pairwise_schedule_creation(): (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ ("insn_b", "insn_d")] - # Create expected maps, align, compare + # Create expected maps and compare sched_map_before_expected = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string([0, ]), + _lex_point_string([0, ]), ) ) - sched_map_before_expected = ensure_dim_names_match_and_align( - sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, - _lex_space_string([1, ]), + _lex_point_string([1, ]), ) ) - sched_map_after_expected = ensure_dim_names_match_and_align( - sched_map_after_expected, sched_map_after) - assert sched_map_before == sched_map_before_expected - assert sched_map_after == sched_map_after_expected + _align_and_compare_maps( + [sched_map_before_expected, sched_map_after_expected], + [sched_map_before, sched_map_after], + ) # ------------------------------------------------------------------------------ # Relationship between insn_c and insn_d --------------------------------------- @@ -286,42 +289,37 @@ def test_pairwise_schedule_creation(): (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ ("insn_c", "insn_d")] - # Create expected maps, align, compare + # Create expected maps and compare sched_map_before_expected = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string([0, ]), + _lex_point_string([0, ]), ) ) - sched_map_before_expected = ensure_dim_names_match_and_align( - sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, - _lex_space_string([1, ]), + _lex_point_string([1, ]), ) ) - sched_map_after_expected = ensure_dim_names_match_and_align( - sched_map_after_expected, sched_map_after) - assert sched_map_before == sched_map_before_expected - assert sched_map_after == sched_map_after_expected + _align_and_compare_maps( + [sched_map_before_expected, sched_map_after_expected], + [sched_map_before, sched_map_after], + ) -def test_pairwise_schedule_creation_parallel(): +def test_pairwise_schedule_creation_with_hw_par_tags(): import islpy as isl from loopy.schedule.checker import ( get_schedules_for_statement_pairs, ) - from loopy.schedule.checker.utils import ( - ensure_dim_names_match_and_align, - ) - # example kernel + # Example kernel knl = lp.make_kernel( [ "{[i]: 0<=i { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "0"], lid_axes=[0, 1], gid_axes=[0]), + _lex_point_string(["i", "0"], lid_axes=[0, 1], gid_axes=[0]), ) ) - sched_map_before_expected = ensure_dim_names_match_and_align( - sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( "[pi, pj] -> { [%s=1, i, j, jj] -> [%s] : 0 <= i < pi and 0 <= j,jj < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "1"], lid_axes=[0, 1], gid_axes=[0]), + _lex_point_string(["i", "1"], lid_axes=[0, 1], gid_axes=[0]), + ) + ) + + _align_and_compare_maps( + [sched_map_before_expected, sched_map_after_expected], + [sched_map_before, sched_map_after], + ) + + # ------------------------------------------------------------------------------ + # Relationship between insn_a and insn_d --------------------------------------- + + # Get two maps + (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + ("insn_a", "insn_d")] + + # Create expected maps and compare + + sched_map_before_expected = isl.Map( + "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" + % ( + STATEMENT_VAR_NAME, + _lex_point_string([0, ], lid_axes=[0, 1], gid_axes=[0]), ) ) - sched_map_after_expected = ensure_dim_names_match_and_align( - sched_map_after_expected, sched_map_after) - assert sched_map_before == sched_map_before_expected - assert sched_map_after == sched_map_after_expected + sched_map_after_expected = isl.Map( + "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" + % ( + STATEMENT_VAR_NAME, + _lex_point_string([1, ], lid_axes=[0, 1], gid_axes=[0]), + ) + ) + + _align_and_compare_maps( + [sched_map_before_expected, sched_map_after_expected], + [sched_map_before, sched_map_after], + ) + + # ------------------------------------------------------------------------------ + # Relationship between insn_b and insn_d --------------------------------------- + + # Get two maps + (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + ("insn_b", "insn_d")] + + # Create expected maps and compare + + sched_map_before_expected = isl.Map( + "[pi, pj] -> { [%s=0, i, j, jj] -> [%s] : 0 <= i < pi and 0 <= j,jj < pj }" + % ( + STATEMENT_VAR_NAME, + _lex_point_string([0, ], lid_axes=[0, 1], gid_axes=[0]), + ) + ) + + sched_map_after_expected = isl.Map( + "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" + % ( + STATEMENT_VAR_NAME, + _lex_point_string([1, ], lid_axes=[0, 1], gid_axes=[0]), + ) + ) + + _align_and_compare_maps( + [sched_map_before_expected, sched_map_after_expected], + [sched_map_before, sched_map_after], + ) + + # ------------------------------------------------------------------------------ # }}} @@ -418,7 +470,9 @@ def test_lex_order_map_creation(): append_marker_to_isl_map_var_names, ) - def _check_lex_map(expected_lex_order_map, n_dims): + def _check_lex_map( + expected_lex_order_map, n_dims, lid_axes_used=[], gid_axes_used=[]): + # Isl ignores the apostrophes, so explicitly add them expected_lex_order_map = append_marker_to_isl_map_var_names( expected_lex_order_map, isl.dim_type.in_, "'") @@ -427,6 +481,9 @@ def _check_lex_map(expected_lex_order_map, n_dims): n_dims=n_dims, before_names=["%s%d'" % (LEX_VAR_PREFIX, i) for i in range(n_dims)], after_names=["%s%d" % (LEX_VAR_PREFIX, i) for i in range(n_dims)], + after_names_concurrent=[ + LTAG_VAR_NAMES[i] for i in lid_axes_used] + [ + GTAG_VAR_NAMES[i] for i in gid_axes_used], ) assert lex_order_map == expected_lex_order_map @@ -465,26 +522,95 @@ def _check_lex_map(expected_lex_order_map, n_dims): _check_lex_map(expected_lex_order_map, 1) + # Lex map for kernel with parallel HW tags + + lid_axes_used = [0, 1] + gid_axes_used = [0, 1, 2] + hw_par_lex_vars = [ + LTAG_VAR_NAMES[i] for i in lid_axes_used] + [ + GTAG_VAR_NAMES[i] for i in gid_axes_used] + expected_lex_order_map = isl.Map( + "{{ " + "[{0}0', {0}1', {0}2', {1}', {2}', {3}', {4}', {5}'] " + "-> [{0}0, {0}1, {0}2, {1}, {2}, {3}, {4}, {5}] :" + "((" + "{0}0' < {0}0 " + ") or (" + "{0}0'={0}0 and {0}1' < {0}1 " + ") or (" + "{0}0'={0}0 and {0}1'={0}1 and {0}2' < {0}2 " + ")) and (" + "{1}' = {1} and {2}' = {2} and {3}' = {3} and {4}' = {4} and {5}' = {5}" + ")" + "}}".format(LEX_VAR_PREFIX, *hw_par_lex_vars)) + + _check_lex_map( + expected_lex_order_map, 3, + lid_axes_used=lid_axes_used, gid_axes_used=gid_axes_used) + # }}} # {{{ test statement instance ordering creation +def _check_sio_for_stmt_pair( + expected_sio, + stmt_id_before, + stmt_id_after, + sched_maps, + expected_seq_lex_dims, + lid_axes_used=[], + gid_axes_used=[], + ): + from loopy.schedule.checker.lexicographic_order_map import ( + get_statement_ordering_map, + create_lex_order_map, + ) + from loopy.schedule.checker.utils import ( + ensure_dim_names_match_and_align, + ) + + # Get pairwise schedule + (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + (stmt_id_before, stmt_id_after)] + + # Get expected lex order map + expected_lex_order_map = create_lex_order_map( + n_dims=expected_seq_lex_dims, + before_names=["%s%d'" % (LEX_VAR_PREFIX, i) + for i in range(expected_seq_lex_dims)], + after_names=["%s%d" % (LEX_VAR_PREFIX, i) + for i in range(expected_seq_lex_dims)], + after_names_concurrent=[ + LTAG_VAR_NAMES[i] for i in lid_axes_used] + [ + GTAG_VAR_NAMES[i] for i in gid_axes_used], + ) + + assert sched_lex_order_map == expected_lex_order_map + + # Create statement instance ordering, + # maps each statement instance to all statement instances occuring later + sio = get_statement_ordering_map( + sched_map_before, + sched_map_after, + sched_lex_order_map, + ) + + sio_aligned = ensure_dim_names_match_and_align(sio, expected_sio) + + assert sio_aligned == expected_sio + + def test_statement_instance_ordering_creation(): import islpy as isl from loopy.schedule.checker import ( get_schedules_for_statement_pairs, ) from loopy.schedule.checker.utils import ( - ensure_dim_names_match_and_align, append_marker_to_isl_map_var_names, ) - from loopy.schedule.checker.lexicographic_order_map import ( - get_statement_ordering_map, - create_lex_order_map, - ) - # example kernel (add deps to fix loop order) + # Example kernel (add deps to fix loop order) knl = lp.make_kernel( [ "{[i]: 0<=itemp = b[i,k] {id=insn_a} + <>temp = b[i,k] {id=stmt_a} end for j - a[i,j] = temp + 1 {id=insn_b,dep=insn_a} - c[i,j] = d[i,j] {id=insn_c,dep=insn_b} + a[i,j] = temp + 1 {id=stmt_b,dep=stmt_a} + c[i,j] = d[i,j] {id=stmt_c,dep=stmt_b} end end for t - e[t] = f[t] {id=insn_d, dep=insn_c} + e[t] = f[t] {id=stmt_d, dep=stmt_c} end """, name="example", @@ -516,61 +642,27 @@ def test_statement_instance_ordering_creation(): knl = lp.prioritize_loops(knl, "i,k") knl = lp.prioritize_loops(knl, "i,j") - # get a linearization + # Get a linearization knl = preprocess_kernel(knl) knl = get_one_linearized_kernel(knl) linearization_items = knl.linearization # Get pairwise schedules - insn_id_pairs = [ - ("insn_a", "insn_b"), - ("insn_a", "insn_c"), - ("insn_a", "insn_d"), - ("insn_b", "insn_c"), - ("insn_b", "insn_d"), - ("insn_c", "insn_d"), + stmt_id_pairs = [ + ("stmt_a", "stmt_b"), + ("stmt_a", "stmt_c"), + ("stmt_a", "stmt_d"), + ("stmt_b", "stmt_c"), + ("stmt_b", "stmt_d"), + ("stmt_c", "stmt_d"), ] sched_maps = get_schedules_for_statement_pairs( knl, linearization_items, - insn_id_pairs, + stmt_id_pairs, ) - def check_sio_for_insn_pair( - insn_id_before, - insn_id_after, - expected_lex_dims, - expected_sio, - ): - - # Get pairwise schedule - (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ - (insn_id_before, insn_id_after)] - - # Get expected lex order map - expected_lex_order_map = create_lex_order_map( - n_dims=expected_lex_dims, - before_names=["%s%d'" % (LEX_VAR_PREFIX, i) - for i in range(expected_lex_dims)], - after_names=["%s%d" % (LEX_VAR_PREFIX, i) - for i in range(expected_lex_dims)], - ) - - assert sched_lex_order_map == expected_lex_order_map - - # create statement instance ordering, - # maps each statement instance to all statement instances occuring later - sio = get_statement_ordering_map( - sched_map_before, - sched_map_after, - sched_lex_order_map, - ) - - sio_aligned = ensure_dim_names_match_and_align(sio, expected_sio) - - assert sio_aligned == expected_sio - - # Relationship between insn_a and insn_b --------------------------------------- + # Relationship between stmt_a and stmt_b --------------------------------------- expected_sio = isl.Map( "[pi, pj, pk] -> {{ " @@ -584,9 +676,9 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair("insn_a", "insn_b", 2, expected_sio) + _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_b", sched_maps, 2) - # Relationship between insn_a and insn_c --------------------------------------- + # Relationship between stmt_a and stmt_c --------------------------------------- expected_sio = isl.Map( "[pi, pj, pk] -> {{ " @@ -600,9 +692,9 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair("insn_a", "insn_c", 2, expected_sio) + _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_c", sched_maps, 2) - # Relationship between insn_a and insn_d --------------------------------------- + # Relationship between stmt_a and stmt_d --------------------------------------- expected_sio = isl.Map( "[pt, pi, pk] -> {{ " @@ -614,9 +706,9 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair("insn_a", "insn_d", 1, expected_sio) + _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_d", sched_maps, 1) - # Relationship between insn_b and insn_c --------------------------------------- + # Relationship between stmt_b and stmt_c --------------------------------------- expected_sio = isl.Map( "[pi, pj] -> {{ " @@ -632,9 +724,9 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair("insn_b", "insn_c", 3, expected_sio) + _check_sio_for_stmt_pair(expected_sio, "stmt_b", "stmt_c", sched_maps, 3) - # Relationship between insn_b and insn_d --------------------------------------- + # Relationship between stmt_b and stmt_d --------------------------------------- expected_sio = isl.Map( "[pt, pi, pj] -> {{ " @@ -646,9 +738,9 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair("insn_b", "insn_d", 1, expected_sio) + _check_sio_for_stmt_pair(expected_sio, "stmt_b", "stmt_d", sched_maps, 1) - # Relationship between insn_c and insn_d --------------------------------------- + # Relationship between stmt_c and stmt_d --------------------------------------- expected_sio = isl.Map( "[pt, pi, pj] -> {{ " @@ -660,7 +752,7 @@ def check_sio_for_insn_pair( expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - check_sio_for_insn_pair("insn_c", "insn_d", 1, expected_sio) + _check_sio_for_stmt_pair(expected_sio, "stmt_c", "stmt_d", sched_maps, 1) # TODO test SIO creation with parallel loops From fc9576de00122739ffedd91983fef14ce003e69f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 27 Feb 2021 19:55:43 -0600 Subject: [PATCH 035/220] stop checking lex map accuracy in _check_sio_for_stmt_pair() (it's already tested separately, and may not be returned with schedule maps later) --- test/test_linearization_checker.py | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 3d8e7203f..22b106eae 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -558,13 +558,9 @@ def _check_sio_for_stmt_pair( stmt_id_before, stmt_id_after, sched_maps, - expected_seq_lex_dims, - lid_axes_used=[], - gid_axes_used=[], ): from loopy.schedule.checker.lexicographic_order_map import ( get_statement_ordering_map, - create_lex_order_map, ) from loopy.schedule.checker.utils import ( ensure_dim_names_match_and_align, @@ -574,20 +570,6 @@ def _check_sio_for_stmt_pair( (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ (stmt_id_before, stmt_id_after)] - # Get expected lex order map - expected_lex_order_map = create_lex_order_map( - n_dims=expected_seq_lex_dims, - before_names=["%s%d'" % (LEX_VAR_PREFIX, i) - for i in range(expected_seq_lex_dims)], - after_names=["%s%d" % (LEX_VAR_PREFIX, i) - for i in range(expected_seq_lex_dims)], - after_names_concurrent=[ - LTAG_VAR_NAMES[i] for i in lid_axes_used] + [ - GTAG_VAR_NAMES[i] for i in gid_axes_used], - ) - - assert sched_lex_order_map == expected_lex_order_map - # Create statement instance ordering, # maps each statement instance to all statement instances occuring later sio = get_statement_ordering_map( @@ -676,7 +658,7 @@ def test_statement_instance_ordering_creation(): expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_b", sched_maps, 2) + _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_b", sched_maps) # Relationship between stmt_a and stmt_c --------------------------------------- @@ -692,7 +674,7 @@ def test_statement_instance_ordering_creation(): expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_c", sched_maps, 2) + _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_c", sched_maps) # Relationship between stmt_a and stmt_d --------------------------------------- @@ -706,7 +688,7 @@ def test_statement_instance_ordering_creation(): expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_d", sched_maps, 1) + _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_d", sched_maps) # Relationship between stmt_b and stmt_c --------------------------------------- @@ -724,7 +706,7 @@ def test_statement_instance_ordering_creation(): expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_b", "stmt_c", sched_maps, 3) + _check_sio_for_stmt_pair(expected_sio, "stmt_b", "stmt_c", sched_maps) # Relationship between stmt_b and stmt_d --------------------------------------- @@ -738,7 +720,7 @@ def test_statement_instance_ordering_creation(): expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_b", "stmt_d", sched_maps, 1) + _check_sio_for_stmt_pair(expected_sio, "stmt_b", "stmt_d", sched_maps) # Relationship between stmt_c and stmt_d --------------------------------------- @@ -752,7 +734,7 @@ def test_statement_instance_ordering_creation(): expected_sio = append_marker_to_isl_map_var_names( expected_sio, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_c", "stmt_d", sched_maps, 1) + _check_sio_for_stmt_pair(expected_sio, "stmt_c", "stmt_d", sched_maps) # TODO test SIO creation with parallel loops From fbba3478215aaac811accc151acd29ea514bfe4c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 27 Feb 2021 21:34:09 -0600 Subject: [PATCH 036/220] started work on test for SIO with parallel kernel (commented out for now; dealing with issue found) --- loopy/schedule/checker/schedule.py | 4 + test/test_linearization_checker.py | 145 ++++++++++++++++++++++++++++- 2 files changed, 145 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 734d568c3..1552449a1 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -269,6 +269,10 @@ def _get_map_for_stmt( params=[], ) + # TODO Either set inames equal to relevant gid/lid var names + # or replace inames with gid/lid var names... + # (otherwise gid/lid conditions will be lost in SIO composition) + # Insert 'statement' dim into domain so that its space allows # for intersection with sched map later dom_to_intersect = add_dims_to_isl_set( diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 22b106eae..bf3f1c0ce 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -128,7 +128,7 @@ def test_pairwise_schedule_creation(): ("insn_c", "insn_d"), ] sched_maps = get_schedules_for_statement_pairs( - proc_knl, + lin_knl, linearization_items, insn_id_pairs, ) @@ -360,7 +360,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): ("insn_b", "insn_d"), ] sched_maps = get_schedules_for_statement_pairs( - proc_knl, + lin_knl, linearization_items, insn_id_pairs, ) @@ -583,7 +583,7 @@ def _check_sio_for_stmt_pair( assert sio_aligned == expected_sio -def test_statement_instance_ordering_creation(): +def test_statement_instance_ordering(): import islpy as isl from loopy.schedule.checker import ( get_schedules_for_statement_pairs, @@ -736,7 +736,144 @@ def test_statement_instance_ordering_creation(): _check_sio_for_stmt_pair(expected_sio, "stmt_c", "stmt_d", sched_maps) -# TODO test SIO creation with parallel loops + +''' +def test_statement_instance_ordering_with_hw_par_tags(): + import islpy as isl + from loopy.schedule.checker import ( + get_schedules_for_statement_pairs, + ) + from loopy.schedule.checker.utils import ( + append_marker_to_isl_map_var_names, + append_marker_to_strings, + ) + + # Example kernel + knl = lp.make_kernel( + [ + "{[i]: 0<=itemp = b[i,k] {id=stmt_a} + end + for j + for jj + a[i,j,jj] = temp + 1 {id=stmt_b,dep=stmt_a} + end + end + end + for t + e[t] = f[t] {id=stmt_d, dep=stmt_b} + end + """, + name="example", + assumptions="pi,pj,pk,pt >= 1", + lang_version=(2018, 2) + ) + knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "f": np.float32}) + knl = lp.prioritize_loops(knl, "i,k") + knl = lp.tag_inames(knl, {"j": "l.1", "jj": "l.0", "t": "g.0"}) + + # Get a linearization + proc_knl = preprocess_kernel(knl) + lin_knl = get_one_linearized_kernel(proc_knl) + linearization_items = lin_knl.linearization + + # Get pairwise schedules + stmt_id_pairs = [ + ("stmt_a", "stmt_b"), + ("stmt_a", "stmt_d"), + ("stmt_b", "stmt_d"), + ] + sched_maps = get_schedules_for_statement_pairs( + lin_knl, + linearization_items, + stmt_id_pairs, + ) + + # Create strings for representing hardware tag portions of sio maps + + # Get par tag names for this kernel + ltag_var_names = [LTAG_VAR_NAMES[lid] for lid in [0, 1]] + gtag_var_names = [GTAG_VAR_NAMES[gid] for gid in [0]] + + # Equality condition, e.g., "lid0' = lid0 and lid1' = lid1, and ..." + par_tag_condition = " and ".join( + ["{0}' = {0}".format(ltag) for ltag in ltag_var_names] + + ["{0}' = {0}".format(gtag) for gtag in gtag_var_names] + ) + + # Comma separated dim names, e.g., "lid0', lid1', gid0'" + par_tag_var_names = ", ".join(ltag_var_names + gtag_var_names) + par_tag_var_names_prime = ", ".join( + append_marker_to_strings(ltag_var_names + gtag_var_names, "'")) + + # Relationship between stmt_a and stmt_b --------------------------------------- + + expected_sio = isl.Map( + "[pi, pj, pk] -> {{ " + "[{0}'=0, i', k', {1}] -> [{0}=1, i, j, {2}] : " + "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i' " + "and {3}; " + "[{0}'=0, i', k', {1}] -> [{0}=1, i=i', j, {2}] : " + "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " + "and {3}" + "}}".format( + STATEMENT_VAR_NAME, + par_tag_var_names_prime, + par_tag_var_names, + par_tag_condition, + ) + ) + # isl ignores these apostrophes, so explicitly add them + expected_sio = append_marker_to_isl_map_var_names( + expected_sio, isl.dim_type.in_, "'") + + _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_b", sched_maps) + + # Relationship between stmt_a and stmt_d --------------------------------------- + + expected_sio = isl.Map( + "[pt, pi, pk] -> {{ " + "[{0}'=0, i', k', {1}] -> [{0}=1, t, {2}] : " + "0 <= i' < pi and 0 <= k' < pk and 0 <= t < pt and {3}" + "}}".format( + STATEMENT_VAR_NAME, + par_tag_var_names_prime, + par_tag_var_names, + par_tag_condition, + ) + ) + # isl ignores these apostrophes, so explicitly add them + expected_sio = append_marker_to_isl_map_var_names( + expected_sio, isl.dim_type.in_, "'") + + _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_d", sched_maps) + + # Relationship between stmt_b and stmt_d --------------------------------------- + + expected_sio = isl.Map( + "[pt, pi, pj] -> {{ " + "[{0}'=0, i', j', {1}] -> [{0}=1, t, {2}] : " + "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt and {3}" + "}}".format( + STATEMENT_VAR_NAME, + par_tag_var_names_prime, + par_tag_var_names, + par_tag_condition, + ) + ) + # isl ignores these apostrophes, so explicitly add them + expected_sio = append_marker_to_isl_map_var_names( + expected_sio, isl.dim_type.in_, "'") + + _check_sio_for_stmt_pair(expected_sio, "stmt_b", "stmt_d", sched_maps) +''' # }}} From f408c86bb432f3e951f6d9dacd76241aec8a4b63 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 3 Mar 2021 20:57:35 -0600 Subject: [PATCH 037/220] set parallel inames equal to corresponding gid/lid var names in schedules; add test for SIO creation with parallel inames; update other tests accordinglyly --- loopy/schedule/checker/schedule.py | 57 ++++---- test/test_linearization_checker.py | 224 +++++++---------------------- 2 files changed, 80 insertions(+), 201 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 1552449a1..c6f5e43e5 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -243,6 +243,31 @@ def generate_pairwise_schedules( # Second, create pairwise schedules for each individual pair of insns + # Get dim names representing local/group axes for this kernel, + # and get the dictionary that will be used later to create a + # constraint requiring {par inames == par axes} in sched + l_axes_used = set() + g_axes_used = set() + par_iname_constraint_dicts = [] + for iname in knl.all_inames(): + ltag = knl.iname_tags_of_type(iname, LocalIndexTag) + if ltag: + # assert len(ltag) == 1 # (should always be true) + ltag_var = LTAG_VAR_NAMES[ltag.pop().axis] + l_axes_used.add(ltag_var) + # Represent constraint 'iname = ltag_var' in par_iname_constraint_dicts: + par_iname_constraint_dicts.append({1: 0, iname: 1, ltag_var: -1}) + continue + gtag = knl.iname_tags_of_type(iname, GroupIndexTag) + if gtag: + # assert len(gtag) == 1 # (should always be true) + gtag_var = GTAG_VAR_NAMES[gtag.pop().axis] + g_axes_used.add(gtag_var) + # Represent constraint 'iname = gtag_var' in par_iname_constraint_dicts: + par_iname_constraint_dicts.append({1: 0, iname: 1, gtag_var: -1}) + continue + conc_lex_dim_names = sorted(l_axes_used) + sorted(g_axes_used) + from loopy.schedule.checker.utils import ( sorted_union_of_names_in_isl_sets, create_symbolic_map_from_tuples, @@ -269,10 +294,6 @@ def _get_map_for_stmt( params=[], ) - # TODO Either set inames equal to relevant gid/lid var names - # or replace inames with gid/lid var names... - # (otherwise gid/lid conditions will be lost in SIO composition) - # Insert 'statement' dim into domain so that its space allows # for intersection with sched map later dom_to_intersect = add_dims_to_isl_set( @@ -287,31 +308,17 @@ def _get_map_for_stmt( )] # Create map - return create_symbolic_map_from_tuples( + sched_map = create_symbolic_map_from_tuples( tuple_pairs_with_domains=zip(tuple_pair, [dom_to_intersect, ]), space=sched_space, ) - # Get local/group axes for this kernel - l_axes_used = set() - g_axes_used = set() - for iname in knl.all_inames(): - ltag = knl.iname_tags_of_type(iname, LocalIndexTag) - if ltag: - assert len(ltag) == 1 # TODO always true? remove? - l_axes_used.add(ltag.pop().axis) - continue - gtag = knl.iname_tags_of_type(iname, GroupIndexTag) - if gtag: - assert len(gtag) == 1 # TODO always true? remove? - g_axes_used.add(gtag.pop().axis) - continue - conc_lex_dim_names = ( - [LTAG_VAR_NAMES[i] for i in sorted(l_axes_used)] + - [GTAG_VAR_NAMES[i] for i in sorted(g_axes_used)] - ) - # TODO (For now, using same loc/glob axes for for all pairwise - # schedules in this knl.) + # Set inames equal to relevant gid/lid var names + for constraint_dict in par_iname_constraint_dicts: + sched_map = sched_map.add_constraint( + isl.Constraint.eq_from_names(sched_map.space, constraint_dict)) + + return sched_map from loopy.schedule.checker.lexicographic_order_map import ( create_lex_order_map, diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index bf3f1c0ce..a1a8c6909 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -58,17 +58,19 @@ def _align_and_compare_maps(maps1, maps2): assert map1_aligned == map2 -def _lex_point_string(dim_vals, lid_axes=[], gid_axes=[]): +def _lex_point_string(dim_vals, lid_inames=[], gid_inames=[]): # Return a string describing a point in a lex space # by assigning values to lex dimension variables # (used to create maps below) - lid_names = [LTAG_VAR_NAMES[i] for i in lid_axes] - gid_names = [GTAG_VAR_NAMES[i] for i in gid_axes] - return ", ".join( ["%s%d=%s" % (LEX_VAR_PREFIX, idx, str(val)) - for idx, val in enumerate(dim_vals)] + lid_names + gid_names) + for idx, val in enumerate(dim_vals)] + + ["%s=%s" % (LTAG_VAR_NAMES[idx], iname) + for idx, iname in enumerate(lid_inames)] + + ["%s=%s" % (GTAG_VAR_NAMES[idx], iname) + for idx, iname in enumerate(gid_inames)] + ) # }}} @@ -322,130 +324,63 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): # Example kernel knl = lp.make_kernel( [ - "{[i]: 0<=itemp = b[i,k] {id=insn_a} - end - for j - for jj - a[i,j,jj] = temp + 1 {id=insn_b,dep=insn_a} + for ii + for j + for jj + <>temp = b[i,ii,j,jj] {id=stmt_a} + a[i,ii,j,jj] = temp + 1 {id=stmt_b,dep=stmt_a} + end end end end - for t - e[t] = f[t] {id=insn_d, dep=insn_b} - end """, name="example", - assumptions="pi,pj,pk,pt >= 1", + assumptions="pi,pj >= 1", + lang_version=(2018, 2) ) - knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "f": np.float32}) - knl = lp.prioritize_loops(knl, "i,k") - knl = lp.tag_inames(knl, {"j": "l.1", "jj": "l.0", "t": "g.0"}) + knl = lp.add_and_infer_dtypes(knl, {"a": np.float32, "b": np.float32}) + knl = lp.tag_inames(knl, {"j": "l.1", "jj": "l.0", "i": "g.0"}) # Get a linearization proc_knl = preprocess_kernel(knl) lin_knl = get_one_linearized_kernel(proc_knl) linearization_items = lin_knl.linearization - insn_id_pairs = [ - ("insn_a", "insn_b"), - ("insn_a", "insn_d"), - ("insn_b", "insn_d"), + stmt_id_pairs = [ + ("stmt_a", "stmt_b"), ] sched_maps = get_schedules_for_statement_pairs( lin_knl, linearization_items, - insn_id_pairs, - ) - - # Relationship between insn_a and insn_b --------------------------------------- - - # Get two maps - (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ - ("insn_a", "insn_b")] - - # Create expected maps and compare - - sched_map_before_expected = isl.Map( - "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" - % ( - STATEMENT_VAR_NAME, - _lex_point_string(["i", "0"], lid_axes=[0, 1], gid_axes=[0]), - ) - ) - - sched_map_after_expected = isl.Map( - "[pi, pj] -> { [%s=1, i, j, jj] -> [%s] : 0 <= i < pi and 0 <= j,jj < pj }" - % ( - STATEMENT_VAR_NAME, - _lex_point_string(["i", "1"], lid_axes=[0, 1], gid_axes=[0]), - ) - ) - - _align_and_compare_maps( - [sched_map_before_expected, sched_map_after_expected], - [sched_map_before, sched_map_after], - ) - - # ------------------------------------------------------------------------------ - # Relationship between insn_a and insn_d --------------------------------------- - - # Get two maps - (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ - ("insn_a", "insn_d")] - - # Create expected maps and compare - - sched_map_before_expected = isl.Map( - "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" - % ( - STATEMENT_VAR_NAME, - _lex_point_string([0, ], lid_axes=[0, 1], gid_axes=[0]), - ) - ) - - sched_map_after_expected = isl.Map( - "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" - % ( - STATEMENT_VAR_NAME, - _lex_point_string([1, ], lid_axes=[0, 1], gid_axes=[0]), - ) - ) - - _align_and_compare_maps( - [sched_map_before_expected, sched_map_after_expected], - [sched_map_before, sched_map_after], + stmt_id_pairs, ) - # ------------------------------------------------------------------------------ - # Relationship between insn_b and insn_d --------------------------------------- + # Relationship between stmt_a and stmt_b --------------------------------------- # Get two maps (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ - ("insn_b", "insn_d")] + ("stmt_a", "stmt_b")] # Create expected maps and compare sched_map_before_expected = isl.Map( - "[pi, pj] -> { [%s=0, i, j, jj] -> [%s] : 0 <= i < pi and 0 <= j,jj < pj }" + "[pi,pj] -> {[%s=0,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, - _lex_point_string([0, ], lid_axes=[0, 1], gid_axes=[0]), + _lex_point_string(["ii", "0"], lid_inames=["jj", "j"], gid_inames=["i"]), ) ) sched_map_after_expected = isl.Map( - "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" + "[pi,pj] -> {[%s=1,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, - _lex_point_string([1, ], lid_axes=[0, 1], gid_axes=[0]), + _lex_point_string(["ii", "1"], lid_inames=["jj", "j"], gid_inames=["i"]), ) ) @@ -737,7 +672,6 @@ def test_statement_instance_ordering(): _check_sio_for_stmt_pair(expected_sio, "stmt_c", "stmt_d", sched_maps) -''' def test_statement_instance_ordering_with_hw_par_tags(): import islpy as isl from loopy.schedule.checker import ( @@ -745,39 +679,33 @@ def test_statement_instance_ordering_with_hw_par_tags(): ) from loopy.schedule.checker.utils import ( append_marker_to_isl_map_var_names, - append_marker_to_strings, + partition_inames_by_concurrency, ) # Example kernel knl = lp.make_kernel( [ - "{[i]: 0<=itemp = b[i,k] {id=stmt_a} - end - for j - for jj - a[i,j,jj] = temp + 1 {id=stmt_b,dep=stmt_a} + for ii + for j + for jj + <>temp = b[i,ii,j,jj] {id=stmt_a} + a[i,ii,j,jj] = temp + 1 {id=stmt_b,dep=stmt_a} + end end end end - for t - e[t] = f[t] {id=stmt_d, dep=stmt_b} - end """, name="example", - assumptions="pi,pj,pk,pt >= 1", + assumptions="pi,pj >= 1", lang_version=(2018, 2) ) - knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "f": np.float32}) - knl = lp.prioritize_loops(knl, "i,k") - knl = lp.tag_inames(knl, {"j": "l.1", "jj": "l.0", "t": "g.0"}) + knl = lp.add_and_infer_dtypes(knl, {"a": np.float32, "b": np.float32}) + knl = lp.tag_inames(knl, {"j": "l.1", "jj": "l.0", "i": "g.0"}) # Get a linearization proc_knl = preprocess_kernel(knl) @@ -787,8 +715,6 @@ def test_statement_instance_ordering_with_hw_par_tags(): # Get pairwise schedules stmt_id_pairs = [ ("stmt_a", "stmt_b"), - ("stmt_a", "stmt_d"), - ("stmt_b", "stmt_d"), ] sched_maps = get_schedules_for_statement_pairs( lin_knl, @@ -796,38 +722,21 @@ def test_statement_instance_ordering_with_hw_par_tags(): stmt_id_pairs, ) - # Create strings for representing hardware tag portions of sio maps - - # Get par tag names for this kernel - ltag_var_names = [LTAG_VAR_NAMES[lid] for lid in [0, 1]] - gtag_var_names = [GTAG_VAR_NAMES[gid] for gid in [0]] - - # Equality condition, e.g., "lid0' = lid0 and lid1' = lid1, and ..." - par_tag_condition = " and ".join( - ["{0}' = {0}".format(ltag) for ltag in ltag_var_names] + - ["{0}' = {0}".format(gtag) for gtag in gtag_var_names] - ) - - # Comma separated dim names, e.g., "lid0', lid1', gid0'" - par_tag_var_names = ", ".join(ltag_var_names + gtag_var_names) - par_tag_var_names_prime = ", ".join( - append_marker_to_strings(ltag_var_names + gtag_var_names, "'")) + # Create string for representing parallel iname condition in sio + conc_inames, _ = partition_inames_by_concurrency(knl) + par_iname_condition = " and ".join( + "{0} = {0}'".format(iname) for iname in conc_inames) # Relationship between stmt_a and stmt_b --------------------------------------- expected_sio = isl.Map( - "[pi, pj, pk] -> {{ " - "[{0}'=0, i', k', {1}] -> [{0}=1, i, j, {2}] : " - "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i' " - "and {3}; " - "[{0}'=0, i', k', {1}] -> [{0}=1, i=i', j, {2}] : " - "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " - "and {3}" + "[pi, pj] -> {{ " + "[{0}'=0, i', ii', j', jj'] -> [{0}=1, i, ii, j, jj] : " + "0 <= i,ii,i',ii' < pi and 0 <= j,jj,j',jj' < pj and ii >= ii' " + "and {1} " "}}".format( STATEMENT_VAR_NAME, - par_tag_var_names_prime, - par_tag_var_names, - par_tag_condition, + par_iname_condition, ) ) # isl ignores these apostrophes, so explicitly add them @@ -836,44 +745,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_b", sched_maps) - # Relationship between stmt_a and stmt_d --------------------------------------- - - expected_sio = isl.Map( - "[pt, pi, pk] -> {{ " - "[{0}'=0, i', k', {1}] -> [{0}=1, t, {2}] : " - "0 <= i' < pi and 0 <= k' < pk and 0 <= t < pt and {3}" - "}}".format( - STATEMENT_VAR_NAME, - par_tag_var_names_prime, - par_tag_var_names, - par_tag_condition, - ) - ) - # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_isl_map_var_names( - expected_sio, isl.dim_type.in_, "'") - - _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_d", sched_maps) - - # Relationship between stmt_b and stmt_d --------------------------------------- - - expected_sio = isl.Map( - "[pt, pi, pj] -> {{ " - "[{0}'=0, i', j', {1}] -> [{0}=1, t, {2}] : " - "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt and {3}" - "}}".format( - STATEMENT_VAR_NAME, - par_tag_var_names_prime, - par_tag_var_names, - par_tag_condition, - ) - ) - # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_isl_map_var_names( - expected_sio, isl.dim_type.in_, "'") - - _check_sio_for_stmt_pair(expected_sio, "stmt_b", "stmt_d", sched_maps) -''' + # ------------------------------------------------------------------------------ # }}} From bef84a6c2930579e07f8a2162de8c6b783c503aa Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 3 Mar 2021 21:05:06 -0600 Subject: [PATCH 038/220] make SIO map strings more concise --- test/test_linearization_checker.py | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index a1a8c6909..495a1a3f2 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -584,9 +584,7 @@ def test_statement_instance_ordering(): expected_sio = isl.Map( "[pi, pj, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, i, j] : " - "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i'; " - "[{0}'=0, i', k'] -> [{0}=1, i=i', j] : " - "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " + "0 <= i,i' < pi and 0 <= k' < pk and 0 <= j < pj and i >= i' " "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them @@ -600,9 +598,7 @@ def test_statement_instance_ordering(): expected_sio = isl.Map( "[pi, pj, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, i, j] : " - "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj and 0 <= i < pi and i > i'; " - "[{0}'=0, i', k'] -> [{0}=1, i=i', j] : " - "0 <= i' < pi and 0 <= k' < pk and 0 <= j < pj " + "0 <= i,i' < pi and 0 <= k' < pk and 0 <= j < pj and i >= i' " "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them @@ -630,11 +626,9 @@ def test_statement_instance_ordering(): expected_sio = isl.Map( "[pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, i, j] : " - "0 <= i' < pi and 0 <= j' < pj and i > i' and 0 <= i < pi and 0 <= j < pj; " + "0 <= i,i' < pi and 0 <= j,j' < pj and i > i'; " "[{0}'=0, i', j'] -> [{0}=1, i=i', j] : " - "0 <= i' < pi and 0 <= j' < pj and j > j' and 0 <= j < pj; " - "[{0}'=0, i', j'] -> [{0}=1, i=i', j=j'] : " - "0 <= i' < pi and 0 <= j' < pj " + "0 <= i' < pi and 0 <= j,j' < pj and j >= j'; " "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them From e15ddaeb1a5266b1d1b24933df081bb4ff120102 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 3 Mar 2021 22:01:51 -0600 Subject: [PATCH 039/220] update doctest --- loopy/schedule/checker/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index f9e9933c6..0dfa02d34 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -81,13 +81,13 @@ def get_schedules_for_statement_pairs( >>> # Print maps >>> print("\n".join( ... str(m).replace("{ ", "{\n").replace(" :", "\n:") - ... for m in schedules[("insn_a", "insn_b")] + ... for m in schedules[("insn_a", "insn_b")[0]] ... )) [pi, pj, pk] -> { - [_lp_linchk_stmt = 0, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 0] + [_lp_linchk_stmt = 0, i, j, k] -> [_lp_linchk_lex0 = i, _lp_linchk_lex1 = 0] : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } [pi, pj, pk] -> { - [_lp_linchk_stmt = 1, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 1] + [_lp_linchk_stmt = 1, i, j, k] -> [_lp_linchk_lex0 = i, _lp_linchk_lex1 = 1] : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } """ From 6af1b23c79f2e778cf9e15989b0d664d5a407739 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 3 Mar 2021 22:02:06 -0600 Subject: [PATCH 040/220] remove commented-out code --- loopy/schedule/checker/utils.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 4c42be861..b5cdb857a 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -29,10 +29,7 @@ def prettier_map_string(map_obj): def add_dims_to_isl_set(isl_set, dim_type, names, new_idx_start): - new_set = isl_set.insert_dims( - dim_type, new_idx_start, len(names) - ) - #.set_dim_name(dim_type, new_idx_start, names[0]) + new_set = isl_set.insert_dims(dim_type, new_idx_start, len(names)) for i, name in enumerate(names): new_set = new_set.set_dim_name(dim_type, new_idx_start+i, name) return new_set From 2740c3dac3cf23ec53d276709c2346430ecff73f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 3 Mar 2021 22:33:34 -0600 Subject: [PATCH 041/220] fix typo in doctest --- loopy/schedule/checker/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 0dfa02d34..c138271f6 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -81,7 +81,7 @@ def get_schedules_for_statement_pairs( >>> # Print maps >>> print("\n".join( ... str(m).replace("{ ", "{\n").replace(" :", "\n:") - ... for m in schedules[("insn_a", "insn_b")[0]] + ... for m in schedules[("insn_a", "insn_b")][0] ... )) [pi, pj, pk] -> { [_lp_linchk_stmt = 0, i, j, k] -> [_lp_linchk_lex0 = i, _lp_linchk_lex1 = 0] From 5a58c4e516f403db09eae438ec8d875a6eedb3de Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 21 Mar 2021 14:14:32 -0500 Subject: [PATCH 042/220] Create lex order maps and SIOs in same function as sched creation (rather than returning schedules and lex maps separately and combining them outside function to get SIOs) to avoid passing extra info around. --- loopy/schedule/checker/__init__.py | 1 + loopy/schedule/checker/schedule.py | 24 +++++++++----- test/test_linearization_checker.py | 50 ++++++++++++++++++++---------- 3 files changed, 52 insertions(+), 23 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index c138271f6..2684950d0 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -91,6 +91,7 @@ def get_schedules_for_statement_pairs( : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } """ + # TODO update docs now that we're returning SIOs # {{{ make sure kernel has been preprocessed diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index c6f5e43e5..a59c579cc 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -148,7 +148,7 @@ def generate_pairwise_schedules( mappings from statement instances to lexicographic time, one for each of the two statements. """ - # TODO update doc + # TODO update docs now that we're returning SIOs from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.kernel.data import (LocalIndexTag, GroupIndexTag) @@ -322,6 +322,7 @@ def _get_map_for_stmt( from loopy.schedule.checker.lexicographic_order_map import ( create_lex_order_map, + get_statement_ordering_map, ) pairwise_schedules = {} @@ -358,16 +359,25 @@ def _get_map_for_stmt( in zip(insn_ids, lex_tuples_simplified, int_sids) ] - # TODO (moved func below up here to avoid passing extra info around) - # Benefit (e.g.): don't want to examine the schedule tuple in separate func - # below to re-determine which parallel - # dims are used. (could simplify everything by always using all dims, which - # would make maps more complex than necessary) + # Create lex order maps and SIOs here (rather than returning schedules + # and lex maps separately and combining them outside function to get + # SIOs) to avoid passing extra info around. Don't want to, e.g., + # examine the schedule tuple in separate func to re-determine which + # parallel dims are used. (could simplify everything by always using + # all dims..., which would make maps more complex than necessary) lex_order_map = create_lex_order_map( after_names=seq_lex_dim_names, after_names_concurrent=conc_lex_dim_names, ) - pairwise_schedules[tuple(insn_ids)] = (tuple(sched_maps), lex_order_map) + # Create statement instance ordering, + # maps each statement instance to all statement instances occuring later + sio = get_statement_ordering_map( + *sched_maps, # note, func accepts exactly two maps + lex_order_map, + ) + + #pairwise_schedules[tuple(insn_ids)] = tuple(sched_maps) + pairwise_schedules[tuple(insn_ids)] = (sio, tuple(sched_maps)) return pairwise_schedules diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 495a1a3f2..6dfb68f68 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -138,7 +138,7 @@ def test_pairwise_schedule_creation(): # Relationship between insn_a and insn_b --------------------------------------- # Get two maps - (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + sio, (sched_map_before, sched_map_after) = sched_maps[ ("insn_a", "insn_b")] # Create expected maps and compare @@ -168,7 +168,7 @@ def test_pairwise_schedule_creation(): # Relationship between insn_a and insn_c --------------------------------------- # Get two maps - (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + sio, (sched_map_before, sched_map_after) = sched_maps[ ("insn_a", "insn_c")] # Create expected maps and compare @@ -198,7 +198,7 @@ def test_pairwise_schedule_creation(): # Relationship between insn_a and insn_d --------------------------------------- # Get two maps - (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + sio, (sched_map_before, sched_map_after) = sched_maps[ ("insn_a", "insn_d")] # Create expected maps and compare @@ -228,7 +228,7 @@ def test_pairwise_schedule_creation(): # Relationship between insn_b and insn_c --------------------------------------- # Get two maps - (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + sio, (sched_map_before, sched_map_after) = sched_maps[ ("insn_b", "insn_c")] # Create expected maps and compare @@ -258,7 +258,7 @@ def test_pairwise_schedule_creation(): # Relationship between insn_b and insn_d --------------------------------------- # Get two maps - (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + sio, (sched_map_before, sched_map_after) = sched_maps[ ("insn_b", "insn_d")] # Create expected maps and compare @@ -288,7 +288,7 @@ def test_pairwise_schedule_creation(): # Relationship between insn_c and insn_d --------------------------------------- # Get two maps - (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + sio, (sched_map_before, sched_map_after) = sched_maps[ ("insn_c", "insn_d")] # Create expected maps and compare @@ -363,7 +363,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): # Relationship between stmt_a and stmt_b --------------------------------------- # Get two maps - (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + sio, (sched_map_before, sched_map_after) = sched_maps[ ("stmt_a", "stmt_b")] # Create expected maps and compare @@ -502,17 +502,9 @@ def _check_sio_for_stmt_pair( ) # Get pairwise schedule - (sched_map_before, sched_map_after), sched_lex_order_map = sched_maps[ + sio, (sched_map_before, sched_map_after) = sched_maps[ (stmt_id_before, stmt_id_after)] - # Create statement instance ordering, - # maps each statement instance to all statement instances occuring later - sio = get_statement_ordering_map( - sched_map_before, - sched_map_after, - sched_lex_order_map, - ) - sio_aligned = ensure_dim_names_match_and_align(sio, expected_sio) assert sio_aligned == expected_sio @@ -741,6 +733,32 @@ def test_statement_instance_ordering_with_hw_par_tags(): # ------------------------------------------------------------------------------ + +# TODO when testing happens-after-barrier map, make sure to test parameter assumption issues: +""" +>>> test_pair2 = append_marker_to_isl_map_var_names(isl.Map("[p] -> { [stmt' = 0, i'=1, j'=p-1] -> [stmt = 1] : p > 1 }"), isl.dim_type.in_, "'") +>>> test_pair3 = append_marker_to_isl_map_var_names(isl.Map("[p] -> { [stmt' = 0, i'=1, j'=p-1] -> [stmt = 1] : p > 2 }"), isl.dim_type.in_, "'") +>>> hab = append_marker_to_isl_map_var_names(isl.Map("[p] -> { [stmt' = 0, i', j'] -> [stmt = 1] : 0 <= i' < p and 0 <= j' <= -2 + p; [stmt' = 0, i', j' = -1 + p] -> [stmt = 1] : 0 <= i' <= -2 + p }"), isl.dim_type.in_, "'") +>>> print(prettier_map_string(hab)) +[p] -> { +[stmt' = 0, i', j'] -> [stmt = 1] : 0 <= i' < p and 0 <= j' <= -2 + p; +[stmt' = 0, i', j' = -1 + p] -> [stmt = 1] : 0 <= i' <= -2 + p +} +>>> print(prettier_map_string(test_pair2)) +[p] -> { +[stmt' = 0, i' = 1, j' = -1 + p] -> [stmt = 1] : p >= 2 +} +>>> print(prettier_map_string(test_pair3)) +[p] -> { +[stmt' = 0, i' = 1, j' = -1 + p] -> [stmt = 1] : p >= 3 +} +>>> test_pair2.is_subset(hab) +False +>>> test_pair3.is_subset(hab) +True +""" + + # }}} From c2e83e1c239bb990a62e2a6e72c2a42690f2c2b1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 21 Mar 2021 19:57:16 -0500 Subject: [PATCH 043/220] start incorporating the bulk of the new blex order/map functionality; still WIP and needs cleanup/tests --- .../checker/lexicographic_order_map.py | 10 +- loopy/schedule/checker/schedule.py | 356 ++++++++++++++++-- loopy/schedule/checker/utils.py | 2 + test/test_linearization_checker.py | 147 ++++---- 4 files changed, 408 insertions(+), 107 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index fb912cb7b..9add041c4 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -76,6 +76,7 @@ def get_lex_order_set( before_names_concurrent=[], after_names_concurrent=[], islvars=None, + conc_var_comparison_op="eq", ): """Return an :class:`islpy.Set` representing a lexicographic ordering with the number of dimensions provided in `before_names` @@ -154,7 +155,7 @@ def get_lex_order_set( lex_order_set = lex_order_set & \ create_elementwise_comparison_conjunction_set( before_names_concurrent, after_names_concurrent, - islvars, op="eq", + islvars, op=conc_var_comparison_op, ) return lex_order_set @@ -165,6 +166,8 @@ def create_lex_order_map( before_names=None, after_names=None, after_names_concurrent=[], + conc_var_comparison_op="eq", + in_dim_marker="'", ): """Return a map from each point in a lexicographic ordering to every point that occurs later in the lexicographic ordering. @@ -201,11 +204,11 @@ def create_lex_order_map( if after_names is None: after_names = ["i%s" % (i) for i in range(n_dims)] if before_names is None: - before_names = append_marker_to_strings(after_names, marker="'") + before_names = append_marker_to_strings(after_names, marker=in_dim_marker) if n_dims is None: n_dims = len(after_names) before_names_concurrent = append_marker_to_strings( - after_names_concurrent, marker="'") + after_names_concurrent, marker=in_dim_marker) assert len(before_names) == len(after_names) == n_dims dim_type = isl.dim_type @@ -214,6 +217,7 @@ def create_lex_order_map( lex_order_set = get_lex_order_set( before_names, after_names, before_names_concurrent, after_names_concurrent, + conc_var_comparison_op=conc_var_comparison_op, ) # Now convert that set to a map. diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index a59c579cc..ec0efb9d8 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -21,6 +21,7 @@ """ import islpy as isl +dt = isl.dim_type.set __doc__ = """ @@ -44,13 +45,21 @@ LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) +BLEX_VAR_PREFIX = "%sblex" % (LIN_CHECK_IDENTIFIER_PREFIX) STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) -# TODO document: +BEFORE_MARK = "'" GTAG_VAR_NAMES = [] LTAG_VAR_NAMES = [] for par_level in [0, 1, 2]: GTAG_VAR_NAMES.append("%sgid%d" % (LIN_CHECK_IDENTIFIER_PREFIX, par_level)) LTAG_VAR_NAMES.append("%slid%d" % (LIN_CHECK_IDENTIFIER_PREFIX, par_level)) +PRE = "pre" +FIRST = "first" +TOP = "top" +BOTTOM = "bottom" +LAST = "last" +POST = "post" +# TODO document new vars def _pad_tuple_with_zeros(tup, desired_length): @@ -152,6 +161,10 @@ def generate_pairwise_schedules( from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.kernel.data import (LocalIndexTag, GroupIndexTag) + from loopy.schedule.checker.lexicographic_order_map import ( + create_lex_order_map, + get_statement_ordering_map, + ) all_insn_ids = set().union(*insn_id_pairs) @@ -162,7 +175,7 @@ def generate_pairwise_schedules( # For each statement, map the insn_id to a tuple representing points # in the lexicographic ordering containing items of :class:`int` or # :class:`str` :mod:`loopy` inames. - stmt_instances = {} + stmt_inst_to_lex = {} # Keep track of the next tuple of points in our lexicographic # ordering, initially this as a 1-d point with value 0 @@ -224,8 +237,8 @@ def generate_pairwise_schedules( # Only process listed insns, otherwise ignore if lp_insn_id in all_insn_ids: - # Add item to stmt_instances - stmt_instances[lp_insn_id] = tuple(next_insn_lex_tuple) + # Add item to stmt_inst_to_lex + stmt_inst_to_lex[lp_insn_id] = tuple(next_insn_lex_tuple) # Increment lex dim val enumerating items in current section of code next_insn_lex_tuple[-1] += 1 @@ -238,11 +251,10 @@ def generate_pairwise_schedules( pass # To save time, stop when we've found all statements - if len(stmt_instances.keys()) == len(all_insn_ids): + if len(stmt_inst_to_lex.keys()) == len(all_insn_ids): + # TODO if combining blex map creation with this pass, cannot stop early break - # Second, create pairwise schedules for each individual pair of insns - # Get dim names representing local/group axes for this kernel, # and get the dictionary that will be used later to create a # constraint requiring {par inames == par axes} in sched @@ -268,6 +280,243 @@ def generate_pairwise_schedules( continue conc_lex_dim_names = sorted(l_axes_used) + sorted(g_axes_used) + # {{{ Create blex ordering (may later be combined with pass above) + + # {{{ Determine which loops contain barriers + + loops_with_barriers = set() + current_inames = set() + + for linearization_item in linearization_items: + if isinstance(linearization_item, EnterLoop): + current_inames.add(linearization_item.iname) + elif isinstance(linearization_item, LeaveLoop): + current_inames.remove(linearization_item.iname) + elif isinstance(linearization_item, Barrier): + loops_with_barriers |= current_inames + # At this point we could technically skip ahead to next enterloop + + # }}} + + # {{{ Get upper and lower bound for each loop that contains a barrier + # (Could try to combine this with pass below but would make things messy) + + iname_bounds_pwaff = {} + blex_map_params = set() + + for iname in loops_with_barriers: + # Get first and last vals for this iname + bounds = knl.get_iname_bounds(iname) + ubound = bounds.upper_bound_pw_aff + lbound = bounds.lower_bound_pw_aff + iname_bounds_pwaff[iname] = (lbound, ubound) + blex_map_params |= set( + lbound.get_var_names(dt.param) + ubound.get_var_names(dt.param)) + + blex_map_params = sorted(blex_map_params) + + # }}} + + # {{{ Construct blueprint for creating blex space and orderings + # TODO combine this pass over the linearization items with the pass above + + stmt_inst_to_blex = {} + subtract_map_blueprint = {} + + # Keep track of the next tuple of points in our blexicographic + # ordering, initially this as a 1-d point with value 0 + next_blex_pt = [0] + n_blex_dims = 1 + iname_to_blexdim = {} + + for linearization_item in linearization_items: + if isinstance(linearization_item, EnterLoop): + enter_iname = linearization_item.iname + if enter_iname in loops_with_barriers: + # update next blex pt + pre_loop_blex_pt = next_blex_pt[:] + next_blex_pt[-1] += 1 + next_blex_pt.append(enter_iname) + next_blex_pt.append(0) + + # store tuples that will be used to create pairs + # that will later be subtracted from happens-before map + first_iter_blex_pt = next_blex_pt[:] + first_iter_blex_pt[-2] = iname_bounds_pwaff[enter_iname][0] + subtract_map_blueprint[enter_iname] = { + PRE: tuple(pre_loop_blex_pt), # make sure to copy + TOP: tuple(next_blex_pt), # make sure to copy + FIRST: tuple(first_iter_blex_pt), # make sure to copy + } + + elif isinstance(linearization_item, LeaveLoop): + leave_iname = linearization_item.iname + if leave_iname in loops_with_barriers: + # update max blex dims + n_blex_dims = max(n_blex_dims, len(next_blex_pt)) + iname_to_blexdim[leave_iname] = len(next_blex_pt)-2 + + # update next blex pt + pre_end_loop_blex_pt = next_blex_pt[:] + next_blex_pt.pop() + next_blex_pt.pop() + next_blex_pt[-1] += 1 + + # store tuples that will be used to create pairs + # that will later be subtracted from happens-before map + last_iter_blex_pt = pre_end_loop_blex_pt[:] + last_iter_blex_pt[-2] = iname_bounds_pwaff[leave_iname][1] + subtract_map_blueprint[leave_iname][BOTTOM] = tuple( + pre_end_loop_blex_pt) + subtract_map_blueprint[leave_iname][LAST] = tuple(last_iter_blex_pt) + subtract_map_blueprint[leave_iname][POST] = tuple(next_blex_pt) + # (make sure ^these are copies) + + elif isinstance(linearization_item, RunInstruction): + # Add item to stmt_inst_to_blex + lp_insn_id = linearization_item.insn_id + stmt_inst_to_blex[lp_insn_id] = tuple(next_blex_pt) + + # Don't increment blex dim val + + elif isinstance(linearization_item, Barrier): + + next_blex_pt[-1] += 1 + + else: + from loopy.schedule import (CallKernel, ReturnFromKernel) + # No action needed for these types of linearization item + assert isinstance( + linearization_item, (CallKernel, ReturnFromKernel)) + pass + + # }}} + + # pad tuples w/zeros + for stmt, tup in stmt_inst_to_blex.items(): + stmt_inst_to_blex[stmt] = _pad_tuple_with_zeros(tup, n_blex_dims) + + # Create names for the blex dimensions for sequential loops + from loopy.schedule.checker.utils import ( + append_marker_to_strings, + ) + seq_blex_dim_names = [ + BLEX_VAR_PREFIX+str(i) for i in range(n_blex_dims)] + seq_blex_dim_names_prime = append_marker_to_strings( + seq_blex_dim_names, marker=BEFORE_MARK) + + blex_order_map = create_lex_order_map( + before_names=seq_blex_dim_names_prime, + after_names=seq_blex_dim_names, + after_names_concurrent=conc_lex_dim_names, + conc_var_comparison_op="ne", + in_dim_marker=BEFORE_MARK, + ) + + iname_to_blexvar = {} + for iname, dim in iname_to_blexdim.items(): + iname_to_blexvar[iname] = seq_blex_dim_names[dim] + iname_to_blexvar[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] + + # Add params to blex map + blex_order_map = blex_order_map.add_dims(dt.param, len(blex_map_params)) + for i, p in enumerate(blex_map_params): + blex_order_map = blex_order_map.set_dim_name(dt.param, i, p) + + # get a set representing blex_order_map space + blex_set_template = isl.align_spaces( + isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map + ).move_dims( + dt.in_, n_blex_dims, dt.out, 0, n_blex_dims + ).domain() + blex_set_affs = isl.affs_from_space(blex_set_template.space) + + def _create_subtraction_map_for_iname(iname, blueprint): + # Note: blueprint[FIRST] and blueprint[LAST] contain pwaffs + + def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): + + # start with a set representing blex_order_map space + blex_set = blex_set_template.copy() + + # add markers to inames in before tuple + # (assume strings are the inames) + before_prime = tuple( + v+BEFORE_MARK if isinstance(v, str) else v for v in before) + before_padded = _pad_tuple_with_zeros(before_prime, n_blex_dims) + after_padded = _pad_tuple_with_zeros(after, n_blex_dims) + + # assign vals to dims + for dim_name, dim_val in zip( + seq_blex_dim_names_prime+seq_blex_dim_names, + before_padded+after_padded): + # (could exploit knowledge of content types of odd/even + # tuple dims to reduce conditionals but would be ugly + # and less robust) + if isinstance(dim_val, int): + # set idx to int val + blex_set &= blex_set_affs[dim_name].eq_set( + blex_set_affs[0]+dim_val) + elif isinstance(dim_val, str): + # assume this is an iname, set idx to corresponding blex var + blex_set &= blex_set_affs[dim_name].eq_set( + blex_set_affs[iname_to_blexvar[dim_val]]) + else: + assert isinstance(dim_val, isl.PwAff) + pwaff_aligned = isl.align_spaces(dim_val, blex_set_affs[0]) + # (doesn't matter which element of blex_set_affs we use^) + blex_set &= blex_set_affs[dim_name].eq_set(pwaff_aligned) + + if wrap_cond: + # i = i' + step + # TODO what about step sizes != 1? + blex_set &= blex_set_affs[iname_to_blexvar[iname]].eq_set( + blex_set_affs[iname_to_blexvar[iname+BEFORE_MARK]] + 1) + + return blex_set + + # enter loop case + full_blex_set = _create_blex_set_from_tuple_pair( + blueprint[PRE], blueprint[FIRST]) + # wrap loop case + full_blex_set |= _create_blex_set_from_tuple_pair( + blueprint[BOTTOM], blueprint[TOP], wrap_cond=True) + # leave loop case + full_blex_set |= _create_blex_set_from_tuple_pair( + blueprint[LAST], blueprint[POST]) + + # add cond to fix iteration value for surrounding loops (i = i') + for surrounding_iname in blueprint[PRE][1::2]: + s_blex_var = iname_to_blexvar[surrounding_iname] + full_blex_set &= blex_set_affs[s_blex_var].eq_set( + blex_set_affs[s_blex_var+BEFORE_MARK]) + + # convert blex set back to map + return isl.Map.from_domain(full_blex_set).move_dims( + dt.out, 0, dt.in_, n_blex_dims, n_blex_dims) + + # subtract unwanted pairs from happens-before blex map + maps_to_subtract = [] + for iname, subdict in subtract_map_blueprint.items(): + maps_to_subtract.append(_create_subtraction_map_for_iname(iname, subdict)) + + if maps_to_subtract: + # get union of maps + map_to_subtract = maps_to_subtract[0] + for other_map in maps_to_subtract[1:]: + map_to_subtract |= other_map + + # get some closure + map_to_subtract, closure_exact = map_to_subtract.transitive_closure() + assert closure_exact # TODO warn instead + + # subtract from blex order map + blex_order_map = blex_order_map - map_to_subtract + + # }}} end blex order/map machinery + + # Second, create pairwise schedules for each individual pair of insns + from loopy.schedule.checker.utils import ( sorted_union_of_names_in_isl_sets, create_symbolic_map_from_tuples, @@ -275,7 +524,7 @@ def generate_pairwise_schedules( ) def _get_map_for_stmt( - insn_id, lex_points, int_sid, seq_lex_dim_names, conc_lex_dim_names): + insn_id, lex_points, int_sid, lex_dim_names): # Get inames domain for statement instance (a BasicSet) dom = knl.get_inames_domain( @@ -290,14 +539,14 @@ def _get_map_for_stmt( sched_space = isl.Space.create_from_names( isl.DEFAULT_CONTEXT, in_=in_names_sched, - out=seq_lex_dim_names+conc_lex_dim_names, + out=lex_dim_names, params=[], ) # Insert 'statement' dim into domain so that its space allows # for intersection with sched map later dom_to_intersect = add_dims_to_isl_set( - dom, isl.dim_type.set, [STATEMENT_VAR_NAME], 0) + dom, dt.set, [STATEMENT_VAR_NAME], 0) # Each map will map statement instances -> lex time. # Right now, statement instance tuples consist of single int. @@ -320,17 +569,19 @@ def _get_map_for_stmt( return sched_map - from loopy.schedule.checker.lexicographic_order_map import ( - create_lex_order_map, - get_statement_ordering_map, - ) - pairwise_schedules = {} for insn_ids in insn_id_pairs: - lex_tuples = [stmt_instances[insn_id] for insn_id in insn_ids] + # Determine integer IDs that will represent each statement in mapping + # (dependency map creation assumes sid_before=0 and sid_after=1, unless + # before and after refer to same stmt, in which case sid_before=sid_after=0) + int_sids = [0, 0] if insn_ids[0] == insn_ids[1] else [0, 1] + + # {{{ Create SIO for intra-thread case (lid0' == lid0, etc) # Simplify tuples to the extent possible ------------------------------------ + lex_tuples = [stmt_inst_to_lex[insn_id] for insn_id in insn_ids] + # At this point, one of the lex tuples may have more dimensions than another; # the missing dims are the fastest-updating dims, and their values should # be zero. Add them. @@ -339,22 +590,18 @@ def _get_map_for_stmt( _pad_tuple_with_zeros(lex_tuple, max_lex_dims) for lex_tuple in lex_tuples] - lex_tuples_simplified = _simplify_lex_dims(*lex_tuples_padded) - # Now generate maps from the blueprint -------------------------------------- + lex_tuples_simplified = _simplify_lex_dims(*lex_tuples_padded) + # Create names for the output dimensions for sequential loops seq_lex_dim_names = [ LEX_VAR_PREFIX+str(i) for i in range(len(lex_tuples_simplified[0]))] - # Determine integer IDs that will represent each statement in mapping - # (dependency map creation assumes sid_before=0 and sid_after=1, unless - # before and after refer to same stmt, in which case sid_before=sid_after=0) - int_sids = [0, 0] if insn_ids[0] == insn_ids[1] else [0, 1] - - sched_maps = [ + intra_thread_sched_maps = [ _get_map_for_stmt( - insn_id, lex_tuple, int_sid, seq_lex_dim_names, conc_lex_dim_names) + insn_id, lex_tuple, int_sid, + seq_lex_dim_names+conc_lex_dim_names) for insn_id, lex_tuple, int_sid in zip(insn_ids, lex_tuples_simplified, int_sids) ] @@ -368,16 +615,67 @@ def _get_map_for_stmt( lex_order_map = create_lex_order_map( after_names=seq_lex_dim_names, after_names_concurrent=conc_lex_dim_names, + conc_var_comparison_op="eq", + in_dim_marker=BEFORE_MARK, ) # Create statement instance ordering, # maps each statement instance to all statement instances occuring later - sio = get_statement_ordering_map( - *sched_maps, # note, func accepts exactly two maps + sio_seq = get_statement_ordering_map( + *intra_thread_sched_maps, # note, func accepts exactly two maps lex_order_map, + before_marker=BEFORE_MARK, + ) + + # }}} + + # {{{ Create SIOs for inter-thread cases (lid0' != lid0, etc) + + # TODO finish separating lid stuff from gid stuff + + # NOTE: use *unsimplified* lex tuples with blex map + + blex_tuples = [stmt_inst_to_blex[insn_id] for insn_id in insn_ids] + + # At this point, one of the lex tuples may have more dimensions than another; + # the missing dims are the fastest-updating dims, and their values should + # be zero. Add them. + max_blex_dims = max([len(blex_tuple) for blex_tuple in blex_tuples]) + blex_tuples_padded = [ + _pad_tuple_with_zeros(blex_tuple, max_blex_dims) + for blex_tuple in blex_tuples] + + # Create names for the output dimensions for sequential loops + seq_blex_dim_names = [ + BLEX_VAR_PREFIX+str(i) for i in range(len(blex_tuples_padded[0]))] + + lconc_sched_maps = [ + _get_map_for_stmt( + insn_id, blex_tuple, int_sid, + seq_blex_dim_names+conc_lex_dim_names) # conc dim names same for all + for insn_id, blex_tuple, int_sid + in zip(insn_ids, blex_tuples_padded, int_sids) + ] + + # Create statement instance ordering + sio_lconc = get_statement_ordering_map( + *lconc_sched_maps, # note, func accepts exactly two maps + blex_order_map, + before_marker=BEFORE_MARK, ) - #pairwise_schedules[tuple(insn_ids)] = tuple(sched_maps) - pairwise_schedules[tuple(insn_ids)] = (sio, tuple(sched_maps)) + # Create statement instance ordering + # TODO + #sio_gconc = get_statement_ordering_map( + # *gconc_sched_maps, # note, func accepts exactly two maps + # g_blex_order_map, + # before_marker=BEFORE_MARK, + # ) + + # }}} + + #pairwise_schedules[tuple(insn_ids)] = tuple(intra_thread_sched_maps) + pairwise_schedules[tuple(insn_ids)] = ( + sio_seq, sio_lconc, tuple(intra_thread_sched_maps)) return pairwise_schedules diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index b5cdb857a..39c7f48e0 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -277,6 +277,8 @@ def create_elementwise_comparison_conjunction_set( for n0, n1 in zip(names0, names1): if op == "eq": conj_set = conj_set & islvars[n0].eq_set(islvars[n1]) + elif op == "ne": + conj_set = conj_set & islvars[n0].ne_set(islvars[n1]) elif op == "lt": conj_set = conj_set & islvars[n0].lt_set(islvars[n1]) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 6dfb68f68..caaa7bb43 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -138,12 +138,12 @@ def test_pairwise_schedule_creation(): # Relationship between insn_a and insn_b --------------------------------------- # Get two maps - sio, (sched_map_before, sched_map_after) = sched_maps[ + sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ ("insn_a", "insn_b")] # Create expected maps and compare - sched_map_before_expected = isl.Map( + sched_map_before_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -151,7 +151,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_expected = isl.Map( + sched_map_after_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -160,7 +160,7 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_expected, sched_map_after_expected], + [sched_map_before_exp, sched_map_after_exp], [sched_map_before, sched_map_after], ) @@ -168,12 +168,12 @@ def test_pairwise_schedule_creation(): # Relationship between insn_a and insn_c --------------------------------------- # Get two maps - sio, (sched_map_before, sched_map_after) = sched_maps[ + sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ ("insn_a", "insn_c")] # Create expected maps and compare - sched_map_before_expected = isl.Map( + sched_map_before_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -181,7 +181,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_expected = isl.Map( + sched_map_after_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -190,7 +190,7 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_expected, sched_map_after_expected], + [sched_map_before_exp, sched_map_after_exp], [sched_map_before, sched_map_after], ) @@ -198,12 +198,12 @@ def test_pairwise_schedule_creation(): # Relationship between insn_a and insn_d --------------------------------------- # Get two maps - sio, (sched_map_before, sched_map_after) = sched_maps[ + sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ ("insn_a", "insn_d")] # Create expected maps and compare - sched_map_before_expected = isl.Map( + sched_map_before_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -211,7 +211,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_expected = isl.Map( + sched_map_after_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -220,7 +220,7 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_expected, sched_map_after_expected], + [sched_map_before_exp, sched_map_after_exp], [sched_map_before, sched_map_after], ) @@ -228,12 +228,12 @@ def test_pairwise_schedule_creation(): # Relationship between insn_b and insn_c --------------------------------------- # Get two maps - sio, (sched_map_before, sched_map_after) = sched_maps[ + sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ ("insn_b", "insn_c")] # Create expected maps and compare - sched_map_before_expected = isl.Map( + sched_map_before_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -241,7 +241,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_expected = isl.Map( + sched_map_after_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -250,7 +250,7 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_expected, sched_map_after_expected], + [sched_map_before_exp, sched_map_after_exp], [sched_map_before, sched_map_after], ) @@ -258,12 +258,12 @@ def test_pairwise_schedule_creation(): # Relationship between insn_b and insn_d --------------------------------------- # Get two maps - sio, (sched_map_before, sched_map_after) = sched_maps[ + sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ ("insn_b", "insn_d")] # Create expected maps and compare - sched_map_before_expected = isl.Map( + sched_map_before_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -271,7 +271,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_expected = isl.Map( + sched_map_after_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -280,7 +280,7 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_expected, sched_map_after_expected], + [sched_map_before_exp, sched_map_after_exp], [sched_map_before, sched_map_after], ) @@ -288,12 +288,12 @@ def test_pairwise_schedule_creation(): # Relationship between insn_c and insn_d --------------------------------------- # Get two maps - sio, (sched_map_before, sched_map_after) = sched_maps[ + sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ ("insn_c", "insn_d")] # Create expected maps and compare - sched_map_before_expected = isl.Map( + sched_map_before_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -301,7 +301,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_expected = isl.Map( + sched_map_after_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -310,7 +310,7 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_expected, sched_map_after_expected], + [sched_map_before_exp, sched_map_after_exp], [sched_map_before, sched_map_after], ) @@ -363,12 +363,12 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): # Relationship between stmt_a and stmt_b --------------------------------------- # Get two maps - sio, (sched_map_before, sched_map_after) = sched_maps[ + sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ ("stmt_a", "stmt_b")] # Create expected maps and compare - sched_map_before_expected = isl.Map( + sched_map_before_exp = isl.Map( "[pi,pj] -> {[%s=0,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, @@ -376,7 +376,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): ) ) - sched_map_after_expected = isl.Map( + sched_map_after_exp = isl.Map( "[pi,pj] -> {[%s=1,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, @@ -385,7 +385,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): ) _align_and_compare_maps( - [sched_map_before_expected, sched_map_after_expected], + [sched_map_before_exp, sched_map_after_exp], [sched_map_before, sched_map_after], ) @@ -406,11 +406,11 @@ def test_lex_order_map_creation(): ) def _check_lex_map( - expected_lex_order_map, n_dims, lid_axes_used=[], gid_axes_used=[]): + exp_lex_order_map, n_dims, lid_axes_used=[], gid_axes_used=[]): # Isl ignores the apostrophes, so explicitly add them - expected_lex_order_map = append_marker_to_isl_map_var_names( - expected_lex_order_map, isl.dim_type.in_, "'") + exp_lex_order_map = append_marker_to_isl_map_var_names( + exp_lex_order_map, isl.dim_type.in_, "'") lex_order_map = create_lex_order_map( n_dims=n_dims, @@ -421,15 +421,15 @@ def _check_lex_map( GTAG_VAR_NAMES[i] for i in gid_axes_used], ) - assert lex_order_map == expected_lex_order_map + assert lex_order_map == exp_lex_order_map assert ( lex_order_map.get_var_names(isl.dim_type.in_) == - expected_lex_order_map.get_var_names(isl.dim_type.in_)) + exp_lex_order_map.get_var_names(isl.dim_type.in_)) assert ( lex_order_map.get_var_names(isl.dim_type.out) == - expected_lex_order_map.get_var_names(isl.dim_type.out)) + exp_lex_order_map.get_var_names(isl.dim_type.out)) - expected_lex_order_map = isl.Map( + exp_lex_order_map = isl.Map( "{{ " "[{0}0', {0}1', {0}2', {0}3', {0}4'] -> [{0}0, {0}1, {0}2, {0}3, {0}4] :" "(" @@ -445,9 +445,9 @@ def _check_lex_map( ")" "}}".format(LEX_VAR_PREFIX)) - _check_lex_map(expected_lex_order_map, 5) + _check_lex_map(exp_lex_order_map, 5) - expected_lex_order_map = isl.Map( + exp_lex_order_map = isl.Map( "{{ " "[{0}0'] -> [{0}0] :" "(" @@ -455,7 +455,7 @@ def _check_lex_map( ")" "}}".format(LEX_VAR_PREFIX)) - _check_lex_map(expected_lex_order_map, 1) + _check_lex_map(exp_lex_order_map, 1) # Lex map for kernel with parallel HW tags @@ -464,7 +464,7 @@ def _check_lex_map( hw_par_lex_vars = [ LTAG_VAR_NAMES[i] for i in lid_axes_used] + [ GTAG_VAR_NAMES[i] for i in gid_axes_used] - expected_lex_order_map = isl.Map( + exp_lex_order_map = isl.Map( "{{ " "[{0}0', {0}1', {0}2', {1}', {2}', {3}', {4}', {5}'] " "-> [{0}0, {0}1, {0}2, {1}, {2}, {3}, {4}, {5}] :" @@ -480,7 +480,7 @@ def _check_lex_map( "}}".format(LEX_VAR_PREFIX, *hw_par_lex_vars)) _check_lex_map( - expected_lex_order_map, 3, + exp_lex_order_map, 3, lid_axes_used=lid_axes_used, gid_axes_used=gid_axes_used) # }}} @@ -489,25 +489,22 @@ def _check_lex_map( # {{{ test statement instance ordering creation def _check_sio_for_stmt_pair( - expected_sio, + exp_sio, stmt_id_before, stmt_id_after, sched_maps, ): - from loopy.schedule.checker.lexicographic_order_map import ( - get_statement_ordering_map, - ) from loopy.schedule.checker.utils import ( ensure_dim_names_match_and_align, ) # Get pairwise schedule - sio, (sched_map_before, sched_map_after) = sched_maps[ + sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ (stmt_id_before, stmt_id_after)] - sio_aligned = ensure_dim_names_match_and_align(sio, expected_sio) + sio_seq_aligned = ensure_dim_names_match_and_align(sio_seq, exp_sio) - assert sio_aligned == expected_sio + assert sio_seq_aligned == exp_sio def test_statement_instance_ordering(): @@ -573,49 +570,49 @@ def test_statement_instance_ordering(): # Relationship between stmt_a and stmt_b --------------------------------------- - expected_sio = isl.Map( + exp_sio_seq = isl.Map( "[pi, pj, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= k' < pk and 0 <= j < pj and i >= i' " "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_isl_map_var_names( - expected_sio, isl.dim_type.in_, "'") + exp_sio_seq = append_marker_to_isl_map_var_names( + exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_b", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_b", sched_maps) # Relationship between stmt_a and stmt_c --------------------------------------- - expected_sio = isl.Map( + exp_sio_seq = isl.Map( "[pi, pj, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= k' < pk and 0 <= j < pj and i >= i' " "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_isl_map_var_names( - expected_sio, isl.dim_type.in_, "'") + exp_sio_seq = append_marker_to_isl_map_var_names( + exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_c", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_c", sched_maps) # Relationship between stmt_a and stmt_d --------------------------------------- - expected_sio = isl.Map( + exp_sio_seq = isl.Map( "[pt, pi, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= k' < pk and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_isl_map_var_names( - expected_sio, isl.dim_type.in_, "'") + exp_sio_seq = append_marker_to_isl_map_var_names( + exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_d", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_d", sched_maps) # Relationship between stmt_b and stmt_c --------------------------------------- - expected_sio = isl.Map( + exp_sio_seq = isl.Map( "[pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= j,j' < pj and i > i'; " @@ -624,38 +621,38 @@ def test_statement_instance_ordering(): "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_isl_map_var_names( - expected_sio, isl.dim_type.in_, "'") + exp_sio_seq = append_marker_to_isl_map_var_names( + exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_b", "stmt_c", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_b", "stmt_c", sched_maps) # Relationship between stmt_b and stmt_d --------------------------------------- - expected_sio = isl.Map( + exp_sio_seq = isl.Map( "[pt, pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_isl_map_var_names( - expected_sio, isl.dim_type.in_, "'") + exp_sio_seq = append_marker_to_isl_map_var_names( + exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_b", "stmt_d", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_b", "stmt_d", sched_maps) # Relationship between stmt_c and stmt_d --------------------------------------- - expected_sio = isl.Map( + exp_sio_seq = isl.Map( "[pt, pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_isl_map_var_names( - expected_sio, isl.dim_type.in_, "'") + exp_sio_seq = append_marker_to_isl_map_var_names( + exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_c", "stmt_d", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_c", "stmt_d", sched_maps) def test_statement_instance_ordering_with_hw_par_tags(): @@ -715,7 +712,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): # Relationship between stmt_a and stmt_b --------------------------------------- - expected_sio = isl.Map( + exp_sio_seq = isl.Map( "[pi, pj] -> {{ " "[{0}'=0, i', ii', j', jj'] -> [{0}=1, i, ii, j, jj] : " "0 <= i,ii,i',ii' < pi and 0 <= j,jj,j',jj' < pj and ii >= ii' " @@ -726,10 +723,10 @@ def test_statement_instance_ordering_with_hw_par_tags(): ) ) # isl ignores these apostrophes, so explicitly add them - expected_sio = append_marker_to_isl_map_var_names( - expected_sio, isl.dim_type.in_, "'") + exp_sio_seq = append_marker_to_isl_map_var_names( + exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(expected_sio, "stmt_a", "stmt_b", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_b", sched_maps) # ------------------------------------------------------------------------------ From 56cb55577bd239e97725026e758a727b0d5ca705 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 22 Mar 2021 12:23:02 -0500 Subject: [PATCH 044/220] rename blex related variables to lblex since they will need to be separated from (global) gblex stuff --- loopy/schedule/checker/schedule.py | 182 ++++++++++++++--------------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index ec0efb9d8..1980705c4 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -302,7 +302,7 @@ def generate_pairwise_schedules( # (Could try to combine this with pass below but would make things messy) iname_bounds_pwaff = {} - blex_map_params = set() + lblex_map_params = set() for iname in loops_with_barriers: # Get first and last vals for this iname @@ -310,78 +310,78 @@ def generate_pairwise_schedules( ubound = bounds.upper_bound_pw_aff lbound = bounds.lower_bound_pw_aff iname_bounds_pwaff[iname] = (lbound, ubound) - blex_map_params |= set( + lblex_map_params |= set( lbound.get_var_names(dt.param) + ubound.get_var_names(dt.param)) - blex_map_params = sorted(blex_map_params) + lblex_map_params = sorted(lblex_map_params) # }}} # {{{ Construct blueprint for creating blex space and orderings # TODO combine this pass over the linearization items with the pass above - stmt_inst_to_blex = {} - subtract_map_blueprint = {} + stmt_inst_to_lblex = {} + lblex_exclusion_info = {} # Keep track of the next tuple of points in our blexicographic # ordering, initially this as a 1-d point with value 0 - next_blex_pt = [0] - n_blex_dims = 1 - iname_to_blexdim = {} + next_lblex_pt = [0] + n_lblex_dims = 1 + iname_to_lblex_dim = {} for linearization_item in linearization_items: if isinstance(linearization_item, EnterLoop): enter_iname = linearization_item.iname if enter_iname in loops_with_barriers: # update next blex pt - pre_loop_blex_pt = next_blex_pt[:] - next_blex_pt[-1] += 1 - next_blex_pt.append(enter_iname) - next_blex_pt.append(0) + pre_loop_lblex_pt = next_lblex_pt[:] + next_lblex_pt[-1] += 1 + next_lblex_pt.append(enter_iname) + next_lblex_pt.append(0) # store tuples that will be used to create pairs # that will later be subtracted from happens-before map - first_iter_blex_pt = next_blex_pt[:] - first_iter_blex_pt[-2] = iname_bounds_pwaff[enter_iname][0] - subtract_map_blueprint[enter_iname] = { - PRE: tuple(pre_loop_blex_pt), # make sure to copy - TOP: tuple(next_blex_pt), # make sure to copy - FIRST: tuple(first_iter_blex_pt), # make sure to copy + first_iter_lblex_pt = next_lblex_pt[:] + first_iter_lblex_pt[-2] = iname_bounds_pwaff[enter_iname][0] + lblex_exclusion_info[enter_iname] = { + PRE: tuple(pre_loop_lblex_pt), # make sure to copy + TOP: tuple(next_lblex_pt), # make sure to copy + FIRST: tuple(first_iter_lblex_pt), # make sure to copy } elif isinstance(linearization_item, LeaveLoop): leave_iname = linearization_item.iname if leave_iname in loops_with_barriers: # update max blex dims - n_blex_dims = max(n_blex_dims, len(next_blex_pt)) - iname_to_blexdim[leave_iname] = len(next_blex_pt)-2 + n_lblex_dims = max(n_lblex_dims, len(next_lblex_pt)) + iname_to_lblex_dim[leave_iname] = len(next_lblex_pt)-2 # update next blex pt - pre_end_loop_blex_pt = next_blex_pt[:] - next_blex_pt.pop() - next_blex_pt.pop() - next_blex_pt[-1] += 1 + pre_end_loop_lblex_pt = next_lblex_pt[:] + next_lblex_pt.pop() + next_lblex_pt.pop() + next_lblex_pt[-1] += 1 # store tuples that will be used to create pairs # that will later be subtracted from happens-before map - last_iter_blex_pt = pre_end_loop_blex_pt[:] - last_iter_blex_pt[-2] = iname_bounds_pwaff[leave_iname][1] - subtract_map_blueprint[leave_iname][BOTTOM] = tuple( - pre_end_loop_blex_pt) - subtract_map_blueprint[leave_iname][LAST] = tuple(last_iter_blex_pt) - subtract_map_blueprint[leave_iname][POST] = tuple(next_blex_pt) + last_iter_lblex_pt = pre_end_loop_lblex_pt[:] + last_iter_lblex_pt[-2] = iname_bounds_pwaff[leave_iname][1] + lblex_exclusion_info[leave_iname][BOTTOM] = tuple( + pre_end_loop_lblex_pt) + lblex_exclusion_info[leave_iname][LAST] = tuple(last_iter_lblex_pt) + lblex_exclusion_info[leave_iname][POST] = tuple(next_lblex_pt) # (make sure ^these are copies) elif isinstance(linearization_item, RunInstruction): - # Add item to stmt_inst_to_blex + # Add item to stmt_inst_to_lblex lp_insn_id = linearization_item.insn_id - stmt_inst_to_blex[lp_insn_id] = tuple(next_blex_pt) + stmt_inst_to_lblex[lp_insn_id] = tuple(next_lblex_pt) # Don't increment blex dim val elif isinstance(linearization_item, Barrier): - next_blex_pt[-1] += 1 + next_lblex_pt[-1] += 1 else: from loopy.schedule import (CallKernel, ReturnFromKernel) @@ -393,43 +393,43 @@ def generate_pairwise_schedules( # }}} # pad tuples w/zeros - for stmt, tup in stmt_inst_to_blex.items(): - stmt_inst_to_blex[stmt] = _pad_tuple_with_zeros(tup, n_blex_dims) + for stmt, tup in stmt_inst_to_lblex.items(): + stmt_inst_to_lblex[stmt] = _pad_tuple_with_zeros(tup, n_lblex_dims) # Create names for the blex dimensions for sequential loops from loopy.schedule.checker.utils import ( append_marker_to_strings, ) - seq_blex_dim_names = [ - BLEX_VAR_PREFIX+str(i) for i in range(n_blex_dims)] - seq_blex_dim_names_prime = append_marker_to_strings( - seq_blex_dim_names, marker=BEFORE_MARK) - - blex_order_map = create_lex_order_map( - before_names=seq_blex_dim_names_prime, - after_names=seq_blex_dim_names, + seq_lblex_dim_names = [ + BLEX_VAR_PREFIX+str(i) for i in range(n_lblex_dims)] + seq_lblex_dim_names_prime = append_marker_to_strings( + seq_lblex_dim_names, marker=BEFORE_MARK) + + lblex_order_map = create_lex_order_map( + before_names=seq_lblex_dim_names_prime, + after_names=seq_lblex_dim_names, after_names_concurrent=conc_lex_dim_names, conc_var_comparison_op="ne", in_dim_marker=BEFORE_MARK, ) - iname_to_blexvar = {} - for iname, dim in iname_to_blexdim.items(): - iname_to_blexvar[iname] = seq_blex_dim_names[dim] - iname_to_blexvar[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] + iname_to_lblex_var = {} + for iname, dim in iname_to_lblex_dim.items(): + iname_to_lblex_var[iname] = seq_lblex_dim_names[dim] + iname_to_lblex_var[iname+BEFORE_MARK] = seq_lblex_dim_names_prime[dim] # Add params to blex map - blex_order_map = blex_order_map.add_dims(dt.param, len(blex_map_params)) - for i, p in enumerate(blex_map_params): - blex_order_map = blex_order_map.set_dim_name(dt.param, i, p) + lblex_order_map = lblex_order_map.add_dims(dt.param, len(lblex_map_params)) + for i, p in enumerate(lblex_map_params): + lblex_order_map = lblex_order_map.set_dim_name(dt.param, i, p) # get a set representing blex_order_map space - blex_set_template = isl.align_spaces( - isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map + lblex_set_template = isl.align_spaces( + isl.Map("[ ] -> { [ ] -> [ ] }"), lblex_order_map ).move_dims( - dt.in_, n_blex_dims, dt.out, 0, n_blex_dims + dt.in_, n_lblex_dims, dt.out, 0, n_lblex_dims ).domain() - blex_set_affs = isl.affs_from_space(blex_set_template.space) + lblex_set_affs = isl.affs_from_space(lblex_set_template.space) def _create_subtraction_map_for_iname(iname, blueprint): # Note: blueprint[FIRST] and blueprint[LAST] contain pwaffs @@ -437,67 +437,67 @@ def _create_subtraction_map_for_iname(iname, blueprint): def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # start with a set representing blex_order_map space - blex_set = blex_set_template.copy() + lblex_set = lblex_set_template.copy() # add markers to inames in before tuple # (assume strings are the inames) before_prime = tuple( v+BEFORE_MARK if isinstance(v, str) else v for v in before) - before_padded = _pad_tuple_with_zeros(before_prime, n_blex_dims) - after_padded = _pad_tuple_with_zeros(after, n_blex_dims) + before_padded = _pad_tuple_with_zeros(before_prime, n_lblex_dims) + after_padded = _pad_tuple_with_zeros(after, n_lblex_dims) # assign vals to dims for dim_name, dim_val in zip( - seq_blex_dim_names_prime+seq_blex_dim_names, + seq_lblex_dim_names_prime+seq_lblex_dim_names, before_padded+after_padded): # (could exploit knowledge of content types of odd/even # tuple dims to reduce conditionals but would be ugly # and less robust) if isinstance(dim_val, int): # set idx to int val - blex_set &= blex_set_affs[dim_name].eq_set( - blex_set_affs[0]+dim_val) + lblex_set &= lblex_set_affs[dim_name].eq_set( + lblex_set_affs[0]+dim_val) elif isinstance(dim_val, str): # assume this is an iname, set idx to corresponding blex var - blex_set &= blex_set_affs[dim_name].eq_set( - blex_set_affs[iname_to_blexvar[dim_val]]) + lblex_set &= lblex_set_affs[dim_name].eq_set( + lblex_set_affs[iname_to_lblex_var[dim_val]]) else: assert isinstance(dim_val, isl.PwAff) - pwaff_aligned = isl.align_spaces(dim_val, blex_set_affs[0]) - # (doesn't matter which element of blex_set_affs we use^) - blex_set &= blex_set_affs[dim_name].eq_set(pwaff_aligned) + pwaff_aligned = isl.align_spaces(dim_val, lblex_set_affs[0]) + # (doesn't matter which element of lblex_set_affs we use^) + lblex_set &= lblex_set_affs[dim_name].eq_set(pwaff_aligned) if wrap_cond: # i = i' + step # TODO what about step sizes != 1? - blex_set &= blex_set_affs[iname_to_blexvar[iname]].eq_set( - blex_set_affs[iname_to_blexvar[iname+BEFORE_MARK]] + 1) + lblex_set &= lblex_set_affs[iname_to_lblex_var[iname]].eq_set( + lblex_set_affs[iname_to_lblex_var[iname+BEFORE_MARK]] + 1) - return blex_set + return lblex_set # enter loop case - full_blex_set = _create_blex_set_from_tuple_pair( + full_lblex_set = _create_blex_set_from_tuple_pair( blueprint[PRE], blueprint[FIRST]) # wrap loop case - full_blex_set |= _create_blex_set_from_tuple_pair( + full_lblex_set |= _create_blex_set_from_tuple_pair( blueprint[BOTTOM], blueprint[TOP], wrap_cond=True) # leave loop case - full_blex_set |= _create_blex_set_from_tuple_pair( + full_lblex_set |= _create_blex_set_from_tuple_pair( blueprint[LAST], blueprint[POST]) # add cond to fix iteration value for surrounding loops (i = i') for surrounding_iname in blueprint[PRE][1::2]: - s_blex_var = iname_to_blexvar[surrounding_iname] - full_blex_set &= blex_set_affs[s_blex_var].eq_set( - blex_set_affs[s_blex_var+BEFORE_MARK]) + s_lblex_var = iname_to_lblex_var[surrounding_iname] + full_lblex_set &= lblex_set_affs[s_lblex_var].eq_set( + lblex_set_affs[s_lblex_var+BEFORE_MARK]) # convert blex set back to map - return isl.Map.from_domain(full_blex_set).move_dims( - dt.out, 0, dt.in_, n_blex_dims, n_blex_dims) + return isl.Map.from_domain(full_lblex_set).move_dims( + dt.out, 0, dt.in_, n_lblex_dims, n_lblex_dims) # subtract unwanted pairs from happens-before blex map maps_to_subtract = [] - for iname, subdict in subtract_map_blueprint.items(): + for iname, subdict in lblex_exclusion_info.items(): maps_to_subtract.append(_create_subtraction_map_for_iname(iname, subdict)) if maps_to_subtract: @@ -511,7 +511,7 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): assert closure_exact # TODO warn instead # subtract from blex order map - blex_order_map = blex_order_map - map_to_subtract + lblex_order_map = lblex_order_map - map_to_subtract # }}} end blex order/map machinery @@ -635,32 +635,32 @@ def _get_map_for_stmt( # NOTE: use *unsimplified* lex tuples with blex map - blex_tuples = [stmt_inst_to_blex[insn_id] for insn_id in insn_ids] + lblex_tuples = [stmt_inst_to_lblex[insn_id] for insn_id in insn_ids] # At this point, one of the lex tuples may have more dimensions than another; # the missing dims are the fastest-updating dims, and their values should # be zero. Add them. - max_blex_dims = max([len(blex_tuple) for blex_tuple in blex_tuples]) - blex_tuples_padded = [ - _pad_tuple_with_zeros(blex_tuple, max_blex_dims) - for blex_tuple in blex_tuples] + max_lblex_dims = max([len(lblex_tuple) for lblex_tuple in lblex_tuples]) + lblex_tuples_padded = [ + _pad_tuple_with_zeros(lblex_tuple, max_lblex_dims) + for lblex_tuple in lblex_tuples] # Create names for the output dimensions for sequential loops - seq_blex_dim_names = [ - BLEX_VAR_PREFIX+str(i) for i in range(len(blex_tuples_padded[0]))] + seq_lblex_dim_names = [ + BLEX_VAR_PREFIX+str(i) for i in range(len(lblex_tuples_padded[0]))] lconc_sched_maps = [ _get_map_for_stmt( - insn_id, blex_tuple, int_sid, - seq_blex_dim_names+conc_lex_dim_names) # conc dim names same for all - for insn_id, blex_tuple, int_sid - in zip(insn_ids, blex_tuples_padded, int_sids) + insn_id, lblex_tuple, int_sid, + seq_lblex_dim_names+conc_lex_dim_names) # conc names same for all + for insn_id, lblex_tuple, int_sid + in zip(insn_ids, lblex_tuples_padded, int_sids) ] # Create statement instance ordering sio_lconc = get_statement_ordering_map( *lconc_sched_maps, # note, func accepts exactly two maps - blex_order_map, + lblex_order_map, before_marker=BEFORE_MARK, ) @@ -668,7 +668,7 @@ def _get_map_for_stmt( # TODO #sio_gconc = get_statement_ordering_map( # *gconc_sched_maps, # note, func accepts exactly two maps - # g_blex_order_map, + # gblex_order_map, # before_marker=BEFORE_MARK, # ) From 111ed536c790335e1a356df4ab61736f858e39a3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 22 Mar 2021 15:30:12 -0500 Subject: [PATCH 045/220] return sched maps for both lex and lblex orderings; collect params for lblex maps during instruction pass instead of before --- loopy/schedule/checker/schedule.py | 55 +++++++------ test/test_linearization_checker.py | 128 ++++++++++++++++++----------- 2 files changed, 110 insertions(+), 73 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 1980705c4..7f83c4032 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -284,7 +284,8 @@ def generate_pairwise_schedules( # {{{ Determine which loops contain barriers - loops_with_barriers = set() + loops_with_lbarriers = set() + loops_with_gbarriers = set() current_inames = set() for linearization_item in linearization_items: @@ -293,7 +294,10 @@ def generate_pairwise_schedules( elif isinstance(linearization_item, LeaveLoop): current_inames.remove(linearization_item.iname) elif isinstance(linearization_item, Barrier): - loops_with_barriers |= current_inames + if linearization_item.synchronization_kind == "local": + loops_with_lbarriers |= current_inames + elif linearization_item.synchronization_kind == "global": + loops_with_gbarriers |= current_inames # At this point we could technically skip ahead to next enterloop # }}} @@ -302,37 +306,29 @@ def generate_pairwise_schedules( # (Could try to combine this with pass below but would make things messy) iname_bounds_pwaff = {} - lblex_map_params = set() - - for iname in loops_with_barriers: + for iname in loops_with_lbarriers: # Get first and last vals for this iname bounds = knl.get_iname_bounds(iname) - ubound = bounds.upper_bound_pw_aff - lbound = bounds.lower_bound_pw_aff - iname_bounds_pwaff[iname] = (lbound, ubound) - lblex_map_params |= set( - lbound.get_var_names(dt.param) + ubound.get_var_names(dt.param)) - - lblex_map_params = sorted(lblex_map_params) + iname_bounds_pwaff[iname] = ( + bounds.lower_bound_pw_aff, bounds.upper_bound_pw_aff) # }}} # {{{ Construct blueprint for creating blex space and orderings # TODO combine this pass over the linearization items with the pass above - stmt_inst_to_lblex = {} - lblex_exclusion_info = {} - - # Keep track of the next tuple of points in our blexicographic - # ordering, initially this as a 1-d point with value 0 - next_lblex_pt = [0] - n_lblex_dims = 1 - iname_to_lblex_dim = {} + stmt_inst_to_lblex = {} # map stmt instances to lblex space + iname_to_lblex_dim = {} # map from inames to corresponding lblex space dim + lblex_exclusion_info = {} # info for creating pairs to subtract from lblex order + lblex_map_params = set() # params needed in lblex map + next_lblex_pt = [0] # next tuple of points in lblex order + n_lblex_dims = 1 # number of dims in lblex space + # do both lblex and gblex processing in single pass through insns for linearization_item in linearization_items: if isinstance(linearization_item, EnterLoop): enter_iname = linearization_item.iname - if enter_iname in loops_with_barriers: + if enter_iname in loops_with_lbarriers: # update next blex pt pre_loop_lblex_pt = next_lblex_pt[:] next_lblex_pt[-1] += 1 @@ -341,17 +337,19 @@ def generate_pairwise_schedules( # store tuples that will be used to create pairs # that will later be subtracted from happens-before map + lbound = iname_bounds_pwaff[enter_iname][0] first_iter_lblex_pt = next_lblex_pt[:] - first_iter_lblex_pt[-2] = iname_bounds_pwaff[enter_iname][0] + first_iter_lblex_pt[-2] = lbound lblex_exclusion_info[enter_iname] = { PRE: tuple(pre_loop_lblex_pt), # make sure to copy TOP: tuple(next_lblex_pt), # make sure to copy FIRST: tuple(first_iter_lblex_pt), # make sure to copy } + lblex_map_params |= set(lbound.get_var_names(dt.param)) elif isinstance(linearization_item, LeaveLoop): leave_iname = linearization_item.iname - if leave_iname in loops_with_barriers: + if leave_iname in loops_with_lbarriers: # update max blex dims n_lblex_dims = max(n_lblex_dims, len(next_lblex_pt)) iname_to_lblex_dim[leave_iname] = len(next_lblex_pt)-2 @@ -364,13 +362,15 @@ def generate_pairwise_schedules( # store tuples that will be used to create pairs # that will later be subtracted from happens-before map + ubound = iname_bounds_pwaff[leave_iname][1] last_iter_lblex_pt = pre_end_loop_lblex_pt[:] - last_iter_lblex_pt[-2] = iname_bounds_pwaff[leave_iname][1] + last_iter_lblex_pt[-2] = ubound lblex_exclusion_info[leave_iname][BOTTOM] = tuple( pre_end_loop_lblex_pt) lblex_exclusion_info[leave_iname][LAST] = tuple(last_iter_lblex_pt) lblex_exclusion_info[leave_iname][POST] = tuple(next_lblex_pt) # (make sure ^these are copies) + lblex_map_params |= set(ubound.get_var_names(dt.param)) elif isinstance(linearization_item, RunInstruction): # Add item to stmt_inst_to_lblex @@ -390,6 +390,8 @@ def generate_pairwise_schedules( linearization_item, (CallKernel, ReturnFromKernel)) pass + lblex_map_params = sorted(lblex_map_params) + # }}} # pad tuples w/zeros @@ -674,8 +676,11 @@ def _get_map_for_stmt( # }}} + # TODO don't return sched maps? #pairwise_schedules[tuple(insn_ids)] = tuple(intra_thread_sched_maps) pairwise_schedules[tuple(insn_ids)] = ( - sio_seq, sio_lconc, tuple(intra_thread_sched_maps)) + (sio_seq, tuple(intra_thread_sched_maps), ), + (sio_lconc, tuple(lconc_sched_maps), ) + ) return pairwise_schedules diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index caaa7bb43..385f83b15 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -129,7 +129,7 @@ def test_pairwise_schedule_creation(): ("insn_b", "insn_d"), ("insn_c", "insn_d"), ] - sched_maps = get_schedules_for_statement_pairs( + scheds = get_schedules_for_statement_pairs( lin_knl, linearization_items, insn_id_pairs, @@ -138,12 +138,16 @@ def test_pairwise_schedule_creation(): # Relationship between insn_a and insn_b --------------------------------------- # Get two maps - sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ + ( + sio_seq, (sched_before, sched_after) + ), ( + sio_lconc, (lconc_sched_before, lconc_sched_after) + ) = scheds[ ("insn_a", "insn_b")] # Create expected maps and compare - sched_map_before_exp = isl.Map( + sched_before_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -151,7 +155,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_exp = isl.Map( + sched_after_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -160,20 +164,24 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_exp, sched_map_after_exp], - [sched_map_before, sched_map_after], + [sched_before_exp, sched_after_exp], + [sched_before, sched_after], ) # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_c --------------------------------------- # Get two maps - sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ + ( + sio_seq, (sched_before, sched_after) + ), ( + sio_lconc, (lconc_sched_before, lconc_sched_after) + ) = scheds[ ("insn_a", "insn_c")] # Create expected maps and compare - sched_map_before_exp = isl.Map( + sched_before_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -181,7 +189,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_exp = isl.Map( + sched_after_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -190,20 +198,24 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_exp, sched_map_after_exp], - [sched_map_before, sched_map_after], + [sched_before_exp, sched_after_exp], + [sched_before, sched_after], ) # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_d --------------------------------------- # Get two maps - sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ + ( + sio_seq, (sched_before, sched_after) + ), ( + sio_lconc, (lconc_sched_before, lconc_sched_after) + ) = scheds[ ("insn_a", "insn_d")] # Create expected maps and compare - sched_map_before_exp = isl.Map( + sched_before_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -211,7 +223,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_exp = isl.Map( + sched_after_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -220,20 +232,24 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_exp, sched_map_after_exp], - [sched_map_before, sched_map_after], + [sched_before_exp, sched_after_exp], + [sched_before, sched_after], ) # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_c --------------------------------------- # Get two maps - sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ + ( + sio_seq, (sched_before, sched_after) + ), ( + sio_lconc, (lconc_sched_before, lconc_sched_after) + ) = scheds[ ("insn_b", "insn_c")] # Create expected maps and compare - sched_map_before_exp = isl.Map( + sched_before_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -241,7 +257,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_exp = isl.Map( + sched_after_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -250,20 +266,24 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_exp, sched_map_after_exp], - [sched_map_before, sched_map_after], + [sched_before_exp, sched_after_exp], + [sched_before, sched_after], ) # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_d --------------------------------------- # Get two maps - sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ + ( + sio_seq, (sched_before, sched_after) + ), ( + sio_lconc, (lconc_sched_before, lconc_sched_after) + ) = scheds[ ("insn_b", "insn_d")] # Create expected maps and compare - sched_map_before_exp = isl.Map( + sched_before_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -271,7 +291,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_exp = isl.Map( + sched_after_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -280,20 +300,24 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_exp, sched_map_after_exp], - [sched_map_before, sched_map_after], + [sched_before_exp, sched_after_exp], + [sched_before, sched_after], ) # ------------------------------------------------------------------------------ # Relationship between insn_c and insn_d --------------------------------------- # Get two maps - sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ + ( + sio_seq, (sched_before, sched_after) + ), ( + sio_lconc, (lconc_sched_before, lconc_sched_after) + ) = scheds[ ("insn_c", "insn_d")] # Create expected maps and compare - sched_map_before_exp = isl.Map( + sched_before_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -301,7 +325,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_map_after_exp = isl.Map( + sched_after_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -310,8 +334,8 @@ def test_pairwise_schedule_creation(): ) _align_and_compare_maps( - [sched_map_before_exp, sched_map_after_exp], - [sched_map_before, sched_map_after], + [sched_before_exp, sched_after_exp], + [sched_before, sched_after], ) @@ -354,7 +378,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): stmt_id_pairs = [ ("stmt_a", "stmt_b"), ] - sched_maps = get_schedules_for_statement_pairs( + scheds = get_schedules_for_statement_pairs( lin_knl, linearization_items, stmt_id_pairs, @@ -363,12 +387,16 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): # Relationship between stmt_a and stmt_b --------------------------------------- # Get two maps - sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ + ( + sio_seq, (sched_before, sched_after) + ), ( + sio_lconc, (lconc_sched_before, lconc_sched_after) + ) = scheds[ ("stmt_a", "stmt_b")] # Create expected maps and compare - sched_map_before_exp = isl.Map( + sched_before_exp = isl.Map( "[pi,pj] -> {[%s=0,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, @@ -376,7 +404,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): ) ) - sched_map_after_exp = isl.Map( + sched_after_exp = isl.Map( "[pi,pj] -> {[%s=1,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, @@ -385,8 +413,8 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): ) _align_and_compare_maps( - [sched_map_before_exp, sched_map_after_exp], - [sched_map_before, sched_map_after], + [sched_before_exp, sched_after_exp], + [sched_before, sched_after], ) # ------------------------------------------------------------------------------ @@ -492,14 +520,18 @@ def _check_sio_for_stmt_pair( exp_sio, stmt_id_before, stmt_id_after, - sched_maps, + scheds, ): from loopy.schedule.checker.utils import ( ensure_dim_names_match_and_align, ) # Get pairwise schedule - sio_seq, sio_lconc, (sched_map_before, sched_map_after) = sched_maps[ + ( + sio_seq, (sched_before, sched_after) + ), ( + sio_lconc, (lconc_sched_before, lconc_sched_after) + ) = scheds[ (stmt_id_before, stmt_id_after)] sio_seq_aligned = ensure_dim_names_match_and_align(sio_seq, exp_sio) @@ -562,7 +594,7 @@ def test_statement_instance_ordering(): ("stmt_b", "stmt_d"), ("stmt_c", "stmt_d"), ] - sched_maps = get_schedules_for_statement_pairs( + scheds = get_schedules_for_statement_pairs( knl, linearization_items, stmt_id_pairs, @@ -580,7 +612,7 @@ def test_statement_instance_ordering(): exp_sio_seq = append_marker_to_isl_map_var_names( exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_b", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_b", scheds) # Relationship between stmt_a and stmt_c --------------------------------------- @@ -594,7 +626,7 @@ def test_statement_instance_ordering(): exp_sio_seq = append_marker_to_isl_map_var_names( exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_c", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_c", scheds) # Relationship between stmt_a and stmt_d --------------------------------------- @@ -608,7 +640,7 @@ def test_statement_instance_ordering(): exp_sio_seq = append_marker_to_isl_map_var_names( exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_d", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_d", scheds) # Relationship between stmt_b and stmt_c --------------------------------------- @@ -624,7 +656,7 @@ def test_statement_instance_ordering(): exp_sio_seq = append_marker_to_isl_map_var_names( exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_b", "stmt_c", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_b", "stmt_c", scheds) # Relationship between stmt_b and stmt_d --------------------------------------- @@ -638,7 +670,7 @@ def test_statement_instance_ordering(): exp_sio_seq = append_marker_to_isl_map_var_names( exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_b", "stmt_d", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_b", "stmt_d", scheds) # Relationship between stmt_c and stmt_d --------------------------------------- @@ -652,7 +684,7 @@ def test_statement_instance_ordering(): exp_sio_seq = append_marker_to_isl_map_var_names( exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_c", "stmt_d", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_c", "stmt_d", scheds) def test_statement_instance_ordering_with_hw_par_tags(): @@ -699,7 +731,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): stmt_id_pairs = [ ("stmt_a", "stmt_b"), ] - sched_maps = get_schedules_for_statement_pairs( + scheds = get_schedules_for_statement_pairs( lin_knl, linearization_items, stmt_id_pairs, @@ -726,7 +758,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): exp_sio_seq = append_marker_to_isl_map_var_names( exp_sio_seq, isl.dim_type.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_b", sched_maps) + _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_b", scheds) # ------------------------------------------------------------------------------ From 0c3890d28e63d32301ac9d2cff0665a7016d4354 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 23 Mar 2021 11:10:34 -0500 Subject: [PATCH 046/220] (WIP) create separate global barrier sio map --- loopy/schedule/checker/schedule.py | 515 ++++++++++++++++++----------- test/test_linearization_checker.py | 16 + 2 files changed, 346 insertions(+), 185 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 7f83c4032..6212b5e44 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -122,7 +122,7 @@ def _simplify_lex_dims(tup0, tup1): def generate_pairwise_schedules( knl, - linearization_items, + lin_items, insn_id_pairs, loops_to_ignore=set(), ): @@ -137,7 +137,7 @@ def generate_pairwise_schedules( kernel will be used to get the domains associated with the inames used in the statements. - :arg linearization_items: A list of :class:`loopy.schedule.ScheduleItem` + :arg lin_items: A list of :class:`loopy.schedule.ScheduleItem` (to be renamed to `loopy.schedule.LinearizationItem`) containing all linearization items for which pairwise schedules will be created. To allow usage of this routine during linearization, a @@ -168,7 +168,7 @@ def generate_pairwise_schedules( all_insn_ids = set().union(*insn_id_pairs) - # First, use one pass through linearization_items to generate a lexicographic + # First, use one pass through lin_items to generate a lexicographic # ordering describing the relative order of *all* statements represented by # all_insn_ids @@ -181,9 +181,9 @@ def generate_pairwise_schedules( # ordering, initially this as a 1-d point with value 0 next_insn_lex_tuple = [0] - for linearization_item in linearization_items: - if isinstance(linearization_item, EnterLoop): - iname = linearization_item.iname + for lin_item in lin_items: + if isinstance(lin_item, EnterLoop): + iname = lin_item.iname if iname in loops_to_ignore: continue @@ -199,8 +199,8 @@ def generate_pairwise_schedules( next_insn_lex_tuple.append(iname) next_insn_lex_tuple.append(0) - elif isinstance(linearization_item, LeaveLoop): - if linearization_item.iname in loops_to_ignore: + elif isinstance(lin_item, LeaveLoop): + if lin_item.iname in loops_to_ignore: continue # Upon leaving a loop, @@ -217,14 +217,14 @@ def generate_pairwise_schedules( # in the simplification step below) next_insn_lex_tuple[-1] += 1 - elif isinstance(linearization_item, (RunInstruction, Barrier)): + elif isinstance(lin_item, (RunInstruction, Barrier)): from loopy.schedule.checker.utils import ( get_insn_id_from_linearization_item, ) - lp_insn_id = get_insn_id_from_linearization_item(linearization_item) + lp_insn_id = get_insn_id_from_linearization_item(lin_item) if lp_insn_id is None: - assert isinstance(linearization_item, Barrier) + assert isinstance(lin_item, Barrier) # Barriers without insn ids were inserted as a result of a # dependency. They don't themselves have dependencies. Ignore them. @@ -247,7 +247,7 @@ def generate_pairwise_schedules( from loopy.schedule import (CallKernel, ReturnFromKernel) # No action needed for these types of linearization item assert isinstance( - linearization_item, (CallKernel, ReturnFromKernel)) + lin_item, (CallKernel, ReturnFromKernel)) pass # To save time, stop when we've found all statements @@ -284,20 +284,16 @@ def generate_pairwise_schedules( # {{{ Determine which loops contain barriers - loops_with_lbarriers = set() - loops_with_gbarriers = set() + loops_with_barriers = {"local": set(), "global": set()} current_inames = set() - for linearization_item in linearization_items: - if isinstance(linearization_item, EnterLoop): - current_inames.add(linearization_item.iname) - elif isinstance(linearization_item, LeaveLoop): - current_inames.remove(linearization_item.iname) - elif isinstance(linearization_item, Barrier): - if linearization_item.synchronization_kind == "local": - loops_with_lbarriers |= current_inames - elif linearization_item.synchronization_kind == "global": - loops_with_gbarriers |= current_inames + for lin_item in lin_items: + if isinstance(lin_item, EnterLoop): + current_inames.add(lin_item.iname) + elif isinstance(lin_item, LeaveLoop): + current_inames.remove(lin_item.iname) + elif isinstance(lin_item, Barrier): + loops_with_barriers[lin_item.synchronization_kind] |= current_inames # At this point we could technically skip ahead to next enterloop # }}} @@ -306,7 +302,7 @@ def generate_pairwise_schedules( # (Could try to combine this with pass below but would make things messy) iname_bounds_pwaff = {} - for iname in loops_with_lbarriers: + for iname in loops_with_barriers["local"] | loops_with_barriers["global"]: # Get first and last vals for this iname bounds = knl.get_iname_bounds(iname) iname_bounds_pwaff[iname] = ( @@ -314,22 +310,279 @@ def generate_pairwise_schedules( # }}} - # {{{ Construct blueprint for creating blex space and orderings - # TODO combine this pass over the linearization items with the pass above + def _collect_blex_ordering_info(sync_kind): + + # {{{ Construct blueprint for creating blex space and orderings + # TODO combine this pass over the linearization items with the pass above + + stmt_inst_to_blex = {} # map stmt instances to blex space + iname_to_blex_dim = {} # map from inames to corresponding blex space dim + blex_exclusion_info = {} # info for creating pairs to subtract from blex order + blex_map_params = set() # params needed in blex map + n_blex_dims = 1 # number of dims in blex space + next_blex_pt = [0] # next tuple of points in blex order + + for lin_item in lin_items: + if isinstance(lin_item, EnterLoop): + enter_iname = lin_item.iname + if enter_iname in loops_with_barriers[sync_kind]: + # update next blex pt + pre_loop_blex_pt = next_blex_pt[:] + next_blex_pt[-1] += 1 + next_blex_pt.append(enter_iname) + next_blex_pt.append(0) + + # store tuples that will be used to create pairs + # that will later be subtracted from happens-before map + lbound = iname_bounds_pwaff[enter_iname][0] + first_iter_blex_pt = next_blex_pt[:] + first_iter_blex_pt[-2] = lbound + blex_exclusion_info[enter_iname] = { + PRE: tuple(pre_loop_blex_pt), # make sure to copy + TOP: tuple(next_blex_pt), # make sure to copy + FIRST: tuple(first_iter_blex_pt), # make sure to copy + } + blex_map_params |= set(lbound.get_var_names(dt.param)) + + elif isinstance(lin_item, LeaveLoop): + leave_iname = lin_item.iname + if leave_iname in loops_with_barriers[sync_kind]: + + # update max blex dims + n_blex_dims = max(n_blex_dims, len(next_blex_pt)) + iname_to_blex_dim[leave_iname] = len(next_blex_pt)-2 + + # update next blex pt + pre_end_loop_blex_pt = next_blex_pt[:] + next_blex_pt.pop() + next_blex_pt.pop() + next_blex_pt[-1] += 1 + + # store tuples that will be used to create pairs + # that will later be subtracted from happens-before map + ubound = iname_bounds_pwaff[leave_iname][1] + last_iter_blex_pt = pre_end_loop_blex_pt[:] + last_iter_blex_pt[-2] = ubound + blex_exclusion_info[leave_iname][BOTTOM] = tuple( + pre_end_loop_blex_pt) + blex_exclusion_info[leave_iname][LAST] = tuple(last_iter_blex_pt) + blex_exclusion_info[leave_iname][POST] = tuple(next_blex_pt) + # (make sure ^these are copies) + blex_map_params |= set(ubound.get_var_names(dt.param)) + + elif isinstance(lin_item, RunInstruction): + # Add item to stmt_inst_to_blex + stmt_inst_to_blex[lin_item.insn_id] = tuple(next_blex_pt) + # Don't increment blex dim val + + elif isinstance(lin_item, Barrier): + # Increment blex dim val + next_blex_pt[-1] += 1 + + else: + from loopy.schedule import (CallKernel, ReturnFromKernel) + # No action needed for these types of linearization item + assert isinstance( + lin_item, (CallKernel, ReturnFromKernel)) + pass + + blex_map_params = sorted(blex_map_params) + + # At this point, some blex tuples may have more dimensions than others; + # the missing dims are the fastest-updating dims, and their values should + # be zero. Add them. + for stmt, tup in stmt_inst_to_blex.items(): + stmt_inst_to_blex[stmt] = _pad_tuple_with_zeros(tup, n_blex_dims) + + # }}} + + # Create names for the blex dimensions for sequential loops + from loopy.schedule.checker.utils import ( + append_marker_to_strings, + ) + seq_blex_dim_names = [ + BLEX_VAR_PREFIX+str(i) for i in range(n_blex_dims)] + seq_blex_dim_names_prime = append_marker_to_strings( + seq_blex_dim_names, marker=BEFORE_MARK) + + blex_order_map = create_lex_order_map( + before_names=seq_blex_dim_names_prime, + after_names=seq_blex_dim_names, + after_names_concurrent=conc_lex_dim_names, + conc_var_comparison_op="ne", + in_dim_marker=BEFORE_MARK, + ) + + iname_to_blex_var = {} + for iname, dim in iname_to_blex_dim.items(): + iname_to_blex_var[iname] = seq_blex_dim_names[dim] + iname_to_blex_var[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] + + # Add params to blex map + blex_order_map = blex_order_map.add_dims(dt.param, len(blex_map_params)) + for i, p in enumerate(blex_map_params): + blex_order_map = blex_order_map.set_dim_name(dt.param, i, p) + + # get a set representing blex_order_map space + blex_set_template = isl.align_spaces( + isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map + ).move_dims( + dt.in_, n_blex_dims, dt.out, 0, n_blex_dims + ).domain() + blex_set_affs = isl.affs_from_space(blex_set_template.space) + + def _create_subtraction_map_for_iname(iname, blueprint): + # Note: blueprint[FIRST] and blueprint[LAST] contain pwaffs + + def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): + + # start with a set representing blex_order_map space + blex_set = blex_set_template.copy() + + # add markers to inames in before tuple + # (assume strings are the inames) + before_prime = tuple( + v+BEFORE_MARK if isinstance(v, str) else v for v in before) + before_padded = _pad_tuple_with_zeros(before_prime, n_blex_dims) + after_padded = _pad_tuple_with_zeros(after, n_blex_dims) + + # assign vals to dims + for dim_name, dim_val in zip( + seq_blex_dim_names_prime+seq_blex_dim_names, + before_padded+after_padded): + # (could exploit knowledge of content types of odd/even + # tuple dims to reduce conditionals but would be ugly + # and less robust) + if isinstance(dim_val, int): + # set idx to int val + blex_set &= blex_set_affs[dim_name].eq_set( + blex_set_affs[0]+dim_val) + elif isinstance(dim_val, str): + # assume this is an iname, set idx to corresponding blex var + blex_set &= blex_set_affs[dim_name].eq_set( + blex_set_affs[iname_to_blex_var[dim_val]]) + else: + assert isinstance(dim_val, isl.PwAff) + pwaff_aligned = isl.align_spaces(dim_val, blex_set_affs[0]) + # (doesn't matter which element of blex_set_affs we use^) + blex_set &= blex_set_affs[dim_name].eq_set(pwaff_aligned) + + if wrap_cond: + # i = i' + step + # TODO what about step sizes != 1? + blex_set &= blex_set_affs[iname_to_blex_var[iname]].eq_set( + blex_set_affs[iname_to_blex_var[iname+BEFORE_MARK]] + 1) + + return blex_set + + # enter loop case + full_blex_set = _create_blex_set_from_tuple_pair( + blueprint[PRE], blueprint[FIRST]) + # wrap loop case + full_blex_set |= _create_blex_set_from_tuple_pair( + blueprint[BOTTOM], blueprint[TOP], wrap_cond=True) + # leave loop case + full_blex_set |= _create_blex_set_from_tuple_pair( + blueprint[LAST], blueprint[POST]) + + # add cond to fix iteration value for surrounding loops (i = i') + for surrounding_iname in blueprint[PRE][1::2]: + s_blex_var = iname_to_blex_var[surrounding_iname] + full_blex_set &= blex_set_affs[s_blex_var].eq_set( + blex_set_affs[s_blex_var+BEFORE_MARK]) + + # convert blex set back to map + return isl.Map.from_domain(full_blex_set).move_dims( + dt.out, 0, dt.in_, n_blex_dims, n_blex_dims) + + # subtract unwanted pairs from happens-before blex map + maps_to_subtract = [] + for iname, subdict in blex_exclusion_info.items(): + maps_to_subtract.append(_create_subtraction_map_for_iname(iname, subdict)) + + if maps_to_subtract: + # get union of maps + map_to_subtract = maps_to_subtract[0] + for other_map in maps_to_subtract[1:]: + map_to_subtract |= other_map + + # get some closure + map_to_subtract, closure_exact = map_to_subtract.transitive_closure() + assert closure_exact # TODO warn instead + + # subtract from blex order map + blex_order_map = blex_order_map - map_to_subtract + + return ( + stmt_inst_to_blex, # map stmt instances to blex space + blex_order_map, + seq_blex_dim_names, + ) + + # {{{ combining local and global stuff in single pass (old, TODO remove?) + """ + GLOBAL = "global" + LOCAL = "local" + stmt_inst_to_blex = {LOCAL: {}, GLOBAL: {}} # map stmt instances to blex space + iname_to_blex_dim = {LOCAL: {}, GLOBAL: {}} # map from inames to corresponding blex space dim + blex_exclusion_info = {LOCAL: {}, GLOBAL: {}} # info for creating pairs to subtract from blex order + blex_map_params = {LOCAL: set(), GLOBAL: set()} # params needed in blex map + next_blex_pt = {LOCAL: [0], GLOBAL: [0]} # next tuple of points in blex order + n_blex_dims = {LOCAL: 1, GLOBAL: 1} # number of dims in blex space + + def _enter_loop_blex_processing(scope, enter_iname): + # scope is either LOCAL or GLOBAL + + pre_loop_blex_pt = next_blex_pt[scope][:] + next_blex_pt[scope][-1] += 1 + next_blex_pt[scope].append(enter_iname) + next_blex_pt[scope].append(0) + + # store tuples that will be used to create pairs + # that will later be subtracted from happens-before map + lbound = iname_bounds_pwaff[enter_iname][0] + first_iter_blex_pt = next_blex_pt[scope][:] + first_iter_blex_pt[-2] = lbound + blex_exclusion_info[scope][enter_iname] = { + PRE: tuple(pre_loop_blex_pt), # make sure to copy + TOP: tuple(next_blex_pt[scope]), # make sure to copy + FIRST: tuple(first_iter_blex_pt), # make sure to copy + } + blex_map_params[scope] |= set(lbound.get_var_names(dt.param)) + + def _leave_loop_blex_processing(scope, leave_iname): + # scope is either LOCAL or GLOBAL + + # update max blex dims + n_blex_dims[scope] = max(n_blex_dims[scope], len(next_blex_pt[scope])) + iname_to_blex_dim[scope][leave_iname] = len(next_blex_pt[scope])-2 + + # update next blex pt + pre_end_loop_blex_pt = next_blex_pt[scope][:] + next_blex_pt[scope].pop() + next_blex_pt[scope].pop() + next_blex_pt[scope][-1] += 1 + + # store tuples that will be used to create pairs + # that will later be subtracted from happens-before map + ubound = iname_bounds_pwaff[leave_iname][1] + last_iter_blex_pt = pre_end_loop_blex_pt[:] + last_iter_blex_pt[-2] = ubound + blex_exclusion_info[scope][leave_iname][BOTTOM] = tuple( + pre_end_loop_blex_pt) + blex_exclusion_info[scope][leave_iname][LAST] = tuple(last_iter_blex_pt) + blex_exclusion_info[scope][leave_iname][POST] = tuple(next_blex_pt[scope]) + # (make sure ^these are copies) + blex_map_params[scope] |= set(ubound.get_var_names(dt.param)) - stmt_inst_to_lblex = {} # map stmt instances to lblex space - iname_to_lblex_dim = {} # map from inames to corresponding lblex space dim - lblex_exclusion_info = {} # info for creating pairs to subtract from lblex order - lblex_map_params = set() # params needed in lblex map - next_lblex_pt = [0] # next tuple of points in lblex order - n_lblex_dims = 1 # number of dims in lblex space # do both lblex and gblex processing in single pass through insns - for linearization_item in linearization_items: - if isinstance(linearization_item, EnterLoop): - enter_iname = linearization_item.iname + for lin_item in lin_items: + if isinstance(lin_item, EnterLoop): + enter_iname = lin_item.iname if enter_iname in loops_with_lbarriers: - # update next blex pt + _enter_loop_blex_processing(LOCAL, enter_iname) + # update next blex pt pre_loop_lblex_pt = next_lblex_pt[:] next_lblex_pt[-1] += 1 next_lblex_pt.append(enter_iname) @@ -346,10 +599,14 @@ def generate_pairwise_schedules( FIRST: tuple(first_iter_lblex_pt), # make sure to copy } lblex_map_params |= set(lbound.get_var_names(dt.param)) + if enter_iname in loops_with_gbarriers: + _enter_loop_blex_processing(GLOBAL, enter_iname) - elif isinstance(linearization_item, LeaveLoop): - leave_iname = linearization_item.iname + elif isinstance(lin_item, LeaveLoop): + leave_iname = lin_item.iname if leave_iname in loops_with_lbarriers: + _leave_loop_blex_processing(LOCAL, leave_iname) + # update max blex dims n_lblex_dims = max(n_lblex_dims, len(next_lblex_pt)) iname_to_lblex_dim[leave_iname] = len(next_lblex_pt)-2 @@ -371,15 +628,20 @@ def generate_pairwise_schedules( lblex_exclusion_info[leave_iname][POST] = tuple(next_lblex_pt) # (make sure ^these are copies) lblex_map_params |= set(ubound.get_var_names(dt.param)) + if leave_iname in loops_with_gbarriers: + _leave_loop_blex_processing(GLOBAL, leave_iname) - elif isinstance(linearization_item, RunInstruction): + elif isinstance(lin_item, RunInstruction): # Add item to stmt_inst_to_lblex - lp_insn_id = linearization_item.insn_id + lp_insn_id = lin_item.insn_id + stmt_inst_to_blex[LOCAL][lp_insn_id] = tuple(next_blex_pt[LOCAL]) + stmt_inst_to_blex[GLOBAL][lp_insn_id] = tuple(next_blex_pt[GLOBAL]) + stmt_inst_to_lblex[lp_insn_id] = tuple(next_lblex_pt) # Don't increment blex dim val - elif isinstance(linearization_item, Barrier): + elif isinstance(lin_item, Barrier): next_lblex_pt[-1] += 1 @@ -387,133 +649,15 @@ def generate_pairwise_schedules( from loopy.schedule import (CallKernel, ReturnFromKernel) # No action needed for these types of linearization item assert isinstance( - linearization_item, (CallKernel, ReturnFromKernel)) + lin_item, (CallKernel, ReturnFromKernel)) pass lblex_map_params = sorted(lblex_map_params) - + """ # }}} - # pad tuples w/zeros - for stmt, tup in stmt_inst_to_lblex.items(): - stmt_inst_to_lblex[stmt] = _pad_tuple_with_zeros(tup, n_lblex_dims) - - # Create names for the blex dimensions for sequential loops - from loopy.schedule.checker.utils import ( - append_marker_to_strings, - ) - seq_lblex_dim_names = [ - BLEX_VAR_PREFIX+str(i) for i in range(n_lblex_dims)] - seq_lblex_dim_names_prime = append_marker_to_strings( - seq_lblex_dim_names, marker=BEFORE_MARK) - - lblex_order_map = create_lex_order_map( - before_names=seq_lblex_dim_names_prime, - after_names=seq_lblex_dim_names, - after_names_concurrent=conc_lex_dim_names, - conc_var_comparison_op="ne", - in_dim_marker=BEFORE_MARK, - ) - - iname_to_lblex_var = {} - for iname, dim in iname_to_lblex_dim.items(): - iname_to_lblex_var[iname] = seq_lblex_dim_names[dim] - iname_to_lblex_var[iname+BEFORE_MARK] = seq_lblex_dim_names_prime[dim] - - # Add params to blex map - lblex_order_map = lblex_order_map.add_dims(dt.param, len(lblex_map_params)) - for i, p in enumerate(lblex_map_params): - lblex_order_map = lblex_order_map.set_dim_name(dt.param, i, p) - - # get a set representing blex_order_map space - lblex_set_template = isl.align_spaces( - isl.Map("[ ] -> { [ ] -> [ ] }"), lblex_order_map - ).move_dims( - dt.in_, n_lblex_dims, dt.out, 0, n_lblex_dims - ).domain() - lblex_set_affs = isl.affs_from_space(lblex_set_template.space) - - def _create_subtraction_map_for_iname(iname, blueprint): - # Note: blueprint[FIRST] and blueprint[LAST] contain pwaffs - - def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): - - # start with a set representing blex_order_map space - lblex_set = lblex_set_template.copy() - - # add markers to inames in before tuple - # (assume strings are the inames) - before_prime = tuple( - v+BEFORE_MARK if isinstance(v, str) else v for v in before) - before_padded = _pad_tuple_with_zeros(before_prime, n_lblex_dims) - after_padded = _pad_tuple_with_zeros(after, n_lblex_dims) - - # assign vals to dims - for dim_name, dim_val in zip( - seq_lblex_dim_names_prime+seq_lblex_dim_names, - before_padded+after_padded): - # (could exploit knowledge of content types of odd/even - # tuple dims to reduce conditionals but would be ugly - # and less robust) - if isinstance(dim_val, int): - # set idx to int val - lblex_set &= lblex_set_affs[dim_name].eq_set( - lblex_set_affs[0]+dim_val) - elif isinstance(dim_val, str): - # assume this is an iname, set idx to corresponding blex var - lblex_set &= lblex_set_affs[dim_name].eq_set( - lblex_set_affs[iname_to_lblex_var[dim_val]]) - else: - assert isinstance(dim_val, isl.PwAff) - pwaff_aligned = isl.align_spaces(dim_val, lblex_set_affs[0]) - # (doesn't matter which element of lblex_set_affs we use^) - lblex_set &= lblex_set_affs[dim_name].eq_set(pwaff_aligned) - - if wrap_cond: - # i = i' + step - # TODO what about step sizes != 1? - lblex_set &= lblex_set_affs[iname_to_lblex_var[iname]].eq_set( - lblex_set_affs[iname_to_lblex_var[iname+BEFORE_MARK]] + 1) - - return lblex_set - - # enter loop case - full_lblex_set = _create_blex_set_from_tuple_pair( - blueprint[PRE], blueprint[FIRST]) - # wrap loop case - full_lblex_set |= _create_blex_set_from_tuple_pair( - blueprint[BOTTOM], blueprint[TOP], wrap_cond=True) - # leave loop case - full_lblex_set |= _create_blex_set_from_tuple_pair( - blueprint[LAST], blueprint[POST]) - - # add cond to fix iteration value for surrounding loops (i = i') - for surrounding_iname in blueprint[PRE][1::2]: - s_lblex_var = iname_to_lblex_var[surrounding_iname] - full_lblex_set &= lblex_set_affs[s_lblex_var].eq_set( - lblex_set_affs[s_lblex_var+BEFORE_MARK]) - - # convert blex set back to map - return isl.Map.from_domain(full_lblex_set).move_dims( - dt.out, 0, dt.in_, n_lblex_dims, n_lblex_dims) - - # subtract unwanted pairs from happens-before blex map - maps_to_subtract = [] - for iname, subdict in lblex_exclusion_info.items(): - maps_to_subtract.append(_create_subtraction_map_for_iname(iname, subdict)) - - if maps_to_subtract: - # get union of maps - map_to_subtract = maps_to_subtract[0] - for other_map in maps_to_subtract[1:]: - map_to_subtract |= other_map - - # get some closure - map_to_subtract, closure_exact = map_to_subtract.transitive_closure() - assert closure_exact # TODO warn instead - - # subtract from blex order map - lblex_order_map = lblex_order_map - map_to_subtract + stmt_inst_to_lblex, lblex_order_map, seq_lblex_dim_names = _collect_blex_ordering_info("local") + stmt_inst_to_gblex, gblex_order_map, seq_gblex_dim_names = _collect_blex_ordering_info("global") # }}} end blex order/map machinery @@ -635,21 +779,9 @@ def _get_map_for_stmt( # TODO finish separating lid stuff from gid stuff - # NOTE: use *unsimplified* lex tuples with blex map - - lblex_tuples = [stmt_inst_to_lblex[insn_id] for insn_id in insn_ids] - - # At this point, one of the lex tuples may have more dimensions than another; - # the missing dims are the fastest-updating dims, and their values should - # be zero. Add them. - max_lblex_dims = max([len(lblex_tuple) for lblex_tuple in lblex_tuples]) - lblex_tuples_padded = [ - _pad_tuple_with_zeros(lblex_tuple, max_lblex_dims) - for lblex_tuple in lblex_tuples] + # NOTE: use *unsimplified* lex tuples with blex map, which have already been padded - # Create names for the output dimensions for sequential loops - seq_lblex_dim_names = [ - BLEX_VAR_PREFIX+str(i) for i in range(len(lblex_tuples_padded[0]))] + lblex_tuples_padded = [stmt_inst_to_lblex[insn_id] for insn_id in insn_ids] lconc_sched_maps = [ _get_map_for_stmt( @@ -666,13 +798,25 @@ def _get_map_for_stmt( before_marker=BEFORE_MARK, ) + # TODO use func to avoid duplicated code here: + + gblex_tuples_padded = [stmt_inst_to_gblex[insn_id] for insn_id in insn_ids] + + gconc_sched_maps = [ + _get_map_for_stmt( + insn_id, gblex_tuple, int_sid, + seq_gblex_dim_names+conc_lex_dim_names) # conc names same for all + for insn_id, gblex_tuple, int_sid + in zip(insn_ids, gblex_tuples_padded, int_sids) + ] + # Create statement instance ordering - # TODO - #sio_gconc = get_statement_ordering_map( - # *gconc_sched_maps, # note, func accepts exactly two maps - # gblex_order_map, - # before_marker=BEFORE_MARK, - # ) + sio_gconc = get_statement_ordering_map( + *gconc_sched_maps, # note, func accepts exactly two maps + gblex_order_map, + before_marker=BEFORE_MARK, + ) + # }}} @@ -680,7 +824,8 @@ def _get_map_for_stmt( #pairwise_schedules[tuple(insn_ids)] = tuple(intra_thread_sched_maps) pairwise_schedules[tuple(insn_ids)] = ( (sio_seq, tuple(intra_thread_sched_maps), ), - (sio_lconc, tuple(lconc_sched_maps), ) + (sio_lconc, tuple(lconc_sched_maps), ), + (sio_gconc, tuple(gconc_sched_maps), ), ) return pairwise_schedules diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 385f83b15..426f15f47 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -142,6 +142,8 @@ def test_pairwise_schedule_creation(): sio_seq, (sched_before, sched_after) ), ( sio_lconc, (lconc_sched_before, lconc_sched_after) + ), ( + sio_gconc, (gconc_sched_before, gconc_sched_after) ) = scheds[ ("insn_a", "insn_b")] @@ -176,6 +178,8 @@ def test_pairwise_schedule_creation(): sio_seq, (sched_before, sched_after) ), ( sio_lconc, (lconc_sched_before, lconc_sched_after) + ), ( + sio_gconc, (gconc_sched_before, gconc_sched_after) ) = scheds[ ("insn_a", "insn_c")] @@ -210,6 +214,8 @@ def test_pairwise_schedule_creation(): sio_seq, (sched_before, sched_after) ), ( sio_lconc, (lconc_sched_before, lconc_sched_after) + ), ( + sio_gconc, (gconc_sched_before, gconc_sched_after) ) = scheds[ ("insn_a", "insn_d")] @@ -244,6 +250,8 @@ def test_pairwise_schedule_creation(): sio_seq, (sched_before, sched_after) ), ( sio_lconc, (lconc_sched_before, lconc_sched_after) + ), ( + sio_gconc, (gconc_sched_before, gconc_sched_after) ) = scheds[ ("insn_b", "insn_c")] @@ -278,6 +286,8 @@ def test_pairwise_schedule_creation(): sio_seq, (sched_before, sched_after) ), ( sio_lconc, (lconc_sched_before, lconc_sched_after) + ), ( + sio_gconc, (gconc_sched_before, gconc_sched_after) ) = scheds[ ("insn_b", "insn_d")] @@ -312,6 +322,8 @@ def test_pairwise_schedule_creation(): sio_seq, (sched_before, sched_after) ), ( sio_lconc, (lconc_sched_before, lconc_sched_after) + ), ( + sio_gconc, (gconc_sched_before, gconc_sched_after) ) = scheds[ ("insn_c", "insn_d")] @@ -391,6 +403,8 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): sio_seq, (sched_before, sched_after) ), ( sio_lconc, (lconc_sched_before, lconc_sched_after) + ), ( + sio_gconc, (gconc_sched_before, gconc_sched_after) ) = scheds[ ("stmt_a", "stmt_b")] @@ -531,6 +545,8 @@ def _check_sio_for_stmt_pair( sio_seq, (sched_before, sched_after) ), ( sio_lconc, (lconc_sched_before, lconc_sched_after) + ), ( + sio_gconc, (gconc_sched_before, gconc_sched_after) ) = scheds[ (stmt_id_before, stmt_id_after)] From 59a829364134673226855e09350a985390c93c09 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 23 Mar 2021 19:29:24 -0500 Subject: [PATCH 047/220] create helper functions add_and_name_isl_dims(), add_eq_isl_constraint_from_names(), add_ne_isl_constraint_from_names() --- loopy/schedule/checker/utils.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 39c7f48e0..a6636c41c 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -35,6 +35,14 @@ def add_dims_to_isl_set(isl_set, dim_type, names, new_idx_start): return new_set +def add_and_name_isl_dims(isl_map, dim_type, names): + new_idx_start = isl_map.dim(dim_type) + new_map = isl_map.add_dims(dim_type, len(names)) + for i, name in enumerate(names): + new_map = new_map.set_dim_name(dim_type, new_idx_start+i, name) + return new_map + + def reorder_dims_by_name( isl_set, dim_type, desired_dims_ordered): """Return an isl_set with the dimensions of the specified dim_type @@ -85,6 +93,23 @@ def ensure_dim_names_match_and_align(obj_map, tgt_map): return isl.align_spaces(obj_map, tgt_map) +def add_eq_isl_constraint_from_names(isl_map, var1, var2): + # add constraint var1 = var2 + return isl_map.add_constraint( + isl.Constraint.eq_from_names( + isl_map.space, + {1: 0, var1: 1, var2: -1})) + + +def add_ne_isl_constraint_from_names(isl_map, var1, var2): + # add constraint var1 != var2 + return isl_map.add_constraint( + isl.Constraint.ineq_from_names(isl_map.space, {1: -1, var1: 1, var2: -1}) + ) | isl_map.add_constraint( + isl.Constraint.ineq_from_names(isl_map.space, {1: -1, var2: 1, var1: -1}) + ) + + def append_marker_to_isl_map_var_names(old_isl_map, dim_type, marker="'"): """Return an :class:`islpy.Map` with a marker appended to the specified dimension names. From d28a031b1fcb060f3a0b33651789ef6d29bed4d7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 23 Mar 2021 19:30:43 -0500 Subject: [PATCH 048/220] don't try to deal with appending conc dims inside get_lex_order_set/map; instead add them after creating the traditional ordering using the existing functions --- .../checker/lexicographic_order_map.py | 55 +++++++------------ loopy/schedule/checker/schedule.py | 45 ++++++++++----- test/test_linearization_checker.py | 42 +------------- 3 files changed, 54 insertions(+), 88 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 9add041c4..7927812b5 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -72,11 +72,9 @@ def get_statement_ordering_map( def get_lex_order_set( - before_names, after_names, - before_names_concurrent=[], - after_names_concurrent=[], + dim_names, islvars=None, - conc_var_comparison_op="eq", + in_dim_marker="'", ): """Return an :class:`islpy.Set` representing a lexicographic ordering with the number of dimensions provided in `before_names` @@ -118,55 +116,48 @@ def get_lex_order_set( # TODO update doc from loopy.schedule.checker.utils import ( - create_elementwise_comparison_conjunction_set, + append_marker_to_strings, ) + in_dim_names = append_marker_to_strings(dim_names, marker=in_dim_marker) + # If no islvars passed, make them using the names provided # (make sure to pass var names in desired order of space dims) if islvars is None: islvars = isl.make_zero_and_vars( - before_names+before_names_concurrent+after_names+after_names_concurrent, + in_dim_names+dim_names, []) # Initialize set with constraint i0' < i0 - lex_order_set = islvars[before_names[0]].lt_set(islvars[after_names[0]]) + lex_order_set = islvars[in_dim_names[0]].lt_set(islvars[dim_names[0]]) # For each dim d, starting with d=1, equality_conj_set will be constrained # by d equalities, e.g., (i0' = i0 and i1' = i1 and ... i(d-1)' = i(d-1)). equality_conj_set = islvars[0].eq_set(islvars[0]) # initialize to 'true' - for i in range(1, len(before_names)): + for i in range(1, len(in_dim_names)): # Add the next equality constraint to equality_conj_set equality_conj_set = equality_conj_set & \ - islvars[before_names[i-1]].eq_set(islvars[after_names[i-1]]) + islvars[in_dim_names[i-1]].eq_set(islvars[dim_names[i-1]]) # Create a set constrained by adding a less-than constraint for this dim, # e.g., (i1' < i1), to the current equality conjunction set. # For each dim d, starting with d=1, this full conjunction will have # d equalities and one inequality, e.g., # (i0' = i0 and i1' = i1 and ... i(d-1)' = i(d-1) and id' < id) - full_conj_set = islvars[before_names[i]].lt_set( - islvars[after_names[i]]) & equality_conj_set + full_conj_set = islvars[in_dim_names[i]].lt_set( + islvars[dim_names[i]]) & equality_conj_set # Union this new constraint with the current lex_order_set lex_order_set = lex_order_set | full_conj_set - lex_order_set = lex_order_set & \ - create_elementwise_comparison_conjunction_set( - before_names_concurrent, after_names_concurrent, - islvars, op=conc_var_comparison_op, - ) - return lex_order_set def create_lex_order_map( n_dims=None, - before_names=None, - after_names=None, - after_names_concurrent=[], - conc_var_comparison_op="eq", + dim_names=None, in_dim_marker="'", ): """Return a map from each point in a lexicographic ordering to every @@ -199,30 +190,22 @@ def create_lex_order_map( """ # TODO update doc - from loopy.schedule.checker.utils import append_marker_to_strings - - if after_names is None: - after_names = ["i%s" % (i) for i in range(n_dims)] - if before_names is None: - before_names = append_marker_to_strings(after_names, marker=in_dim_marker) + if dim_names is None: + dim_names = ["i%s" % (i) for i in range(n_dims)] if n_dims is None: - n_dims = len(after_names) - before_names_concurrent = append_marker_to_strings( - after_names_concurrent, marker=in_dim_marker) + n_dims = len(dim_names) - assert len(before_names) == len(after_names) == n_dims + assert len(dim_names) == n_dims dim_type = isl.dim_type # First, get a set representing the lexicographic ordering. lex_order_set = get_lex_order_set( - before_names, after_names, - before_names_concurrent, after_names_concurrent, - conc_var_comparison_op=conc_var_comparison_op, + dim_names, + in_dim_marker=in_dim_marker, ) # Now convert that set to a map. lex_map = isl.Map.from_domain(lex_order_set) return lex_map.move_dims( dim_type.out, 0, dim_type.in_, - len(before_names) + len(before_names_concurrent), - len(after_names) + len(after_names_concurrent)) + n_dims, n_dims) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 6212b5e44..65f27f742 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -165,6 +165,12 @@ def generate_pairwise_schedules( create_lex_order_map, get_statement_ordering_map, ) + from loopy.schedule.checker.utils import ( + add_and_name_isl_dims, + append_marker_to_strings, + add_eq_isl_constraint_from_names, + add_ne_isl_constraint_from_names, + ) all_insn_ids = set().union(*insn_id_pairs) @@ -397,31 +403,36 @@ def _collect_blex_ordering_info(sync_kind): # }}} # Create names for the blex dimensions for sequential loops - from loopy.schedule.checker.utils import ( - append_marker_to_strings, - ) seq_blex_dim_names = [ BLEX_VAR_PREFIX+str(i) for i in range(n_blex_dims)] seq_blex_dim_names_prime = append_marker_to_strings( seq_blex_dim_names, marker=BEFORE_MARK) blex_order_map = create_lex_order_map( - before_names=seq_blex_dim_names_prime, - after_names=seq_blex_dim_names, - after_names_concurrent=conc_lex_dim_names, - conc_var_comparison_op="ne", + dim_names=seq_blex_dim_names, in_dim_marker=BEFORE_MARK, ) + # Add lid/gid dims to lex order map + blex_order_map = add_and_name_isl_dims( + blex_order_map, dt.out, conc_lex_dim_names) + blex_order_map = add_and_name_isl_dims( + blex_order_map, dt.in_, append_marker_to_strings(conc_lex_dim_names)) + # Constrain lid/gid vars to be *not* equal + # TODO do right thing with conc vars for lblex, gblex case + # TODO LEFT OFF HERE + for var_name in conc_lex_dim_names: + blex_order_map = add_ne_isl_constraint_from_names( + blex_order_map, var_name, var_name+BEFORE_MARK) + iname_to_blex_var = {} for iname, dim in iname_to_blex_dim.items(): iname_to_blex_var[iname] = seq_blex_dim_names[dim] iname_to_blex_var[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] # Add params to blex map - blex_order_map = blex_order_map.add_dims(dt.param, len(blex_map_params)) - for i, p in enumerate(blex_map_params): - blex_order_map = blex_order_map.set_dim_name(dt.param, i, p) + blex_order_map = add_and_name_isl_dims( + blex_order_map, dt.param, blex_map_params) # get a set representing blex_order_map space blex_set_template = isl.align_spaces( @@ -759,12 +770,20 @@ def _get_map_for_stmt( # parallel dims are used. (could simplify everything by always using # all dims..., which would make maps more complex than necessary) lex_order_map = create_lex_order_map( - after_names=seq_lex_dim_names, - after_names_concurrent=conc_lex_dim_names, - conc_var_comparison_op="eq", + dim_names=seq_lex_dim_names, in_dim_marker=BEFORE_MARK, ) + # Add lid/gid dims to lex order map + lex_order_map = add_and_name_isl_dims( + lex_order_map, dt.out, conc_lex_dim_names) + lex_order_map = add_and_name_isl_dims( + lex_order_map, dt.in_, append_marker_to_strings(conc_lex_dim_names)) + # Constrain lid/gid vars to be equal + for var_name in conc_lex_dim_names: + lex_order_map = add_eq_isl_constraint_from_names( + lex_order_map, var_name, var_name+BEFORE_MARK) + # Create statement instance ordering, # maps each statement instance to all statement instances occuring later sio_seq = get_statement_ordering_map( diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 426f15f47..c0a3e8f95 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -447,8 +447,7 @@ def test_lex_order_map_creation(): append_marker_to_isl_map_var_names, ) - def _check_lex_map( - exp_lex_order_map, n_dims, lid_axes_used=[], gid_axes_used=[]): + def _check_lex_map(exp_lex_order_map, n_dims): # Isl ignores the apostrophes, so explicitly add them exp_lex_order_map = append_marker_to_isl_map_var_names( @@ -456,20 +455,11 @@ def _check_lex_map( lex_order_map = create_lex_order_map( n_dims=n_dims, - before_names=["%s%d'" % (LEX_VAR_PREFIX, i) for i in range(n_dims)], - after_names=["%s%d" % (LEX_VAR_PREFIX, i) for i in range(n_dims)], - after_names_concurrent=[ - LTAG_VAR_NAMES[i] for i in lid_axes_used] + [ - GTAG_VAR_NAMES[i] for i in gid_axes_used], + dim_names=["%s%d" % (LEX_VAR_PREFIX, i) for i in range(n_dims)], ) assert lex_order_map == exp_lex_order_map - assert ( - lex_order_map.get_var_names(isl.dim_type.in_) == - exp_lex_order_map.get_var_names(isl.dim_type.in_)) - assert ( - lex_order_map.get_var_names(isl.dim_type.out) == - exp_lex_order_map.get_var_names(isl.dim_type.out)) + assert lex_order_map.get_var_dict() == exp_lex_order_map.get_var_dict() exp_lex_order_map = isl.Map( "{{ " @@ -499,32 +489,6 @@ def _check_lex_map( _check_lex_map(exp_lex_order_map, 1) - # Lex map for kernel with parallel HW tags - - lid_axes_used = [0, 1] - gid_axes_used = [0, 1, 2] - hw_par_lex_vars = [ - LTAG_VAR_NAMES[i] for i in lid_axes_used] + [ - GTAG_VAR_NAMES[i] for i in gid_axes_used] - exp_lex_order_map = isl.Map( - "{{ " - "[{0}0', {0}1', {0}2', {1}', {2}', {3}', {4}', {5}'] " - "-> [{0}0, {0}1, {0}2, {1}, {2}, {3}, {4}, {5}] :" - "((" - "{0}0' < {0}0 " - ") or (" - "{0}0'={0}0 and {0}1' < {0}1 " - ") or (" - "{0}0'={0}0 and {0}1'={0}1 and {0}2' < {0}2 " - ")) and (" - "{1}' = {1} and {2}' = {2} and {3}' = {3} and {4}' = {4} and {5}' = {5}" - ")" - "}}".format(LEX_VAR_PREFIX, *hw_par_lex_vars)) - - _check_lex_map( - exp_lex_order_map, 3, - lid_axes_used=lid_axes_used, gid_axes_used=gid_axes_used) - # }}} From 805cab45e134febabb3af2318a7c4edb873db501 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 23 Mar 2021 19:34:04 -0500 Subject: [PATCH 049/220] rename add_dims_to_isl_set()->insert_and_name_isl_dims() --- loopy/schedule/checker/schedule.py | 4 ++-- loopy/schedule/checker/utils.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 65f27f742..42fecac1e 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -677,7 +677,7 @@ def _leave_loop_blex_processing(scope, leave_iname): from loopy.schedule.checker.utils import ( sorted_union_of_names_in_isl_sets, create_symbolic_map_from_tuples, - add_dims_to_isl_set, + insert_and_name_isl_dims, ) def _get_map_for_stmt( @@ -702,7 +702,7 @@ def _get_map_for_stmt( # Insert 'statement' dim into domain so that its space allows # for intersection with sched map later - dom_to_intersect = add_dims_to_isl_set( + dom_to_intersect = insert_and_name_isl_dims( dom, dt.set, [STATEMENT_VAR_NAME], 0) # Each map will map statement instances -> lex time. diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index a6636c41c..d8ef1c771 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -28,7 +28,7 @@ def prettier_map_string(map_obj): ).replace("{ ", "{\n").replace(" }", "\n}").replace("; ", ";\n") -def add_dims_to_isl_set(isl_set, dim_type, names, new_idx_start): +def insert_and_name_isl_dims(isl_set, dim_type, names, new_idx_start): new_set = isl_set.insert_dims(dim_type, new_idx_start, len(names)) for i, name in enumerate(names): new_set = new_set.set_dim_name(dim_type, new_idx_start+i, name) From 98aef7c7ad28997141ce7398189c4a4760ae09c3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 23 Mar 2021 19:52:20 -0500 Subject: [PATCH 050/220] for lblex map, constrain gids to be equal --- loopy/schedule/checker/schedule.py | 28 +++++++++++++++------------- loopy/schedule/checker/utils.py | 9 --------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 42fecac1e..a0ce65d34 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -169,7 +169,6 @@ def generate_pairwise_schedules( add_and_name_isl_dims, append_marker_to_strings, add_eq_isl_constraint_from_names, - add_ne_isl_constraint_from_names, ) all_insn_ids = set().union(*insn_id_pairs) @@ -264,15 +263,15 @@ def generate_pairwise_schedules( # Get dim names representing local/group axes for this kernel, # and get the dictionary that will be used later to create a # constraint requiring {par inames == par axes} in sched - l_axes_used = set() - g_axes_used = set() + lid_lex_dim_names = set() + gid_lex_dim_names = set() par_iname_constraint_dicts = [] for iname in knl.all_inames(): ltag = knl.iname_tags_of_type(iname, LocalIndexTag) if ltag: # assert len(ltag) == 1 # (should always be true) ltag_var = LTAG_VAR_NAMES[ltag.pop().axis] - l_axes_used.add(ltag_var) + lid_lex_dim_names.add(ltag_var) # Represent constraint 'iname = ltag_var' in par_iname_constraint_dicts: par_iname_constraint_dicts.append({1: 0, iname: 1, ltag_var: -1}) continue @@ -280,11 +279,12 @@ def generate_pairwise_schedules( if gtag: # assert len(gtag) == 1 # (should always be true) gtag_var = GTAG_VAR_NAMES[gtag.pop().axis] - g_axes_used.add(gtag_var) + gid_lex_dim_names.add(gtag_var) # Represent constraint 'iname = gtag_var' in par_iname_constraint_dicts: par_iname_constraint_dicts.append({1: 0, iname: 1, gtag_var: -1}) continue - conc_lex_dim_names = sorted(l_axes_used) + sorted(g_axes_used) + lid_lex_dim_names = sorted(lid_lex_dim_names) + gid_lex_dim_names = sorted(gid_lex_dim_names) # {{{ Create blex ordering (may later be combined with pass above) @@ -316,6 +316,8 @@ def generate_pairwise_schedules( # }}} + conc_lex_dim_names = lid_lex_dim_names + gid_lex_dim_names + def _collect_blex_ordering_info(sync_kind): # {{{ Construct blueprint for creating blex space and orderings @@ -418,12 +420,12 @@ def _collect_blex_ordering_info(sync_kind): blex_order_map, dt.out, conc_lex_dim_names) blex_order_map = add_and_name_isl_dims( blex_order_map, dt.in_, append_marker_to_strings(conc_lex_dim_names)) - # Constrain lid/gid vars to be *not* equal - # TODO do right thing with conc vars for lblex, gblex case - # TODO LEFT OFF HERE - for var_name in conc_lex_dim_names: - blex_order_map = add_ne_isl_constraint_from_names( - blex_order_map, var_name, var_name+BEFORE_MARK) + if sync_kind == "local": + # Constrain gid vars to be equal + for var_name in gid_lex_dim_names: + blex_order_map = add_eq_isl_constraint_from_names( + blex_order_map, var_name, var_name+BEFORE_MARK) + # (if sync_kind == "global", don't need constraints on lid/gid vars) iname_to_blex_var = {} for iname, dim in iname_to_blex_dim.items(): @@ -434,7 +436,7 @@ def _collect_blex_ordering_info(sync_kind): blex_order_map = add_and_name_isl_dims( blex_order_map, dt.param, blex_map_params) - # get a set representing blex_order_map space + # Get a set representing blex_order_map space blex_set_template = isl.align_spaces( isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map ).move_dims( diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index d8ef1c771..c079e0a61 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -101,15 +101,6 @@ def add_eq_isl_constraint_from_names(isl_map, var1, var2): {1: 0, var1: 1, var2: -1})) -def add_ne_isl_constraint_from_names(isl_map, var1, var2): - # add constraint var1 != var2 - return isl_map.add_constraint( - isl.Constraint.ineq_from_names(isl_map.space, {1: -1, var1: 1, var2: -1}) - ) | isl_map.add_constraint( - isl.Constraint.ineq_from_names(isl_map.space, {1: -1, var2: 1, var1: -1}) - ) - - def append_marker_to_isl_map_var_names(old_isl_map, dim_type, marker="'"): """Return an :class:`islpy.Map` with a marker appended to the specified dimension names. From 54a8364694673f5aaaad3ea8ecfa9cf845ecd2cd Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 23 Mar 2021 20:06:19 -0500 Subject: [PATCH 051/220] minor cleanup --- loopy/schedule/checker/schedule.py | 161 +++-------------------------- 1 file changed, 13 insertions(+), 148 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index a0ce65d34..ebf607c99 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -321,11 +321,10 @@ def generate_pairwise_schedules( def _collect_blex_ordering_info(sync_kind): # {{{ Construct blueprint for creating blex space and orderings - # TODO combine this pass over the linearization items with the pass above stmt_inst_to_blex = {} # map stmt instances to blex space iname_to_blex_dim = {} # map from inames to corresponding blex space dim - blex_exclusion_info = {} # info for creating pairs to subtract from blex order + blex_exclusion_info = {} # info for creating maps to exclude from blex order blex_map_params = set() # params needed in blex map n_blex_dims = 1 # number of dims in blex space next_blex_pt = [0] # next tuple of points in blex order @@ -334,7 +333,7 @@ def _collect_blex_ordering_info(sync_kind): if isinstance(lin_item, EnterLoop): enter_iname = lin_item.iname if enter_iname in loops_with_barriers[sync_kind]: - # update next blex pt + # update next blex pt pre_loop_blex_pt = next_blex_pt[:] next_blex_pt[-1] += 1 next_blex_pt.append(enter_iname) @@ -444,7 +443,7 @@ def _collect_blex_ordering_info(sync_kind): ).domain() blex_set_affs = isl.affs_from_space(blex_set_template.space) - def _create_subtraction_map_for_iname(iname, blueprint): + def _create_excluded_map_for_iname(iname, blueprint): # Note: blueprint[FIRST] and blueprint[LAST] contain pwaffs def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): @@ -511,7 +510,7 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # subtract unwanted pairs from happens-before blex map maps_to_subtract = [] for iname, subdict in blex_exclusion_info.items(): - maps_to_subtract.append(_create_subtraction_map_for_iname(iname, subdict)) + maps_to_subtract.append(_create_excluded_map_for_iname(iname, subdict)) if maps_to_subtract: # get union of maps @@ -532,145 +531,12 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): seq_blex_dim_names, ) - # {{{ combining local and global stuff in single pass (old, TODO remove?) - """ - GLOBAL = "global" - LOCAL = "local" - stmt_inst_to_blex = {LOCAL: {}, GLOBAL: {}} # map stmt instances to blex space - iname_to_blex_dim = {LOCAL: {}, GLOBAL: {}} # map from inames to corresponding blex space dim - blex_exclusion_info = {LOCAL: {}, GLOBAL: {}} # info for creating pairs to subtract from blex order - blex_map_params = {LOCAL: set(), GLOBAL: set()} # params needed in blex map - next_blex_pt = {LOCAL: [0], GLOBAL: [0]} # next tuple of points in blex order - n_blex_dims = {LOCAL: 1, GLOBAL: 1} # number of dims in blex space - - def _enter_loop_blex_processing(scope, enter_iname): - # scope is either LOCAL or GLOBAL - - pre_loop_blex_pt = next_blex_pt[scope][:] - next_blex_pt[scope][-1] += 1 - next_blex_pt[scope].append(enter_iname) - next_blex_pt[scope].append(0) - - # store tuples that will be used to create pairs - # that will later be subtracted from happens-before map - lbound = iname_bounds_pwaff[enter_iname][0] - first_iter_blex_pt = next_blex_pt[scope][:] - first_iter_blex_pt[-2] = lbound - blex_exclusion_info[scope][enter_iname] = { - PRE: tuple(pre_loop_blex_pt), # make sure to copy - TOP: tuple(next_blex_pt[scope]), # make sure to copy - FIRST: tuple(first_iter_blex_pt), # make sure to copy - } - blex_map_params[scope] |= set(lbound.get_var_names(dt.param)) - - def _leave_loop_blex_processing(scope, leave_iname): - # scope is either LOCAL or GLOBAL - - # update max blex dims - n_blex_dims[scope] = max(n_blex_dims[scope], len(next_blex_pt[scope])) - iname_to_blex_dim[scope][leave_iname] = len(next_blex_pt[scope])-2 - - # update next blex pt - pre_end_loop_blex_pt = next_blex_pt[scope][:] - next_blex_pt[scope].pop() - next_blex_pt[scope].pop() - next_blex_pt[scope][-1] += 1 - - # store tuples that will be used to create pairs - # that will later be subtracted from happens-before map - ubound = iname_bounds_pwaff[leave_iname][1] - last_iter_blex_pt = pre_end_loop_blex_pt[:] - last_iter_blex_pt[-2] = ubound - blex_exclusion_info[scope][leave_iname][BOTTOM] = tuple( - pre_end_loop_blex_pt) - blex_exclusion_info[scope][leave_iname][LAST] = tuple(last_iter_blex_pt) - blex_exclusion_info[scope][leave_iname][POST] = tuple(next_blex_pt[scope]) - # (make sure ^these are copies) - blex_map_params[scope] |= set(ubound.get_var_names(dt.param)) - - - # do both lblex and gblex processing in single pass through insns - for lin_item in lin_items: - if isinstance(lin_item, EnterLoop): - enter_iname = lin_item.iname - if enter_iname in loops_with_lbarriers: - _enter_loop_blex_processing(LOCAL, enter_iname) - # update next blex pt - pre_loop_lblex_pt = next_lblex_pt[:] - next_lblex_pt[-1] += 1 - next_lblex_pt.append(enter_iname) - next_lblex_pt.append(0) - - # store tuples that will be used to create pairs - # that will later be subtracted from happens-before map - lbound = iname_bounds_pwaff[enter_iname][0] - first_iter_lblex_pt = next_lblex_pt[:] - first_iter_lblex_pt[-2] = lbound - lblex_exclusion_info[enter_iname] = { - PRE: tuple(pre_loop_lblex_pt), # make sure to copy - TOP: tuple(next_lblex_pt), # make sure to copy - FIRST: tuple(first_iter_lblex_pt), # make sure to copy - } - lblex_map_params |= set(lbound.get_var_names(dt.param)) - if enter_iname in loops_with_gbarriers: - _enter_loop_blex_processing(GLOBAL, enter_iname) - - elif isinstance(lin_item, LeaveLoop): - leave_iname = lin_item.iname - if leave_iname in loops_with_lbarriers: - _leave_loop_blex_processing(LOCAL, leave_iname) - - # update max blex dims - n_lblex_dims = max(n_lblex_dims, len(next_lblex_pt)) - iname_to_lblex_dim[leave_iname] = len(next_lblex_pt)-2 - - # update next blex pt - pre_end_loop_lblex_pt = next_lblex_pt[:] - next_lblex_pt.pop() - next_lblex_pt.pop() - next_lblex_pt[-1] += 1 - - # store tuples that will be used to create pairs - # that will later be subtracted from happens-before map - ubound = iname_bounds_pwaff[leave_iname][1] - last_iter_lblex_pt = pre_end_loop_lblex_pt[:] - last_iter_lblex_pt[-2] = ubound - lblex_exclusion_info[leave_iname][BOTTOM] = tuple( - pre_end_loop_lblex_pt) - lblex_exclusion_info[leave_iname][LAST] = tuple(last_iter_lblex_pt) - lblex_exclusion_info[leave_iname][POST] = tuple(next_lblex_pt) - # (make sure ^these are copies) - lblex_map_params |= set(ubound.get_var_names(dt.param)) - if leave_iname in loops_with_gbarriers: - _leave_loop_blex_processing(GLOBAL, leave_iname) - - elif isinstance(lin_item, RunInstruction): - # Add item to stmt_inst_to_lblex - lp_insn_id = lin_item.insn_id - stmt_inst_to_blex[LOCAL][lp_insn_id] = tuple(next_blex_pt[LOCAL]) - stmt_inst_to_blex[GLOBAL][lp_insn_id] = tuple(next_blex_pt[GLOBAL]) - - stmt_inst_to_lblex[lp_insn_id] = tuple(next_lblex_pt) - - # Don't increment blex dim val - - elif isinstance(lin_item, Barrier): - - next_lblex_pt[-1] += 1 - - else: - from loopy.schedule import (CallKernel, ReturnFromKernel) - # No action needed for these types of linearization item - assert isinstance( - lin_item, (CallKernel, ReturnFromKernel)) - pass - - lblex_map_params = sorted(lblex_map_params) - """ - # }}} - - stmt_inst_to_lblex, lblex_order_map, seq_lblex_dim_names = _collect_blex_ordering_info("local") - stmt_inst_to_gblex, gblex_order_map, seq_gblex_dim_names = _collect_blex_ordering_info("global") + (stmt_inst_to_lblex, + lblex_order_map, + seq_lblex_dim_names) = _collect_blex_ordering_info("local") + (stmt_inst_to_gblex, + gblex_order_map, + seq_gblex_dim_names) = _collect_blex_ordering_info("global") # }}} end blex order/map machinery @@ -796,11 +662,11 @@ def _get_map_for_stmt( # }}} - # {{{ Create SIOs for inter-thread cases (lid0' != lid0, etc) + # {{{ Create SIOs for intra-group case (gid0' == gid0, etc) # TODO finish separating lid stuff from gid stuff - # NOTE: use *unsimplified* lex tuples with blex map, which have already been padded + # Use *unsimplified* lex tuples with blex map, which have already been padded lblex_tuples_padded = [stmt_inst_to_lblex[insn_id] for insn_id in insn_ids] @@ -838,10 +704,9 @@ def _get_map_for_stmt( before_marker=BEFORE_MARK, ) - # }}} - # TODO don't return sched maps? + # TODO have option to return sched maps, but default to not returning them #pairwise_schedules[tuple(insn_ids)] = tuple(intra_thread_sched_maps) pairwise_schedules[tuple(insn_ids)] = ( (sio_seq, tuple(intra_thread_sched_maps), ), From 4ab33df56e52a956620c5f57066b202574b8f50b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 24 Mar 2021 14:05:40 -0500 Subject: [PATCH 052/220] make returning schedules optional; default to just sio --- loopy/schedule/checker/__init__.py | 2 ++ loopy/schedule/checker/schedule.py | 14 +++++++++----- test/test_linearization_checker.py | 4 ++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 2684950d0..dba847239 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -27,6 +27,7 @@ def get_schedules_for_statement_pairs( knl, linearization_items, insn_id_pairs, + return_schedules=False, ): r"""For each statement pair in a subset of all statement pairs found in a linearized kernel, determine the (relative) order in which the statement @@ -135,6 +136,7 @@ def get_schedules_for_statement_pairs( linearization_items, insn_id_pairs, loops_to_ignore=conc_loop_inames, + return_schedules=return_schedules, ) # }}} diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index ebf607c99..3545e1547 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -125,6 +125,7 @@ def generate_pairwise_schedules( lin_items, insn_id_pairs, loops_to_ignore=set(), + return_schedules=False, ): r"""For each statement pair in a subset of all statement pairs found in a linearized kernel, determine the (relative) order in which the statement @@ -708,10 +709,13 @@ def _get_map_for_stmt( # TODO have option to return sched maps, but default to not returning them #pairwise_schedules[tuple(insn_ids)] = tuple(intra_thread_sched_maps) - pairwise_schedules[tuple(insn_ids)] = ( - (sio_seq, tuple(intra_thread_sched_maps), ), - (sio_lconc, tuple(lconc_sched_maps), ), - (sio_gconc, tuple(gconc_sched_maps), ), - ) + if return_schedules: + pairwise_schedules[tuple(insn_ids)] = ( + (sio_seq, tuple(intra_thread_sched_maps), ), + (sio_lconc, tuple(lconc_sched_maps), ), + (sio_gconc, tuple(gconc_sched_maps), ), + ) + else: + pairwise_schedules[tuple(insn_ids)] = (sio_seq, sio_lconc, sio_gconc) return pairwise_schedules diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index c0a3e8f95..3ba4d5517 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -133,6 +133,7 @@ def test_pairwise_schedule_creation(): lin_knl, linearization_items, insn_id_pairs, + return_schedules=True, ) # Relationship between insn_a and insn_b --------------------------------------- @@ -394,6 +395,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): lin_knl, linearization_items, stmt_id_pairs, + return_schedules=True, ) # Relationship between stmt_a and stmt_b --------------------------------------- @@ -578,6 +580,7 @@ def test_statement_instance_ordering(): knl, linearization_items, stmt_id_pairs, + return_schedules=True, ) # Relationship between stmt_a and stmt_b --------------------------------------- @@ -715,6 +718,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): lin_knl, linearization_items, stmt_id_pairs, + return_schedules=True, ) # Create string for representing parallel iname condition in sio From 80fa247c2066d0985639679b4b09e6037d291395 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 24 Mar 2021 14:44:22 -0500 Subject: [PATCH 053/220] (WIP) initial first test for schedules w/barriers --- test/test_linearization_checker.py | 120 ++++++++++++++++++++++++++--- 1 file changed, 110 insertions(+), 10 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 3ba4d5517..776558d2c 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -37,6 +37,7 @@ ) from loopy.schedule.checker.schedule import ( LEX_VAR_PREFIX, + BLEX_VAR_PREFIX, STATEMENT_VAR_NAME, LTAG_VAR_NAMES, GTAG_VAR_NAMES, @@ -58,13 +59,14 @@ def _align_and_compare_maps(maps1, maps2): assert map1_aligned == map2 -def _lex_point_string(dim_vals, lid_inames=[], gid_inames=[]): +def _lex_point_string(dim_vals, lid_inames=[], gid_inames=[], prefix=LEX_VAR_PREFIX): # Return a string describing a point in a lex space # by assigning values to lex dimension variables # (used to create maps below) + # TODO make lid/gid condition optional return ", ".join( - ["%s%d=%s" % (LEX_VAR_PREFIX, idx, str(val)) + ["%s%d=%s" % (prefix, idx, str(val)) for idx, val in enumerate(dim_vals)] + ["%s=%s" % (LTAG_VAR_NAMES[idx], iname) for idx, iname in enumerate(lid_inames)] + @@ -435,6 +437,101 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): # ------------------------------------------------------------------------------ + +def test_pairwise_schedule_creation_with_lbarriers(): + import islpy as isl + from loopy.schedule.checker import ( + get_schedules_for_statement_pairs, + ) + from loopy.schedule.checker.utils import ( + append_marker_to_isl_map_var_names, + ) + dt = isl.dim_type + + knl = lp.make_kernel( + [ + "{[i,j]: 0<=i,jtemp0 = 0 {id=0} + ... lbarrier {id=b0,dep=0} + <>temp1 = 1 {id=1,dep=b0} + for i + <>tempi0 = 0 {id=i0,dep=1} + ... lbarrier {id=ib0,dep=i0} + <>tempi1 = 0 {id=i1,dep=ib0} + <>tempi2 = 0 {id=i2,dep=i1} + for j + <>tempj0 = 0 {id=j0,dep=i2} + ... lbarrier {id=jb0,dep=j0} + <>tempj1 = 0 {id=j1,dep=jb0} + end + end + <>temp2 = 0 {id=2,dep=i0} + """, + name="funky", + assumptions="p >= 1", + lang_version=(2018, 2) + ) + + # Get a linearization + proc_knl = preprocess_kernel(knl) + lin_knl = get_one_linearized_kernel(proc_knl) + linearization_items = lin_knl.linearization + + insn_id_pairs = [("j1", "2")] + scheds = get_schedules_for_statement_pairs( + lin_knl, linearization_items, insn_id_pairs, return_schedules=True) + + # Get two maps + ( + sio_seq, (sched_map_before, sched_map_after) + ), ( + sio_lconc, (lconc_sched_before, lconc_sched_after) + ), ( + sio_gconc, (gconc_sched_before, gconc_sched_after) + ) = scheds[insn_id_pairs[0]] + + # Create expected maps and compare + + lconc_sched_before_exp = isl.Map( + "[p] -> {[%s=0,i,j] -> [%s] : 0 <= i,j < p}" + % ( + STATEMENT_VAR_NAME, + _lex_point_string(["2", "i", "2", "j", "1"], prefix=BLEX_VAR_PREFIX), + ) + ) + + lconc_sched_after_exp = isl.Map( + "[ ] -> {[%s=1] -> [%s]}" + % ( + STATEMENT_VAR_NAME, + _lex_point_string(["3", "0", "0", "0", "0"], prefix=BLEX_VAR_PREFIX), + ) + ) + + _align_and_compare_maps( + [lconc_sched_before_exp, lconc_sched_after_exp], + [lconc_sched_before, lconc_sched_after], + ) + + hab_test_pair = isl.Map( + "[p] -> {" + "[stmt' = 0, i'=1, j'=p-1] -> [stmt = 1] : p > 2" + "}") + hab_test_pair = append_marker_to_isl_map_var_names( + hab_test_pair, dt.in_, "'") + + #blex_pts_for_test_pair = isl.Map( + # "[p] -> {" + # "[blex0' = 2, blex1' = 1, blex2' = 2, blex3' = p - 1, blex4' = 1] -> " + # "[blex0 = 3, blex1 = 0, blex2 = 0, blex3 = 0, blex4 = 0]" + # "}") + #blex_pts_for_test_pair = append_marker_to_isl_map_var_names( + # blex_pts_for_test_pair, dt.in_, "'") + + assert hab_test_pair.is_subset(sio_lconc) + # }}} @@ -448,12 +545,13 @@ def test_lex_order_map_creation(): from loopy.schedule.checker.utils import ( append_marker_to_isl_map_var_names, ) + dt = isl.dim_type def _check_lex_map(exp_lex_order_map, n_dims): # Isl ignores the apostrophes, so explicitly add them exp_lex_order_map = append_marker_to_isl_map_var_names( - exp_lex_order_map, isl.dim_type.in_, "'") + exp_lex_order_map, dt.in_, "'") lex_order_map = create_lex_order_map( n_dims=n_dims, @@ -529,6 +627,7 @@ def test_statement_instance_ordering(): from loopy.schedule.checker.utils import ( append_marker_to_isl_map_var_names, ) + dt = isl.dim_type # Example kernel (add deps to fix loop order) knl = lp.make_kernel( @@ -593,7 +692,7 @@ def test_statement_instance_ordering(): ) # isl ignores these apostrophes, so explicitly add them exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, isl.dim_type.in_, "'") + exp_sio_seq, dt.in_, "'") _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_b", scheds) @@ -607,7 +706,7 @@ def test_statement_instance_ordering(): ) # isl ignores these apostrophes, so explicitly add them exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, isl.dim_type.in_, "'") + exp_sio_seq, dt.in_, "'") _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_c", scheds) @@ -621,7 +720,7 @@ def test_statement_instance_ordering(): ) # isl ignores these apostrophes, so explicitly add them exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, isl.dim_type.in_, "'") + exp_sio_seq, dt.in_, "'") _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_d", scheds) @@ -637,7 +736,7 @@ def test_statement_instance_ordering(): ) # isl ignores these apostrophes, so explicitly add them exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, isl.dim_type.in_, "'") + exp_sio_seq, dt.in_, "'") _check_sio_for_stmt_pair(exp_sio_seq, "stmt_b", "stmt_c", scheds) @@ -651,7 +750,7 @@ def test_statement_instance_ordering(): ) # isl ignores these apostrophes, so explicitly add them exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, isl.dim_type.in_, "'") + exp_sio_seq, dt.in_, "'") _check_sio_for_stmt_pair(exp_sio_seq, "stmt_b", "stmt_d", scheds) @@ -665,7 +764,7 @@ def test_statement_instance_ordering(): ) # isl ignores these apostrophes, so explicitly add them exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, isl.dim_type.in_, "'") + exp_sio_seq, dt.in_, "'") _check_sio_for_stmt_pair(exp_sio_seq, "stmt_c", "stmt_d", scheds) @@ -679,6 +778,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): append_marker_to_isl_map_var_names, partition_inames_by_concurrency, ) + dt = isl.dim_type # Example kernel knl = lp.make_kernel( @@ -740,7 +840,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): ) # isl ignores these apostrophes, so explicitly add them exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, isl.dim_type.in_, "'") + exp_sio_seq, dt.in_, "'") _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_b", scheds) From 528303ca28703db7e6994cbe8abdfee3618da603 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 24 Mar 2021 14:44:45 -0500 Subject: [PATCH 054/220] use isl.Map.get_var_dict() to compare all dim names more concisely --- loopy/schedule/checker/utils.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index c079e0a61..fb8674d9a 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -86,9 +86,7 @@ def reorder_dims_by_name( def ensure_dim_names_match_and_align(obj_map, tgt_map): # first make sure names match - assert all( - set(obj_map.get_var_names(dt)) == set(tgt_map.get_var_names(dt)) - for dt in [isl.dim_type.in_, isl.dim_type.out, isl.dim_type.param]) + assert obj_map.get_var_dict() == tgt_map.get_var_dict() return isl.align_spaces(obj_map, tgt_map) From 8287ef46f9ef10a980442a98ef1637c47284da88 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 24 Mar 2021 18:05:52 -0500 Subject: [PATCH 055/220] undo previous (broken) change: don't force all dims to be in the same place before aligning dims. duh. --- loopy/schedule/checker/utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index fb8674d9a..c079e0a61 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -86,7 +86,9 @@ def reorder_dims_by_name( def ensure_dim_names_match_and_align(obj_map, tgt_map): # first make sure names match - assert obj_map.get_var_dict() == tgt_map.get_var_dict() + assert all( + set(obj_map.get_var_names(dt)) == set(tgt_map.get_var_names(dt)) + for dt in [isl.dim_type.in_, isl.dim_type.out, isl.dim_type.param]) return isl.align_spaces(obj_map, tgt_map) From 7b7169cf545314a5ec8f9a59568ff6bba5d5c9c8 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 24 Mar 2021 18:07:17 -0500 Subject: [PATCH 056/220] distinguish between the number of blex dims with and without parallel lid/gid dims --- loopy/schedule/checker/schedule.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 3545e1547..5392578f6 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -327,7 +327,7 @@ def _collect_blex_ordering_info(sync_kind): iname_to_blex_dim = {} # map from inames to corresponding blex space dim blex_exclusion_info = {} # info for creating maps to exclude from blex order blex_map_params = set() # params needed in blex map - n_blex_dims = 1 # number of dims in blex space + n_seq_blex_dims = 1 # num dims representing sequential order in blex space next_blex_pt = [0] # next tuple of points in blex order for lin_item in lin_items: @@ -357,7 +357,7 @@ def _collect_blex_ordering_info(sync_kind): if leave_iname in loops_with_barriers[sync_kind]: # update max blex dims - n_blex_dims = max(n_blex_dims, len(next_blex_pt)) + n_seq_blex_dims = max(n_seq_blex_dims, len(next_blex_pt)) iname_to_blex_dim[leave_iname] = len(next_blex_pt)-2 # update next blex pt @@ -400,13 +400,13 @@ def _collect_blex_ordering_info(sync_kind): # the missing dims are the fastest-updating dims, and their values should # be zero. Add them. for stmt, tup in stmt_inst_to_blex.items(): - stmt_inst_to_blex[stmt] = _pad_tuple_with_zeros(tup, n_blex_dims) + stmt_inst_to_blex[stmt] = _pad_tuple_with_zeros(tup, n_seq_blex_dims) # }}} # Create names for the blex dimensions for sequential loops seq_blex_dim_names = [ - BLEX_VAR_PREFIX+str(i) for i in range(n_blex_dims)] + BLEX_VAR_PREFIX+str(i) for i in range(n_seq_blex_dims)] seq_blex_dim_names_prime = append_marker_to_strings( seq_blex_dim_names, marker=BEFORE_MARK) @@ -437,6 +437,7 @@ def _collect_blex_ordering_info(sync_kind): blex_order_map, dt.param, blex_map_params) # Get a set representing blex_order_map space + n_blex_dims = n_seq_blex_dims + len(conc_lex_dim_names) blex_set_template = isl.align_spaces( isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map ).move_dims( @@ -456,8 +457,8 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # (assume strings are the inames) before_prime = tuple( v+BEFORE_MARK if isinstance(v, str) else v for v in before) - before_padded = _pad_tuple_with_zeros(before_prime, n_blex_dims) - after_padded = _pad_tuple_with_zeros(after, n_blex_dims) + before_padded = _pad_tuple_with_zeros(before_prime, n_seq_blex_dims) + after_padded = _pad_tuple_with_zeros(after, n_seq_blex_dims) # assign vals to dims for dim_name, dim_val in zip( @@ -555,6 +556,8 @@ def _get_map_for_stmt( # Get inames domain for statement instance (a BasicSet) dom = knl.get_inames_domain( knl.id_to_insn[insn_id].within_inames) + # (note that this domain may include inames that are + # not in stmt.within_inames) # Create map space (an isl space in current implementation) # {('statement', ) -> @@ -582,6 +585,12 @@ def _get_map_for_stmt( lex_points )] + # Note that lex_points may have fewer dims than the out-dim of sched_space + # if sched_space includes concurrent lid/gid dims. This is okay because + # the following symbolic map creation step, when assigning dim values, + # zips the space dims with the lex tuple, and any leftover lid/gid dims + # will not be assigned a value yet, which is what we want. + # Create map sched_map = create_symbolic_map_from_tuples( tuple_pairs_with_domains=zip(tuple_pair, [dom_to_intersect, ]), From 295f644d5b4df48f9ce39f968879e7129849cbdf Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 24 Mar 2021 18:42:27 -0500 Subject: [PATCH 057/220] make a sched/sio test for case with local barriers --- test/test_linearization_checker.py | 269 ++++++++++++++++------------- 1 file changed, 145 insertions(+), 124 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 776558d2c..ee15fc3db 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -42,6 +42,9 @@ LTAG_VAR_NAMES, GTAG_VAR_NAMES, ) +from loopy.schedule.checker.utils import ( + ensure_dim_names_match_and_align, +) logger = logging.getLogger(__name__) @@ -49,9 +52,6 @@ # {{{ helper functions for map creation/handling def _align_and_compare_maps(maps1, maps2): - from loopy.schedule.checker.utils import ( - ensure_dim_names_match_and_align, - ) for map1, map2 in zip(maps1, maps2): # Align maps and compare @@ -63,7 +63,6 @@ def _lex_point_string(dim_vals, lid_inames=[], gid_inames=[], prefix=LEX_VAR_PRE # Return a string describing a point in a lex space # by assigning values to lex dimension variables # (used to create maps below) - # TODO make lid/gid condition optional return ", ".join( ["%s%d=%s" % (prefix, idx, str(val)) @@ -418,7 +417,10 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): "[pi,pj] -> {[%s=0,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, - _lex_point_string(["ii", "0"], lid_inames=["jj", "j"], gid_inames=["i"]), + _lex_point_string( + ["ii", "0"], + lid_inames=["jj", "j"], gid_inames=["i"], + ), ) ) @@ -426,7 +428,10 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): "[pi,pj] -> {[%s=1,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, - _lex_point_string(["ii", "1"], lid_inames=["jj", "j"], gid_inames=["i"]), + _lex_point_string( + ["ii", "1"], + lid_inames=["jj", "j"], gid_inames=["i"], + ), ) ) @@ -437,101 +442,6 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): # ------------------------------------------------------------------------------ - -def test_pairwise_schedule_creation_with_lbarriers(): - import islpy as isl - from loopy.schedule.checker import ( - get_schedules_for_statement_pairs, - ) - from loopy.schedule.checker.utils import ( - append_marker_to_isl_map_var_names, - ) - dt = isl.dim_type - - knl = lp.make_kernel( - [ - "{[i,j]: 0<=i,jtemp0 = 0 {id=0} - ... lbarrier {id=b0,dep=0} - <>temp1 = 1 {id=1,dep=b0} - for i - <>tempi0 = 0 {id=i0,dep=1} - ... lbarrier {id=ib0,dep=i0} - <>tempi1 = 0 {id=i1,dep=ib0} - <>tempi2 = 0 {id=i2,dep=i1} - for j - <>tempj0 = 0 {id=j0,dep=i2} - ... lbarrier {id=jb0,dep=j0} - <>tempj1 = 0 {id=j1,dep=jb0} - end - end - <>temp2 = 0 {id=2,dep=i0} - """, - name="funky", - assumptions="p >= 1", - lang_version=(2018, 2) - ) - - # Get a linearization - proc_knl = preprocess_kernel(knl) - lin_knl = get_one_linearized_kernel(proc_knl) - linearization_items = lin_knl.linearization - - insn_id_pairs = [("j1", "2")] - scheds = get_schedules_for_statement_pairs( - lin_knl, linearization_items, insn_id_pairs, return_schedules=True) - - # Get two maps - ( - sio_seq, (sched_map_before, sched_map_after) - ), ( - sio_lconc, (lconc_sched_before, lconc_sched_after) - ), ( - sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[insn_id_pairs[0]] - - # Create expected maps and compare - - lconc_sched_before_exp = isl.Map( - "[p] -> {[%s=0,i,j] -> [%s] : 0 <= i,j < p}" - % ( - STATEMENT_VAR_NAME, - _lex_point_string(["2", "i", "2", "j", "1"], prefix=BLEX_VAR_PREFIX), - ) - ) - - lconc_sched_after_exp = isl.Map( - "[ ] -> {[%s=1] -> [%s]}" - % ( - STATEMENT_VAR_NAME, - _lex_point_string(["3", "0", "0", "0", "0"], prefix=BLEX_VAR_PREFIX), - ) - ) - - _align_and_compare_maps( - [lconc_sched_before_exp, lconc_sched_after_exp], - [lconc_sched_before, lconc_sched_after], - ) - - hab_test_pair = isl.Map( - "[p] -> {" - "[stmt' = 0, i'=1, j'=p-1] -> [stmt = 1] : p > 2" - "}") - hab_test_pair = append_marker_to_isl_map_var_names( - hab_test_pair, dt.in_, "'") - - #blex_pts_for_test_pair = isl.Map( - # "[p] -> {" - # "[blex0' = 2, blex1' = 1, blex2' = 2, blex3' = p - 1, blex4' = 1] -> " - # "[blex0 = 3, blex1 = 0, blex2 = 0, blex3 = 0, blex4 = 0]" - # "}") - #blex_pts_for_test_pair = append_marker_to_isl_map_var_names( - # blex_pts_for_test_pair, dt.in_, "'") - - assert hab_test_pair.is_subset(sio_lconc) - # }}} @@ -846,31 +756,142 @@ def test_statement_instance_ordering_with_hw_par_tags(): # ------------------------------------------------------------------------------ +# }}} -# TODO when testing happens-after-barrier map, make sure to test parameter assumption issues: -""" ->>> test_pair2 = append_marker_to_isl_map_var_names(isl.Map("[p] -> { [stmt' = 0, i'=1, j'=p-1] -> [stmt = 1] : p > 1 }"), isl.dim_type.in_, "'") ->>> test_pair3 = append_marker_to_isl_map_var_names(isl.Map("[p] -> { [stmt' = 0, i'=1, j'=p-1] -> [stmt = 1] : p > 2 }"), isl.dim_type.in_, "'") ->>> hab = append_marker_to_isl_map_var_names(isl.Map("[p] -> { [stmt' = 0, i', j'] -> [stmt = 1] : 0 <= i' < p and 0 <= j' <= -2 + p; [stmt' = 0, i', j' = -1 + p] -> [stmt = 1] : 0 <= i' <= -2 + p }"), isl.dim_type.in_, "'") ->>> print(prettier_map_string(hab)) -[p] -> { -[stmt' = 0, i', j'] -> [stmt = 1] : 0 <= i' < p and 0 <= j' <= -2 + p; -[stmt' = 0, i', j' = -1 + p] -> [stmt = 1] : 0 <= i' <= -2 + p -} ->>> print(prettier_map_string(test_pair2)) -[p] -> { -[stmt' = 0, i' = 1, j' = -1 + p] -> [stmt = 1] : p >= 2 -} ->>> print(prettier_map_string(test_pair3)) -[p] -> { -[stmt' = 0, i' = 1, j' = -1 + p] -> [stmt = 1] : p >= 3 -} ->>> test_pair2.is_subset(hab) -False ->>> test_pair3.is_subset(hab) -True -""" +# {{{ SIOs and schedules with barriers + +def test_sios_and_schedules_with_lbarriers(): + import islpy as isl + from loopy.schedule.checker import ( + get_schedules_for_statement_pairs, + ) + from loopy.schedule.checker.utils import ( + append_marker_to_isl_map_var_names, + ) + dt = isl.dim_type + + knl = lp.make_kernel( + [ + #"{[i,j,l0,l1,g0]: 0<=i,j,l0,l1,g0temp0 = 0 {id=0} + ... lbarrier {id=b0,dep=0} + <>temp1 = 1 {id=1,dep=b0} + for i + <>tempi0 = 0 {id=i0,dep=1} + ... lbarrier {id=ib0,dep=i0} + <>tempi1 = 0 {id=i1,dep=ib0} + <>tempi2 = 0 {id=i2,dep=i1} + for j + <>tempj0 = 0 {id=j0,dep=i2} + ... lbarrier {id=jb0,dep=j0} + <>tempj1 = 0 {id=j1,dep=jb0} + end + end + <>temp2 = 0 {id=2,dep=i0} + end + end + end + """, + name="funky", + assumptions="p1,p2 >= 1", + lang_version=(2018, 2) + ) + knl = lp.tag_inames(knl, {"l0": "l.0", "l1": "l.1", "g0": "g.0"}) + + # Get a linearization + proc_knl = preprocess_kernel(knl) + lin_knl = get_one_linearized_kernel(proc_knl) + linearization_items = lin_knl.linearization + + insn_id_pairs = [("j1", "2")] + scheds = get_schedules_for_statement_pairs( + lin_knl, linearization_items, insn_id_pairs, return_schedules=True) + + # Get two maps + ( + sio_seq, (sched_map_before, sched_map_after) + ), ( + sio_lconc, (lconc_sched_before, lconc_sched_after) + ), ( + sio_gconc, (gconc_sched_before, gconc_sched_after) + ) = scheds[insn_id_pairs[0]] + + # Create expected maps and compare + + lconc_sched_before_exp = isl.Map( + "[p1,p2] -> {[%s=0,i,j,l0,l1,g0] -> [%s] : 0<=i,j {[%s=1,l0,l1,g0] -> [%s] : 0<=l0,l1,g0 {{" + "[{0}' = 0, i', j'=p1-1, g0', l0', l1'] -> [{0} = 1, l0, l1, g0] : " + "0 <= i' <= {1} and " # constrain i + "p1 >= {2} and " # constrain p + "0<=l0',l1',g0',l0,l1,g0 {{" + "[{0}' = 0, i', j'=p1-1, g0', l0', l1'] -> [{0} = 1, l0, l1, g0] : " + "0 <= i' <= {1} and " # constrain i + "p1 >= {2} and " # constrain p + "0<=l0',l1',g0',l0,l1,g0 Date: Thu, 25 Mar 2021 13:33:28 -0500 Subject: [PATCH 058/220] in ensure_dim_names_match_and_align(), raise informative error when map names don't match instead of just failing on assert --- loopy/schedule/checker/utils.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index c079e0a61..4ae2fbf64 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -86,9 +86,14 @@ def reorder_dims_by_name( def ensure_dim_names_match_and_align(obj_map, tgt_map): # first make sure names match - assert all( - set(obj_map.get_var_names(dt)) == set(tgt_map.get_var_names(dt)) - for dt in [isl.dim_type.in_, isl.dim_type.out, isl.dim_type.param]) + if not all( + set(obj_map.get_var_names(dt)) == set(tgt_map.get_var_names(dt)) + for dt in + [isl.dim_type.in_, isl.dim_type.out, isl.dim_type.param]): + raise ValueError( + "Cannot align spaces; names don't match:\n%s\n%s" + % (prettier_map_string(obj_map), prettier_map_string(tgt_map)) + ) return isl.align_spaces(obj_map, tgt_map) From df5192ab726905f8f641e8b40f8e9a1a879b1e0d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 25 Mar 2021 13:33:51 -0500 Subject: [PATCH 059/220] add todo to fix doctest --- loopy/schedule/checker/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index dba847239..f2caec55f 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -92,7 +92,7 @@ def get_schedules_for_statement_pairs( : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } """ - # TODO update docs now that we're returning SIOs + # TODO update docs and docstring now that we're returning SIOs # {{{ make sure kernel has been preprocessed From 96d4c21636178377e6855f7a127fae88f4049a04 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 25 Mar 2021 13:35:13 -0500 Subject: [PATCH 060/220] further lbarrier sio tests; also improve testing code with better helper funcs to reduce duplicated code --- test/test_linearization_checker.py | 239 ++++++++++++++++++----------- 1 file changed, 148 insertions(+), 91 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index ee15fc3db..fb15511ed 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -26,6 +26,7 @@ import sys import numpy as np import loopy as lp +import islpy as isl from pyopencl.tools import ( # noqa pytest_generate_tests_for_pyopencl as pytest_generate_tests) @@ -41,6 +42,7 @@ STATEMENT_VAR_NAME, LTAG_VAR_NAMES, GTAG_VAR_NAMES, + BEFORE_MARK, ) from loopy.schedule.checker.utils import ( ensure_dim_names_match_and_align, @@ -52,10 +54,15 @@ # {{{ helper functions for map creation/handling def _align_and_compare_maps(maps1, maps2): + from loopy.schedule.checker.utils import prettier_map_string for map1, map2 in zip(maps1, maps2): # Align maps and compare map1_aligned = ensure_dim_names_match_and_align(map1, map2) + if map1_aligned != map2: + print("Maps not equal:") + print(prettier_map_string(map1_aligned)) + print(prettier_map_string(map2)) assert map1_aligned == map2 @@ -73,13 +80,21 @@ def _lex_point_string(dim_vals, lid_inames=[], gid_inames=[], prefix=LEX_VAR_PRE for idx, iname in enumerate(gid_inames)] ) + +def _isl_map_with_marked_dims(s): + from loopy.schedule.checker.utils import ( + append_marker_to_isl_map_var_names, + ) + dt = isl.dim_type + # Isl ignores the apostrophes in map strings, until they are explicitly added + return append_marker_to_isl_map_var_names(isl.Map(s), dt.in_, BEFORE_MARK) + # }}} # {{{ test pairwise schedule creation def test_pairwise_schedule_creation(): - import islpy as isl from loopy.schedule.checker import ( get_schedules_for_statement_pairs, ) @@ -139,7 +154,7 @@ def test_pairwise_schedule_creation(): # Relationship between insn_a and insn_b --------------------------------------- - # Get two maps + # Get maps (include schedules, just for test purposes) ( sio_seq, (sched_before, sched_after) ), ( @@ -175,7 +190,7 @@ def test_pairwise_schedule_creation(): # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_c --------------------------------------- - # Get two maps + # Get maps (include schedules, just for test purposes) ( sio_seq, (sched_before, sched_after) ), ( @@ -211,7 +226,7 @@ def test_pairwise_schedule_creation(): # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_d --------------------------------------- - # Get two maps + # Get maps (include schedules, just for test purposes) ( sio_seq, (sched_before, sched_after) ), ( @@ -247,7 +262,7 @@ def test_pairwise_schedule_creation(): # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_c --------------------------------------- - # Get two maps + # Get maps (include schedules, just for test purposes) ( sio_seq, (sched_before, sched_after) ), ( @@ -283,7 +298,7 @@ def test_pairwise_schedule_creation(): # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_d --------------------------------------- - # Get two maps + # Get maps (include schedules, just for test purposes) ( sio_seq, (sched_before, sched_after) ), ( @@ -319,7 +334,7 @@ def test_pairwise_schedule_creation(): # ------------------------------------------------------------------------------ # Relationship between insn_c and insn_d --------------------------------------- - # Get two maps + # Get maps (include schedules, just for test purposes) ( sio_seq, (sched_before, sched_after) ), ( @@ -354,7 +369,6 @@ def test_pairwise_schedule_creation(): def test_pairwise_schedule_creation_with_hw_par_tags(): - import islpy as isl from loopy.schedule.checker import ( get_schedules_for_statement_pairs, ) @@ -401,7 +415,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): # Relationship between stmt_a and stmt_b --------------------------------------- - # Get two maps + # Get maps (include schedules, just for test purposes) ( sio_seq, (sched_before, sched_after) ), ( @@ -448,21 +462,12 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): # {{{ test lex order map creation def test_lex_order_map_creation(): - import islpy as isl from loopy.schedule.checker.lexicographic_order_map import ( create_lex_order_map, ) - from loopy.schedule.checker.utils import ( - append_marker_to_isl_map_var_names, - ) - dt = isl.dim_type def _check_lex_map(exp_lex_order_map, n_dims): - # Isl ignores the apostrophes, so explicitly add them - exp_lex_order_map = append_marker_to_isl_map_var_names( - exp_lex_order_map, dt.in_, "'") - lex_order_map = create_lex_order_map( n_dims=n_dims, dim_names=["%s%d" % (LEX_VAR_PREFIX, i) for i in range(n_dims)], @@ -471,7 +476,7 @@ def _check_lex_map(exp_lex_order_map, n_dims): assert lex_order_map == exp_lex_order_map assert lex_order_map.get_var_dict() == exp_lex_order_map.get_var_dict() - exp_lex_order_map = isl.Map( + exp_lex_order_map = _isl_map_with_marked_dims( "{{ " "[{0}0', {0}1', {0}2', {0}3', {0}4'] -> [{0}0, {0}1, {0}2, {0}3, {0}4] :" "(" @@ -489,7 +494,7 @@ def _check_lex_map(exp_lex_order_map, n_dims): _check_lex_map(exp_lex_order_map, 5) - exp_lex_order_map = isl.Map( + exp_lex_order_map = _isl_map_with_marked_dims( "{{ " "[{0}0'] -> [{0}0] :" "(" @@ -505,39 +510,49 @@ def _check_lex_map(exp_lex_order_map, n_dims): # {{{ test statement instance ordering creation def _check_sio_for_stmt_pair( - exp_sio, stmt_id_before, stmt_id_after, - scheds, + sio_dict, + exp_sio_seq=None, + exp_sched_before_seq=None, + exp_sched_after_seq=None, + exp_sio_lconc=None, + exp_sched_before_lconc=None, + exp_sched_after_lconc=None, + exp_sio_gconc=None, + exp_sched_before_gconc=None, + exp_sched_after_gconc=None, ): from loopy.schedule.checker.utils import ( ensure_dim_names_match_and_align, ) - # Get pairwise schedule + # Check whether scheds were included + #try: ( sio_seq, (sched_before, sched_after) ), ( - sio_lconc, (lconc_sched_before, lconc_sched_after) + sio_lconc, (sched_before_lconc, sched_after_lconc) ), ( - sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[ + sio_gconc, (sched_before_gconc, sched_after_gconc) + ) = sio_dict[ (stmt_id_before, stmt_id_after)] + #except : + # sio_seq, sio_lconc, sio_gconc = sio_dict[ + # (stmt_id_before, stmt_id_after)] - sio_seq_aligned = ensure_dim_names_match_and_align(sio_seq, exp_sio) + # TODO left off here, check all passed maps, + # en eliminate _align_and_comp... - assert sio_seq_aligned == exp_sio + sio_seq_aligned = ensure_dim_names_match_and_align(exp_sio_seq, sio_seq) + + assert sio_seq_aligned == exp_sio_seq def test_statement_instance_ordering(): - import islpy as isl from loopy.schedule.checker import ( get_schedules_for_statement_pairs, ) - from loopy.schedule.checker.utils import ( - append_marker_to_isl_map_var_names, - ) - dt = isl.dim_type # Example kernel (add deps to fix loop order) knl = lp.make_kernel( @@ -594,49 +609,40 @@ def test_statement_instance_ordering(): # Relationship between stmt_a and stmt_b --------------------------------------- - exp_sio_seq = isl.Map( + exp_sio_seq = _isl_map_with_marked_dims( "[pi, pj, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= k' < pk and 0 <= j < pj and i >= i' " "}}".format(STATEMENT_VAR_NAME) ) - # isl ignores these apostrophes, so explicitly add them - exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, dt.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_b", scheds) + _check_sio_for_stmt_pair("stmt_a", "stmt_b", scheds, exp_sio_seq=exp_sio_seq) # Relationship between stmt_a and stmt_c --------------------------------------- - exp_sio_seq = isl.Map( + exp_sio_seq = _isl_map_with_marked_dims( "[pi, pj, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= k' < pk and 0 <= j < pj and i >= i' " "}}".format(STATEMENT_VAR_NAME) ) - # isl ignores these apostrophes, so explicitly add them - exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, dt.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_c", scheds) + _check_sio_for_stmt_pair("stmt_a", "stmt_c", scheds, exp_sio_seq=exp_sio_seq) # Relationship between stmt_a and stmt_d --------------------------------------- - exp_sio_seq = isl.Map( + exp_sio_seq = _isl_map_with_marked_dims( "[pt, pi, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= k' < pk and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) - # isl ignores these apostrophes, so explicitly add them - exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, dt.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_d", scheds) + _check_sio_for_stmt_pair("stmt_a", "stmt_d", scheds, exp_sio_seq=exp_sio_seq) # Relationship between stmt_b and stmt_c --------------------------------------- - exp_sio_seq = isl.Map( + exp_sio_seq = _isl_map_with_marked_dims( "[pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= j,j' < pj and i > i'; " @@ -644,51 +650,39 @@ def test_statement_instance_ordering(): "0 <= i' < pi and 0 <= j,j' < pj and j >= j'; " "}}".format(STATEMENT_VAR_NAME) ) - # isl ignores these apostrophes, so explicitly add them - exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, dt.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_b", "stmt_c", scheds) + _check_sio_for_stmt_pair("stmt_b", "stmt_c", scheds, exp_sio_seq=exp_sio_seq) # Relationship between stmt_b and stmt_d --------------------------------------- - exp_sio_seq = isl.Map( + exp_sio_seq = _isl_map_with_marked_dims( "[pt, pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) - # isl ignores these apostrophes, so explicitly add them - exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, dt.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_b", "stmt_d", scheds) + _check_sio_for_stmt_pair("stmt_b", "stmt_d", scheds, exp_sio_seq=exp_sio_seq) # Relationship between stmt_c and stmt_d --------------------------------------- - exp_sio_seq = isl.Map( + exp_sio_seq = _isl_map_with_marked_dims( "[pt, pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) - # isl ignores these apostrophes, so explicitly add them - exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, dt.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_c", "stmt_d", scheds) + _check_sio_for_stmt_pair("stmt_c", "stmt_d", scheds, exp_sio_seq=exp_sio_seq) def test_statement_instance_ordering_with_hw_par_tags(): - import islpy as isl from loopy.schedule.checker import ( get_schedules_for_statement_pairs, ) from loopy.schedule.checker.utils import ( - append_marker_to_isl_map_var_names, partition_inames_by_concurrency, ) - dt = isl.dim_type # Example kernel knl = lp.make_kernel( @@ -738,7 +732,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): # Relationship between stmt_a and stmt_b --------------------------------------- - exp_sio_seq = isl.Map( + exp_sio_seq = _isl_map_with_marked_dims( "[pi, pj] -> {{ " "[{0}'=0, i', ii', j', jj'] -> [{0}=1, i, ii, j, jj] : " "0 <= i,ii,i',ii' < pi and 0 <= j,jj,j',jj' < pj and ii >= ii' " @@ -748,11 +742,8 @@ def test_statement_instance_ordering_with_hw_par_tags(): par_iname_condition, ) ) - # isl ignores these apostrophes, so explicitly add them - exp_sio_seq = append_marker_to_isl_map_var_names( - exp_sio_seq, dt.in_, "'") - _check_sio_for_stmt_pair(exp_sio_seq, "stmt_a", "stmt_b", scheds) + _check_sio_for_stmt_pair("stmt_a", "stmt_b", scheds, exp_sio_seq=exp_sio_seq) # ------------------------------------------------------------------------------ @@ -762,14 +753,9 @@ def test_statement_instance_ordering_with_hw_par_tags(): # {{{ SIOs and schedules with barriers def test_sios_and_schedules_with_lbarriers(): - import islpy as isl from loopy.schedule.checker import ( get_schedules_for_statement_pairs, ) - from loopy.schedule.checker.utils import ( - append_marker_to_isl_map_var_names, - ) - dt = isl.dim_type knl = lp.make_kernel( [ @@ -811,23 +797,28 @@ def test_sios_and_schedules_with_lbarriers(): lin_knl = get_one_linearized_kernel(proc_knl) linearization_items = lin_knl.linearization - insn_id_pairs = [("j1", "2")] + insn_id_pairs = [("j1", "2"), ("1", "i0")] scheds = get_schedules_for_statement_pairs( lin_knl, linearization_items, insn_id_pairs, return_schedules=True) - # Get two maps + # Relationship between j1 and 2 -------------------------------------------- + + # Get maps (include schedules, just for test purposes) ( sio_seq, (sched_map_before, sched_map_after) ), ( sio_lconc, (lconc_sched_before, lconc_sched_after) ), ( sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[insn_id_pairs[0]] + ) = scheds[("j1", "2")] # Create expected maps and compare + conc_iname_bound_str = "0<=l0,l1,g0 {[%s=0,i,j,l0,l1,g0] -> [%s] : 0<=i,j {[%s=0,i,j,l0,l1,g0] -> [%s] : 0<=i,j {[%s=1,l0,l1,g0] -> [%s] : 0<=l0,l1,g0 {[%s=1,l0,l1,g0] -> [%s] : %s}" % ( STATEMENT_VAR_NAME, _lex_point_string( @@ -847,32 +839,45 @@ def test_sios_and_schedules_with_lbarriers(): lid_inames=["l0", "l1"], gid_inames=["g0"], prefix=BLEX_VAR_PREFIX, ), + conc_iname_bound_str, + ) + ) + + sio_lconc_exp = _isl_map_with_marked_dims( + "[p1,p2] -> {{ " + "[{0}'=0,i',j',l0',l1',g0'] -> [{0}=1,l0,l1,g0] : " + "((0 <= i' < p1 and 0 <= j' < p1-1) or " # not last iteration of j + " (0 <= i' < p1-1 and 0 <= j' < p1))" # not last iteration of i + "and g0 = g0' " # within a single group + "and {1} and {2}" # conc iname bounds + "}}".format( + STATEMENT_VAR_NAME, + conc_iname_bound_str, + conc_iname_bound_str_p, ) ) _align_and_compare_maps( - [lconc_sched_before_exp, lconc_sched_after_exp], - [lconc_sched_before, lconc_sched_after], + [lconc_sched_before_exp, lconc_sched_after_exp, sio_lconc_exp], + [lconc_sched_before, lconc_sched_after, sio_lconc], ) - # Check for some example pairs in the sio_lconc map + # Check for some key example pairs in the sio_lconc map # As long as this is not the last iteration of the i loop, then there # should be a barrier between the last instance of statement j1 # and statement 2: p1_val = 7 last_i_val = p1_val - 1 - max_non_last_i_val = last_i_val - 1 + max_non_last_i_val = last_i_val - 1 # max i val that isn't the last iteration - wanted_pairs = isl.Map( + wanted_pairs = _isl_map_with_marked_dims( "[p1,p2] -> {{" "[{0}' = 0, i', j'=p1-1, g0', l0', l1'] -> [{0} = 1, l0, l1, g0] : " "0 <= i' <= {1} and " # constrain i "p1 >= {2} and " # constrain p "0<=l0',l1',g0',l0,l1,g0 {{" "[{0}' = 0, i', j'=p1-1, g0', l0', l1'] -> [{0} = 1, l0, l1, g0] : " "0 <= i' <= {1} and " # constrain i "p1 >= {2} and " # constrain p "0<=l0',l1',g0',l0,l1,g0 {[%s=0,l0,l1,g0] -> [%s] : 0<=l0,l1,g0 {[%s=1,i,j,l0,l1,g0] -> [%s] : 0<=i,j {{ " + "[{0}'=0,l0',l1',g0'] -> [{0}=1,i,j,l0,l1,g0] : " + "1 <= i < p1 and 0 <= j < p1 " # not first iteration of i + "and g0 = g0' " # within a single group + "and {1} and {2}" # conc iname bounds + "}}".format( + STATEMENT_VAR_NAME, + conc_iname_bound_str, + conc_iname_bound_str_p, + ) + ) + + _align_and_compare_maps( + [lconc_sched_before_exp, lconc_sched_after_exp, sio_lconc_exp], + [lconc_sched_before, lconc_sched_after, sio_lconc], + ) # }}} From 46e1bb198486f469fe36a53eb6d5ede6f834d6e3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 25 Mar 2021 19:04:03 -0500 Subject: [PATCH 061/220] use new-and-improved _check_sio_for_stmt_pair() to make tests more concise --- test/test_linearization_checker.py | 307 ++++++++++++----------------- 1 file changed, 125 insertions(+), 182 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index fb15511ed..be73e1bb2 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -53,10 +53,10 @@ # {{{ helper functions for map creation/handling -def _align_and_compare_maps(maps1, maps2): +def _align_and_compare_maps(maps): from loopy.schedule.checker.utils import prettier_map_string - for map1, map2 in zip(maps1, maps2): + for map1, map2 in maps: # Align maps and compare map1_aligned = ensure_dim_names_match_and_align(map1, map2) if map1_aligned != map2: @@ -149,24 +149,14 @@ def test_pairwise_schedule_creation(): lin_knl, linearization_items, insn_id_pairs, - return_schedules=True, + return_schedules=True, # include schedules for testing ) # Relationship between insn_a and insn_b --------------------------------------- - # Get maps (include schedules, just for test purposes) - ( - sio_seq, (sched_before, sched_after) - ), ( - sio_lconc, (lconc_sched_before, lconc_sched_after) - ), ( - sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[ - ("insn_a", "insn_b")] - # Create expected maps and compare - sched_before_exp = isl.Map( + sched_before_seq_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -174,7 +164,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_exp = isl.Map( + sched_after_seq_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -182,27 +172,18 @@ def test_pairwise_schedule_creation(): ) ) - _align_and_compare_maps( - [sched_before_exp, sched_after_exp], - [sched_before, sched_after], + _check_sio_for_stmt_pair( + "insn_a", "insn_b", scheds, + sched_before_seq_exp=sched_before_seq_exp, + sched_after_seq_exp=sched_after_seq_exp, ) # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_c --------------------------------------- - # Get maps (include schedules, just for test purposes) - ( - sio_seq, (sched_before, sched_after) - ), ( - sio_lconc, (lconc_sched_before, lconc_sched_after) - ), ( - sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[ - ("insn_a", "insn_c")] - # Create expected maps and compare - sched_before_exp = isl.Map( + sched_before_seq_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -210,7 +191,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_exp = isl.Map( + sched_after_seq_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -218,27 +199,18 @@ def test_pairwise_schedule_creation(): ) ) - _align_and_compare_maps( - [sched_before_exp, sched_after_exp], - [sched_before, sched_after], + _check_sio_for_stmt_pair( + "insn_a", "insn_c", scheds, + sched_before_seq_exp=sched_before_seq_exp, + sched_after_seq_exp=sched_after_seq_exp, ) # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_d --------------------------------------- - # Get maps (include schedules, just for test purposes) - ( - sio_seq, (sched_before, sched_after) - ), ( - sio_lconc, (lconc_sched_before, lconc_sched_after) - ), ( - sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[ - ("insn_a", "insn_d")] - # Create expected maps and compare - sched_before_exp = isl.Map( + sched_before_seq_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -246,7 +218,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_exp = isl.Map( + sched_after_seq_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -254,27 +226,18 @@ def test_pairwise_schedule_creation(): ) ) - _align_and_compare_maps( - [sched_before_exp, sched_after_exp], - [sched_before, sched_after], + _check_sio_for_stmt_pair( + "insn_a", "insn_d", scheds, + sched_before_seq_exp=sched_before_seq_exp, + sched_after_seq_exp=sched_after_seq_exp, ) # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_c --------------------------------------- - # Get maps (include schedules, just for test purposes) - ( - sio_seq, (sched_before, sched_after) - ), ( - sio_lconc, (lconc_sched_before, lconc_sched_after) - ), ( - sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[ - ("insn_b", "insn_c")] - # Create expected maps and compare - sched_before_exp = isl.Map( + sched_before_seq_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -282,7 +245,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_exp = isl.Map( + sched_after_seq_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -290,27 +253,18 @@ def test_pairwise_schedule_creation(): ) ) - _align_and_compare_maps( - [sched_before_exp, sched_after_exp], - [sched_before, sched_after], + _check_sio_for_stmt_pair( + "insn_b", "insn_c", scheds, + sched_before_seq_exp=sched_before_seq_exp, + sched_after_seq_exp=sched_after_seq_exp, ) # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_d --------------------------------------- - # Get maps (include schedules, just for test purposes) - ( - sio_seq, (sched_before, sched_after) - ), ( - sio_lconc, (lconc_sched_before, lconc_sched_after) - ), ( - sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[ - ("insn_b", "insn_d")] - # Create expected maps and compare - sched_before_exp = isl.Map( + sched_before_seq_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -318,7 +272,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_exp = isl.Map( + sched_after_seq_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -326,27 +280,18 @@ def test_pairwise_schedule_creation(): ) ) - _align_and_compare_maps( - [sched_before_exp, sched_after_exp], - [sched_before, sched_after], + _check_sio_for_stmt_pair( + "insn_b", "insn_d", scheds, + sched_before_seq_exp=sched_before_seq_exp, + sched_after_seq_exp=sched_after_seq_exp, ) # ------------------------------------------------------------------------------ # Relationship between insn_c and insn_d --------------------------------------- - # Get maps (include schedules, just for test purposes) - ( - sio_seq, (sched_before, sched_after) - ), ( - sio_lconc, (lconc_sched_before, lconc_sched_after) - ), ( - sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[ - ("insn_c", "insn_d")] - # Create expected maps and compare - sched_before_exp = isl.Map( + sched_before_seq_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -354,7 +299,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_exp = isl.Map( + sched_after_seq_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -362,9 +307,10 @@ def test_pairwise_schedule_creation(): ) ) - _align_and_compare_maps( - [sched_before_exp, sched_after_exp], - [sched_before, sched_after], + _check_sio_for_stmt_pair( + "insn_c", "insn_d", scheds, + sched_before_seq_exp=sched_before_seq_exp, + sched_after_seq_exp=sched_after_seq_exp, ) @@ -415,19 +361,9 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): # Relationship between stmt_a and stmt_b --------------------------------------- - # Get maps (include schedules, just for test purposes) - ( - sio_seq, (sched_before, sched_after) - ), ( - sio_lconc, (lconc_sched_before, lconc_sched_after) - ), ( - sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[ - ("stmt_a", "stmt_b")] - # Create expected maps and compare - sched_before_exp = isl.Map( + sched_before_seq_exp = isl.Map( "[pi,pj] -> {[%s=0,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, @@ -438,7 +374,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): ) ) - sched_after_exp = isl.Map( + sched_after_seq_exp = isl.Map( "[pi,pj] -> {[%s=1,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, @@ -449,9 +385,10 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): ) ) - _align_and_compare_maps( - [sched_before_exp, sched_after_exp], - [sched_before, sched_after], + _check_sio_for_stmt_pair( + "stmt_a", "stmt_b", scheds, + sched_before_seq_exp=sched_before_seq_exp, + sched_after_seq_exp=sched_after_seq_exp, ) # ------------------------------------------------------------------------------ @@ -513,40 +450,48 @@ def _check_sio_for_stmt_pair( stmt_id_before, stmt_id_after, sio_dict, - exp_sio_seq=None, - exp_sched_before_seq=None, - exp_sched_after_seq=None, - exp_sio_lconc=None, - exp_sched_before_lconc=None, - exp_sched_after_lconc=None, - exp_sio_gconc=None, - exp_sched_before_gconc=None, - exp_sched_after_gconc=None, + sio_seq_exp=None, + sched_before_seq_exp=None, + sched_after_seq_exp=None, + sio_lconc_exp=None, + sched_before_lconc_exp=None, + sched_after_lconc_exp=None, + sio_gconc_exp=None, + sched_before_gconc_exp=None, + sched_after_gconc_exp=None, ): - from loopy.schedule.checker.utils import ( - ensure_dim_names_match_and_align, - ) - - # Check whether scheds were included - #try: - ( - sio_seq, (sched_before, sched_after) - ), ( - sio_lconc, (sched_before_lconc, sched_after_lconc) - ), ( - sio_gconc, (sched_before_gconc, sched_after_gconc) - ) = sio_dict[ - (stmt_id_before, stmt_id_after)] - #except : - # sio_seq, sio_lconc, sio_gconc = sio_dict[ - # (stmt_id_before, stmt_id_after)] - - # TODO left off here, check all passed maps, - # en eliminate _align_and_comp... - sio_seq_aligned = ensure_dim_names_match_and_align(exp_sio_seq, sio_seq) + maps_found = sio_dict[(stmt_id_before, stmt_id_after)] + + # Check whether scheds were included in sio_dict + if isinstance(maps_found[0], tuple): + # Scheds were included + ( + sio_seq, (sched_before_seq, sched_after_seq) + ), ( + sio_lconc, (sched_before_lconc, sched_after_lconc) + ), ( + sio_gconc, (sched_before_gconc, sched_after_gconc) + ) = maps_found + map_candidates = zip([ + sio_seq_exp, sched_before_seq_exp, sched_after_seq_exp, + sio_lconc_exp, sched_before_lconc_exp, sched_after_lconc_exp, + sio_gconc_exp, sched_before_gconc_exp, sched_after_gconc_exp, + ], [ + sio_seq, sched_before_seq, sched_after_seq, + sio_lconc, sched_before_lconc, sched_after_lconc, + sio_gconc, sched_before_gconc, sched_after_gconc, + ]) + else: + # Scheds not included + sio_seq, sio_lconc, sio_gconc = maps_found + map_candidates = zip( + [sio_seq_exp, sio_lconc_exp, sio_gconc_exp, ], + [sio_seq, sio_lconc, sio_gconc, ]) - assert sio_seq_aligned == exp_sio_seq + # Only compare to maps that were passed + maps_to_compare = [(m1, m2) for m1, m2 in map_candidates if m1 is not None] + _align_and_compare_maps(maps_to_compare) def test_statement_instance_ordering(): @@ -609,40 +554,40 @@ def test_statement_instance_ordering(): # Relationship between stmt_a and stmt_b --------------------------------------- - exp_sio_seq = _isl_map_with_marked_dims( + sio_seq_exp = _isl_map_with_marked_dims( "[pi, pj, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= k' < pk and 0 <= j < pj and i >= i' " "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_a", "stmt_b", scheds, exp_sio_seq=exp_sio_seq) + _check_sio_for_stmt_pair("stmt_a", "stmt_b", scheds, sio_seq_exp=sio_seq_exp) # Relationship between stmt_a and stmt_c --------------------------------------- - exp_sio_seq = _isl_map_with_marked_dims( + sio_seq_exp = _isl_map_with_marked_dims( "[pi, pj, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= k' < pk and 0 <= j < pj and i >= i' " "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_a", "stmt_c", scheds, exp_sio_seq=exp_sio_seq) + _check_sio_for_stmt_pair("stmt_a", "stmt_c", scheds, sio_seq_exp=sio_seq_exp) # Relationship between stmt_a and stmt_d --------------------------------------- - exp_sio_seq = _isl_map_with_marked_dims( + sio_seq_exp = _isl_map_with_marked_dims( "[pt, pi, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= k' < pk and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_a", "stmt_d", scheds, exp_sio_seq=exp_sio_seq) + _check_sio_for_stmt_pair("stmt_a", "stmt_d", scheds, sio_seq_exp=sio_seq_exp) # Relationship between stmt_b and stmt_c --------------------------------------- - exp_sio_seq = _isl_map_with_marked_dims( + sio_seq_exp = _isl_map_with_marked_dims( "[pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= j,j' < pj and i > i'; " @@ -651,29 +596,29 @@ def test_statement_instance_ordering(): "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_b", "stmt_c", scheds, exp_sio_seq=exp_sio_seq) + _check_sio_for_stmt_pair("stmt_b", "stmt_c", scheds, sio_seq_exp=sio_seq_exp) # Relationship between stmt_b and stmt_d --------------------------------------- - exp_sio_seq = _isl_map_with_marked_dims( + sio_seq_exp = _isl_map_with_marked_dims( "[pt, pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_b", "stmt_d", scheds, exp_sio_seq=exp_sio_seq) + _check_sio_for_stmt_pair("stmt_b", "stmt_d", scheds, sio_seq_exp=sio_seq_exp) # Relationship between stmt_c and stmt_d --------------------------------------- - exp_sio_seq = _isl_map_with_marked_dims( + sio_seq_exp = _isl_map_with_marked_dims( "[pt, pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_c", "stmt_d", scheds, exp_sio_seq=exp_sio_seq) + _check_sio_for_stmt_pair("stmt_c", "stmt_d", scheds, sio_seq_exp=sio_seq_exp) def test_statement_instance_ordering_with_hw_par_tags(): @@ -732,7 +677,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): # Relationship between stmt_a and stmt_b --------------------------------------- - exp_sio_seq = _isl_map_with_marked_dims( + sio_seq_exp = _isl_map_with_marked_dims( "[pi, pj] -> {{ " "[{0}'=0, i', ii', j', jj'] -> [{0}=1, i, ii, j, jj] : " "0 <= i,ii,i',ii' < pi and 0 <= j,jj,j',jj' < pj and ii >= ii' " @@ -743,7 +688,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): ) ) - _check_sio_for_stmt_pair("stmt_a", "stmt_b", scheds, exp_sio_seq=exp_sio_seq) + _check_sio_for_stmt_pair("stmt_a", "stmt_b", scheds, sio_seq_exp=sio_seq_exp) # ------------------------------------------------------------------------------ @@ -799,25 +744,18 @@ def test_sios_and_schedules_with_lbarriers(): insn_id_pairs = [("j1", "2"), ("1", "i0")] scheds = get_schedules_for_statement_pairs( - lin_knl, linearization_items, insn_id_pairs, return_schedules=True) + lin_knl, linearization_items, insn_id_pairs, + return_schedules=True, # include schedules for testing + ) # Relationship between j1 and 2 -------------------------------------------- - # Get maps (include schedules, just for test purposes) - ( - sio_seq, (sched_map_before, sched_map_after) - ), ( - sio_lconc, (lconc_sched_before, lconc_sched_after) - ), ( - sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[("j1", "2")] - # Create expected maps and compare conc_iname_bound_str = "0<=l0,l1,g0 {[%s=0,i,j,l0,l1,g0] -> [%s] : 0<=i,j {[%s=1,l0,l1,g0] -> [%s] : %s}" % ( STATEMENT_VAR_NAME, @@ -857,13 +795,24 @@ def test_sios_and_schedules_with_lbarriers(): ) ) - _align_and_compare_maps( - [lconc_sched_before_exp, lconc_sched_after_exp, sio_lconc_exp], - [lconc_sched_before, lconc_sched_after, sio_lconc], + _check_sio_for_stmt_pair( + "j1", "2", scheds, + sio_lconc_exp=sio_lconc_exp, + sched_before_lconc_exp=sched_before_lconc_exp, + sched_after_lconc_exp=sched_after_lconc_exp, ) # Check for some key example pairs in the sio_lconc map + # Get maps + ( + sio_seq, (sched_map_before, sched_map_after) + ), ( + sio_lconc, (sched_before_lconc, sched_after_lconc) + ), ( + sio_gconc, (sched_before_gconc, sched_after_gconc) + ) = scheds[("j1", "2")] + # As long as this is not the last iteration of the i loop, then there # should be a barrier between the last instance of statement j1 # and statement 2: @@ -898,18 +847,9 @@ def test_sios_and_schedules_with_lbarriers(): # Relationship between 1 and i0 -------------------------------------------- - # Get maps (include schedules, just for test purposes) - ( - sio_seq, (sched_map_before, sched_map_after) - ), ( - sio_lconc, (lconc_sched_before, lconc_sched_after) - ), ( - sio_gconc, (gconc_sched_before, gconc_sched_after) - ) = scheds[("1", "i0")] - # Create expected maps and compare - lconc_sched_before_exp = isl.Map( + sched_before_lconc_exp = isl.Map( "[p2] -> {[%s=0,l0,l1,g0] -> [%s] : 0<=l0,l1,g0 {[%s=1,i,j,l0,l1,g0] -> [%s] : 0<=i,j Date: Thu, 25 Mar 2021 19:05:10 -0500 Subject: [PATCH 062/220] insn->stmt --- test/test_linearization_checker.py | 48 +++++++++++++++--------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index be73e1bb2..e44c5eec5 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -100,8 +100,8 @@ def test_pairwise_schedule_creation(): ) # Example kernel - # insn_c depends on insn_b only to create deterministic order - # insn_d depends on insn_c only to create deterministic order + # stmt_c depends on stmt_b only to create deterministic order + # stmt_d depends on stmt_c only to create deterministic order knl = lp.make_kernel( [ "{[i]: 0<=itemp = b[i,k] {id=insn_a} + <>temp = b[i,k] {id=stmt_a} end for j - a[i,j] = temp + 1 {id=insn_b,dep=insn_a} - c[i,j] = d[i,j] {id=insn_c,dep=insn_b} + a[i,j] = temp + 1 {id=stmt_b,dep=stmt_a} + c[i,j] = d[i,j] {id=stmt_c,dep=stmt_b} end end for t - e[t] = f[t] {id=insn_d, dep=insn_c} + e[t] = f[t] {id=stmt_d, dep=stmt_c} end """, name="example", @@ -138,12 +138,12 @@ def test_pairwise_schedule_creation(): linearization_items = lin_knl.linearization insn_id_pairs = [ - ("insn_a", "insn_b"), - ("insn_a", "insn_c"), - ("insn_a", "insn_d"), - ("insn_b", "insn_c"), - ("insn_b", "insn_d"), - ("insn_c", "insn_d"), + ("stmt_a", "stmt_b"), + ("stmt_a", "stmt_c"), + ("stmt_a", "stmt_d"), + ("stmt_b", "stmt_c"), + ("stmt_b", "stmt_d"), + ("stmt_c", "stmt_d"), ] scheds = get_schedules_for_statement_pairs( lin_knl, @@ -152,7 +152,7 @@ def test_pairwise_schedule_creation(): return_schedules=True, # include schedules for testing ) - # Relationship between insn_a and insn_b --------------------------------------- + # Relationship between stmt_a and stmt_b --------------------------------------- # Create expected maps and compare @@ -173,13 +173,13 @@ def test_pairwise_schedule_creation(): ) _check_sio_for_stmt_pair( - "insn_a", "insn_b", scheds, + "stmt_a", "stmt_b", scheds, sched_before_seq_exp=sched_before_seq_exp, sched_after_seq_exp=sched_after_seq_exp, ) # ------------------------------------------------------------------------------ - # Relationship between insn_a and insn_c --------------------------------------- + # Relationship between stmt_a and stmt_c --------------------------------------- # Create expected maps and compare @@ -200,13 +200,13 @@ def test_pairwise_schedule_creation(): ) _check_sio_for_stmt_pair( - "insn_a", "insn_c", scheds, + "stmt_a", "stmt_c", scheds, sched_before_seq_exp=sched_before_seq_exp, sched_after_seq_exp=sched_after_seq_exp, ) # ------------------------------------------------------------------------------ - # Relationship between insn_a and insn_d --------------------------------------- + # Relationship between stmt_a and stmt_d --------------------------------------- # Create expected maps and compare @@ -227,13 +227,13 @@ def test_pairwise_schedule_creation(): ) _check_sio_for_stmt_pair( - "insn_a", "insn_d", scheds, + "stmt_a", "stmt_d", scheds, sched_before_seq_exp=sched_before_seq_exp, sched_after_seq_exp=sched_after_seq_exp, ) # ------------------------------------------------------------------------------ - # Relationship between insn_b and insn_c --------------------------------------- + # Relationship between stmt_b and stmt_c --------------------------------------- # Create expected maps and compare @@ -254,13 +254,13 @@ def test_pairwise_schedule_creation(): ) _check_sio_for_stmt_pair( - "insn_b", "insn_c", scheds, + "stmt_b", "stmt_c", scheds, sched_before_seq_exp=sched_before_seq_exp, sched_after_seq_exp=sched_after_seq_exp, ) # ------------------------------------------------------------------------------ - # Relationship between insn_b and insn_d --------------------------------------- + # Relationship between stmt_b and stmt_d --------------------------------------- # Create expected maps and compare @@ -281,13 +281,13 @@ def test_pairwise_schedule_creation(): ) _check_sio_for_stmt_pair( - "insn_b", "insn_d", scheds, + "stmt_b", "stmt_d", scheds, sched_before_seq_exp=sched_before_seq_exp, sched_after_seq_exp=sched_after_seq_exp, ) # ------------------------------------------------------------------------------ - # Relationship between insn_c and insn_d --------------------------------------- + # Relationship between stmt_c and stmt_d --------------------------------------- # Create expected maps and compare @@ -308,7 +308,7 @@ def test_pairwise_schedule_creation(): ) _check_sio_for_stmt_pair( - "insn_c", "insn_d", scheds, + "stmt_c", "stmt_d", scheds, sched_before_seq_exp=sched_before_seq_exp, sched_after_seq_exp=sched_after_seq_exp, ) From a029c6719d0d678d017482bc4f1fc2c05c91577a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 25 Mar 2021 19:19:02 -0500 Subject: [PATCH 063/220] only increment barrier count if barrier scope matches --- loopy/schedule/checker/schedule.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 5392578f6..974f4051b 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -384,8 +384,9 @@ def _collect_blex_ordering_info(sync_kind): # Don't increment blex dim val elif isinstance(lin_item, Barrier): - # Increment blex dim val - next_blex_pt[-1] += 1 + # Increment blex dim val if the sync scope matches + if lin_item.synchronization_kind == sync_kind: + next_blex_pt[-1] += 1 else: from loopy.schedule import (CallKernel, ReturnFromKernel) From 264dfda337af0f213f73c5525cd91acc6a054af7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 25 Mar 2021 19:32:55 -0500 Subject: [PATCH 064/220] add some tests with global barriers --- test/test_linearization_checker.py | 83 +++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index e44c5eec5..be67f685a 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -697,7 +697,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): # {{{ SIOs and schedules with barriers -def test_sios_and_schedules_with_lbarriers(): +def test_sios_and_schedules_with_barriers(): from loopy.schedule.checker import ( get_schedules_for_statement_pairs, ) @@ -718,6 +718,7 @@ def test_sios_and_schedules_with_lbarriers(): for i <>tempi0 = 0 {id=i0,dep=1} ... lbarrier {id=ib0,dep=i0} + ... gbarrier {id=ibb0,dep=i0} <>tempi1 = 0 {id=i1,dep=ib0} <>tempi2 = 0 {id=i2,dep=i1} for j @@ -795,11 +796,52 @@ def test_sios_and_schedules_with_lbarriers(): ) ) + sched_before_gconc_exp = isl.Map( + "[p1,p2] -> {[%s=0,i,j,l0,l1,g0] -> [%s] : 0<=i,j {[%s=1,l0,l1,g0] -> [%s] : %s}" + % ( + STATEMENT_VAR_NAME, + _lex_point_string( + ["2", "0", "0"], + lid_inames=["l0", "l1"], gid_inames=["g0"], + prefix=BLEX_VAR_PREFIX, + ), + conc_iname_bound_str, + ) + ) + + sio_gconc_exp = _isl_map_with_marked_dims( + "[p1,p2] -> {{ " + "[{0}'=0,i',j',l0',l1',g0'] -> [{0}=1,l0,l1,g0] : " + "0 <= i' < p1-1 and 0 <= j' < p1 " # not last iteration of j + "and {1} and {2}" # conc iname bounds + "}}".format( + STATEMENT_VAR_NAME, + conc_iname_bound_str, + conc_iname_bound_str_p, + ) + ) + _check_sio_for_stmt_pair( "j1", "2", scheds, sio_lconc_exp=sio_lconc_exp, sched_before_lconc_exp=sched_before_lconc_exp, sched_after_lconc_exp=sched_after_lconc_exp, + sio_gconc_exp=sio_gconc_exp, + sched_before_gconc_exp=sched_before_gconc_exp, + sched_after_gconc_exp=sched_after_gconc_exp, ) # Check for some key example pairs in the sio_lconc map @@ -886,11 +928,50 @@ def test_sios_and_schedules_with_lbarriers(): ) ) + sched_before_gconc_exp = isl.Map( + "[p2] -> {[%s=0,l0,l1,g0] -> [%s] : 0<=l0,l1,g0 {[%s=1,i,j,l0,l1,g0] -> [%s] : 0<=i,j {{ " + "[{0}'=0,l0',l1',g0'] -> [{0}=1,i,j,l0,l1,g0] : " + "1 <= i < p1 and 0 <= j < p1 " # not first iteration of i + "and {1} and {2}" # conc iname bounds + "}}".format( + STATEMENT_VAR_NAME, + conc_iname_bound_str, + conc_iname_bound_str_p, + ) + ) + _check_sio_for_stmt_pair( "1", "i0", scheds, sio_lconc_exp=sio_lconc_exp, sched_before_lconc_exp=sched_before_lconc_exp, sched_after_lconc_exp=sched_after_lconc_exp, + sio_gconc_exp=sio_gconc_exp, + sched_before_gconc_exp=sched_before_gconc_exp, + sched_after_gconc_exp=sched_after_gconc_exp, ) # }}} From d49333fe5796145aeab9e392f52c4e6ef4b4c958 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 25 Mar 2021 21:22:43 -0500 Subject: [PATCH 065/220] use variable bounds in parallel+barrier sio/sched test; clean up expected map syntax with pre-made iname bounds strings --- test/test_linearization_checker.py | 154 +++++++++++++++++++---------- 1 file changed, 101 insertions(+), 53 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index be67f685a..1d0bc5748 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -702,11 +702,11 @@ def test_sios_and_schedules_with_barriers(): get_schedules_for_statement_pairs, ) + assumptions = "ij_end >= ij_start + 1 and lg_end >= 1" knl = lp.make_kernel( [ - #"{[i,j,l0,l1,g0]: 0<=i,j,l0,l1,g0 {[%s=0,i,j,l0,l1,g0] -> [%s] : 0<=i,j {" + "[%s=0, i, j, l0, l1, g0] -> [%s] : " + "%s and %s}" # iname bounds % ( STATEMENT_VAR_NAME, _lex_point_string( - ["2", "i", "2", "j", "1"], + ["2", "i", "2", "j", "1"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], prefix=BLEX_VAR_PREFIX, ), + iname_bound_str, conc_iname_bound_str, ) ) sched_after_lconc_exp = isl.Map( - "[p2] -> {[%s=1,l0,l1,g0] -> [%s] : %s}" + "[lg_end] -> {[%s=1, l0, l1, g0] -> [%s] : %s}" % ( STATEMENT_VAR_NAME, _lex_point_string( - ["3", "0", "0", "0", "0"], + ["3", "0", "0", "0", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], prefix=BLEX_VAR_PREFIX, ), @@ -783,38 +789,45 @@ def test_sios_and_schedules_with_barriers(): ) sio_lconc_exp = _isl_map_with_marked_dims( - "[p1,p2] -> {{ " - "[{0}'=0,i',j',l0',l1',g0'] -> [{0}=1,l0,l1,g0] : " - "((0 <= i' < p1 and 0 <= j' < p1-1) or " # not last iteration of j - " (0 <= i' < p1-1 and 0 <= j' < p1))" # not last iteration of i + "[ij_start, ij_end, lg_end] -> {{ " + "[{0}'=0, i', j', l0', l1', g0'] -> [{0}=1, l0, l1, g0] : " + "(ij_start <= j' < ij_end-1 or " # not last iteration of j + " ij_start <= i' < ij_end-1) " # not last iteration of i "and g0 = g0' " # within a single group - "and {1} and {2}" # conc iname bounds + "and {1} and {2} and {3} " # iname bounds + "and {4}" # param assumptions "}}".format( STATEMENT_VAR_NAME, + iname_bound_str_p, conc_iname_bound_str, conc_iname_bound_str_p, + assumptions, ) ) sched_before_gconc_exp = isl.Map( - "[p1,p2] -> {[%s=0,i,j,l0,l1,g0] -> [%s] : 0<=i,j {" + "[%s=0, i, j, l0, l1, g0] -> [%s] : " + "%s and %s}" # iname bounds % ( STATEMENT_VAR_NAME, _lex_point_string( - ["1", "i", "1"], + ["1", "i", "1"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], prefix=BLEX_VAR_PREFIX, ), + iname_bound_str, conc_iname_bound_str, ) ) sched_after_gconc_exp = isl.Map( - "[p2] -> {[%s=1,l0,l1,g0] -> [%s] : %s}" + "[lg_end] -> {[%s=1, l0, l1, g0] -> [%s] : " + "%s}" # iname bounds % ( STATEMENT_VAR_NAME, _lex_point_string( - ["2", "0", "0"], + ["2", "0", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], prefix=BLEX_VAR_PREFIX, ), @@ -823,14 +836,17 @@ def test_sios_and_schedules_with_barriers(): ) sio_gconc_exp = _isl_map_with_marked_dims( - "[p1,p2] -> {{ " - "[{0}'=0,i',j',l0',l1',g0'] -> [{0}=1,l0,l1,g0] : " - "0 <= i' < p1-1 and 0 <= j' < p1 " # not last iteration of j - "and {1} and {2}" # conc iname bounds + "[ij_start,ij_end,lg_end] -> {{ " + "[{0}'=0, i', j', l0', l1', g0'] -> [{0}=1, l0, l1, g0] : " + "ij_start <= i' < ij_end-1 " # not last iteration of i + "and {1} and {2} and {3} " # iname bounds + "and {4}" # param assumptions "}}".format( STATEMENT_VAR_NAME, + iname_bound_str_p, conc_iname_bound_str, conc_iname_bound_str_p, + assumptions, ) ) @@ -858,17 +874,24 @@ def test_sios_and_schedules_with_barriers(): # As long as this is not the last iteration of the i loop, then there # should be a barrier between the last instance of statement j1 # and statement 2: - p1_val = 7 - last_i_val = p1_val - 1 + ij_end_val = 7 + last_i_val = ij_end_val - 1 max_non_last_i_val = last_i_val - 1 # max i val that isn't the last iteration wanted_pairs = _isl_map_with_marked_dims( - "[p1,p2] -> {{" - "[{0}' = 0, i', j'=p1-1, g0', l0', l1'] -> [{0} = 1, l0, l1, g0] : " - "0 <= i' <= {1} and " # constrain i - "p1 >= {2} and " # constrain p - "0<=l0',l1',g0',l0,l1,g0 {{" + "[{0}' = 0, i', j'=ij_end-1, g0', l0', l1'] -> [{0} = 1, l0, l1, g0] : " + "ij_start <= i' <= {1} " # constrain i + "and ij_end >= {2} " # constrain ij_end + "and g0 = g0' " # within a single group + "and {3} and {4} " # conc iname bounds + "}}".format( + STATEMENT_VAR_NAME, + max_non_last_i_val, + ij_end_val, + conc_iname_bound_str, + conc_iname_bound_str_p, + )) wanted_pairs = ensure_dim_names_match_and_align(wanted_pairs, sio_lconc) assert wanted_pairs.is_subset(sio_lconc) @@ -877,12 +900,19 @@ def test_sios_and_schedules_with_barriers(): # should NOT be a barrier between the last instance of statement j1 # and statement 2: unwanted_pairs = _isl_map_with_marked_dims( - "[p1,p2] -> {{" - "[{0}' = 0, i', j'=p1-1, g0', l0', l1'] -> [{0} = 1, l0, l1, g0] : " - "0 <= i' <= {1} and " # constrain i - "p1 >= {2} and " # constrain p - "0<=l0',l1',g0',l0,l1,g0 {{" + "[{0}' = 0, i', j'=ij_end-1, g0', l0', l1'] -> [{0} = 1, l0, l1, g0] : " + "ij_start <= i' <= {1} " # constrain i + "and ij_end >= {2} " # constrain p + "and g0 = g0' " # within a single group + "and {3} and {4} " # conc iname bounds + "}}".format( + STATEMENT_VAR_NAME, + last_i_val, + ij_end_val, + conc_iname_bound_str, + conc_iname_bound_str_p, + )) unwanted_pairs = ensure_dim_names_match_and_align(unwanted_pairs, sio_lconc) assert not unwanted_pairs.is_subset(sio_lconc) @@ -892,75 +922,93 @@ def test_sios_and_schedules_with_barriers(): # Create expected maps and compare sched_before_lconc_exp = isl.Map( - "[p2] -> {[%s=0,l0,l1,g0] -> [%s] : 0<=l0,l1,g0 {[%s=0, l0, l1, g0] -> [%s] : " + "%s}" # iname bounds % ( STATEMENT_VAR_NAME, _lex_point_string( - ["1", "0", "0", "0", "0"], + ["1", "0", "0", "0", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], prefix=BLEX_VAR_PREFIX, ), + conc_iname_bound_str, ) ) sched_after_lconc_exp = isl.Map( - "[p1,p2] -> {[%s=1,i,j,l0,l1,g0] -> [%s] : 0<=i,j {" + "[%s=1, i, j, l0, l1, g0] -> [%s] : " + "%s and %s}" # iname bounds % ( STATEMENT_VAR_NAME, _lex_point_string( - ["2", "i", "0", "0", "0"], + ["2", "i", "0", "0", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], prefix=BLEX_VAR_PREFIX, ), + iname_bound_str, + conc_iname_bound_str, ) ) sio_lconc_exp = _isl_map_with_marked_dims( - "[p1,p2] -> {{ " - "[{0}'=0,l0',l1',g0'] -> [{0}=1,i,j,l0,l1,g0] : " - "1 <= i < p1 and 0 <= j < p1 " # not first iteration of i + "[ij_start, ij_end, lg_end] -> {{ " + "[{0}'=0, l0', l1', g0'] -> [{0}=1, i, j, l0, l1, g0] : " + "ij_start + 1 <= i < ij_end " # not first iteration of i "and g0 = g0' " # within a single group - "and {1} and {2}" # conc iname bounds + "and {1} and {2} and {3} " # iname bounds + "and {4}" # param assumptions "}}".format( STATEMENT_VAR_NAME, + iname_bound_str, conc_iname_bound_str, conc_iname_bound_str_p, + assumptions, ) ) sched_before_gconc_exp = isl.Map( - "[p2] -> {[%s=0,l0,l1,g0] -> [%s] : 0<=l0,l1,g0 {[%s=0, l0, l1, g0] -> [%s] : " + "%s}" # iname bounds % ( STATEMENT_VAR_NAME, _lex_point_string( - ["0", "0", "0"], + ["0", "0", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], prefix=BLEX_VAR_PREFIX, ), + conc_iname_bound_str, ) ) sched_after_gconc_exp = isl.Map( - "[p1,p2] -> {[%s=1,i,j,l0,l1,g0] -> [%s] : 0<=i,j {" + "[%s=1, i, j, l0, l1, g0] -> [%s] : " + "%s and %s}" # iname bounds % ( STATEMENT_VAR_NAME, _lex_point_string( - ["1", "i", "0"], + ["1", "i", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], prefix=BLEX_VAR_PREFIX, ), + iname_bound_str, + conc_iname_bound_str, ) ) sio_gconc_exp = _isl_map_with_marked_dims( - "[p1,p2] -> {{ " - "[{0}'=0,l0',l1',g0'] -> [{0}=1,i,j,l0,l1,g0] : " - "1 <= i < p1 and 0 <= j < p1 " # not first iteration of i - "and {1} and {2}" # conc iname bounds + "[ij_start, ij_end, lg_end] -> {{ " + "[{0}'=0, l0', l1', g0'] -> [{0}=1, i, j, l0, l1, g0] : " + "ij_start + 1 <= i < ij_end " # not first iteration of i + "and {1} and {2} and {3} " # iname bounds + "and {4}" # param assumptions "}}".format( STATEMENT_VAR_NAME, + iname_bound_str, conc_iname_bound_str, conc_iname_bound_str_p, + assumptions, ) ) From 7cf548898c8920359b9947f029e8e6beb5b7cc6c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 25 Mar 2021 21:32:19 -0500 Subject: [PATCH 066/220] update doctest --- loopy/schedule/checker/__init__.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index f2caec55f..904f2f867 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -61,35 +61,30 @@ def get_schedules_for_statement_pairs( >>> import numpy as np >>> # Make kernel ----------------------------------------------------------- >>> knl = lp.make_kernel( - ... "{[i,j,k]: 0<=i>> knl = lp.add_and_infer_dtypes(knl, {"a": np.float32, "b": np.float32}) - >>> knl = lp.prioritize_loops(knl, "i,j") - >>> knl = lp.prioritize_loops(knl, "i,k") >>> # Get a linearization >>> knl = lp.get_one_linearized_kernel(lp.preprocess_kernel(knl)) >>> # Get a pairwise schedule ----------------------------------------------- >>> from loopy.schedule.checker import get_schedules_for_statement_pairs >>> # Get two maps ---------------------------------------------------------- - >>> schedules = get_schedules_for_statement_pairs( + >>> sio_dict = get_schedules_for_statement_pairs( ... knl, ... knl.linearization, ... [("insn_a", "insn_b")], ... ) - >>> # Print maps + >>> # Print map >>> print("\n".join( ... str(m).replace("{ ", "{\n").replace(" :", "\n:") - ... for m in schedules[("insn_a", "insn_b")][0] + ... for m in sio_dict[("insn_a", "insn_b")][0] ... )) [pi, pj, pk] -> { - [_lp_linchk_stmt = 0, i, j, k] -> [_lp_linchk_lex0 = i, _lp_linchk_lex1 = 0] - : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } - [pi, pj, pk] -> { - [_lp_linchk_stmt = 1, i, j, k] -> [_lp_linchk_lex0 = i, _lp_linchk_lex1 = 1] - : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + [_lp_linchk_stmt' = 0, j', k'] -> [_lp_linchk_stmt = 1, j, k] + : 0 <= j < pj and 0 <= k < pk and 0 <= j' < pj and 0 <= k' < pk } """ # TODO update docs and docstring now that we're returning SIOs From e92401b0d09ac69d9b22ce187dff61e0bc5ca476 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 26 Mar 2021 15:07:59 -0500 Subject: [PATCH 067/220] fix doctest (?) --- loopy/schedule/checker/__init__.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 904f2f867..e99658cd1 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -78,16 +78,14 @@ def get_schedules_for_statement_pairs( ... [("insn_a", "insn_b")], ... ) >>> # Print map - >>> print("\n".join( - ... str(m).replace("{ ", "{\n").replace(" :", "\n:") - ... for m in sio_dict[("insn_a", "insn_b")][0] - ... )) + >>> print(str(sio_dict[("insn_a", "insn_b")][0] + ... ).replace("{ ", "{\n").replace(" :", "\n:")) [pi, pj, pk] -> { [_lp_linchk_stmt' = 0, j', k'] -> [_lp_linchk_stmt = 1, j, k] : 0 <= j < pj and 0 <= k < pk and 0 <= j' < pj and 0 <= k' < pk } """ - # TODO update docs and docstring now that we're returning SIOs + # TODO update docs and doctest now that we're returning SIOs # {{{ make sure kernel has been preprocessed From 6a4d64703a089b1d645ef39ed1395c03f42b589c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 26 Mar 2021 15:08:41 -0500 Subject: [PATCH 068/220] use const class for special blex strings --- loopy/schedule/checker/schedule.py | 73 ++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 974f4051b..0395172d9 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -53,12 +53,6 @@ for par_level in [0, 1, 2]: GTAG_VAR_NAMES.append("%sgid%d" % (LIN_CHECK_IDENTIFIER_PREFIX, par_level)) LTAG_VAR_NAMES.append("%slid%d" % (LIN_CHECK_IDENTIFIER_PREFIX, par_level)) -PRE = "pre" -FIRST = "first" -TOP = "top" -BOTTOM = "bottom" -LAST = "last" -POST = "post" # TODO document new vars @@ -120,6 +114,43 @@ def _simplify_lex_dims(tup0, tup1): return tuple(new_tup0), tuple(new_tup1) +class SpecialLexPointWRTLoop: + """Strings specifying a particular position in a lexicographic + ordering of statements relative to a loop. + + .. attribute:: PRE + A :class:`str` indicating the last lexicographic point that + precedes the loop. + + .. attribute:: FIRST + A :class:`str` indicating the first lexicographic point in the + first loop iteration (i.e., with the iname set to its min. val). + + .. attribute:: TOP + A :class:`str` indicating the first lexicographic point in + an arbitrary loop iteration. + + .. attribute:: BOTTOM + A :class:`str` indicating the last lexicographic point in + an arbitrary loop iteration. + + .. attribute:: LAST + A :class:`str` indicating the last lexicographic point in the + last loop iteration (i.e., with the iname set to its max val). + + .. attribute:: POST + A :class:`str` indicating the first lexicographic point that + follows the loop. + """ + + PRE = "pre" + FIRST = "first" + TOP = "top" + BOTTOM = "bottom" + LAST = "last" + POST = "post" + + def generate_pairwise_schedules( knl, lin_items, @@ -171,6 +202,7 @@ def generate_pairwise_schedules( append_marker_to_strings, add_eq_isl_constraint_from_names, ) + slex = SpecialLexPointWRTLoop all_insn_ids = set().union(*insn_id_pairs) @@ -346,9 +378,9 @@ def _collect_blex_ordering_info(sync_kind): first_iter_blex_pt = next_blex_pt[:] first_iter_blex_pt[-2] = lbound blex_exclusion_info[enter_iname] = { - PRE: tuple(pre_loop_blex_pt), # make sure to copy - TOP: tuple(next_blex_pt), # make sure to copy - FIRST: tuple(first_iter_blex_pt), # make sure to copy + slex.PRE: tuple(pre_loop_blex_pt), # make sure to copy + slex.TOP: tuple(next_blex_pt), # make sure to copy + slex.FIRST: tuple(first_iter_blex_pt), # make sure to copy } blex_map_params |= set(lbound.get_var_names(dt.param)) @@ -371,10 +403,12 @@ def _collect_blex_ordering_info(sync_kind): ubound = iname_bounds_pwaff[leave_iname][1] last_iter_blex_pt = pre_end_loop_blex_pt[:] last_iter_blex_pt[-2] = ubound - blex_exclusion_info[leave_iname][BOTTOM] = tuple( + blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( pre_end_loop_blex_pt) - blex_exclusion_info[leave_iname][LAST] = tuple(last_iter_blex_pt) - blex_exclusion_info[leave_iname][POST] = tuple(next_blex_pt) + blex_exclusion_info[leave_iname][slex.LAST] = tuple( + last_iter_blex_pt) + blex_exclusion_info[leave_iname][slex.POST] = tuple( + next_blex_pt) # (make sure ^these are copies) blex_map_params |= set(ubound.get_var_names(dt.param)) @@ -447,7 +481,7 @@ def _collect_blex_ordering_info(sync_kind): blex_set_affs = isl.affs_from_space(blex_set_template.space) def _create_excluded_map_for_iname(iname, blueprint): - # Note: blueprint[FIRST] and blueprint[LAST] contain pwaffs + # Note: blueprint[slex.FIRST] and blueprint[slex.LAST] contain pwaffs def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): @@ -492,16 +526,16 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # enter loop case full_blex_set = _create_blex_set_from_tuple_pair( - blueprint[PRE], blueprint[FIRST]) + blueprint[slex.PRE], blueprint[slex.FIRST]) # wrap loop case full_blex_set |= _create_blex_set_from_tuple_pair( - blueprint[BOTTOM], blueprint[TOP], wrap_cond=True) + blueprint[slex.BOTTOM], blueprint[slex.TOP], wrap_cond=True) # leave loop case full_blex_set |= _create_blex_set_from_tuple_pair( - blueprint[LAST], blueprint[POST]) + blueprint[slex.LAST], blueprint[slex.POST]) # add cond to fix iteration value for surrounding loops (i = i') - for surrounding_iname in blueprint[PRE][1::2]: + for surrounding_iname in blueprint[slex.PRE][1::2]: s_blex_var = iname_to_blex_var[surrounding_iname] full_blex_set &= blex_set_affs[s_blex_var].eq_set( blex_set_affs[s_blex_var+BEFORE_MARK]) @@ -717,15 +751,16 @@ def _get_map_for_stmt( # }}} - # TODO have option to return sched maps, but default to not returning them - #pairwise_schedules[tuple(insn_ids)] = tuple(intra_thread_sched_maps) if return_schedules: + # Store sched maps along with SIOs + # (currently helpful for testing; also could be desired by a user) pairwise_schedules[tuple(insn_ids)] = ( (sio_seq, tuple(intra_thread_sched_maps), ), (sio_lconc, tuple(lconc_sched_maps), ), (sio_gconc, tuple(gconc_sched_maps), ), ) else: + # Store SIOs pairwise_schedules[tuple(insn_ids)] = (sio_seq, sio_lconc, sio_gconc) return pairwise_schedules From dfb7b116ad82b7702bd7b2dd4b1faffac52121e7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 26 Mar 2021 15:12:38 -0500 Subject: [PATCH 069/220] use same map prefix for blex/lex vars --- loopy/schedule/checker/schedule.py | 3 +-- test/test_linearization_checker.py | 13 ++----------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 0395172d9..b3bedb105 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -45,7 +45,6 @@ LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) -BLEX_VAR_PREFIX = "%sblex" % (LIN_CHECK_IDENTIFIER_PREFIX) STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) BEFORE_MARK = "'" GTAG_VAR_NAMES = [] @@ -441,7 +440,7 @@ def _collect_blex_ordering_info(sync_kind): # Create names for the blex dimensions for sequential loops seq_blex_dim_names = [ - BLEX_VAR_PREFIX+str(i) for i in range(n_seq_blex_dims)] + LEX_VAR_PREFIX+str(i) for i in range(n_seq_blex_dims)] seq_blex_dim_names_prime = append_marker_to_strings( seq_blex_dim_names, marker=BEFORE_MARK) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 1d0bc5748..38e9309ff 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -38,7 +38,6 @@ ) from loopy.schedule.checker.schedule import ( LEX_VAR_PREFIX, - BLEX_VAR_PREFIX, STATEMENT_VAR_NAME, LTAG_VAR_NAMES, GTAG_VAR_NAMES, @@ -66,13 +65,13 @@ def _align_and_compare_maps(maps): assert map1_aligned == map2 -def _lex_point_string(dim_vals, lid_inames=[], gid_inames=[], prefix=LEX_VAR_PREFIX): +def _lex_point_string(dim_vals, lid_inames=[], gid_inames=[]): # Return a string describing a point in a lex space # by assigning values to lex dimension variables # (used to create maps below) return ", ".join( - ["%s%d=%s" % (prefix, idx, str(val)) + ["%s%d=%s" % (LEX_VAR_PREFIX, idx, str(val)) for idx, val in enumerate(dim_vals)] + ["%s=%s" % (LTAG_VAR_NAMES[idx], iname) for idx, iname in enumerate(lid_inames)] + @@ -768,7 +767,6 @@ def test_sios_and_schedules_with_barriers(): _lex_point_string( ["2", "i", "2", "j", "1"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], - prefix=BLEX_VAR_PREFIX, ), iname_bound_str, conc_iname_bound_str, @@ -782,7 +780,6 @@ def test_sios_and_schedules_with_barriers(): _lex_point_string( ["3", "0", "0", "0", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], - prefix=BLEX_VAR_PREFIX, ), conc_iname_bound_str, ) @@ -814,7 +811,6 @@ def test_sios_and_schedules_with_barriers(): _lex_point_string( ["1", "i", "1"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], - prefix=BLEX_VAR_PREFIX, ), iname_bound_str, conc_iname_bound_str, @@ -829,7 +825,6 @@ def test_sios_and_schedules_with_barriers(): _lex_point_string( ["2", "0", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], - prefix=BLEX_VAR_PREFIX, ), conc_iname_bound_str, ) @@ -929,7 +924,6 @@ def test_sios_and_schedules_with_barriers(): _lex_point_string( ["1", "0", "0", "0", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], - prefix=BLEX_VAR_PREFIX, ), conc_iname_bound_str, ) @@ -944,7 +938,6 @@ def test_sios_and_schedules_with_barriers(): _lex_point_string( ["2", "i", "0", "0", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], - prefix=BLEX_VAR_PREFIX, ), iname_bound_str, conc_iname_bound_str, @@ -975,7 +968,6 @@ def test_sios_and_schedules_with_barriers(): _lex_point_string( ["0", "0", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], - prefix=BLEX_VAR_PREFIX, ), conc_iname_bound_str, ) @@ -990,7 +982,6 @@ def test_sios_and_schedules_with_barriers(): _lex_point_string( ["1", "i", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], - prefix=BLEX_VAR_PREFIX, ), iname_bound_str, conc_iname_bound_str, From ca9a8f0c29f6de7818da1ff0a32f7bd18793fd6a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 26 Mar 2021 15:34:09 -0500 Subject: [PATCH 070/220] update docs for consts --- loopy/schedule/checker/schedule.py | 39 +++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index b3bedb105..adfddea93 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -27,32 +27,49 @@ .. data:: LIN_CHECK_IDENTIFIER_PREFIX - The prefix for identifiers involved in linearization checking. + The :class:`str` prefix for identifiers involved in linearization + checking. .. data:: LEX_VAR_PREFIX - E.g., a prefix of ``_lp_linchk_lex`` might yield lexicographic dimension - variables ``_lp_linchk_lex0``, ``_lp_linchk_lex1``, ``_lp_linchk_lex2``. Cf. - :ref:`reserved-identifiers`. + The :class:`str` prefix for the variables representing the + dimensions in the lexicographic ordering used in a pairwise schedule. E.g., + a prefix of ``_lp_linchk_lex`` might yield lexicographic dimension + variables ``_lp_linchk_lex0``, ``_lp_linchk_lex1``, ``_lp_linchk_lex2``. + Cf. :ref:`reserved-identifiers`. .. data:: STATEMENT_VAR_NAME - Set the :class:`str` specifying the prefix to be used for the variables - representing the dimensions in the lexicographic ordering used in a - pairwise schedule. + The :class:`str` name for the statement-identifying dimension of maps + representing schedules and statement instance orderings. + +.. data:: LTAG_VAR_NAME + + An array of :class:`str` names for map dimensions carrying values for local + (intra work-group) thread identifiers in maps representing schedules and + statement instance orderings. + +.. data:: GTAG_VAR_NAME + + An array of :class:`str` names for map dimensions carrying values for group + identifiers in maps representing schedules and statement instance orderings. + +.. data:: BEFORE_MARK + + The :class:`str` identifier to be appended to input dimension names in + maps representing schedules and statement instance orderings. """ LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) -BEFORE_MARK = "'" -GTAG_VAR_NAMES = [] LTAG_VAR_NAMES = [] +GTAG_VAR_NAMES = [] for par_level in [0, 1, 2]: - GTAG_VAR_NAMES.append("%sgid%d" % (LIN_CHECK_IDENTIFIER_PREFIX, par_level)) LTAG_VAR_NAMES.append("%slid%d" % (LIN_CHECK_IDENTIFIER_PREFIX, par_level)) -# TODO document new vars + GTAG_VAR_NAMES.append("%sgid%d" % (LIN_CHECK_IDENTIFIER_PREFIX, par_level)) +BEFORE_MARK = "'" def _pad_tuple_with_zeros(tup, desired_length): From 5b52894ca9c4f67c19436d98f30cf9e0c8d4b323 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 26 Mar 2021 16:46:11 -0500 Subject: [PATCH 071/220] combine instruction pass that determine which loops contain barriers with pass that computes the intra-thread schedule --- loopy/schedule/checker/schedule.py | 91 ++++++++++++++++-------------- 1 file changed, 48 insertions(+), 43 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index adfddea93..ac2429bb1 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -206,6 +206,8 @@ def generate_pairwise_schedules( each of the two statements. """ # TODO update docs now that we're returning SIOs + # TODO rename loops_to_ignore to loops_to_ignore_for_intra_thread_stuff... + # TODO handle 'vec' appropriately; then remove loops_to_ignore? from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.kernel.data import (LocalIndexTag, GroupIndexTag) @@ -222,22 +224,30 @@ def generate_pairwise_schedules( all_insn_ids = set().union(*insn_id_pairs) - # First, use one pass through lin_items to generate a lexicographic - # ordering describing the relative order of *all* statements represented by - # all_insn_ids + # First, use one pass through lin_items to generate an *intra-work-item* + # lexicographic ordering describing the relative order of all statements + # represented by all_insn_ids # For each statement, map the insn_id to a tuple representing points - # in the lexicographic ordering containing items of :class:`int` or - # :class:`str` :mod:`loopy` inames. + # in the intra-group lexicographic ordering containing items of :class:`int` or + # :class:`str` :mod:`loopy` inames stmt_inst_to_lex = {} # Keep track of the next tuple of points in our lexicographic # ordering, initially this as a 1-d point with value 0 next_insn_lex_tuple = [0] + # While we're passing through, determine which loops contain barriers, + # this information will be used later when creating *intra-group* and + # *global* lexicographic orderings + loops_with_barriers = {"local": set(), "global": set()} + current_inames = set() + for lin_item in lin_items: if isinstance(lin_item, EnterLoop): iname = lin_item.iname + current_inames.add(iname) + if iname in loops_to_ignore: continue @@ -254,7 +264,10 @@ def generate_pairwise_schedules( next_insn_lex_tuple.append(0) elif isinstance(lin_item, LeaveLoop): - if lin_item.iname in loops_to_ignore: + iname = lin_item.iname + current_inames.remove(iname) + + if iname in loops_to_ignore: continue # Upon leaving a loop, @@ -271,15 +284,22 @@ def generate_pairwise_schedules( # in the simplification step below) next_insn_lex_tuple[-1] += 1 - elif isinstance(lin_item, (RunInstruction, Barrier)): - from loopy.schedule.checker.utils import ( - get_insn_id_from_linearization_item, - ) - lp_insn_id = get_insn_id_from_linearization_item(lin_item) + elif isinstance(lin_item, RunInstruction): + lp_insn_id = lin_item.insn_id - if lp_insn_id is None: - assert isinstance(lin_item, Barrier) + # Only process listed insns, otherwise ignore + if lp_insn_id in all_insn_ids: + # Add item to stmt_inst_to_lex + stmt_inst_to_lex[lp_insn_id] = tuple(next_insn_lex_tuple) + + # Increment lex dim val enumerating items in current section of code + next_insn_lex_tuple[-1] += 1 + + elif isinstance(lin_item, Barrier): + lp_insn_id = lin_item.originating_insn_id + loops_with_barriers[lin_item.synchronization_kind] |= current_inames + if lp_insn_id is None: # Barriers without insn ids were inserted as a result of a # dependency. They don't themselves have dependencies. Ignore them. @@ -289,7 +309,7 @@ def generate_pairwise_schedules( continue - # Only process listed insns, otherwise ignore + # If barrier was identified in listed insns, process it if lp_insn_id in all_insn_ids: # Add item to stmt_inst_to_lex stmt_inst_to_lex[lp_insn_id] = tuple(next_insn_lex_tuple) @@ -304,55 +324,40 @@ def generate_pairwise_schedules( lin_item, (CallKernel, ReturnFromKernel)) pass - # To save time, stop when we've found all statements - if len(stmt_inst_to_lex.keys()) == len(all_insn_ids): - # TODO if combining blex map creation with this pass, cannot stop early - break + # {{{ Create blex dim names representing parallel axes - # Get dim names representing local/group axes for this kernel, - # and get the dictionary that will be used later to create a - # constraint requiring {par inames == par axes} in sched + # Create blex dim names representing lid/gid axes, and create the dicts + # that will be used later to create map constraints that match each + # parallel iname to the corresponding blex dim name in schedules, + # i.e., i = lid0, j = lid1, etc. lid_lex_dim_names = set() gid_lex_dim_names = set() par_iname_constraint_dicts = [] for iname in knl.all_inames(): ltag = knl.iname_tags_of_type(iname, LocalIndexTag) if ltag: - # assert len(ltag) == 1 # (should always be true) + assert len(ltag) == 1 # (should always be true) ltag_var = LTAG_VAR_NAMES[ltag.pop().axis] lid_lex_dim_names.add(ltag_var) - # Represent constraint 'iname = ltag_var' in par_iname_constraint_dicts: par_iname_constraint_dicts.append({1: 0, iname: 1, ltag_var: -1}) - continue + + continue # shouldn't be any GroupIndexTags + gtag = knl.iname_tags_of_type(iname, GroupIndexTag) if gtag: - # assert len(gtag) == 1 # (should always be true) + assert len(gtag) == 1 # (should always be true) gtag_var = GTAG_VAR_NAMES[gtag.pop().axis] gid_lex_dim_names.add(gtag_var) - # Represent constraint 'iname = gtag_var' in par_iname_constraint_dicts: par_iname_constraint_dicts.append({1: 0, iname: 1, gtag_var: -1}) - continue + + # Sort for consistent dimension ordering lid_lex_dim_names = sorted(lid_lex_dim_names) gid_lex_dim_names = sorted(gid_lex_dim_names) - # {{{ Create blex ordering (may later be combined with pass above) - - # {{{ Determine which loops contain barriers - - loops_with_barriers = {"local": set(), "global": set()} - current_inames = set() - - for lin_item in lin_items: - if isinstance(lin_item, EnterLoop): - current_inames.add(lin_item.iname) - elif isinstance(lin_item, LeaveLoop): - current_inames.remove(lin_item.iname) - elif isinstance(lin_item, Barrier): - loops_with_barriers[lin_item.synchronization_kind] |= current_inames - # At this point we could technically skip ahead to next enterloop - # }}} + # {{{ Create blex ordering (may later be combined with pass above) + # {{{ Get upper and lower bound for each loop that contains a barrier # (Could try to combine this with pass below but would make things messy) From ae657dbaa5eb423ff81e3ac7be06925d62afecb3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 26 Mar 2021 16:46:30 -0500 Subject: [PATCH 072/220] remove func get_insn_id_from_linearization_item() (no longer used) --- loopy/schedule/checker/utils.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 4ae2fbf64..9382d070a 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -253,14 +253,6 @@ def partition_inames_by_concurrency(knl): return conc_inames, all_inames-conc_inames -def get_insn_id_from_linearization_item(linearization_item): - from loopy.schedule import Barrier - if isinstance(linearization_item, Barrier): - return linearization_item.originating_insn_id - else: - return linearization_item.insn_id - - def get_EnterLoop_inames(linearization_items): from loopy.schedule import EnterLoop From 84ea6e0d9fa063509a772f08063c6f56a6fb949b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 26 Mar 2021 21:56:29 -0500 Subject: [PATCH 073/220] significant code cleanup and organization --- loopy/schedule/checker/schedule.py | 350 ++++++++++++++++++----------- 1 file changed, 219 insertions(+), 131 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index ac2429bb1..714044a78 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -224,18 +224,20 @@ def generate_pairwise_schedules( all_insn_ids = set().union(*insn_id_pairs) - # First, use one pass through lin_items to generate an *intra-work-item* + # {{{ Intra-thread lex order creation + + # First, use one pass through lin_items to generate an *intra-thread* # lexicographic ordering describing the relative order of all statements # represented by all_insn_ids # For each statement, map the insn_id to a tuple representing points - # in the intra-group lexicographic ordering containing items of :class:`int` or + # in the intra-thread lexicographic ordering containing items of :class:`int` or # :class:`str` :mod:`loopy` inames - stmt_inst_to_lex = {} + stmt_inst_to_lex_intra_thread = {} # Keep track of the next tuple of points in our lexicographic # ordering, initially this as a 1-d point with value 0 - next_insn_lex_tuple = [0] + next_lex_tuple = [0] # While we're passing through, determine which loops contain barriers, # this information will be used later when creating *intra-group* and @@ -251,17 +253,17 @@ def generate_pairwise_schedules( if iname in loops_to_ignore: continue - # Increment next_insn_lex_tuple[-1] for statements in the section - # of code after this EnterLoop. + # Increment next_lex_tuple[-1] for statements in the section + # of code between this EnterLoop and the matching LeaveLoop. # (not technically necessary if no statement was added in the # previous section; gratuitous incrementing is counteracted # in the simplification step below) - next_insn_lex_tuple[-1] += 1 + next_lex_tuple[-1] += 1 - # Upon entering a loop, add one lex dimension for the loop variable, + # Upon entering a loop, add one lex dimension for the loop iteration, # add second lex dim to enumerate sections of code within new loop - next_insn_lex_tuple.append(iname) - next_insn_lex_tuple.append(0) + next_lex_tuple.append(iname) + next_lex_tuple.append(0) elif isinstance(lin_item, LeaveLoop): iname = lin_item.iname @@ -270,30 +272,28 @@ def generate_pairwise_schedules( if iname in loops_to_ignore: continue - # Upon leaving a loop, - # pop lex dimension for enumerating code sections within this loop, and - # pop lex dimension for the loop variable, and - # increment lex dim val enumerating items in current section of code - next_insn_lex_tuple.pop() - next_insn_lex_tuple.pop() + # Upon leaving a loop: + # - Pop lex dim for enumerating code sections within this loop + # - Pop lex dim for the loop iteration + # - Increment lex dim val enumerating items in current section of code + next_lex_tuple.pop() + next_lex_tuple.pop() + next_lex_tuple[-1] += 1 - # Increment next_insn_lex_tuple[-1] for statements in the section - # of code after this LeaveLoop. # (not technically necessary if no statement was added in the # previous section; gratuitous incrementing is counteracted # in the simplification step below) - next_insn_lex_tuple[-1] += 1 elif isinstance(lin_item, RunInstruction): lp_insn_id = lin_item.insn_id # Only process listed insns, otherwise ignore if lp_insn_id in all_insn_ids: - # Add item to stmt_inst_to_lex - stmt_inst_to_lex[lp_insn_id] = tuple(next_insn_lex_tuple) + # Add item to stmt_inst_to_lex_intra_thread + stmt_inst_to_lex_intra_thread[lp_insn_id] = tuple(next_lex_tuple) # Increment lex dim val enumerating items in current section of code - next_insn_lex_tuple[-1] += 1 + next_lex_tuple[-1] += 1 elif isinstance(lin_item, Barrier): lp_insn_id = lin_item.originating_insn_id @@ -311,11 +311,11 @@ def generate_pairwise_schedules( # If barrier was identified in listed insns, process it if lp_insn_id in all_insn_ids: - # Add item to stmt_inst_to_lex - stmt_inst_to_lex[lp_insn_id] = tuple(next_insn_lex_tuple) + # Add item to stmt_inst_to_lex_intra_thread + stmt_inst_to_lex_intra_thread[lp_insn_id] = tuple(next_lex_tuple) # Increment lex dim val enumerating items in current section of code - next_insn_lex_tuple[-1] += 1 + next_lex_tuple[-1] += 1 else: from loopy.schedule import (CallKernel, ReturnFromKernel) @@ -324,12 +324,14 @@ def generate_pairwise_schedules( lin_item, (CallKernel, ReturnFromKernel)) pass - # {{{ Create blex dim names representing parallel axes + # }}} + + # {{{ Create lex dim names representing parallel axes - # Create blex dim names representing lid/gid axes, and create the dicts - # that will be used later to create map constraints that match each - # parallel iname to the corresponding blex dim name in schedules, - # i.e., i = lid0, j = lid1, etc. + # Create lex dim names representing lid/gid axes. + # At the same time, create the dicts that will be used later to create map + # constraints that match each parallel iname to the corresponding lex dim + # name in schedules, i.e., i = lid0, j = lid1, etc. lid_lex_dim_names = set() gid_lex_dim_names = set() par_iname_constraint_dicts = [] @@ -341,7 +343,7 @@ def generate_pairwise_schedules( lid_lex_dim_names.add(ltag_var) par_iname_constraint_dicts.append({1: 0, iname: 1, ltag_var: -1}) - continue # shouldn't be any GroupIndexTags + continue # Shouldn't be any GroupIndexTags gtag = knl.iname_tags_of_type(iname, GroupIndexTag) if gtag: @@ -356,71 +358,119 @@ def generate_pairwise_schedules( # }}} - # {{{ Create blex ordering (may later be combined with pass above) + # {{{ Intra-group and global blex ("barrier-lex") order creation + + # (may be combined with pass above in future) + + # In blex space, we order barrier-delimited sections of code. + # Each statement instance within a single barrier-delimited section will + # map to the same blex point. The resulting statement instance ordering + # will map each statement to all statements that occur in a later + # barrier-delimited section. + + # To achieve this, we will first create a map from statement instances to + # lexicographic space almost as before, though we will not increment the + # fastest-updating lex dim with each statement, and we will increment it + # with each barrier encountered. To denote these differences, we refer to + # this space as 'blex' space. + # The resulting pairwise schedule, if composed with a map defining a + # standard lexicographic ordering (SIO), would include a number of unwanted + # 'before->after' pairs, so before creating the SIO, we will subtract the + # unwanted pairs from the standard lex order map, yielding the 'blex' order + # map. # {{{ Get upper and lower bound for each loop that contains a barrier - # (Could try to combine this with pass below but would make things messy) iname_bounds_pwaff = {} for iname in loops_with_barriers["local"] | loops_with_barriers["global"]: - # Get first and last vals for this iname bounds = knl.get_iname_bounds(iname) iname_bounds_pwaff[iname] = ( bounds.lower_bound_pw_aff, bounds.upper_bound_pw_aff) # }}} - conc_lex_dim_names = lid_lex_dim_names + gid_lex_dim_names + all_par_lex_dim_names = lid_lex_dim_names + gid_lex_dim_names - def _collect_blex_ordering_info(sync_kind): + # {{{ _gather_blex_ordering_info() - # {{{ Construct blueprint for creating blex space and orderings + def _gather_blex_ordering_info(sync_kind): + # For the given sync_kind ("local" or "global"), create a mapping from + # statement instances to blex space (dict), as well as a mapping + # defining the blex ordering (isl map from blex space -> blex space) - stmt_inst_to_blex = {} # map stmt instances to blex space - iname_to_blex_dim = {} # map from inames to corresponding blex space dim - blex_exclusion_info = {} # info for creating maps to exclude from blex order - blex_map_params = set() # params needed in blex map - n_seq_blex_dims = 1 # num dims representing sequential order in blex space - next_blex_pt = [0] # next tuple of points in blex order + # Note that, unlike in the intra-thread case, there will be a single + # blex ordering map defining the blex ordering for all statement pairs, + # rather than separate (smaller) lex ordering maps for each pair + + # {{{ First, create map from stmt instances to blex space. + + # At the same time, gather information necessary to create the + # blex ordering map, i.e., for each loop, gather the 6 lex order tuples + # defined above in SpecialLexPointWRTLoop that will be required to + # create sub-maps which will be *excluded* (subtracted) from a standard + # lexicographic ordering in order to create the blex ordering + + stmt_inst_to_blex = {} # Map stmt instances to blex space + iname_to_blex_dim = {} # Map from inames to corresponding blex space dim + blex_exclusion_info = {} # Info for creating maps to exclude from blex order + blex_order_map_params = set() # Params needed in blex order map + n_seq_blex_dims = 1 # Num dims representing sequential order in blex space + next_blex_tuple = [0] # Next tuple of points in blex order for lin_item in lin_items: if isinstance(lin_item, EnterLoop): enter_iname = lin_item.iname if enter_iname in loops_with_barriers[sync_kind]: - # update next blex pt - pre_loop_blex_pt = next_blex_pt[:] - next_blex_pt[-1] += 1 - next_blex_pt.append(enter_iname) - next_blex_pt.append(0) + pre_loop_blex_pt = next_blex_tuple[:] + + # Increment next_blex_tuple[-1] for statements in the section + # of code between this EnterLoop and the matching LeaveLoop. + next_blex_tuple[-1] += 1 + + # Upon entering a loop, add one blex dimension for the loop + # iteration, add second blex dim to enumerate sections of + # code within new loop + next_blex_tuple.append(enter_iname) + next_blex_tuple.append(0) - # store tuples that will be used to create pairs - # that will later be subtracted from happens-before map + # Store 3 tuples that will be used later to create pairs + # that will later be subtracted from the blex order map lbound = iname_bounds_pwaff[enter_iname][0] - first_iter_blex_pt = next_blex_pt[:] + first_iter_blex_pt = next_blex_tuple[:] first_iter_blex_pt[-2] = lbound blex_exclusion_info[enter_iname] = { - slex.PRE: tuple(pre_loop_blex_pt), # make sure to copy - slex.TOP: tuple(next_blex_pt), # make sure to copy - slex.FIRST: tuple(first_iter_blex_pt), # make sure to copy + slex.PRE: tuple(pre_loop_blex_pt), + slex.TOP: tuple(next_blex_tuple), + slex.FIRST: tuple(first_iter_blex_pt), } - blex_map_params |= set(lbound.get_var_names(dt.param)) + # (make sure ^these are copies) + + # Store any new params found + blex_order_map_params |= set(lbound.get_var_names(dt.param)) elif isinstance(lin_item, LeaveLoop): leave_iname = lin_item.iname if leave_iname in loops_with_barriers[sync_kind]: - # update max blex dims - n_seq_blex_dims = max(n_seq_blex_dims, len(next_blex_pt)) - iname_to_blex_dim[leave_iname] = len(next_blex_pt)-2 + # Update max blex dims + n_seq_blex_dims = max(n_seq_blex_dims, len(next_blex_tuple)) - # update next blex pt - pre_end_loop_blex_pt = next_blex_pt[:] - next_blex_pt.pop() - next_blex_pt.pop() - next_blex_pt[-1] += 1 + # Record the blex dim for this loop iname + iname_to_blex_dim[leave_iname] = len(next_blex_tuple)-2 - # store tuples that will be used to create pairs - # that will later be subtracted from happens-before map + # update next blex pt + pre_end_loop_blex_pt = next_blex_tuple[:] + + # Upon leaving a loop: + # - Pop lex dim for enumerating code sections within this loop + # - Pop lex dim for the loop iteration + # - Increment lex dim val enumerating items in current section + next_blex_tuple.pop() + next_blex_tuple.pop() + next_blex_tuple[-1] += 1 + + # Store 3 tuples that will be used later to create pairs + # that will later be subtracted from the blex order map ubound = iname_bounds_pwaff[leave_iname][1] last_iter_blex_pt = pre_end_loop_blex_pt[:] last_iter_blex_pt[-2] = ubound @@ -429,19 +479,22 @@ def _collect_blex_ordering_info(sync_kind): blex_exclusion_info[leave_iname][slex.LAST] = tuple( last_iter_blex_pt) blex_exclusion_info[leave_iname][slex.POST] = tuple( - next_blex_pt) + next_blex_tuple) # (make sure ^these are copies) - blex_map_params |= set(ubound.get_var_names(dt.param)) + + # Store any new params found + blex_order_map_params |= set(ubound.get_var_names(dt.param)) elif isinstance(lin_item, RunInstruction): - # Add item to stmt_inst_to_blex - stmt_inst_to_blex[lin_item.insn_id] = tuple(next_blex_pt) - # Don't increment blex dim val + # Add stmt->blex pair to stmt_inst_to_blex + stmt_inst_to_blex[lin_item.insn_id] = tuple(next_blex_tuple) + + # (Don't increment blex dim val) elif isinstance(lin_item, Barrier): # Increment blex dim val if the sync scope matches if lin_item.synchronization_kind == sync_kind: - next_blex_pt[-1] += 1 + next_blex_tuple[-1] += 1 else: from loopy.schedule import (CallKernel, ReturnFromKernel) @@ -450,7 +503,7 @@ def _collect_blex_ordering_info(sync_kind): lin_item, (CallKernel, ReturnFromKernel)) pass - blex_map_params = sorted(blex_map_params) + blex_order_map_params = sorted(blex_order_map_params) # At this point, some blex tuples may have more dimensions than others; # the missing dims are the fastest-updating dims, and their values should @@ -460,40 +513,50 @@ def _collect_blex_ordering_info(sync_kind): # }}} + # {{{ Create the blex order map + + # {{{ Create the initial (pre-subtraction) blex order map + # Create names for the blex dimensions for sequential loops seq_blex_dim_names = [ LEX_VAR_PREFIX+str(i) for i in range(n_seq_blex_dims)] seq_blex_dim_names_prime = append_marker_to_strings( seq_blex_dim_names, marker=BEFORE_MARK) + # Begin with the blex order map created as a standard lex order map blex_order_map = create_lex_order_map( dim_names=seq_blex_dim_names, in_dim_marker=BEFORE_MARK, ) - # Add lid/gid dims to lex order map + # Add LID/GID dims to blex order map blex_order_map = add_and_name_isl_dims( - blex_order_map, dt.out, conc_lex_dim_names) + blex_order_map, dt.out, all_par_lex_dim_names) blex_order_map = add_and_name_isl_dims( - blex_order_map, dt.in_, append_marker_to_strings(conc_lex_dim_names)) + blex_order_map, dt.in_, append_marker_to_strings(all_par_lex_dim_names)) if sync_kind == "local": - # Constrain gid vars to be equal + # For intra-group case, constrain GID 'before' to equal GID 'after' for var_name in gid_lex_dim_names: blex_order_map = add_eq_isl_constraint_from_names( blex_order_map, var_name, var_name+BEFORE_MARK) - # (if sync_kind == "global", don't need constraints on lid/gid vars) + # (if sync_kind == "global", don't need constraints on LID/GID vars) + + # }}} + + # {{{ Subtract unwanted pairs from happens-before blex map + # Create map from iname to corresponding blex dim name iname_to_blex_var = {} for iname, dim in iname_to_blex_dim.items(): iname_to_blex_var[iname] = seq_blex_dim_names[dim] iname_to_blex_var[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] - # Add params to blex map + # Add bounds params needed in blex map blex_order_map = add_and_name_isl_dims( - blex_order_map, dt.param, blex_map_params) + blex_order_map, dt.param, blex_order_map_params) # Get a set representing blex_order_map space - n_blex_dims = n_seq_blex_dims + len(conc_lex_dim_names) + n_blex_dims = n_seq_blex_dims + len(all_par_lex_dim_names) blex_set_template = isl.align_spaces( isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map ).move_dims( @@ -501,104 +564,129 @@ def _collect_blex_ordering_info(sync_kind): ).domain() blex_set_affs = isl.affs_from_space(blex_set_template.space) + # {{{ _create_excluded_map_for_iname + def _create_excluded_map_for_iname(iname, blueprint): - # Note: blueprint[slex.FIRST] and blueprint[slex.LAST] contain pwaffs + # Create the blex->blex pairs that must be subtracted from the + # initial blex order map for this particular loop: + # PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST + + # Note: only blueprint[slex.FIRST] & blueprint[slex.LAST] contain pwaffs + + # {{{ _create_blex_set_from_tuple_pair def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): + # Given a before->after tuple pair in the blueprint, which may + # have dim vals described by strings (inames) and pwaffs, + # create an ISL set in blex space that can be converted into + # the ISL map to be subtracted - # start with a set representing blex_order_map space + # Start with a set representing blex_order_map space blex_set = blex_set_template.copy() - # add markers to inames in before tuple - # (assume strings are the inames) + # Add markers to inames in the 'before' tuple + # (all strings should be inames) before_prime = tuple( v+BEFORE_MARK if isinstance(v, str) else v for v in before) before_padded = _pad_tuple_with_zeros(before_prime, n_seq_blex_dims) after_padded = _pad_tuple_with_zeros(after, n_seq_blex_dims) - # assign vals to dims + # Assign vals in the tuple to dims in the ISL set for dim_name, dim_val in zip( seq_blex_dim_names_prime+seq_blex_dim_names, before_padded+after_padded): - # (could exploit knowledge of content types of odd/even - # tuple dims to reduce conditionals but would be ugly - # and less robust) + if isinstance(dim_val, int): - # set idx to int val + # Set idx to int val blex_set &= blex_set_affs[dim_name].eq_set( blex_set_affs[0]+dim_val) elif isinstance(dim_val, str): - # assume this is an iname, set idx to corresponding blex var + # This is an iname, set idx to corresponding blex var blex_set &= blex_set_affs[dim_name].eq_set( blex_set_affs[iname_to_blex_var[dim_val]]) else: + # This is a pwaff iname bound, align and intersect assert isinstance(dim_val, isl.PwAff) pwaff_aligned = isl.align_spaces(dim_val, blex_set_affs[0]) - # (doesn't matter which element of blex_set_affs we use^) + # (doesn't matter which blex_set_affs item we align to^) blex_set &= blex_set_affs[dim_name].eq_set(pwaff_aligned) if wrap_cond: - # i = i' + step - # TODO what about step sizes != 1? + # This is the BOTTOM->TOP pair, add condition i = i' + 1 blex_set &= blex_set_affs[iname_to_blex_var[iname]].eq_set( blex_set_affs[iname_to_blex_var[iname+BEFORE_MARK]] + 1) return blex_set - # enter loop case + # }}} + + # Create pairs to be subtracted (sets will be converted to map) + + # Enter loop case: PRE->FIRST full_blex_set = _create_blex_set_from_tuple_pair( blueprint[slex.PRE], blueprint[slex.FIRST]) - # wrap loop case + # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) full_blex_set |= _create_blex_set_from_tuple_pair( blueprint[slex.BOTTOM], blueprint[slex.TOP], wrap_cond=True) - # leave loop case + # Leave loop case: LAST->POST full_blex_set |= _create_blex_set_from_tuple_pair( blueprint[slex.LAST], blueprint[slex.POST]) - # add cond to fix iteration value for surrounding loops (i = i') + # Add condition to fix iteration value for *surrounding* loops (j = j') for surrounding_iname in blueprint[slex.PRE][1::2]: s_blex_var = iname_to_blex_var[surrounding_iname] full_blex_set &= blex_set_affs[s_blex_var].eq_set( blex_set_affs[s_blex_var+BEFORE_MARK]) - # convert blex set back to map + # Convert blex set back to map return isl.Map.from_domain(full_blex_set).move_dims( dt.out, 0, dt.in_, n_blex_dims, n_blex_dims) - # subtract unwanted pairs from happens-before blex map + # }}} + + # Create map for each iname maps_to_subtract = [] for iname, subdict in blex_exclusion_info.items(): maps_to_subtract.append(_create_excluded_map_for_iname(iname, subdict)) if maps_to_subtract: - # get union of maps + + # Get union of maps map_to_subtract = maps_to_subtract[0] for other_map in maps_to_subtract[1:]: map_to_subtract |= other_map - # get some closure + # Get transitive closure of maps map_to_subtract, closure_exact = map_to_subtract.transitive_closure() - assert closure_exact # TODO warn instead + assert closure_exact # TODO warn instead? - # subtract from blex order map + # Subtract closure from blex order map blex_order_map = blex_order_map - map_to_subtract + # }}} + + # }}} + return ( stmt_inst_to_blex, # map stmt instances to blex space blex_order_map, seq_blex_dim_names, ) + # }}} + + # Get the blex schedule blueprint (dict will become a map below) and + # blex order map w.r.t. local and global barriers (stmt_inst_to_lblex, lblex_order_map, - seq_lblex_dim_names) = _collect_blex_ordering_info("local") + seq_lblex_dim_names) = _gather_blex_ordering_info("local") (stmt_inst_to_gblex, gblex_order_map, - seq_gblex_dim_names) = _collect_blex_ordering_info("global") + seq_gblex_dim_names) = _gather_blex_ordering_info("global") # }}} end blex order/map machinery - # Second, create pairwise schedules for each individual pair of insns + # {{{ Create pairwise schedules (ISL maps) for each stmt pair from loopy.schedule.checker.utils import ( sorted_union_of_names_in_isl_sets, @@ -606,6 +694,8 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): insert_and_name_isl_dims, ) + # {{{ _get_map_for_stmt() + def _get_map_for_stmt( insn_id, lex_points, int_sid, lex_dim_names): @@ -634,7 +724,7 @@ def _get_map_for_stmt( dom, dt.set, [STATEMENT_VAR_NAME], 0) # Each map will map statement instances -> lex time. - # Right now, statement instance tuples consist of single int. + # At this point, statement instance tuples consist of single int. # Add all inames from domains to each map domain tuple. tuple_pair = [( (int_sid, ) + tuple(dom_inames_ordered), @@ -642,9 +732,9 @@ def _get_map_for_stmt( )] # Note that lex_points may have fewer dims than the out-dim of sched_space - # if sched_space includes concurrent lid/gid dims. This is okay because + # if sched_space includes concurrent LID/GID dims. This is okay because # the following symbolic map creation step, when assigning dim values, - # zips the space dims with the lex tuple, and any leftover lid/gid dims + # zips the space dims with the lex tuple, and any leftover LID/GID dims # will not be assigned a value yet, which is what we want. # Create map @@ -660,22 +750,25 @@ def _get_map_for_stmt( return sched_map + # }}} + pairwise_schedules = {} for insn_ids in insn_id_pairs: # Determine integer IDs that will represent each statement in mapping # (dependency map creation assumes sid_before=0 and sid_after=1, unless - # before and after refer to same stmt, in which case sid_before=sid_after=0) + # before and after refer to same stmt, in which case + # sid_before=sid_after=0) int_sids = [0, 0] if insn_ids[0] == insn_ids[1] else [0, 1] - # {{{ Create SIO for intra-thread case (lid0' == lid0, etc) + # {{{ Create SIO for intra-thread case (lid0' == lid0, gid0' == gid0, etc) # Simplify tuples to the extent possible ------------------------------------ - lex_tuples = [stmt_inst_to_lex[insn_id] for insn_id in insn_ids] + lex_tuples = [stmt_inst_to_lex_intra_thread[insn_id] for insn_id in insn_ids] - # At this point, one of the lex tuples may have more dimensions than another; - # the missing dims are the fastest-updating dims, and their values should - # be zero. Add them. + # At this point, one of the lex tuples may have more dimensions than + # another; the missing dims are the fastest-updating dims, and their + # values should be zero. Add them. max_lex_dims = max([len(lex_tuple) for lex_tuple in lex_tuples]) lex_tuples_padded = [ _pad_tuple_with_zeros(lex_tuple, max_lex_dims) @@ -692,17 +785,12 @@ def _get_map_for_stmt( intra_thread_sched_maps = [ _get_map_for_stmt( insn_id, lex_tuple, int_sid, - seq_lex_dim_names+conc_lex_dim_names) + seq_lex_dim_names+all_par_lex_dim_names) for insn_id, lex_tuple, int_sid in zip(insn_ids, lex_tuples_simplified, int_sids) ] - # Create lex order maps and SIOs here (rather than returning schedules - # and lex maps separately and combining them outside function to get - # SIOs) to avoid passing extra info around. Don't want to, e.g., - # examine the schedule tuple in separate func to re-determine which - # parallel dims are used. (could simplify everything by always using - # all dims..., which would make maps more complex than necessary) + # Create pairwise lex order map (pairwise only in the intra-thread case) lex_order_map = create_lex_order_map( dim_names=seq_lex_dim_names, in_dim_marker=BEFORE_MARK, @@ -710,16 +798,16 @@ def _get_map_for_stmt( # Add lid/gid dims to lex order map lex_order_map = add_and_name_isl_dims( - lex_order_map, dt.out, conc_lex_dim_names) + lex_order_map, dt.out, all_par_lex_dim_names) lex_order_map = add_and_name_isl_dims( - lex_order_map, dt.in_, append_marker_to_strings(conc_lex_dim_names)) + lex_order_map, dt.in_, append_marker_to_strings(all_par_lex_dim_names)) # Constrain lid/gid vars to be equal - for var_name in conc_lex_dim_names: + for var_name in all_par_lex_dim_names: lex_order_map = add_eq_isl_constraint_from_names( lex_order_map, var_name, var_name+BEFORE_MARK) # Create statement instance ordering, - # maps each statement instance to all statement instances occuring later + # maps each statement instance to all statement instances occurring later sio_seq = get_statement_ordering_map( *intra_thread_sched_maps, # note, func accepts exactly two maps lex_order_map, @@ -730,8 +818,6 @@ def _get_map_for_stmt( # {{{ Create SIOs for intra-group case (gid0' == gid0, etc) - # TODO finish separating lid stuff from gid stuff - # Use *unsimplified* lex tuples with blex map, which have already been padded lblex_tuples_padded = [stmt_inst_to_lblex[insn_id] for insn_id in insn_ids] @@ -739,7 +825,7 @@ def _get_map_for_stmt( lconc_sched_maps = [ _get_map_for_stmt( insn_id, lblex_tuple, int_sid, - seq_lblex_dim_names+conc_lex_dim_names) # conc names same for all + seq_lblex_dim_names+all_par_lex_dim_names) # Par names same for all for insn_id, lblex_tuple, int_sid in zip(insn_ids, lblex_tuples_padded, int_sids) ] @@ -758,7 +844,7 @@ def _get_map_for_stmt( gconc_sched_maps = [ _get_map_for_stmt( insn_id, gblex_tuple, int_sid, - seq_gblex_dim_names+conc_lex_dim_names) # conc names same for all + seq_gblex_dim_names+all_par_lex_dim_names) # Par names same for all for insn_id, gblex_tuple, int_sid in zip(insn_ids, gblex_tuples_padded, int_sids) ] @@ -781,7 +867,9 @@ def _get_map_for_stmt( (sio_gconc, tuple(gconc_sched_maps), ), ) else: - # Store SIOs + # Store SIOs only pairwise_schedules[tuple(insn_ids)] = (sio_seq, sio_lconc, sio_gconc) + # }}} + return pairwise_schedules From 2cd77f6c3ed93bdfea7dbc29beedec3221f1cee9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 26 Mar 2021 21:57:53 -0500 Subject: [PATCH 074/220] another doctest fix --- loopy/schedule/checker/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index e99658cd1..a5858bde0 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -82,7 +82,7 @@ def get_schedules_for_statement_pairs( ... ).replace("{ ", "{\n").replace(" :", "\n:")) [pi, pj, pk] -> { [_lp_linchk_stmt' = 0, j', k'] -> [_lp_linchk_stmt = 1, j, k] - : 0 <= j < pj and 0 <= k < pk and 0 <= j' < pj and 0 <= k' < pk } + : 0 <= j' < pj and 0 <= k' < pk and 0 <= j < pj and 0 <= k < pk } """ # TODO update docs and doctest now that we're returning SIOs From 3d939eff3a55aef47fc597c075d594ef24a67ddd Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 27 Mar 2021 17:04:02 -0500 Subject: [PATCH 075/220] more code cleanup and organization --- loopy/schedule/checker/schedule.py | 198 ++++++++++++++++------------- 1 file changed, 113 insertions(+), 85 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 714044a78..b849a2ccf 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -23,6 +23,9 @@ import islpy as isl dt = isl.dim_type.set + +# {{{ Constants + __doc__ = """ .. data:: LIN_CHECK_IDENTIFIER_PREFIX @@ -71,10 +74,20 @@ GTAG_VAR_NAMES.append("%sgid%d" % (LIN_CHECK_IDENTIFIER_PREFIX, par_level)) BEFORE_MARK = "'" +# }}} + + +# {{{ Helper Functions + +# {{{ _pad_tuple_with_zeros def _pad_tuple_with_zeros(tup, desired_length): return tup[:] + tuple([0]*(desired_length-len(tup))) +# }}} + + +# {{{ _simplify_lex_dims def _simplify_lex_dims(tup0, tup1): """Simplify a pair of lex tuples in order to reduce the complexity of @@ -129,6 +142,12 @@ def _simplify_lex_dims(tup0, tup1): else: return tuple(new_tup0), tuple(new_tup1) +# }}} + +# }}} + + +# {{{ class SpecialLexPointWRTLoop class SpecialLexPointWRTLoop: """Strings specifying a particular position in a lexicographic @@ -166,6 +185,10 @@ class SpecialLexPointWRTLoop: LAST = "last" POST = "post" +# }}} + + +# {{{ generate_pairwise_schedules def generate_pairwise_schedules( knl, @@ -219,6 +242,9 @@ def generate_pairwise_schedules( add_and_name_isl_dims, append_marker_to_strings, add_eq_isl_constraint_from_names, + sorted_union_of_names_in_isl_sets, + create_symbolic_map_from_tuples, + insert_and_name_isl_dims, ) slex = SpecialLexPointWRTLoop @@ -362,22 +388,24 @@ def generate_pairwise_schedules( # (may be combined with pass above in future) - # In blex space, we order barrier-delimited sections of code. - # Each statement instance within a single barrier-delimited section will - # map to the same blex point. The resulting statement instance ordering - # will map each statement to all statements that occur in a later - # barrier-delimited section. - - # To achieve this, we will first create a map from statement instances to - # lexicographic space almost as before, though we will not increment the - # fastest-updating lex dim with each statement, and we will increment it - # with each barrier encountered. To denote these differences, we refer to - # this space as 'blex' space. - # The resulting pairwise schedule, if composed with a map defining a - # standard lexicographic ordering (SIO), would include a number of unwanted - # 'before->after' pairs, so before creating the SIO, we will subtract the - # unwanted pairs from the standard lex order map, yielding the 'blex' order - # map. + """In blex space, we order barrier-delimited sections of code. + Each statement instance within a single barrier-delimited section will + map to the same blex point. The resulting statement instance ordering + (SIO) will map each statement to all statements that occur in a later + barrier-delimited section. + + To achieve this, we will first create a map from statement instances to + lexicographic space almost as we did above in the intra-thread case, + though we will not increment the fastest-updating lex dim with each + statement, and we will increment it with each barrier encountered. To + denote these differences, we refer to this space as 'blex' space. + + The resulting pairwise schedule, if composed with a map defining a + standard lexicographic ordering to create an SIO, would include a number + of unwanted 'before->after' pairs of statement instances, so before + creating the SIO, we will subtract unwanted pairs from a standard + lex order map, yielding the 'blex' order map. + """ # {{{ Get upper and lower bound for each loop that contains a barrier @@ -389,18 +417,21 @@ def generate_pairwise_schedules( # }}} + # {{{ Create blex order maps and blex tuples defining statement ordering (x2) + all_par_lex_dim_names = lid_lex_dim_names + gid_lex_dim_names - # {{{ _gather_blex_ordering_info() + # {{{ _gather_blex_ordering_info(sync_kind): gather blex info for sync_kind def _gather_blex_ordering_info(sync_kind): - # For the given sync_kind ("local" or "global"), create a mapping from - # statement instances to blex space (dict), as well as a mapping - # defining the blex ordering (isl map from blex space -> blex space) + """For the given sync_kind ("local" or "global"), create a mapping from + statement instances to blex space (dict), as well as a mapping + defining the blex ordering (isl map from blex space -> blex space) - # Note that, unlike in the intra-thread case, there will be a single - # blex ordering map defining the blex ordering for all statement pairs, - # rather than separate (smaller) lex ordering maps for each pair + Note that, unlike in the intra-thread case, there will be a single + blex ordering map defining the blex ordering for all statement pairs, + rather than separate (smaller) lex ordering maps for each pair + """ # {{{ First, create map from stmt instances to blex space. @@ -458,9 +489,8 @@ def _gather_blex_ordering_info(sync_kind): # Record the blex dim for this loop iname iname_to_blex_dim[leave_iname] = len(next_blex_tuple)-2 - # update next blex pt + # Update next blex pt pre_end_loop_blex_pt = next_blex_tuple[:] - # Upon leaving a loop: # - Pop lex dim for enumerating code sections within this loop # - Pop lex dim for the loop iteration @@ -513,7 +543,7 @@ def _gather_blex_ordering_info(sync_kind): # }}} - # {{{ Create the blex order map + # {{{ Second, create the blex order map # {{{ Create the initial (pre-subtraction) blex order map @@ -567,19 +597,26 @@ def _gather_blex_ordering_info(sync_kind): # {{{ _create_excluded_map_for_iname def _create_excluded_map_for_iname(iname, blueprint): - # Create the blex->blex pairs that must be subtracted from the - # initial blex order map for this particular loop: - # PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST + """Create the blex->blex pairs that must be subtracted from the + initial blex order map for this particular loop using the 6 blex + tuples in the blueprint: + PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST + """ # Note: only blueprint[slex.FIRST] & blueprint[slex.LAST] contain pwaffs # {{{ _create_blex_set_from_tuple_pair def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): - # Given a before->after tuple pair in the blueprint, which may - # have dim vals described by strings (inames) and pwaffs, - # create an ISL set in blex space that can be converted into - # the ISL map to be subtracted + """Given a before->after tuple pair in the blueprint, which may + have dim vals described by ints, strings (inames), and pwaffs, + create an ISL set in blex space that can be converted into + the ISL map to be subtracted + """ + # (Vars from outside func used here: + # iname, blex_set_affs, blex_set_template, iname_to_blex_var, + # n_seq_blex_dims, seq_blex_dim_names, + # seq_blex_dim_names_prime) # Start with a set representing blex_order_map space blex_set = blex_set_template.copy() @@ -618,9 +655,10 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): return blex_set - # }}} + # }}} end _create_blex_set_from_tuple_pair() - # Create pairs to be subtracted (sets will be converted to map) + # Create pairs to be subtracted + # (set will be converted to map) # Enter loop case: PRE->FIRST full_blex_set = _create_blex_set_from_tuple_pair( @@ -642,9 +680,9 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): return isl.Map.from_domain(full_blex_set).move_dims( dt.out, 0, dt.in_, n_blex_dims, n_blex_dims) - # }}} + # }}} end _create_excluded_map_for_iname() - # Create map for each iname + # Create map to subtract for each iname maps_to_subtract = [] for iname, subdict in blex_exclusion_info.items(): maps_to_subtract.append(_create_excluded_map_for_iname(iname, subdict)) @@ -673,7 +711,7 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): seq_blex_dim_names, ) - # }}} + # }}} end _gather_blex_ordering_info(sync_kind) # Get the blex schedule blueprint (dict will become a map below) and # blex order map w.r.t. local and global barriers @@ -684,15 +722,11 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): gblex_order_map, seq_gblex_dim_names) = _gather_blex_ordering_info("global") - # }}} end blex order/map machinery + # }}} - # {{{ Create pairwise schedules (ISL maps) for each stmt pair + # }}} end intra-group and global blex order creation - from loopy.schedule.checker.utils import ( - sorted_union_of_names_in_isl_sets, - create_symbolic_map_from_tuples, - insert_and_name_isl_dims, - ) + # {{{ Create pairwise schedules (ISL maps) for each stmt pair # {{{ _get_map_for_stmt() @@ -816,45 +850,37 @@ def _get_map_for_stmt( # }}} - # {{{ Create SIOs for intra-group case (gid0' == gid0, etc) - - # Use *unsimplified* lex tuples with blex map, which have already been padded - - lblex_tuples_padded = [stmt_inst_to_lblex[insn_id] for insn_id in insn_ids] - - lconc_sched_maps = [ - _get_map_for_stmt( - insn_id, lblex_tuple, int_sid, - seq_lblex_dim_names+all_par_lex_dim_names) # Par names same for all - for insn_id, lblex_tuple, int_sid - in zip(insn_ids, lblex_tuples_padded, int_sids) - ] - - # Create statement instance ordering - sio_lconc = get_statement_ordering_map( - *lconc_sched_maps, # note, func accepts exactly two maps - lblex_order_map, - before_marker=BEFORE_MARK, - ) + # {{{ Create SIOs for intra-group case (gid0' == gid0, etc) and global case + + def _get_sched_maps_and_sio( + stmt_inst_to_blex, blex_order_map, seq_blex_dim_names): + # (Vars from outside func used here: + # insn_ids, int_sids, all_par_lex_dim_names) + + # Use *unsimplified* lex tuples w/ blex map, which are already padded + blex_tuples_padded = [stmt_inst_to_blex[insn_id] for insn_id in insn_ids] + + par_sched_maps = [ + _get_map_for_stmt( + insn_id, blex_tuple, int_sid, + seq_blex_dim_names+all_par_lex_dim_names) # all par names + for insn_id, blex_tuple, int_sid + in zip(insn_ids, blex_tuples_padded, int_sids) + ] + + # Create statement instance ordering + sio_par = get_statement_ordering_map( + *par_sched_maps, # note, func accepts exactly two maps + blex_order_map, + before_marker=BEFORE_MARK, + ) - # TODO use func to avoid duplicated code here: + return par_sched_maps, sio_par - gblex_tuples_padded = [stmt_inst_to_gblex[insn_id] for insn_id in insn_ids] - - gconc_sched_maps = [ - _get_map_for_stmt( - insn_id, gblex_tuple, int_sid, - seq_gblex_dim_names+all_par_lex_dim_names) # Par names same for all - for insn_id, gblex_tuple, int_sid - in zip(insn_ids, gblex_tuples_padded, int_sids) - ] - - # Create statement instance ordering - sio_gconc = get_statement_ordering_map( - *gconc_sched_maps, # note, func accepts exactly two maps - gblex_order_map, - before_marker=BEFORE_MARK, - ) + lpar_sched_maps, sio_lpar = _get_sched_maps_and_sio( + stmt_inst_to_lblex, lblex_order_map, seq_lblex_dim_names) + gpar_sched_maps, sio_gpar = _get_sched_maps_and_sio( + stmt_inst_to_gblex, gblex_order_map, seq_gblex_dim_names) # }}} @@ -863,13 +889,15 @@ def _get_map_for_stmt( # (currently helpful for testing; also could be desired by a user) pairwise_schedules[tuple(insn_ids)] = ( (sio_seq, tuple(intra_thread_sched_maps), ), - (sio_lconc, tuple(lconc_sched_maps), ), - (sio_gconc, tuple(gconc_sched_maps), ), + (sio_lpar, tuple(lpar_sched_maps), ), + (sio_gpar, tuple(gpar_sched_maps), ), ) else: # Store SIOs only - pairwise_schedules[tuple(insn_ids)] = (sio_seq, sio_lconc, sio_gconc) + pairwise_schedules[tuple(insn_ids)] = (sio_seq, sio_lpar, sio_gpar) # }}} return pairwise_schedules + +# }}} From 0f3f2799f609eb17d24694bec50499c8e3212103 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 27 Mar 2021 17:05:30 -0500 Subject: [PATCH 076/220] another doctest typo --- loopy/schedule/checker/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index a5858bde0..7989df68d 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -80,7 +80,7 @@ def get_schedules_for_statement_pairs( >>> # Print map >>> print(str(sio_dict[("insn_a", "insn_b")][0] ... ).replace("{ ", "{\n").replace(" :", "\n:")) - [pi, pj, pk] -> { + [pj, pk] -> { [_lp_linchk_stmt' = 0, j', k'] -> [_lp_linchk_stmt = 1, j, k] : 0 <= j' < pj and 0 <= k' < pk and 0 <= j < pj and 0 <= k < pk } From c0a4c58e97d3e54ee094658bf8aafb12116dfacc Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 27 Mar 2021 19:57:44 -0500 Subject: [PATCH 077/220] rename get_schedules_for_statement_pairs()->get_pairwise_statement_orderings() and generate_pairwise_schedules()->get_pairwise_statement_orderings_inner(); update lots of documentation --- loopy/schedule/checker/__init__.py | 68 +++++++++++-------- .../checker/lexicographic_order_map.py | 67 +++++++++--------- loopy/schedule/checker/schedule.py | 44 +++++++----- test/test_linearization_checker.py | 20 +++--- 4 files changed, 107 insertions(+), 92 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 7989df68d..7644fddac 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -21,39 +21,46 @@ """ -# {{{ create a pairwise schedules for statement pairs +# {{{ get pairwise statement orderings -def get_schedules_for_statement_pairs( +def get_pairwise_statement_orderings( knl, - linearization_items, + lin_items, insn_id_pairs, return_schedules=False, ): r"""For each statement pair in a subset of all statement pairs found in a linearized kernel, determine the (relative) order in which the statement - instances are executed. For each pair, describe this relative ordering with - a pair of mappings from statement instances to points in a single - lexicographic ordering (a ``pairwise schedule''). When determining the - relative ordering, ignore concurrent inames. + instances are executed. For each pair, represent this relative ordering as + a ``statement instance ordering`` (SIO): a map from each instance of the + first statement to all instances of the second statement that occur + later. :arg knl: A preprocessed :class:`loopy.kernel.LoopKernel` containing the - linearization items that will be used to create a schedule. + linearization items that will be used to create the SIOs. - :arg linearization_items: A list of :class:`loopy.schedule.ScheduleItem` - (to be renamed to `loopy.schedule.LinearizationItem`) containing - all linearization items for which pairwise schedules will be - created. To allow usage of this routine during linearization, a - truncated (i.e. partial) linearization may be passed through this - argument. + :arg lin_items: A list of :class:`loopy.schedule.ScheduleItem` + (to be renamed to `loopy.schedule.LinearizationItem`) containing all + linearization items for which SIOs will be created. To allow usage of + this routine during linearization, a truncated (i.e. partial) + linearization may be passed through this argument. - :arg insn_id_pairs: A list containing pairs of instruction - identifiers. + :arg insn_id_pairs: A list containing pairs of instruction identifiers. + + :arg return_schedules: A :class:`bool` determining whether to include + pairwise schedules in the returned dictionary. :returns: A dictionary mapping each two-tuple of instruction identifiers - provided in `insn_id_pairs` to a corresponding two-tuple containing two - :class:`islpy.Map`\ s representing a pairwise schedule as two - mappings from statement instances to lexicographic time, one for - each of the two statements. + provided in `insn_id_pairs` to a statement instance ordering, realized + as an :class:`islpy.Map` from each instance of the first statement to + all instances of the second statement that occur later. + + Optional (mainly used for testing): If `return_schedules = True`, each + dict value will be a two-tuple containing the statement instance + ordering and also a ``pairwise schedule'', a pair of mappings from + statement instances to points in a single lexicographic ordering, + realized as a two-tuple containing two :class:`islpy.Map`\ s, one for + each statement. .. doctest: @@ -70,9 +77,9 @@ def get_schedules_for_statement_pairs( >>> # Get a linearization >>> knl = lp.get_one_linearized_kernel(lp.preprocess_kernel(knl)) >>> # Get a pairwise schedule ----------------------------------------------- - >>> from loopy.schedule.checker import get_schedules_for_statement_pairs + >>> from loopy.schedule.checker import get_pairwise_statement_orderings >>> # Get two maps ---------------------------------------------------------- - >>> sio_dict = get_schedules_for_statement_pairs( + >>> sio_dict = get_pairwise_statement_orderings( ... knl, ... knl.linearization, ... [("insn_a", "insn_b")], @@ -85,7 +92,6 @@ def get_schedules_for_statement_pairs( : 0 <= j' < pj and 0 <= k' < pk and 0 <= j < pj and 0 <= k < pk } """ - # TODO update docs and doctest now that we're returning SIOs # {{{ make sure kernel has been preprocessed @@ -97,16 +103,17 @@ def get_schedules_for_statement_pairs( # }}} # {{{ Find any EnterLoop inames that are tagged as concurrent - # so that generate_pairwise_schedule() knows to ignore them + # so that get_pairwise_statement_orderings_inner() knows to ignore them # (In the future, this shouldn't be necessary because there # won't be any inames with ConcurrentTags in EnterLoop linearization items. - # Test which exercises this: test_linearization_checker_with_stroud_bernstein()) + # Test which exercises this in downstream PR: + # test_linearization_checker_with_stroud_bernstein()) from loopy.schedule.checker.utils import ( partition_inames_by_concurrency, get_EnterLoop_inames, ) conc_inames, _ = partition_inames_by_concurrency(knl) - enterloop_inames = get_EnterLoop_inames(linearization_items) + enterloop_inames = get_EnterLoop_inames(lin_items) conc_loop_inames = conc_inames & enterloop_inames # The only concurrent EnterLoop inames should be Vec and ILP @@ -122,11 +129,12 @@ def get_schedules_for_statement_pairs( # {{{ Create two mappings from {statement instance: lex point} - # include only instructions involved in this dependency - from loopy.schedule.checker.schedule import generate_pairwise_schedules - return generate_pairwise_schedules( + from loopy.schedule.checker.schedule import ( + get_pairwise_statement_orderings_inner + ) + return get_pairwise_statement_orderings_inner( knl, - linearization_items, + lin_items, insn_id_pairs, loops_to_ignore=conc_loop_inames, return_schedules=return_schedules, diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 7927812b5..20f889975 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -77,33 +77,34 @@ def get_lex_order_set( in_dim_marker="'", ): """Return an :class:`islpy.Set` representing a lexicographic ordering - with the number of dimensions provided in `before_names` - (equal to the number of dimensions in `after_names`). + over a space with the number of dimensions provided in `dim_names` + (the set itself will have twice this many dimensions in order to + represent the ordering as before-after pairs of points). - :arg before_names: A list of :class:`str` variable names to be used + :arg dim_names: A list of :class:`str` variable names to be used to describe lexicographic space dimensions for a point in a lexicographic - ordering that occurs before another point, which will be represented using - `after_names`. (see example below) + ordering. (see example below) - :arg after_names: A list of :class:`str` variable names to be used - to describe lexicographic space dimensions for a point in a lexicographic - ordering that occurs after another point, which will be represented using - `before_names`. (see example below) - - :arg islvars: A dictionary mapping variable names in `before_names` and - `after_names` to :class:`islpy.PwAff` instances that represent each - of the variables (islvars may be produced by `islpy.make_zero_and_vars`). + :arg islvars: A dictionary mapping variable names in `dim_names` to + :class:`islpy.PwAff` instances that represent each of the variables + (islvars may be produced by `islpy.make_zero_and_vars`). The key '0' is also include and represents a :class:`islpy.PwAff` zero - constant. This dictionary defines the space to be used for the set. If no - value is passed, the dictionary will be made using `before_names` - and `after_names`. - - :returns: An :class:`islpy.Set` representing a big-endian lexicographic ordering - with the number of dimensions provided in `before_names`. The set - has one dimension for each name in *both* `before_names` and - `after_names`, and contains all points which meet a 'happens before' + constant. This dictionary defines the space to be used for the set and + must also include versions of `dim_names` with the `in_dim_marker` + appended. If no value is passed, the dictionary will be made using + `dim_names` and `dim_names` with the `in_dim_marker` appended. + + :arg in_dim_marker: A :class:`str` to be appended to dimension names to + distinguish corresponding dimensions in before-after pairs of points. + (see example below) + + :returns: An :class:`islpy.Set` representing a big-endian lexicographic + ordering with the number of dimensions provided in `dim_names`. The set + has two dimensions for each name in `dim_names`, one identified by the + given name and another identified by the same name with `in_dim_marker` + appended. The set contains all points which meet a 'happens before' constraint defining the lexicographic ordering. E.g., if - `before_names = [i0', i1', i2']` and `after_names = [i0, i1, i2]`, + `dim_names = [i0, i1, i2]` and `in_dim_marker="'"`, return the set containing all points in a 3-dimensional, big-endian lexicographic ordering such that point `[i0', i1', i2']` happens before `[i0, i1, i2]`. I.e., return:: @@ -113,7 +114,6 @@ def get_lex_order_set( or (i0' = i0 and i1' = i1 and i2' < i2)} """ - # TODO update doc from loopy.schedule.checker.utils import ( append_marker_to_strings, @@ -165,30 +165,27 @@ def create_lex_order_map( :arg n_dims: An :class:`int` representing the number of dimensions in the lexicographic ordering. If not provided, `n_dims` will be - set to length of `after_names`. + set to length of `dim_names`. - :arg before_names: A list of :class:`str` variable names to be used - to describe lexicographic space dimensions for a point in a lexicographic - ordering that occurs before another point, which will be represented using - `after_names`. (see example below) + :arg dim_names: A list of :class:`str` variable names for the + lexicographic space dimensions. - :arg after_names: A list of :class:`str` variable names to be used - to describe lexicographic space dimensions for a point in a lexicographic - ordering that occurs after another point, which will be represented using - `before_names`. (see example below) + :arg in_dim_marker: A :class:`str` to be appended to `dim_names` to create + the names for the input dimensions of the map, thereby distinguishing + them from the corresponding output dimensions in before-after pairs of + points. (see example below) :returns: An :class:`islpy.Map` representing a lexicographic ordering as a mapping from each point in lexicographic time to every point that occurs later in lexicographic time. - E.g., if `before_names = [i0', i1', i2']` and - `after_names = [i0, i1, i2]`, return the map:: + E.g., if `dim_names = [i0, i1, i2]` and `in_dim_marker = "'"`, + return the map:: {[i0', i1', i2'] -> [i0, i1, i2] : i0' < i0 or (i0' = i0 and i1' < i1) or (i0' = i0 and i1' = i1 and i2' < i2)} """ - # TODO update doc if dim_names is None: dim_names = ["i%s" % (i) for i in range(n_dims)] diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index b849a2ccf..7fef51819 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -150,8 +150,8 @@ def _simplify_lex_dims(tup0, tup1): # {{{ class SpecialLexPointWRTLoop class SpecialLexPointWRTLoop: - """Strings specifying a particular position in a lexicographic - ordering of statements relative to a loop. + """Strings identifying a particular point or set of points in a + lexicographic ordering of statements, specified relative to a loop. .. attribute:: PRE A :class:`str` indicating the last lexicographic point that @@ -188,9 +188,9 @@ class SpecialLexPointWRTLoop: # }}} -# {{{ generate_pairwise_schedules +# {{{ get_pairwise_statement_orderings_inner -def generate_pairwise_schedules( +def get_pairwise_statement_orderings_inner( knl, lin_items, insn_id_pairs, @@ -199,21 +199,23 @@ def generate_pairwise_schedules( ): r"""For each statement pair in a subset of all statement pairs found in a linearized kernel, determine the (relative) order in which the statement - instances are executed. For each pair, describe this relative ordering with - a pair of mappings from statement instances to points in a single - lexicographic ordering (a ``pairwise schedule''). + instances are executed. For each pair, represent this relative ordering as + a ``statement instance ordering`` (SIO): a map from each instance of the + first statement to all instances of the second statement that occur + later. :arg knl: A preprocessed :class:`loopy.kernel.LoopKernel` containing the - linearization items that will be used to create a schedule. This + linearization items that will be used to create the SIOs. This kernel will be used to get the domains associated with the inames - used in the statements. + used in the statements, and to determine which inames have been + tagged with parallel tags. :arg lin_items: A list of :class:`loopy.schedule.ScheduleItem` (to be renamed to `loopy.schedule.LinearizationItem`) containing - all linearization items for which pairwise schedules will be + all linearization items for which SIOs will be created. To allow usage of this routine during linearization, a truncated (i.e. partial) linearization may be passed through this - argument. + argument :arg insn_id_pairs: A list containing pairs of instruction identifiers. @@ -222,14 +224,22 @@ def generate_pairwise_schedules( contain concurrent inames tagged with the ``vec`` or ``ilp`` array access tags. + :arg return_schedules: A :class:`bool` determining whether to include + pairwise schedules in the returned dictionary. + :returns: A dictionary mapping each two-tuple of instruction identifiers - provided in `insn_id_pairs` to a corresponding two-tuple containing two - :class:`islpy.Map`\ s representing a pairwise schedule as two - mappings from statement instances to lexicographic time, one for - each of the two statements. + provided in `insn_id_pairs` to a statement instance ordering, realized + as an :class:`islpy.Map` from each instance of the first + statement to all instances of the second statement that occur later. + + Optional (mainly used for testing): If `return_schedules=True`, + each dict value will be a two-tuple containing the statement instance + ordering and also a ``pairwise schedule'', a pair of + mappings from statement instances to points in a single lexicographic + ordering, realized as a two-tuple containing two + :class:`islpy.Map`\ s, one for each statement. + """ - # TODO update docs now that we're returning SIOs - # TODO rename loops_to_ignore to loops_to_ignore_for_intra_thread_stuff... # TODO handle 'vec' appropriately; then remove loops_to_ignore? from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 38e9309ff..63126643a 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -95,7 +95,7 @@ def _isl_map_with_marked_dims(s): def test_pairwise_schedule_creation(): from loopy.schedule.checker import ( - get_schedules_for_statement_pairs, + get_pairwise_statement_orderings, ) # Example kernel @@ -144,7 +144,7 @@ def test_pairwise_schedule_creation(): ("stmt_b", "stmt_d"), ("stmt_c", "stmt_d"), ] - scheds = get_schedules_for_statement_pairs( + scheds = get_pairwise_statement_orderings( lin_knl, linearization_items, insn_id_pairs, @@ -315,7 +315,7 @@ def test_pairwise_schedule_creation(): def test_pairwise_schedule_creation_with_hw_par_tags(): from loopy.schedule.checker import ( - get_schedules_for_statement_pairs, + get_pairwise_statement_orderings, ) # Example kernel @@ -351,7 +351,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): stmt_id_pairs = [ ("stmt_a", "stmt_b"), ] - scheds = get_schedules_for_statement_pairs( + scheds = get_pairwise_statement_orderings( lin_knl, linearization_items, stmt_id_pairs, @@ -495,7 +495,7 @@ def _check_sio_for_stmt_pair( def test_statement_instance_ordering(): from loopy.schedule.checker import ( - get_schedules_for_statement_pairs, + get_pairwise_statement_orderings, ) # Example kernel (add deps to fix loop order) @@ -544,7 +544,7 @@ def test_statement_instance_ordering(): ("stmt_b", "stmt_d"), ("stmt_c", "stmt_d"), ] - scheds = get_schedules_for_statement_pairs( + scheds = get_pairwise_statement_orderings( knl, linearization_items, stmt_id_pairs, @@ -622,7 +622,7 @@ def test_statement_instance_ordering(): def test_statement_instance_ordering_with_hw_par_tags(): from loopy.schedule.checker import ( - get_schedules_for_statement_pairs, + get_pairwise_statement_orderings, ) from loopy.schedule.checker.utils import ( partition_inames_by_concurrency, @@ -662,7 +662,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): stmt_id_pairs = [ ("stmt_a", "stmt_b"), ] - scheds = get_schedules_for_statement_pairs( + scheds = get_pairwise_statement_orderings( lin_knl, linearization_items, stmt_id_pairs, @@ -698,7 +698,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): def test_sios_and_schedules_with_barriers(): from loopy.schedule.checker import ( - get_schedules_for_statement_pairs, + get_pairwise_statement_orderings, ) assumptions = "ij_end >= ij_start + 1 and lg_end >= 1" @@ -743,7 +743,7 @@ def test_sios_and_schedules_with_barriers(): linearization_items = lin_knl.linearization insn_id_pairs = [("j1", "2"), ("1", "i0")] - scheds = get_schedules_for_statement_pairs( + scheds = get_pairwise_statement_orderings( lin_knl, linearization_items, insn_id_pairs, return_schedules=True, # include schedules for testing ) From 13d5e1260f4b120205e9493485f46f4159fcddd5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 28 Mar 2021 18:21:51 -0500 Subject: [PATCH 078/220] update comments about vec --- loopy/schedule/checker/__init__.py | 5 +---- loopy/schedule/checker/schedule.py | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 7644fddac..577ab3dc4 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -104,10 +104,7 @@ def get_pairwise_statement_orderings( # {{{ Find any EnterLoop inames that are tagged as concurrent # so that get_pairwise_statement_orderings_inner() knows to ignore them - # (In the future, this shouldn't be necessary because there - # won't be any inames with ConcurrentTags in EnterLoop linearization items. - # Test which exercises this in downstream PR: - # test_linearization_checker_with_stroud_bernstein()) + # (In the future, this should only include inames tagged with 'vec'.) from loopy.schedule.checker.utils import ( partition_inames_by_concurrency, get_EnterLoop_inames, diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 7fef51819..cf70cf3c5 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -240,7 +240,6 @@ def get_pairwise_statement_orderings_inner( :class:`islpy.Map`\ s, one for each statement. """ - # TODO handle 'vec' appropriately; then remove loops_to_ignore? from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.kernel.data import (LocalIndexTag, GroupIndexTag) From 283b747d0a3842350d2bb1f1df942d09d52f65f0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 31 Mar 2021 17:42:26 -0500 Subject: [PATCH 079/220] rename var pairwise_schedules->pairwise_sios --- loopy/schedule/checker/schedule.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index cf70cf3c5..7ce61d5a3 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -795,7 +795,7 @@ def _get_map_for_stmt( # }}} - pairwise_schedules = {} + pairwise_sios = {} for insn_ids in insn_id_pairs: # Determine integer IDs that will represent each statement in mapping # (dependency map creation assumes sid_before=0 and sid_after=1, unless @@ -896,17 +896,17 @@ def _get_sched_maps_and_sio( if return_schedules: # Store sched maps along with SIOs # (currently helpful for testing; also could be desired by a user) - pairwise_schedules[tuple(insn_ids)] = ( + pairwise_sios[tuple(insn_ids)] = ( (sio_seq, tuple(intra_thread_sched_maps), ), (sio_lpar, tuple(lpar_sched_maps), ), (sio_gpar, tuple(gpar_sched_maps), ), ) else: # Store SIOs only - pairwise_schedules[tuple(insn_ids)] = (sio_seq, sio_lpar, sio_gpar) + pairwise_sios[tuple(insn_ids)] = (sio_seq, sio_lpar, sio_gpar) # }}} - return pairwise_schedules + return pairwise_sios # }}} From cb6ca3dbf097275d85095ab8d5fb7deb7cf6236a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 31 Mar 2021 18:33:53 -0500 Subject: [PATCH 080/220] return a namedtuple with the sios and pwscheds; update docs accordingly --- loopy/schedule/checker/__init__.py | 26 +++++------ loopy/schedule/checker/schedule.py | 55 ++++++++++++----------- test/test_linearization_checker.py | 70 ++++++++++-------------------- 3 files changed, 67 insertions(+), 84 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 577ab3dc4..1cf8bc4e8 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -27,7 +27,6 @@ def get_pairwise_statement_orderings( knl, lin_items, insn_id_pairs, - return_schedules=False, ): r"""For each statement pair in a subset of all statement pairs found in a linearized kernel, determine the (relative) order in which the statement @@ -51,16 +50,18 @@ def get_pairwise_statement_orderings( pairwise schedules in the returned dictionary. :returns: A dictionary mapping each two-tuple of instruction identifiers - provided in `insn_id_pairs` to a statement instance ordering, realized - as an :class:`islpy.Map` from each instance of the first statement to - all instances of the second statement that occur later. - - Optional (mainly used for testing): If `return_schedules = True`, each - dict value will be a two-tuple containing the statement instance - ordering and also a ``pairwise schedule'', a pair of mappings from - statement instances to points in a single lexicographic ordering, - realized as a two-tuple containing two :class:`islpy.Map`\ s, one for - each statement. + provided in `insn_id_pairs` to a :class:`collections.namedtuple` + containing the intra-thread SIO (`sio_intra_thread`), intra-group SIO + (`sio_intra_group`), and global SIO (`sio_global`), each realized + as an :class:`islpy.Map` from each instance of the first + statement to all instances of the second statement that occur later, + as well as the intra-thread pairwise schedule (`pwsched_intra_thread`), + intra-group pairwise schedule (`pwsched_intra_group`), and the global + pairwise schedule (`pwsched_global`), each containing a pair of + mappings from statement instances to points in a lexicographic + ordering, one for each statement. Note that a pairwise schedule + alone cannot be used to reproduce the corresponding SIO without the + corresponding (unique) lexicographic order map, which is not returned. .. doctest: @@ -85,7 +86,7 @@ def get_pairwise_statement_orderings( ... [("insn_a", "insn_b")], ... ) >>> # Print map - >>> print(str(sio_dict[("insn_a", "insn_b")][0] + >>> print(str(sio_dict[("insn_a", "insn_b")].sio_intra_thread ... ).replace("{ ", "{\n").replace(" :", "\n:")) [pj, pk] -> { [_lp_linchk_stmt' = 0, j', k'] -> [_lp_linchk_stmt = 1, j, k] @@ -134,7 +135,6 @@ def get_pairwise_statement_orderings( lin_items, insn_id_pairs, loops_to_ignore=conc_loop_inames, - return_schedules=return_schedules, ) # }}} diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 7ce61d5a3..0f39f727d 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -195,7 +195,6 @@ def get_pairwise_statement_orderings_inner( lin_items, insn_id_pairs, loops_to_ignore=set(), - return_schedules=False, ): r"""For each statement pair in a subset of all statement pairs found in a linearized kernel, determine the (relative) order in which the statement @@ -224,21 +223,19 @@ def get_pairwise_statement_orderings_inner( contain concurrent inames tagged with the ``vec`` or ``ilp`` array access tags. - :arg return_schedules: A :class:`bool` determining whether to include - pairwise schedules in the returned dictionary. - :returns: A dictionary mapping each two-tuple of instruction identifiers - provided in `insn_id_pairs` to a statement instance ordering, realized + provided in `insn_id_pairs` to a :class:`collections.namedtuple` + containing the intra-thread SIO (`sio_intra_thread`), intra-group SIO + (`sio_intra_group`), and global SIO (`sio_global`), each realized as an :class:`islpy.Map` from each instance of the first - statement to all instances of the second statement that occur later. - - Optional (mainly used for testing): If `return_schedules=True`, - each dict value will be a two-tuple containing the statement instance - ordering and also a ``pairwise schedule'', a pair of - mappings from statement instances to points in a single lexicographic - ordering, realized as a two-tuple containing two - :class:`islpy.Map`\ s, one for each statement. - + statement to all instances of the second statement that occur later, + as well as the intra-thread pairwise schedule (`pwsched_intra_thread`), + intra-group pairwise schedule (`pwsched_intra_group`), and the global + pairwise schedule (`pwsched_global`), each containing a pair of + mappings from statement instances to points in a lexicographic + ordering, one for each statement. Note that a pairwise schedule + alone cannot be used to reproduce the corresponding SIO without the + corresponding (unique) lexicographic order map, which is not returned. """ from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) @@ -796,6 +793,16 @@ def _get_map_for_stmt( # }}} pairwise_sios = {} + from collections import namedtuple + StatementOrdering = namedtuple( + 'StatementOrdering', + [ + 'sio_intra_thread', 'pwsched_intra_thread', + 'sio_intra_group', 'pwsched_intra_group', + 'sio_global', 'pwsched_global', + ]) + # ("sio" = statement instance ordering; "pwsched" = pairwise schedule) + for insn_ids in insn_id_pairs: # Determine integer IDs that will represent each statement in mapping # (dependency map creation assumes sid_before=0 and sid_after=1, unless @@ -893,17 +900,15 @@ def _get_sched_maps_and_sio( # }}} - if return_schedules: - # Store sched maps along with SIOs - # (currently helpful for testing; also could be desired by a user) - pairwise_sios[tuple(insn_ids)] = ( - (sio_seq, tuple(intra_thread_sched_maps), ), - (sio_lpar, tuple(lpar_sched_maps), ), - (sio_gpar, tuple(gpar_sched_maps), ), - ) - else: - # Store SIOs only - pairwise_sios[tuple(insn_ids)] = (sio_seq, sio_lpar, sio_gpar) + # Store sched maps along with SIOs + pairwise_sios[tuple(insn_ids)] = StatementOrdering( + sio_intra_thread=sio_seq, + pwsched_intra_thread=tuple(intra_thread_sched_maps), + sio_intra_group=sio_lpar, + pwsched_intra_group=tuple(lpar_sched_maps), + sio_global=sio_gpar, + pwsched_global=tuple(gpar_sched_maps), + ) # }}} diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 63126643a..8ab98ed45 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -148,7 +148,6 @@ def test_pairwise_schedule_creation(): lin_knl, linearization_items, insn_id_pairs, - return_schedules=True, # include schedules for testing ) # Relationship between stmt_a and stmt_b --------------------------------------- @@ -355,7 +354,6 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): lin_knl, linearization_items, stmt_id_pairs, - return_schedules=True, ) # Relationship between stmt_a and stmt_b --------------------------------------- @@ -448,7 +446,7 @@ def _check_lex_map(exp_lex_order_map, n_dims): def _check_sio_for_stmt_pair( stmt_id_before, stmt_id_after, - sio_dict, + all_sios, sio_seq_exp=None, sched_before_seq_exp=None, sched_after_seq_exp=None, @@ -460,33 +458,21 @@ def _check_sio_for_stmt_pair( sched_after_gconc_exp=None, ): - maps_found = sio_dict[(stmt_id_before, stmt_id_after)] - - # Check whether scheds were included in sio_dict - if isinstance(maps_found[0], tuple): - # Scheds were included - ( - sio_seq, (sched_before_seq, sched_after_seq) - ), ( - sio_lconc, (sched_before_lconc, sched_after_lconc) - ), ( - sio_gconc, (sched_before_gconc, sched_after_gconc) - ) = maps_found - map_candidates = zip([ - sio_seq_exp, sched_before_seq_exp, sched_after_seq_exp, - sio_lconc_exp, sched_before_lconc_exp, sched_after_lconc_exp, - sio_gconc_exp, sched_before_gconc_exp, sched_after_gconc_exp, - ], [ - sio_seq, sched_before_seq, sched_after_seq, - sio_lconc, sched_before_lconc, sched_after_lconc, - sio_gconc, sched_before_gconc, sched_after_gconc, - ]) - else: - # Scheds not included - sio_seq, sio_lconc, sio_gconc = maps_found - map_candidates = zip( - [sio_seq_exp, sio_lconc_exp, sio_gconc_exp, ], - [sio_seq, sio_lconc, sio_gconc, ]) + order_info = all_sios[(stmt_id_before, stmt_id_after)] + + # Get pairs of maps to compare for equality + map_candidates = zip([ + sio_seq_exp, sched_before_seq_exp, sched_after_seq_exp, + sio_lconc_exp, sched_before_lconc_exp, sched_after_lconc_exp, + sio_gconc_exp, sched_before_gconc_exp, sched_after_gconc_exp, + ], [ + order_info.sio_intra_thread, + order_info.pwsched_intra_thread[0], order_info.pwsched_intra_thread[1], + order_info.sio_intra_group, + order_info.pwsched_intra_group[0], order_info.pwsched_intra_group[1], + order_info.sio_global, + order_info.pwsched_global[0], order_info.pwsched_global[1], + ]) # Only compare to maps that were passed maps_to_compare = [(m1, m2) for m1, m2 in map_candidates if m1 is not None] @@ -548,7 +534,6 @@ def test_statement_instance_ordering(): knl, linearization_items, stmt_id_pairs, - return_schedules=True, ) # Relationship between stmt_a and stmt_b --------------------------------------- @@ -666,7 +651,6 @@ def test_statement_instance_ordering_with_hw_par_tags(): lin_knl, linearization_items, stmt_id_pairs, - return_schedules=True, ) # Create string for representing parallel iname condition in sio @@ -744,9 +728,7 @@ def test_sios_and_schedules_with_barriers(): insn_id_pairs = [("j1", "2"), ("1", "i0")] scheds = get_pairwise_statement_orderings( - lin_knl, linearization_items, insn_id_pairs, - return_schedules=True, # include schedules for testing - ) + lin_knl, linearization_items, insn_id_pairs) # Relationship between j1 and 2 -------------------------------------------- @@ -858,13 +840,7 @@ def test_sios_and_schedules_with_barriers(): # Check for some key example pairs in the sio_lconc map # Get maps - ( - sio_seq, (sched_map_before, sched_map_after) - ), ( - sio_lconc, (sched_before_lconc, sched_after_lconc) - ), ( - sio_gconc, (sched_before_gconc, sched_after_gconc) - ) = scheds[("j1", "2")] + order_info = scheds[("j1", "2")] # As long as this is not the last iteration of the i loop, then there # should be a barrier between the last instance of statement j1 @@ -887,9 +863,10 @@ def test_sios_and_schedules_with_barriers(): conc_iname_bound_str, conc_iname_bound_str_p, )) - wanted_pairs = ensure_dim_names_match_and_align(wanted_pairs, sio_lconc) + wanted_pairs = ensure_dim_names_match_and_align( + wanted_pairs, order_info.sio_intra_group) - assert wanted_pairs.is_subset(sio_lconc) + assert wanted_pairs.is_subset(order_info.sio_intra_group) # If this IS the last iteration of the i loop, then there # should NOT be a barrier between the last instance of statement j1 @@ -908,9 +885,10 @@ def test_sios_and_schedules_with_barriers(): conc_iname_bound_str, conc_iname_bound_str_p, )) - unwanted_pairs = ensure_dim_names_match_and_align(unwanted_pairs, sio_lconc) + unwanted_pairs = ensure_dim_names_match_and_align( + unwanted_pairs, order_info.sio_intra_group) - assert not unwanted_pairs.is_subset(sio_lconc) + assert not unwanted_pairs.is_subset(order_info.sio_intra_group) # Relationship between 1 and i0 -------------------------------------------- From 3843eb9d52a49bcb932074cb806601d4c8d6d6cb Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 31 Mar 2021 18:58:49 -0500 Subject: [PATCH 081/220] rename some variables to provide more precise information --- loopy/schedule/checker/schedule.py | 44 ++++---- test/test_linearization_checker.py | 168 +++++++++++++++-------------- 2 files changed, 112 insertions(+), 100 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 0f39f727d..77a2354ca 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -559,7 +559,7 @@ def _gather_blex_ordering_info(sync_kind): seq_blex_dim_names_prime = append_marker_to_strings( seq_blex_dim_names, marker=BEFORE_MARK) - # Begin with the blex order map created as a standard lex order map + # Begin with the blex order map created as a standard lexicographical order blex_order_map = create_lex_order_map( dim_names=seq_blex_dim_names, in_dim_marker=BEFORE_MARK, @@ -602,19 +602,20 @@ def _gather_blex_ordering_info(sync_kind): # {{{ _create_excluded_map_for_iname - def _create_excluded_map_for_iname(iname, blueprint): + def _create_excluded_map_for_iname(iname, key_lex_tuples): """Create the blex->blex pairs that must be subtracted from the initial blex order map for this particular loop using the 6 blex - tuples in the blueprint: + tuples in the key_lex_tuples: PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST """ - # Note: only blueprint[slex.FIRST] & blueprint[slex.LAST] contain pwaffs + # Note: + # only key_lex_tuples[slex.FIRST] & key_lex_tuples[slex.LAST] are pwaffs # {{{ _create_blex_set_from_tuple_pair def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): - """Given a before->after tuple pair in the blueprint, which may + """Given a before->after tuple pair in the key_lex_tuples, which may have dim vals described by ints, strings (inames), and pwaffs, create an ISL set in blex space that can be converted into the ISL map to be subtracted @@ -668,16 +669,17 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # Enter loop case: PRE->FIRST full_blex_set = _create_blex_set_from_tuple_pair( - blueprint[slex.PRE], blueprint[slex.FIRST]) + key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST]) # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) full_blex_set |= _create_blex_set_from_tuple_pair( - blueprint[slex.BOTTOM], blueprint[slex.TOP], wrap_cond=True) + key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], + wrap_cond=True) # Leave loop case: LAST->POST full_blex_set |= _create_blex_set_from_tuple_pair( - blueprint[slex.LAST], blueprint[slex.POST]) + key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST]) # Add condition to fix iteration value for *surrounding* loops (j = j') - for surrounding_iname in blueprint[slex.PRE][1::2]: + for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: s_blex_var = iname_to_blex_var[surrounding_iname] full_blex_set &= blex_set_affs[s_blex_var].eq_set( blex_set_affs[s_blex_var+BEFORE_MARK]) @@ -795,11 +797,11 @@ def _get_map_for_stmt( pairwise_sios = {} from collections import namedtuple StatementOrdering = namedtuple( - 'StatementOrdering', + "StatementOrdering", [ - 'sio_intra_thread', 'pwsched_intra_thread', - 'sio_intra_group', 'pwsched_intra_group', - 'sio_global', 'pwsched_global', + "sio_intra_thread", "pwsched_intra_thread", + "sio_intra_group", "pwsched_intra_group", + "sio_global", "pwsched_global", ]) # ("sio" = statement instance ordering; "pwsched" = pairwise schedule) @@ -858,7 +860,7 @@ def _get_map_for_stmt( # Create statement instance ordering, # maps each statement instance to all statement instances occurring later - sio_seq = get_statement_ordering_map( + sio_intra_thread = get_statement_ordering_map( *intra_thread_sched_maps, # note, func accepts exactly two maps lex_order_map, before_marker=BEFORE_MARK, @@ -893,21 +895,21 @@ def _get_sched_maps_and_sio( return par_sched_maps, sio_par - lpar_sched_maps, sio_lpar = _get_sched_maps_and_sio( + pwsched_intra_group, sio_intra_group = _get_sched_maps_and_sio( stmt_inst_to_lblex, lblex_order_map, seq_lblex_dim_names) - gpar_sched_maps, sio_gpar = _get_sched_maps_and_sio( + pwsched_global, sio_global = _get_sched_maps_and_sio( stmt_inst_to_gblex, gblex_order_map, seq_gblex_dim_names) # }}} # Store sched maps along with SIOs pairwise_sios[tuple(insn_ids)] = StatementOrdering( - sio_intra_thread=sio_seq, + sio_intra_thread=sio_intra_thread, pwsched_intra_thread=tuple(intra_thread_sched_maps), - sio_intra_group=sio_lpar, - pwsched_intra_group=tuple(lpar_sched_maps), - sio_global=sio_gpar, - pwsched_global=tuple(gpar_sched_maps), + sio_intra_group=sio_intra_group, + pwsched_intra_group=tuple(pwsched_intra_group), + sio_global=sio_global, + pwsched_global=tuple(pwsched_global), ) # }}} diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 8ab98ed45..fa8dd58b4 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -154,7 +154,7 @@ def test_pairwise_schedule_creation(): # Create expected maps and compare - sched_before_seq_exp = isl.Map( + sched_before_intra_thread_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -162,7 +162,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_seq_exp = isl.Map( + sched_after_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -172,8 +172,8 @@ def test_pairwise_schedule_creation(): _check_sio_for_stmt_pair( "stmt_a", "stmt_b", scheds, - sched_before_seq_exp=sched_before_seq_exp, - sched_after_seq_exp=sched_after_seq_exp, + sched_before_intra_thread_exp=sched_before_intra_thread_exp, + sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) # ------------------------------------------------------------------------------ @@ -181,7 +181,7 @@ def test_pairwise_schedule_creation(): # Create expected maps and compare - sched_before_seq_exp = isl.Map( + sched_before_intra_thread_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -189,7 +189,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_seq_exp = isl.Map( + sched_after_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -199,8 +199,8 @@ def test_pairwise_schedule_creation(): _check_sio_for_stmt_pair( "stmt_a", "stmt_c", scheds, - sched_before_seq_exp=sched_before_seq_exp, - sched_after_seq_exp=sched_after_seq_exp, + sched_before_intra_thread_exp=sched_before_intra_thread_exp, + sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) # ------------------------------------------------------------------------------ @@ -208,7 +208,7 @@ def test_pairwise_schedule_creation(): # Create expected maps and compare - sched_before_seq_exp = isl.Map( + sched_before_intra_thread_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -216,7 +216,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_seq_exp = isl.Map( + sched_after_intra_thread_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -226,8 +226,8 @@ def test_pairwise_schedule_creation(): _check_sio_for_stmt_pair( "stmt_a", "stmt_d", scheds, - sched_before_seq_exp=sched_before_seq_exp, - sched_after_seq_exp=sched_after_seq_exp, + sched_before_intra_thread_exp=sched_before_intra_thread_exp, + sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) # ------------------------------------------------------------------------------ @@ -235,7 +235,7 @@ def test_pairwise_schedule_creation(): # Create expected maps and compare - sched_before_seq_exp = isl.Map( + sched_before_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -243,7 +243,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_seq_exp = isl.Map( + sched_after_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -253,8 +253,8 @@ def test_pairwise_schedule_creation(): _check_sio_for_stmt_pair( "stmt_b", "stmt_c", scheds, - sched_before_seq_exp=sched_before_seq_exp, - sched_after_seq_exp=sched_after_seq_exp, + sched_before_intra_thread_exp=sched_before_intra_thread_exp, + sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) # ------------------------------------------------------------------------------ @@ -262,7 +262,7 @@ def test_pairwise_schedule_creation(): # Create expected maps and compare - sched_before_seq_exp = isl.Map( + sched_before_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -270,7 +270,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_seq_exp = isl.Map( + sched_after_intra_thread_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -280,8 +280,8 @@ def test_pairwise_schedule_creation(): _check_sio_for_stmt_pair( "stmt_b", "stmt_d", scheds, - sched_before_seq_exp=sched_before_seq_exp, - sched_after_seq_exp=sched_after_seq_exp, + sched_before_intra_thread_exp=sched_before_intra_thread_exp, + sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) # ------------------------------------------------------------------------------ @@ -289,7 +289,7 @@ def test_pairwise_schedule_creation(): # Create expected maps and compare - sched_before_seq_exp = isl.Map( + sched_before_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -297,7 +297,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_seq_exp = isl.Map( + sched_after_intra_thread_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -307,8 +307,8 @@ def test_pairwise_schedule_creation(): _check_sio_for_stmt_pair( "stmt_c", "stmt_d", scheds, - sched_before_seq_exp=sched_before_seq_exp, - sched_after_seq_exp=sched_after_seq_exp, + sched_before_intra_thread_exp=sched_before_intra_thread_exp, + sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) @@ -360,7 +360,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): # Create expected maps and compare - sched_before_seq_exp = isl.Map( + sched_before_intra_thread_exp = isl.Map( "[pi,pj] -> {[%s=0,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, @@ -371,7 +371,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): ) ) - sched_after_seq_exp = isl.Map( + sched_after_intra_thread_exp = isl.Map( "[pi,pj] -> {[%s=1,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, @@ -384,8 +384,8 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): _check_sio_for_stmt_pair( "stmt_a", "stmt_b", scheds, - sched_before_seq_exp=sched_before_seq_exp, - sched_after_seq_exp=sched_after_seq_exp, + sched_before_intra_thread_exp=sched_before_intra_thread_exp, + sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) # ------------------------------------------------------------------------------ @@ -447,24 +447,27 @@ def _check_sio_for_stmt_pair( stmt_id_before, stmt_id_after, all_sios, - sio_seq_exp=None, - sched_before_seq_exp=None, - sched_after_seq_exp=None, - sio_lconc_exp=None, - sched_before_lconc_exp=None, - sched_after_lconc_exp=None, - sio_gconc_exp=None, - sched_before_gconc_exp=None, - sched_after_gconc_exp=None, + sio_intra_thread_exp=None, + sched_before_intra_thread_exp=None, + sched_after_intra_thread_exp=None, + sio_intra_group_exp=None, + sched_before_intra_group_exp=None, + sched_after_intra_group_exp=None, + sio_global_exp=None, + sched_before_global_exp=None, + sched_after_global_exp=None, ): order_info = all_sios[(stmt_id_before, stmt_id_after)] # Get pairs of maps to compare for equality map_candidates = zip([ - sio_seq_exp, sched_before_seq_exp, sched_after_seq_exp, - sio_lconc_exp, sched_before_lconc_exp, sched_after_lconc_exp, - sio_gconc_exp, sched_before_gconc_exp, sched_after_gconc_exp, + sio_intra_thread_exp, + sched_before_intra_thread_exp, sched_after_intra_thread_exp, + sio_intra_group_exp, + sched_before_intra_group_exp, sched_after_intra_group_exp, + sio_global_exp, + sched_before_global_exp, sched_after_global_exp, ], [ order_info.sio_intra_thread, order_info.pwsched_intra_thread[0], order_info.pwsched_intra_thread[1], @@ -538,40 +541,43 @@ def test_statement_instance_ordering(): # Relationship between stmt_a and stmt_b --------------------------------------- - sio_seq_exp = _isl_map_with_marked_dims( + sio_intra_thread_exp = _isl_map_with_marked_dims( "[pi, pj, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= k' < pk and 0 <= j < pj and i >= i' " "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_a", "stmt_b", scheds, sio_seq_exp=sio_seq_exp) + _check_sio_for_stmt_pair( + "stmt_a", "stmt_b", scheds, sio_intra_thread_exp=sio_intra_thread_exp) # Relationship between stmt_a and stmt_c --------------------------------------- - sio_seq_exp = _isl_map_with_marked_dims( + sio_intra_thread_exp = _isl_map_with_marked_dims( "[pi, pj, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= k' < pk and 0 <= j < pj and i >= i' " "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_a", "stmt_c", scheds, sio_seq_exp=sio_seq_exp) + _check_sio_for_stmt_pair( + "stmt_a", "stmt_c", scheds, sio_intra_thread_exp=sio_intra_thread_exp) # Relationship between stmt_a and stmt_d --------------------------------------- - sio_seq_exp = _isl_map_with_marked_dims( + sio_intra_thread_exp = _isl_map_with_marked_dims( "[pt, pi, pk] -> {{ " "[{0}'=0, i', k'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= k' < pk and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_a", "stmt_d", scheds, sio_seq_exp=sio_seq_exp) + _check_sio_for_stmt_pair( + "stmt_a", "stmt_d", scheds, sio_intra_thread_exp=sio_intra_thread_exp) # Relationship between stmt_b and stmt_c --------------------------------------- - sio_seq_exp = _isl_map_with_marked_dims( + sio_intra_thread_exp = _isl_map_with_marked_dims( "[pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, i, j] : " "0 <= i,i' < pi and 0 <= j,j' < pj and i > i'; " @@ -580,29 +586,32 @@ def test_statement_instance_ordering(): "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_b", "stmt_c", scheds, sio_seq_exp=sio_seq_exp) + _check_sio_for_stmt_pair( + "stmt_b", "stmt_c", scheds, sio_intra_thread_exp=sio_intra_thread_exp) # Relationship between stmt_b and stmt_d --------------------------------------- - sio_seq_exp = _isl_map_with_marked_dims( + sio_intra_thread_exp = _isl_map_with_marked_dims( "[pt, pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_b", "stmt_d", scheds, sio_seq_exp=sio_seq_exp) + _check_sio_for_stmt_pair( + "stmt_b", "stmt_d", scheds, sio_intra_thread_exp=sio_intra_thread_exp) # Relationship between stmt_c and stmt_d --------------------------------------- - sio_seq_exp = _isl_map_with_marked_dims( + sio_intra_thread_exp = _isl_map_with_marked_dims( "[pt, pi, pj] -> {{ " "[{0}'=0, i', j'] -> [{0}=1, t] : " "0 <= i' < pi and 0 <= j' < pj and 0 <= t < pt " "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair("stmt_c", "stmt_d", scheds, sio_seq_exp=sio_seq_exp) + _check_sio_for_stmt_pair( + "stmt_c", "stmt_d", scheds, sio_intra_thread_exp=sio_intra_thread_exp) def test_statement_instance_ordering_with_hw_par_tags(): @@ -660,7 +669,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): # Relationship between stmt_a and stmt_b --------------------------------------- - sio_seq_exp = _isl_map_with_marked_dims( + sio_intra_thread_exp = _isl_map_with_marked_dims( "[pi, pj] -> {{ " "[{0}'=0, i', ii', j', jj'] -> [{0}=1, i, ii, j, jj] : " "0 <= i,ii,i',ii' < pi and 0 <= j,jj,j',jj' < pj and ii >= ii' " @@ -671,7 +680,8 @@ def test_statement_instance_ordering_with_hw_par_tags(): ) ) - _check_sio_for_stmt_pair("stmt_a", "stmt_b", scheds, sio_seq_exp=sio_seq_exp) + _check_sio_for_stmt_pair( + "stmt_a", "stmt_b", scheds, sio_intra_thread_exp=sio_intra_thread_exp) # ------------------------------------------------------------------------------ @@ -740,7 +750,7 @@ def test_sios_and_schedules_with_barriers(): conc_iname_bound_str = "0 <= l0,l1,g0 < lg_end" conc_iname_bound_str_p = "0 <= l0',l1',g0' < lg_end" - sched_before_lconc_exp = isl.Map( + sched_before_intra_group_exp = isl.Map( "[ij_start, ij_end, lg_end] -> {" "[%s=0, i, j, l0, l1, g0] -> [%s] : " "%s and %s}" # iname bounds @@ -755,7 +765,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_after_lconc_exp = isl.Map( + sched_after_intra_group_exp = isl.Map( "[lg_end] -> {[%s=1, l0, l1, g0] -> [%s] : %s}" % ( STATEMENT_VAR_NAME, @@ -767,7 +777,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sio_lconc_exp = _isl_map_with_marked_dims( + sio_intra_group_exp = _isl_map_with_marked_dims( "[ij_start, ij_end, lg_end] -> {{ " "[{0}'=0, i', j', l0', l1', g0'] -> [{0}=1, l0, l1, g0] : " "(ij_start <= j' < ij_end-1 or " # not last iteration of j @@ -784,7 +794,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_before_gconc_exp = isl.Map( + sched_before_global_exp = isl.Map( "[ij_start, ij_end, lg_end] -> {" "[%s=0, i, j, l0, l1, g0] -> [%s] : " "%s and %s}" # iname bounds @@ -799,7 +809,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_after_gconc_exp = isl.Map( + sched_after_global_exp = isl.Map( "[lg_end] -> {[%s=1, l0, l1, g0] -> [%s] : " "%s}" # iname bounds % ( @@ -812,7 +822,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sio_gconc_exp = _isl_map_with_marked_dims( + sio_global_exp = _isl_map_with_marked_dims( "[ij_start,ij_end,lg_end] -> {{ " "[{0}'=0, i', j', l0', l1', g0'] -> [{0}=1, l0, l1, g0] : " "ij_start <= i' < ij_end-1 " # not last iteration of i @@ -829,15 +839,15 @@ def test_sios_and_schedules_with_barriers(): _check_sio_for_stmt_pair( "j1", "2", scheds, - sio_lconc_exp=sio_lconc_exp, - sched_before_lconc_exp=sched_before_lconc_exp, - sched_after_lconc_exp=sched_after_lconc_exp, - sio_gconc_exp=sio_gconc_exp, - sched_before_gconc_exp=sched_before_gconc_exp, - sched_after_gconc_exp=sched_after_gconc_exp, + sio_intra_group_exp=sio_intra_group_exp, + sched_before_intra_group_exp=sched_before_intra_group_exp, + sched_after_intra_group_exp=sched_after_intra_group_exp, + sio_global_exp=sio_global_exp, + sched_before_global_exp=sched_before_global_exp, + sched_after_global_exp=sched_after_global_exp, ) - # Check for some key example pairs in the sio_lconc map + # Check for some key example pairs in the sio_intra_group map # Get maps order_info = scheds[("j1", "2")] @@ -894,7 +904,7 @@ def test_sios_and_schedules_with_barriers(): # Create expected maps and compare - sched_before_lconc_exp = isl.Map( + sched_before_intra_group_exp = isl.Map( "[lg_end] -> {[%s=0, l0, l1, g0] -> [%s] : " "%s}" # iname bounds % ( @@ -907,7 +917,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_after_lconc_exp = isl.Map( + sched_after_intra_group_exp = isl.Map( "[ij_start, ij_end, lg_end] -> {" "[%s=1, i, j, l0, l1, g0] -> [%s] : " "%s and %s}" # iname bounds @@ -922,7 +932,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sio_lconc_exp = _isl_map_with_marked_dims( + sio_intra_group_exp = _isl_map_with_marked_dims( "[ij_start, ij_end, lg_end] -> {{ " "[{0}'=0, l0', l1', g0'] -> [{0}=1, i, j, l0, l1, g0] : " "ij_start + 1 <= i < ij_end " # not first iteration of i @@ -938,7 +948,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_before_gconc_exp = isl.Map( + sched_before_global_exp = isl.Map( "[lg_end] -> {[%s=0, l0, l1, g0] -> [%s] : " "%s}" # iname bounds % ( @@ -951,7 +961,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_after_gconc_exp = isl.Map( + sched_after_global_exp = isl.Map( "[ij_start, ij_end, lg_end] -> {" "[%s=1, i, j, l0, l1, g0] -> [%s] : " "%s and %s}" # iname bounds @@ -966,7 +976,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sio_gconc_exp = _isl_map_with_marked_dims( + sio_global_exp = _isl_map_with_marked_dims( "[ij_start, ij_end, lg_end] -> {{ " "[{0}'=0, l0', l1', g0'] -> [{0}=1, i, j, l0, l1, g0] : " "ij_start + 1 <= i < ij_end " # not first iteration of i @@ -983,12 +993,12 @@ def test_sios_and_schedules_with_barriers(): _check_sio_for_stmt_pair( "1", "i0", scheds, - sio_lconc_exp=sio_lconc_exp, - sched_before_lconc_exp=sched_before_lconc_exp, - sched_after_lconc_exp=sched_after_lconc_exp, - sio_gconc_exp=sio_gconc_exp, - sched_before_gconc_exp=sched_before_gconc_exp, - sched_after_gconc_exp=sched_after_gconc_exp, + sio_intra_group_exp=sio_intra_group_exp, + sched_before_intra_group_exp=sched_before_intra_group_exp, + sched_after_intra_group_exp=sched_after_intra_group_exp, + sio_global_exp=sio_global_exp, + sched_before_global_exp=sched_before_global_exp, + sched_after_global_exp=sched_after_global_exp, ) # }}} From 7dd60a50e45274413d060ff9e1a6628166fef8d1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 1 Apr 2021 00:02:03 -0500 Subject: [PATCH 082/220] fix documentation --- loopy/schedule/checker/__init__.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 1cf8bc4e8..6a2ecb9c5 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -46,9 +46,6 @@ def get_pairwise_statement_orderings( :arg insn_id_pairs: A list containing pairs of instruction identifiers. - :arg return_schedules: A :class:`bool` determining whether to include - pairwise schedules in the returned dictionary. - :returns: A dictionary mapping each two-tuple of instruction identifiers provided in `insn_id_pairs` to a :class:`collections.namedtuple` containing the intra-thread SIO (`sio_intra_thread`), intra-group SIO @@ -77,9 +74,8 @@ def get_pairwise_statement_orderings( >>> knl = lp.add_and_infer_dtypes(knl, {"a": np.float32, "b": np.float32}) >>> # Get a linearization >>> knl = lp.get_one_linearized_kernel(lp.preprocess_kernel(knl)) - >>> # Get a pairwise schedule ----------------------------------------------- + >>> # Get pairwise order info ----------------------------------------------- >>> from loopy.schedule.checker import get_pairwise_statement_orderings - >>> # Get two maps ---------------------------------------------------------- >>> sio_dict = get_pairwise_statement_orderings( ... knl, ... knl.linearization, From 2f97cc958eaf12bd640e7c704c7305ad474f6512 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 1 Apr 2021 00:02:53 -0500 Subject: [PATCH 083/220] more variable renaming to clarify output from get_pairwise_statement_orderings() --- test/test_linearization_checker.py | 78 +++++++++++++++--------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index fa8dd58b4..fa197bccd 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -144,7 +144,7 @@ def test_pairwise_schedule_creation(): ("stmt_b", "stmt_d"), ("stmt_c", "stmt_d"), ] - scheds = get_pairwise_statement_orderings( + pworders = get_pairwise_statement_orderings( lin_knl, linearization_items, insn_id_pairs, @@ -170,8 +170,8 @@ def test_pairwise_schedule_creation(): ) ) - _check_sio_for_stmt_pair( - "stmt_a", "stmt_b", scheds, + _check_orderings_for_stmt_pair( + "stmt_a", "stmt_b", pworders, sched_before_intra_thread_exp=sched_before_intra_thread_exp, sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) @@ -197,8 +197,8 @@ def test_pairwise_schedule_creation(): ) ) - _check_sio_for_stmt_pair( - "stmt_a", "stmt_c", scheds, + _check_orderings_for_stmt_pair( + "stmt_a", "stmt_c", pworders, sched_before_intra_thread_exp=sched_before_intra_thread_exp, sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) @@ -224,8 +224,8 @@ def test_pairwise_schedule_creation(): ) ) - _check_sio_for_stmt_pair( - "stmt_a", "stmt_d", scheds, + _check_orderings_for_stmt_pair( + "stmt_a", "stmt_d", pworders, sched_before_intra_thread_exp=sched_before_intra_thread_exp, sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) @@ -251,8 +251,8 @@ def test_pairwise_schedule_creation(): ) ) - _check_sio_for_stmt_pair( - "stmt_b", "stmt_c", scheds, + _check_orderings_for_stmt_pair( + "stmt_b", "stmt_c", pworders, sched_before_intra_thread_exp=sched_before_intra_thread_exp, sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) @@ -278,8 +278,8 @@ def test_pairwise_schedule_creation(): ) ) - _check_sio_for_stmt_pair( - "stmt_b", "stmt_d", scheds, + _check_orderings_for_stmt_pair( + "stmt_b", "stmt_d", pworders, sched_before_intra_thread_exp=sched_before_intra_thread_exp, sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) @@ -305,8 +305,8 @@ def test_pairwise_schedule_creation(): ) ) - _check_sio_for_stmt_pair( - "stmt_c", "stmt_d", scheds, + _check_orderings_for_stmt_pair( + "stmt_c", "stmt_d", pworders, sched_before_intra_thread_exp=sched_before_intra_thread_exp, sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) @@ -350,7 +350,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): stmt_id_pairs = [ ("stmt_a", "stmt_b"), ] - scheds = get_pairwise_statement_orderings( + pworders = get_pairwise_statement_orderings( lin_knl, linearization_items, stmt_id_pairs, @@ -382,8 +382,8 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): ) ) - _check_sio_for_stmt_pair( - "stmt_a", "stmt_b", scheds, + _check_orderings_for_stmt_pair( + "stmt_a", "stmt_b", pworders, sched_before_intra_thread_exp=sched_before_intra_thread_exp, sched_after_intra_thread_exp=sched_after_intra_thread_exp, ) @@ -443,7 +443,7 @@ def _check_lex_map(exp_lex_order_map, n_dims): # {{{ test statement instance ordering creation -def _check_sio_for_stmt_pair( +def _check_orderings_for_stmt_pair( stmt_id_before, stmt_id_after, all_sios, @@ -533,7 +533,7 @@ def test_statement_instance_ordering(): ("stmt_b", "stmt_d"), ("stmt_c", "stmt_d"), ] - scheds = get_pairwise_statement_orderings( + pworders = get_pairwise_statement_orderings( knl, linearization_items, stmt_id_pairs, @@ -548,8 +548,8 @@ def test_statement_instance_ordering(): "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair( - "stmt_a", "stmt_b", scheds, sio_intra_thread_exp=sio_intra_thread_exp) + _check_orderings_for_stmt_pair( + "stmt_a", "stmt_b", pworders, sio_intra_thread_exp=sio_intra_thread_exp) # Relationship between stmt_a and stmt_c --------------------------------------- @@ -560,8 +560,8 @@ def test_statement_instance_ordering(): "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair( - "stmt_a", "stmt_c", scheds, sio_intra_thread_exp=sio_intra_thread_exp) + _check_orderings_for_stmt_pair( + "stmt_a", "stmt_c", pworders, sio_intra_thread_exp=sio_intra_thread_exp) # Relationship between stmt_a and stmt_d --------------------------------------- @@ -572,8 +572,8 @@ def test_statement_instance_ordering(): "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair( - "stmt_a", "stmt_d", scheds, sio_intra_thread_exp=sio_intra_thread_exp) + _check_orderings_for_stmt_pair( + "stmt_a", "stmt_d", pworders, sio_intra_thread_exp=sio_intra_thread_exp) # Relationship between stmt_b and stmt_c --------------------------------------- @@ -586,8 +586,8 @@ def test_statement_instance_ordering(): "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair( - "stmt_b", "stmt_c", scheds, sio_intra_thread_exp=sio_intra_thread_exp) + _check_orderings_for_stmt_pair( + "stmt_b", "stmt_c", pworders, sio_intra_thread_exp=sio_intra_thread_exp) # Relationship between stmt_b and stmt_d --------------------------------------- @@ -598,8 +598,8 @@ def test_statement_instance_ordering(): "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair( - "stmt_b", "stmt_d", scheds, sio_intra_thread_exp=sio_intra_thread_exp) + _check_orderings_for_stmt_pair( + "stmt_b", "stmt_d", pworders, sio_intra_thread_exp=sio_intra_thread_exp) # Relationship between stmt_c and stmt_d --------------------------------------- @@ -610,8 +610,8 @@ def test_statement_instance_ordering(): "}}".format(STATEMENT_VAR_NAME) ) - _check_sio_for_stmt_pair( - "stmt_c", "stmt_d", scheds, sio_intra_thread_exp=sio_intra_thread_exp) + _check_orderings_for_stmt_pair( + "stmt_c", "stmt_d", pworders, sio_intra_thread_exp=sio_intra_thread_exp) def test_statement_instance_ordering_with_hw_par_tags(): @@ -656,7 +656,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): stmt_id_pairs = [ ("stmt_a", "stmt_b"), ] - scheds = get_pairwise_statement_orderings( + pworders = get_pairwise_statement_orderings( lin_knl, linearization_items, stmt_id_pairs, @@ -680,8 +680,8 @@ def test_statement_instance_ordering_with_hw_par_tags(): ) ) - _check_sio_for_stmt_pair( - "stmt_a", "stmt_b", scheds, sio_intra_thread_exp=sio_intra_thread_exp) + _check_orderings_for_stmt_pair( + "stmt_a", "stmt_b", pworders, sio_intra_thread_exp=sio_intra_thread_exp) # ------------------------------------------------------------------------------ @@ -737,7 +737,7 @@ def test_sios_and_schedules_with_barriers(): linearization_items = lin_knl.linearization insn_id_pairs = [("j1", "2"), ("1", "i0")] - scheds = get_pairwise_statement_orderings( + pworders = get_pairwise_statement_orderings( lin_knl, linearization_items, insn_id_pairs) # Relationship between j1 and 2 -------------------------------------------- @@ -837,8 +837,8 @@ def test_sios_and_schedules_with_barriers(): ) ) - _check_sio_for_stmt_pair( - "j1", "2", scheds, + _check_orderings_for_stmt_pair( + "j1", "2", pworders, sio_intra_group_exp=sio_intra_group_exp, sched_before_intra_group_exp=sched_before_intra_group_exp, sched_after_intra_group_exp=sched_after_intra_group_exp, @@ -850,7 +850,7 @@ def test_sios_and_schedules_with_barriers(): # Check for some key example pairs in the sio_intra_group map # Get maps - order_info = scheds[("j1", "2")] + order_info = pworders[("j1", "2")] # As long as this is not the last iteration of the i loop, then there # should be a barrier between the last instance of statement j1 @@ -991,8 +991,8 @@ def test_sios_and_schedules_with_barriers(): ) ) - _check_sio_for_stmt_pair( - "1", "i0", scheds, + _check_orderings_for_stmt_pair( + "1", "i0", pworders, sio_intra_group_exp=sio_intra_group_exp, sched_before_intra_group_exp=sched_before_intra_group_exp, sched_after_intra_group_exp=sched_after_intra_group_exp, From 8091b636fed200ff6602fbdb78828ce8f781ccea Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 4 Apr 2021 20:37:20 -0500 Subject: [PATCH 084/220] in intra-group and global orderings, don't add loop dims to lex order if iname is in loops_to_ignore (vec/ilp) --- loopy/schedule/checker/schedule.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 77a2354ca..4a8d1a479 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -457,7 +457,7 @@ def _gather_blex_ordering_info(sync_kind): for lin_item in lin_items: if isinstance(lin_item, EnterLoop): enter_iname = lin_item.iname - if enter_iname in loops_with_barriers[sync_kind]: + if enter_iname in loops_with_barriers[sync_kind] - loops_to_ignore: pre_loop_blex_pt = next_blex_tuple[:] # Increment next_blex_tuple[-1] for statements in the section @@ -487,7 +487,7 @@ def _gather_blex_ordering_info(sync_kind): elif isinstance(lin_item, LeaveLoop): leave_iname = lin_item.iname - if leave_iname in loops_with_barriers[sync_kind]: + if leave_iname in loops_with_barriers[sync_kind] - loops_to_ignore: # Update max blex dims n_seq_blex_dims = max(n_seq_blex_dims, len(next_blex_tuple)) From 0bf7a6e4549ca1de9715adbfe4530673b2824496 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 4 Apr 2021 20:38:20 -0500 Subject: [PATCH 085/220] add sched/sio test with vec+barrier --- test/test_linearization_checker.py | 219 ++++++++++++++++++++++++++++- 1 file changed, 217 insertions(+), 2 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index fa197bccd..8f6ccb616 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -740,7 +740,7 @@ def test_sios_and_schedules_with_barriers(): pworders = get_pairwise_statement_orderings( lin_knl, linearization_items, insn_id_pairs) - # Relationship between j1 and 2 -------------------------------------------- + # {{{ Relationship between j1 and 2 # Create expected maps and compare @@ -900,7 +900,9 @@ def test_sios_and_schedules_with_barriers(): assert not unwanted_pairs.is_subset(order_info.sio_intra_group) - # Relationship between 1 and i0 -------------------------------------------- + # }}} + + # {{{ Relationship between 1 and i0 # Create expected maps and compare @@ -1001,6 +1003,219 @@ def test_sios_and_schedules_with_barriers(): sched_after_global_exp=sched_after_global_exp, ) + # }}} + +# }}} + + +# {{{ SIOs and schedules with vec tag + +def test_sios_and_schedules_with_vec_and_barriers(): + from loopy.schedule.checker import ( + get_pairwise_statement_orderings, + ) + + knl = lp.make_kernel( + "{[i, j, l0] : 0 <= i < 4 and 0 <= j < n and 0 <= l0 < 32}", + """ + for l0 + for i + for j + b[i,j,l0] = 1 {id=s1} + ... lbarrier {id=b,dep=s1} + c[i,j,l0] = 2 {id=s2, dep=b} + end + end + end + """) + knl = lp.add_and_infer_dtypes(knl, {"b": "float32", "c": "float32"}) + + knl = lp.tag_inames(knl, {"i": "vec", "l0": "l.0"}) + + # Get a linearization + proc_knl = preprocess_kernel(knl) + lin_knl = get_one_linearized_kernel(proc_knl) + linearization_items = lin_knl.linearization + + insn_id_pairs = [("s1", "s2")] + pworders = get_pairwise_statement_orderings( + lin_knl, linearization_items, insn_id_pairs) + + # {{{ Relationship between s1 and s2 + + # Create expected maps and compare + + # Iname bound strings to facilitate creation of expected maps + iname_bound_str = "0 <= i < 4 and 0 <= j < n" + iname_bound_str_p = "0 <= i' < 4 and 0 <= j' < n" + conc_iname_bound_str = "0 <= l0 < 32" + conc_iname_bound_str_p = "0 <= l0' < 32" + + # {{{ Intra-thread + + sched_s1_intra_thread_exp = isl.Map( + "[n] -> {" + "[%s=0, i, j, l0] -> [%s] : " + "%s and %s}" # iname bounds + % ( + STATEMENT_VAR_NAME, + _lex_point_string( + ["j", "0"], # lex points (initial matching dim gets removed) + lid_inames=["l0"], + ), + iname_bound_str, + conc_iname_bound_str, + ) + ) + + sched_s2_intra_thread_exp = isl.Map( + "[n] -> {" + "[%s=1, i, j, l0] -> [%s] : " + "%s and %s}" # iname bounds + % ( + STATEMENT_VAR_NAME, + _lex_point_string( + ["j", "1"], # lex points (initial matching dim gets removed) + lid_inames=["l0"], + ), + iname_bound_str, + conc_iname_bound_str, + ) + ) + + sio_intra_thread_exp = _isl_map_with_marked_dims( + "[n] -> {{ " + "[{0}'=0, i', j', l0'] -> [{0}=1, i, j, l0] : " + "j' <= j " + "and l0 = l0' " # within a single thread + "and {1} and {2} and {3} and {4}" # iname bounds + "}}".format( + STATEMENT_VAR_NAME, + iname_bound_str, + iname_bound_str_p, + conc_iname_bound_str, + conc_iname_bound_str_p, + ) + ) + + # }}} + + # {{{ Intra-group + + # Intra-group scheds would be same due to lbarrier, + # but since lex tuples are not simplified in intra-group/global + # cases, there's an extra lex dim: + + sched_s1_intra_group_exp = isl.Map( + "[n] -> {" + "[%s=0, i, j, l0] -> [%s] : " + "%s and %s}" # iname bounds + % ( + STATEMENT_VAR_NAME, + _lex_point_string( + ["1", "j", "0"], # lex points + lid_inames=["l0"], + ), + iname_bound_str, + conc_iname_bound_str, + ) + ) + + sched_s2_intra_group_exp = isl.Map( + "[n] -> {" + "[%s=1, i, j, l0] -> [%s] : " + "%s and %s}" # iname bounds + % ( + STATEMENT_VAR_NAME, + _lex_point_string( + ["1", "j", "1"], # lex points + lid_inames=["l0"], + ), + iname_bound_str, + conc_iname_bound_str, + ) + ) + + sio_intra_group_exp = _isl_map_with_marked_dims( + "[n] -> {{ " + "[{0}'=0, i', j', l0'] -> [{0}=1, i, j, l0] : " + "j' <= j " + "and {1} and {2} and {3} and {4}" # iname bounds + "}}".format( + STATEMENT_VAR_NAME, + iname_bound_str, + iname_bound_str_p, + conc_iname_bound_str, + conc_iname_bound_str_p, + ) + ) + + # }}} + + # {{{ Global + + sched_s1_global_exp = isl.Map( + "[n] -> {" + "[%s=0, i, j, l0] -> [%s] : " + "%s and %s}" # iname bounds + % ( + STATEMENT_VAR_NAME, + _lex_point_string( + ["0"], # lex points + lid_inames=["l0"], + ), + iname_bound_str, + conc_iname_bound_str, + ) + ) + + # (same as s1 except for statement id because no global barriers) + sched_s2_global_exp = isl.Map( + "[n] -> {" + "[%s=1, i, j, l0] -> [%s] : " + "%s and %s}" # iname bounds + % ( + STATEMENT_VAR_NAME, + _lex_point_string( + ["0"], # lex points + lid_inames=["l0"], + ), + iname_bound_str, + conc_iname_bound_str, + ) + ) + + sio_global_exp = _isl_map_with_marked_dims( + "[n] -> {{ " + "[{0}'=0, i', j', l0'] -> [{0}=1, i, j, l0] : " + "False " + "and {1} and {2} and {3} and {4}" # iname bounds + "}}".format( + STATEMENT_VAR_NAME, + iname_bound_str, + iname_bound_str_p, + conc_iname_bound_str, + conc_iname_bound_str_p, + ) + ) + + # }}} + + _check_orderings_for_stmt_pair( + "s1", "s2", pworders, + sio_intra_thread_exp=sio_intra_thread_exp, + sched_before_intra_thread_exp=sched_s1_intra_thread_exp, + sched_after_intra_thread_exp=sched_s2_intra_thread_exp, + sio_intra_group_exp=sio_intra_group_exp, + sched_before_intra_group_exp=sched_s1_intra_group_exp, + sched_after_intra_group_exp=sched_s2_intra_group_exp, + sio_global_exp=sio_global_exp, + sched_before_global_exp=sched_s1_global_exp, + sched_after_global_exp=sched_s2_global_exp, + ) + + # }}} + # }}} From 81dcaf7c640a9d2399cfcc86d5c81d5d3bbe9bff Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 4 Apr 2021 21:21:39 -0500 Subject: [PATCH 086/220] improve formatting and code readibility --- test/test_linearization_checker.py | 363 ++++++++++++++++------------- 1 file changed, 205 insertions(+), 158 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 8f6ccb616..7c2272c82 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -50,7 +50,7 @@ logger = logging.getLogger(__name__) -# {{{ helper functions for map creation/handling +# {{{ Helper functions for map creation/handling def _align_and_compare_maps(maps): from loopy.schedule.checker.utils import prettier_map_string @@ -88,12 +88,51 @@ def _isl_map_with_marked_dims(s): # Isl ignores the apostrophes in map strings, until they are explicitly added return append_marker_to_isl_map_var_names(isl.Map(s), dt.in_, BEFORE_MARK) + +def _check_orderings_for_stmt_pair( + stmt_id_before, + stmt_id_after, + all_sios, + sio_intra_thread_exp=None, + sched_before_intra_thread_exp=None, + sched_after_intra_thread_exp=None, + sio_intra_group_exp=None, + sched_before_intra_group_exp=None, + sched_after_intra_group_exp=None, + sio_global_exp=None, + sched_before_global_exp=None, + sched_after_global_exp=None, + ): + + order_info = all_sios[(stmt_id_before, stmt_id_after)] + + # Get pairs of maps to compare for equality + map_candidates = zip([ + sio_intra_thread_exp, + sched_before_intra_thread_exp, sched_after_intra_thread_exp, + sio_intra_group_exp, + sched_before_intra_group_exp, sched_after_intra_group_exp, + sio_global_exp, + sched_before_global_exp, sched_after_global_exp, + ], [ + order_info.sio_intra_thread, + order_info.pwsched_intra_thread[0], order_info.pwsched_intra_thread[1], + order_info.sio_intra_group, + order_info.pwsched_intra_group[0], order_info.pwsched_intra_group[1], + order_info.sio_global, + order_info.pwsched_global[0], order_info.pwsched_global[1], + ]) + + # Only compare to maps that were passed + maps_to_compare = [(m1, m2) for m1, m2 in map_candidates if m1 is not None] + _align_and_compare_maps(maps_to_compare) + # }}} -# {{{ test pairwise schedule creation +# {{{ test_intra_thread_pairwise_schedule_creation() -def test_pairwise_schedule_creation(): +def test_intra_thread_pairwise_schedule_creation(): from loopy.schedule.checker import ( get_pairwise_statement_orderings, ) @@ -136,7 +175,7 @@ def test_pairwise_schedule_creation(): lin_knl = get_one_linearized_kernel(proc_knl) linearization_items = lin_knl.linearization - insn_id_pairs = [ + stmt_id_pairs = [ ("stmt_a", "stmt_b"), ("stmt_a", "stmt_c"), ("stmt_a", "stmt_d"), @@ -147,14 +186,14 @@ def test_pairwise_schedule_creation(): pworders = get_pairwise_statement_orderings( lin_knl, linearization_items, - insn_id_pairs, + stmt_id_pairs, ) - # Relationship between stmt_a and stmt_b --------------------------------------- + # {{{ Relationship between stmt_a and stmt_b # Create expected maps and compare - sched_before_intra_thread_exp = isl.Map( + sched_stmt_a_intra_thread_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -162,7 +201,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_intra_thread_exp = isl.Map( + sched_stmt_b_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -172,16 +211,17 @@ def test_pairwise_schedule_creation(): _check_orderings_for_stmt_pair( "stmt_a", "stmt_b", pworders, - sched_before_intra_thread_exp=sched_before_intra_thread_exp, - sched_after_intra_thread_exp=sched_after_intra_thread_exp, + sched_before_intra_thread_exp=sched_stmt_a_intra_thread_exp, + sched_after_intra_thread_exp=sched_stmt_b_intra_thread_exp, ) - # ------------------------------------------------------------------------------ - # Relationship between stmt_a and stmt_c --------------------------------------- + # }}} + + # {{{ Relationship between stmt_a and stmt_c # Create expected maps and compare - sched_before_intra_thread_exp = isl.Map( + sched_stmt_a_intra_thread_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -189,7 +229,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_intra_thread_exp = isl.Map( + sched_stmt_c_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -199,16 +239,17 @@ def test_pairwise_schedule_creation(): _check_orderings_for_stmt_pair( "stmt_a", "stmt_c", pworders, - sched_before_intra_thread_exp=sched_before_intra_thread_exp, - sched_after_intra_thread_exp=sched_after_intra_thread_exp, + sched_before_intra_thread_exp=sched_stmt_a_intra_thread_exp, + sched_after_intra_thread_exp=sched_stmt_c_intra_thread_exp, ) - # ------------------------------------------------------------------------------ - # Relationship between stmt_a and stmt_d --------------------------------------- + # }}} + + # {{{ Relationship between stmt_a and stmt_d # Create expected maps and compare - sched_before_intra_thread_exp = isl.Map( + sched_stmt_a_intra_thread_exp = isl.Map( "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, @@ -216,7 +257,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_intra_thread_exp = isl.Map( + sched_stmt_d_intra_thread_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -226,16 +267,17 @@ def test_pairwise_schedule_creation(): _check_orderings_for_stmt_pair( "stmt_a", "stmt_d", pworders, - sched_before_intra_thread_exp=sched_before_intra_thread_exp, - sched_after_intra_thread_exp=sched_after_intra_thread_exp, + sched_before_intra_thread_exp=sched_stmt_a_intra_thread_exp, + sched_after_intra_thread_exp=sched_stmt_d_intra_thread_exp, ) - # ------------------------------------------------------------------------------ - # Relationship between stmt_b and stmt_c --------------------------------------- + # }}} + + # {{{ Relationship between stmt_b and stmt_c # Create expected maps and compare - sched_before_intra_thread_exp = isl.Map( + sched_stmt_b_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -243,7 +285,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_intra_thread_exp = isl.Map( + sched_stmt_c_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -253,16 +295,17 @@ def test_pairwise_schedule_creation(): _check_orderings_for_stmt_pair( "stmt_b", "stmt_c", pworders, - sched_before_intra_thread_exp=sched_before_intra_thread_exp, - sched_after_intra_thread_exp=sched_after_intra_thread_exp, + sched_before_intra_thread_exp=sched_stmt_b_intra_thread_exp, + sched_after_intra_thread_exp=sched_stmt_c_intra_thread_exp, ) - # ------------------------------------------------------------------------------ - # Relationship between stmt_b and stmt_d --------------------------------------- + # }}} + + # {{{ Relationship between stmt_b and stmt_d # Create expected maps and compare - sched_before_intra_thread_exp = isl.Map( + sched_stmt_b_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -270,7 +313,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_intra_thread_exp = isl.Map( + sched_stmt_d_intra_thread_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -280,16 +323,17 @@ def test_pairwise_schedule_creation(): _check_orderings_for_stmt_pair( "stmt_b", "stmt_d", pworders, - sched_before_intra_thread_exp=sched_before_intra_thread_exp, - sched_after_intra_thread_exp=sched_after_intra_thread_exp, + sched_before_intra_thread_exp=sched_stmt_b_intra_thread_exp, + sched_after_intra_thread_exp=sched_stmt_d_intra_thread_exp, ) - # ------------------------------------------------------------------------------ - # Relationship between stmt_c and stmt_d --------------------------------------- + # }}} + + # {{{ Relationship between stmt_c and stmt_d # Create expected maps and compare - sched_before_intra_thread_exp = isl.Map( + sched_stmt_c_intra_thread_exp = isl.Map( "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, @@ -297,7 +341,7 @@ def test_pairwise_schedule_creation(): ) ) - sched_after_intra_thread_exp = isl.Map( + sched_stmt_d_intra_thread_exp = isl.Map( "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, @@ -307,12 +351,20 @@ def test_pairwise_schedule_creation(): _check_orderings_for_stmt_pair( "stmt_c", "stmt_d", pworders, - sched_before_intra_thread_exp=sched_before_intra_thread_exp, - sched_after_intra_thread_exp=sched_after_intra_thread_exp, + sched_before_intra_thread_exp=sched_stmt_c_intra_thread_exp, + sched_after_intra_thread_exp=sched_stmt_d_intra_thread_exp, ) + # }}} + +# }}} + + +# {{{ test_pairwise_schedule_creation_with_hw_par_tags() def test_pairwise_schedule_creation_with_hw_par_tags(): + # (further sched testing in SIO tests below) + from loopy.schedule.checker import ( get_pairwise_statement_orderings, ) @@ -356,11 +408,11 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): stmt_id_pairs, ) - # Relationship between stmt_a and stmt_b --------------------------------------- + # {{{ Relationship between stmt_a and stmt_b # Create expected maps and compare - sched_before_intra_thread_exp = isl.Map( + sched_stmt_a_intra_thread_exp = isl.Map( "[pi,pj] -> {[%s=0,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, @@ -371,7 +423,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): ) ) - sched_after_intra_thread_exp = isl.Map( + sched_stmt_b_intra_thread_exp = isl.Map( "[pi,pj] -> {[%s=1,i,ii,j,jj] -> [%s] : 0 <= i,ii < pi and 0 <= j,jj < pj}" % ( STATEMENT_VAR_NAME, @@ -384,16 +436,16 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): _check_orderings_for_stmt_pair( "stmt_a", "stmt_b", pworders, - sched_before_intra_thread_exp=sched_before_intra_thread_exp, - sched_after_intra_thread_exp=sched_after_intra_thread_exp, + sched_before_intra_thread_exp=sched_stmt_a_intra_thread_exp, + sched_after_intra_thread_exp=sched_stmt_b_intra_thread_exp, ) - # ------------------------------------------------------------------------------ + # }}} # }}} -# {{{ test lex order map creation +# {{{ test_lex_order_map_creation() def test_lex_order_map_creation(): from loopy.schedule.checker.lexicographic_order_map import ( @@ -441,48 +493,9 @@ def _check_lex_map(exp_lex_order_map, n_dims): # }}} -# {{{ test statement instance ordering creation +# {{{ test_intra_thread_statement_instance_ordering() -def _check_orderings_for_stmt_pair( - stmt_id_before, - stmt_id_after, - all_sios, - sio_intra_thread_exp=None, - sched_before_intra_thread_exp=None, - sched_after_intra_thread_exp=None, - sio_intra_group_exp=None, - sched_before_intra_group_exp=None, - sched_after_intra_group_exp=None, - sio_global_exp=None, - sched_before_global_exp=None, - sched_after_global_exp=None, - ): - - order_info = all_sios[(stmt_id_before, stmt_id_after)] - - # Get pairs of maps to compare for equality - map_candidates = zip([ - sio_intra_thread_exp, - sched_before_intra_thread_exp, sched_after_intra_thread_exp, - sio_intra_group_exp, - sched_before_intra_group_exp, sched_after_intra_group_exp, - sio_global_exp, - sched_before_global_exp, sched_after_global_exp, - ], [ - order_info.sio_intra_thread, - order_info.pwsched_intra_thread[0], order_info.pwsched_intra_thread[1], - order_info.sio_intra_group, - order_info.pwsched_intra_group[0], order_info.pwsched_intra_group[1], - order_info.sio_global, - order_info.pwsched_global[0], order_info.pwsched_global[1], - ]) - - # Only compare to maps that were passed - maps_to_compare = [(m1, m2) for m1, m2 in map_candidates if m1 is not None] - _align_and_compare_maps(maps_to_compare) - - -def test_statement_instance_ordering(): +def test_intra_thread_statement_instance_ordering(): from loopy.schedule.checker import ( get_pairwise_statement_orderings, ) @@ -539,7 +552,7 @@ def test_statement_instance_ordering(): stmt_id_pairs, ) - # Relationship between stmt_a and stmt_b --------------------------------------- + # {{{ Relationship between stmt_a and stmt_b sio_intra_thread_exp = _isl_map_with_marked_dims( "[pi, pj, pk] -> {{ " @@ -551,7 +564,9 @@ def test_statement_instance_ordering(): _check_orderings_for_stmt_pair( "stmt_a", "stmt_b", pworders, sio_intra_thread_exp=sio_intra_thread_exp) - # Relationship between stmt_a and stmt_c --------------------------------------- + # }}} + + # {{{ Relationship between stmt_a and stmt_c sio_intra_thread_exp = _isl_map_with_marked_dims( "[pi, pj, pk] -> {{ " @@ -563,7 +578,9 @@ def test_statement_instance_ordering(): _check_orderings_for_stmt_pair( "stmt_a", "stmt_c", pworders, sio_intra_thread_exp=sio_intra_thread_exp) - # Relationship between stmt_a and stmt_d --------------------------------------- + # }}} + + # {{{ Relationship between stmt_a and stmt_d sio_intra_thread_exp = _isl_map_with_marked_dims( "[pt, pi, pk] -> {{ " @@ -575,7 +592,9 @@ def test_statement_instance_ordering(): _check_orderings_for_stmt_pair( "stmt_a", "stmt_d", pworders, sio_intra_thread_exp=sio_intra_thread_exp) - # Relationship between stmt_b and stmt_c --------------------------------------- + # }}} + + # {{{ Relationship between stmt_b and stmt_c sio_intra_thread_exp = _isl_map_with_marked_dims( "[pi, pj] -> {{ " @@ -589,7 +608,9 @@ def test_statement_instance_ordering(): _check_orderings_for_stmt_pair( "stmt_b", "stmt_c", pworders, sio_intra_thread_exp=sio_intra_thread_exp) - # Relationship between stmt_b and stmt_d --------------------------------------- + # }}} + + # {{{ Relationship between stmt_b and stmt_d sio_intra_thread_exp = _isl_map_with_marked_dims( "[pt, pi, pj] -> {{ " @@ -601,7 +622,9 @@ def test_statement_instance_ordering(): _check_orderings_for_stmt_pair( "stmt_b", "stmt_d", pworders, sio_intra_thread_exp=sio_intra_thread_exp) - # Relationship between stmt_c and stmt_d --------------------------------------- + # }}} + + # {{{ Relationship between stmt_c and stmt_d sio_intra_thread_exp = _isl_map_with_marked_dims( "[pt, pi, pj] -> {{ " @@ -613,6 +636,12 @@ def test_statement_instance_ordering(): _check_orderings_for_stmt_pair( "stmt_c", "stmt_d", pworders, sio_intra_thread_exp=sio_intra_thread_exp) + # }}} + +# }}} + + +# {{{ test_statement_instance_ordering_with_hw_par_tags() def test_statement_instance_ordering_with_hw_par_tags(): from loopy.schedule.checker import ( @@ -667,7 +696,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): par_iname_condition = " and ".join( "{0} = {0}'".format(iname) for iname in conc_inames) - # Relationship between stmt_a and stmt_b --------------------------------------- + # {{{ Relationship between stmt_a and stmt_b sio_intra_thread_exp = _isl_map_with_marked_dims( "[pi, pj] -> {{ " @@ -683,12 +712,12 @@ def test_statement_instance_ordering_with_hw_par_tags(): _check_orderings_for_stmt_pair( "stmt_a", "stmt_b", pworders, sio_intra_thread_exp=sio_intra_thread_exp) - # ------------------------------------------------------------------------------ + # }}} # }}} -# {{{ SIOs and schedules with barriers +# {{{ test_sios_and_schedules_with_barriers() def test_sios_and_schedules_with_barriers(): from loopy.schedule.checker import ( @@ -705,22 +734,22 @@ def test_sios_and_schedules_with_barriers(): for g0 for l0 for l1 - <>temp0 = 0 {id=0} - ... lbarrier {id=b0,dep=0} - <>temp1 = 1 {id=1,dep=b0} + <>temp0 = 0 {id=stmt_0} + ... lbarrier {id=stmt_b0,dep=stmt_0} + <>temp1 = 1 {id=stmt_1,dep=stmt_b0} for i - <>tempi0 = 0 {id=i0,dep=1} - ... lbarrier {id=ib0,dep=i0} - ... gbarrier {id=ibb0,dep=i0} - <>tempi1 = 0 {id=i1,dep=ib0} - <>tempi2 = 0 {id=i2,dep=i1} + <>tempi0 = 0 {id=stmt_i0,dep=stmt_1} + ... lbarrier {id=stmt_ib0,dep=stmt_i0} + ... gbarrier {id=stmt_ibb0,dep=stmt_i0} + <>tempi1 = 0 {id=stmt_i1,dep=stmt_ib0} + <>tempi2 = 0 {id=stmt_i2,dep=stmt_i1} for j - <>tempj0 = 0 {id=j0,dep=i2} - ... lbarrier {id=jb0,dep=j0} - <>tempj1 = 0 {id=j1,dep=jb0} + <>tempj0 = 0 {id=stmt_j0,dep=stmt_i2} + ... lbarrier {id=stmt_jb0,dep=stmt_j0} + <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} end end - <>temp2 = 0 {id=2,dep=i0} + <>temp2 = 0 {id=stmt_2,dep=stmt_i0} end end end @@ -736,11 +765,11 @@ def test_sios_and_schedules_with_barriers(): lin_knl = get_one_linearized_kernel(proc_knl) linearization_items = lin_knl.linearization - insn_id_pairs = [("j1", "2"), ("1", "i0")] + stmt_id_pairs = [("stmt_j1", "stmt_2"), ("stmt_1", "stmt_i0")] pworders = get_pairwise_statement_orderings( - lin_knl, linearization_items, insn_id_pairs) + lin_knl, linearization_items, stmt_id_pairs) - # {{{ Relationship between j1 and 2 + # {{{ Relationship between stmt_j1 and stmt_2 # Create expected maps and compare @@ -750,7 +779,9 @@ def test_sios_and_schedules_with_barriers(): conc_iname_bound_str = "0 <= l0,l1,g0 < lg_end" conc_iname_bound_str_p = "0 <= l0',l1',g0' < lg_end" - sched_before_intra_group_exp = isl.Map( + # {{{ Intra-group + + sched_stmt_j1_intra_group_exp = isl.Map( "[ij_start, ij_end, lg_end] -> {" "[%s=0, i, j, l0, l1, g0] -> [%s] : " "%s and %s}" # iname bounds @@ -765,7 +796,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_after_intra_group_exp = isl.Map( + sched_stmt_2_intra_group_exp = isl.Map( "[lg_end] -> {[%s=1, l0, l1, g0] -> [%s] : %s}" % ( STATEMENT_VAR_NAME, @@ -794,7 +825,11 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_before_global_exp = isl.Map( + # }}} + + # {{{ Global + + sched_stmt_j1_global_exp = isl.Map( "[ij_start, ij_end, lg_end] -> {" "[%s=0, i, j, l0, l1, g0] -> [%s] : " "%s and %s}" # iname bounds @@ -809,7 +844,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_after_global_exp = isl.Map( + sched_stmt_2_global_exp = isl.Map( "[lg_end] -> {[%s=1, l0, l1, g0] -> [%s] : " "%s}" # iname bounds % ( @@ -837,24 +872,26 @@ def test_sios_and_schedules_with_barriers(): ) ) + # }}} + _check_orderings_for_stmt_pair( - "j1", "2", pworders, + "stmt_j1", "stmt_2", pworders, sio_intra_group_exp=sio_intra_group_exp, - sched_before_intra_group_exp=sched_before_intra_group_exp, - sched_after_intra_group_exp=sched_after_intra_group_exp, + sched_before_intra_group_exp=sched_stmt_j1_intra_group_exp, + sched_after_intra_group_exp=sched_stmt_2_intra_group_exp, sio_global_exp=sio_global_exp, - sched_before_global_exp=sched_before_global_exp, - sched_after_global_exp=sched_after_global_exp, + sched_before_global_exp=sched_stmt_j1_global_exp, + sched_after_global_exp=sched_stmt_2_global_exp, ) - # Check for some key example pairs in the sio_intra_group map + # {{{ Check for some key example pairs in the sio_intra_group map # Get maps - order_info = pworders[("j1", "2")] + order_info = pworders[("stmt_j1", "stmt_2")] # As long as this is not the last iteration of the i loop, then there - # should be a barrier between the last instance of statement j1 - # and statement 2: + # should be a barrier between the last instance of statement stmt_j1 + # and statement stmt_2: ij_end_val = 7 last_i_val = ij_end_val - 1 max_non_last_i_val = last_i_val - 1 # max i val that isn't the last iteration @@ -879,8 +916,8 @@ def test_sios_and_schedules_with_barriers(): assert wanted_pairs.is_subset(order_info.sio_intra_group) # If this IS the last iteration of the i loop, then there - # should NOT be a barrier between the last instance of statement j1 - # and statement 2: + # should NOT be a barrier between the last instance of statement stmt_j1 + # and statement stmt_2: unwanted_pairs = _isl_map_with_marked_dims( "[ij_start, ij_end, lg_end] -> {{" "[{0}' = 0, i', j'=ij_end-1, g0', l0', l1'] -> [{0} = 1, l0, l1, g0] : " @@ -902,11 +939,15 @@ def test_sios_and_schedules_with_barriers(): # }}} - # {{{ Relationship between 1 and i0 + # }}} + + # {{{ Relationship between stmt_1 and stmt_i0 # Create expected maps and compare - sched_before_intra_group_exp = isl.Map( + # {{{ Intra-group + + sched_stmt_1_intra_group_exp = isl.Map( "[lg_end] -> {[%s=0, l0, l1, g0] -> [%s] : " "%s}" # iname bounds % ( @@ -919,7 +960,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_after_intra_group_exp = isl.Map( + sched_stmt_i0_intra_group_exp = isl.Map( "[ij_start, ij_end, lg_end] -> {" "[%s=1, i, j, l0, l1, g0] -> [%s] : " "%s and %s}" # iname bounds @@ -950,7 +991,11 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_before_global_exp = isl.Map( + # }}} + + # {{{ Global + + sched_stmt_1_global_exp = isl.Map( "[lg_end] -> {[%s=0, l0, l1, g0] -> [%s] : " "%s}" # iname bounds % ( @@ -963,7 +1008,7 @@ def test_sios_and_schedules_with_barriers(): ) ) - sched_after_global_exp = isl.Map( + sched_stmt_i0_global_exp = isl.Map( "[ij_start, ij_end, lg_end] -> {" "[%s=1, i, j, l0, l1, g0] -> [%s] : " "%s and %s}" # iname bounds @@ -993,14 +1038,16 @@ def test_sios_and_schedules_with_barriers(): ) ) + # }}} + _check_orderings_for_stmt_pair( - "1", "i0", pworders, + "stmt_1", "stmt_i0", pworders, sio_intra_group_exp=sio_intra_group_exp, - sched_before_intra_group_exp=sched_before_intra_group_exp, - sched_after_intra_group_exp=sched_after_intra_group_exp, + sched_before_intra_group_exp=sched_stmt_1_intra_group_exp, + sched_after_intra_group_exp=sched_stmt_i0_intra_group_exp, sio_global_exp=sio_global_exp, - sched_before_global_exp=sched_before_global_exp, - sched_after_global_exp=sched_after_global_exp, + sched_before_global_exp=sched_stmt_1_global_exp, + sched_after_global_exp=sched_stmt_i0_global_exp, ) # }}} @@ -1008,7 +1055,7 @@ def test_sios_and_schedules_with_barriers(): # }}} -# {{{ SIOs and schedules with vec tag +# {{{ test_sios_and_schedules_with_vec_and_barriers() def test_sios_and_schedules_with_vec_and_barriers(): from loopy.schedule.checker import ( @@ -1021,9 +1068,9 @@ def test_sios_and_schedules_with_vec_and_barriers(): for l0 for i for j - b[i,j,l0] = 1 {id=s1} - ... lbarrier {id=b,dep=s1} - c[i,j,l0] = 2 {id=s2, dep=b} + b[i,j,l0] = 1 {id=stmt_1} + ... lbarrier {id=b,dep=stmt_1} + c[i,j,l0] = 2 {id=stmt_2, dep=b} end end end @@ -1037,11 +1084,11 @@ def test_sios_and_schedules_with_vec_and_barriers(): lin_knl = get_one_linearized_kernel(proc_knl) linearization_items = lin_knl.linearization - insn_id_pairs = [("s1", "s2")] + stmt_id_pairs = [("stmt_1", "stmt_2")] pworders = get_pairwise_statement_orderings( - lin_knl, linearization_items, insn_id_pairs) + lin_knl, linearization_items, stmt_id_pairs) - # {{{ Relationship between s1 and s2 + # {{{ Relationship between stmt_1 and stmt_2 # Create expected maps and compare @@ -1053,7 +1100,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): # {{{ Intra-thread - sched_s1_intra_thread_exp = isl.Map( + sched_stmt_1_intra_thread_exp = isl.Map( "[n] -> {" "[%s=0, i, j, l0] -> [%s] : " "%s and %s}" # iname bounds @@ -1068,7 +1115,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): ) ) - sched_s2_intra_thread_exp = isl.Map( + sched_stmt_2_intra_thread_exp = isl.Map( "[n] -> {" "[%s=1, i, j, l0] -> [%s] : " "%s and %s}" # iname bounds @@ -1106,7 +1153,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): # but since lex tuples are not simplified in intra-group/global # cases, there's an extra lex dim: - sched_s1_intra_group_exp = isl.Map( + sched_stmt_1_intra_group_exp = isl.Map( "[n] -> {" "[%s=0, i, j, l0] -> [%s] : " "%s and %s}" # iname bounds @@ -1121,7 +1168,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): ) ) - sched_s2_intra_group_exp = isl.Map( + sched_stmt_2_intra_group_exp = isl.Map( "[n] -> {" "[%s=1, i, j, l0] -> [%s] : " "%s and %s}" # iname bounds @@ -1154,7 +1201,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): # {{{ Global - sched_s1_global_exp = isl.Map( + sched_stmt_1_global_exp = isl.Map( "[n] -> {" "[%s=0, i, j, l0] -> [%s] : " "%s and %s}" # iname bounds @@ -1169,8 +1216,8 @@ def test_sios_and_schedules_with_vec_and_barriers(): ) ) - # (same as s1 except for statement id because no global barriers) - sched_s2_global_exp = isl.Map( + # (same as stmt_1 except for statement id because no global barriers) + sched_stmt_2_global_exp = isl.Map( "[n] -> {" "[%s=1, i, j, l0] -> [%s] : " "%s and %s}" # iname bounds @@ -1202,16 +1249,16 @@ def test_sios_and_schedules_with_vec_and_barriers(): # }}} _check_orderings_for_stmt_pair( - "s1", "s2", pworders, + "stmt_1", "stmt_2", pworders, sio_intra_thread_exp=sio_intra_thread_exp, - sched_before_intra_thread_exp=sched_s1_intra_thread_exp, - sched_after_intra_thread_exp=sched_s2_intra_thread_exp, + sched_before_intra_thread_exp=sched_stmt_1_intra_thread_exp, + sched_after_intra_thread_exp=sched_stmt_2_intra_thread_exp, sio_intra_group_exp=sio_intra_group_exp, - sched_before_intra_group_exp=sched_s1_intra_group_exp, - sched_after_intra_group_exp=sched_s2_intra_group_exp, + sched_before_intra_group_exp=sched_stmt_1_intra_group_exp, + sched_after_intra_group_exp=sched_stmt_2_intra_group_exp, sio_global_exp=sio_global_exp, - sched_before_global_exp=sched_s1_global_exp, - sched_after_global_exp=sched_s2_global_exp, + sched_before_global_exp=sched_stmt_1_global_exp, + sched_after_global_exp=sched_stmt_2_global_exp, ) # }}} From ff0155e75a21063df2b004e8ff1ae7926fbbd361 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 4 Apr 2021 22:33:30 -0500 Subject: [PATCH 087/220] var renaming instruction->statement --- loopy/schedule/checker/__init__.py | 18 ++++----- loopy/schedule/checker/schedule.py | 62 +++++++++++++++--------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 6a2ecb9c5..5a492660b 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -26,7 +26,7 @@ def get_pairwise_statement_orderings( knl, lin_items, - insn_id_pairs, + stmt_id_pairs, ): r"""For each statement pair in a subset of all statement pairs found in a linearized kernel, determine the (relative) order in which the statement @@ -44,10 +44,10 @@ def get_pairwise_statement_orderings( this routine during linearization, a truncated (i.e. partial) linearization may be passed through this argument. - :arg insn_id_pairs: A list containing pairs of instruction identifiers. + :arg stmt_id_pairs: A list containing pairs of statement identifiers. - :returns: A dictionary mapping each two-tuple of instruction identifiers - provided in `insn_id_pairs` to a :class:`collections.namedtuple` + :returns: A dictionary mapping each two-tuple of statement identifiers + provided in `stmt_id_pairs` to a :class:`collections.namedtuple` containing the intra-thread SIO (`sio_intra_thread`), intra-group SIO (`sio_intra_group`), and global SIO (`sio_global`), each realized as an :class:`islpy.Map` from each instance of the first @@ -68,8 +68,8 @@ def get_pairwise_statement_orderings( >>> knl = lp.make_kernel( ... "{[j,k]: 0<=j>> knl = lp.add_and_infer_dtypes(knl, {"a": np.float32, "b": np.float32}) >>> # Get a linearization @@ -79,10 +79,10 @@ def get_pairwise_statement_orderings( >>> sio_dict = get_pairwise_statement_orderings( ... knl, ... knl.linearization, - ... [("insn_a", "insn_b")], + ... [("stmt_a", "stmt_b")], ... ) >>> # Print map - >>> print(str(sio_dict[("insn_a", "insn_b")].sio_intra_thread + >>> print(str(sio_dict[("stmt_a", "stmt_b")].sio_intra_thread ... ).replace("{ ", "{\n").replace(" :", "\n:")) [pj, pk] -> { [_lp_linchk_stmt' = 0, j', k'] -> [_lp_linchk_stmt = 1, j, k] @@ -129,7 +129,7 @@ def get_pairwise_statement_orderings( return get_pairwise_statement_orderings_inner( knl, lin_items, - insn_id_pairs, + stmt_id_pairs, loops_to_ignore=conc_loop_inames, ) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 4a8d1a479..6b509f694 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -193,7 +193,7 @@ class SpecialLexPointWRTLoop: def get_pairwise_statement_orderings_inner( knl, lin_items, - insn_id_pairs, + stmt_id_pairs, loops_to_ignore=set(), ): r"""For each statement pair in a subset of all statement pairs found in a @@ -216,15 +216,15 @@ def get_pairwise_statement_orderings_inner( truncated (i.e. partial) linearization may be passed through this argument - :arg insn_id_pairs: A list containing pairs of instruction identifiers. + :arg stmt_id_pairs: A list containing pairs of statement identifiers. :arg loops_to_ignore: A set of inames that will be ignored when determining the relative ordering of statements. This will typically contain concurrent inames tagged with the ``vec`` or ``ilp`` array access tags. - :returns: A dictionary mapping each two-tuple of instruction identifiers - provided in `insn_id_pairs` to a :class:`collections.namedtuple` + :returns: A dictionary mapping each two-tuple of statement identifiers + provided in `stmt_id_pairs` to a :class:`collections.namedtuple` containing the intra-thread SIO (`sio_intra_thread`), intra-group SIO (`sio_intra_group`), and global SIO (`sio_global`), each realized as an :class:`islpy.Map` from each instance of the first @@ -254,15 +254,15 @@ def get_pairwise_statement_orderings_inner( ) slex = SpecialLexPointWRTLoop - all_insn_ids = set().union(*insn_id_pairs) + all_stmt_ids = set().union(*stmt_id_pairs) # {{{ Intra-thread lex order creation # First, use one pass through lin_items to generate an *intra-thread* # lexicographic ordering describing the relative order of all statements - # represented by all_insn_ids + # represented by all_stmt_ids - # For each statement, map the insn_id to a tuple representing points + # For each statement, map the stmt_id to a tuple representing points # in the intra-thread lexicographic ordering containing items of :class:`int` or # :class:`str` :mod:`loopy` inames stmt_inst_to_lex_intra_thread = {} @@ -317,22 +317,22 @@ def get_pairwise_statement_orderings_inner( # in the simplification step below) elif isinstance(lin_item, RunInstruction): - lp_insn_id = lin_item.insn_id + lp_stmt_id = lin_item.insn_id - # Only process listed insns, otherwise ignore - if lp_insn_id in all_insn_ids: + # Only process listed stmts, otherwise ignore + if lp_stmt_id in all_stmt_ids: # Add item to stmt_inst_to_lex_intra_thread - stmt_inst_to_lex_intra_thread[lp_insn_id] = tuple(next_lex_tuple) + stmt_inst_to_lex_intra_thread[lp_stmt_id] = tuple(next_lex_tuple) # Increment lex dim val enumerating items in current section of code next_lex_tuple[-1] += 1 elif isinstance(lin_item, Barrier): - lp_insn_id = lin_item.originating_insn_id + lp_stmt_id = lin_item.originating_insn_id loops_with_barriers[lin_item.synchronization_kind] |= current_inames - if lp_insn_id is None: - # Barriers without insn ids were inserted as a result of a + if lp_stmt_id is None: + # Barriers without stmt ids were inserted as a result of a # dependency. They don't themselves have dependencies. Ignore them. # FIXME: It's possible that we could record metadata about them @@ -341,10 +341,10 @@ def get_pairwise_statement_orderings_inner( continue - # If barrier was identified in listed insns, process it - if lp_insn_id in all_insn_ids: + # If barrier was identified in listed stmts, process it + if lp_stmt_id in all_stmt_ids: # Add item to stmt_inst_to_lex_intra_thread - stmt_inst_to_lex_intra_thread[lp_insn_id] = tuple(next_lex_tuple) + stmt_inst_to_lex_intra_thread[lp_stmt_id] = tuple(next_lex_tuple) # Increment lex dim val enumerating items in current section of code next_lex_tuple[-1] += 1 @@ -739,11 +739,11 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # {{{ _get_map_for_stmt() def _get_map_for_stmt( - insn_id, lex_points, int_sid, lex_dim_names): + stmt_id, lex_points, int_sid, lex_dim_names): # Get inames domain for statement instance (a BasicSet) dom = knl.get_inames_domain( - knl.id_to_insn[insn_id].within_inames) + knl.id_to_insn[stmt_id].within_inames) # (note that this domain may include inames that are # not in stmt.within_inames) @@ -805,18 +805,18 @@ def _get_map_for_stmt( ]) # ("sio" = statement instance ordering; "pwsched" = pairwise schedule) - for insn_ids in insn_id_pairs: + for stmt_ids in stmt_id_pairs: # Determine integer IDs that will represent each statement in mapping # (dependency map creation assumes sid_before=0 and sid_after=1, unless # before and after refer to same stmt, in which case # sid_before=sid_after=0) - int_sids = [0, 0] if insn_ids[0] == insn_ids[1] else [0, 1] + int_sids = [0, 0] if stmt_ids[0] == stmt_ids[1] else [0, 1] # {{{ Create SIO for intra-thread case (lid0' == lid0, gid0' == gid0, etc) # Simplify tuples to the extent possible ------------------------------------ - lex_tuples = [stmt_inst_to_lex_intra_thread[insn_id] for insn_id in insn_ids] + lex_tuples = [stmt_inst_to_lex_intra_thread[stmt_id] for stmt_id in stmt_ids] # At this point, one of the lex tuples may have more dimensions than # another; the missing dims are the fastest-updating dims, and their @@ -836,10 +836,10 @@ def _get_map_for_stmt( intra_thread_sched_maps = [ _get_map_for_stmt( - insn_id, lex_tuple, int_sid, + stmt_id, lex_tuple, int_sid, seq_lex_dim_names+all_par_lex_dim_names) - for insn_id, lex_tuple, int_sid - in zip(insn_ids, lex_tuples_simplified, int_sids) + for stmt_id, lex_tuple, int_sid + in zip(stmt_ids, lex_tuples_simplified, int_sids) ] # Create pairwise lex order map (pairwise only in the intra-thread case) @@ -873,17 +873,17 @@ def _get_map_for_stmt( def _get_sched_maps_and_sio( stmt_inst_to_blex, blex_order_map, seq_blex_dim_names): # (Vars from outside func used here: - # insn_ids, int_sids, all_par_lex_dim_names) + # stmt_ids, int_sids, all_par_lex_dim_names) # Use *unsimplified* lex tuples w/ blex map, which are already padded - blex_tuples_padded = [stmt_inst_to_blex[insn_id] for insn_id in insn_ids] + blex_tuples_padded = [stmt_inst_to_blex[stmt_id] for stmt_id in stmt_ids] par_sched_maps = [ _get_map_for_stmt( - insn_id, blex_tuple, int_sid, + stmt_id, blex_tuple, int_sid, seq_blex_dim_names+all_par_lex_dim_names) # all par names - for insn_id, blex_tuple, int_sid - in zip(insn_ids, blex_tuples_padded, int_sids) + for stmt_id, blex_tuple, int_sid + in zip(stmt_ids, blex_tuples_padded, int_sids) ] # Create statement instance ordering @@ -903,7 +903,7 @@ def _get_sched_maps_and_sio( # }}} # Store sched maps along with SIOs - pairwise_sios[tuple(insn_ids)] = StatementOrdering( + pairwise_sios[tuple(stmt_ids)] = StatementOrdering( sio_intra_thread=sio_intra_thread, pwsched_intra_thread=tuple(intra_thread_sched_maps), sio_intra_group=sio_intra_group, From 1e6af20937270eb05776e28b9346198411c03f4f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 5 Apr 2021 05:49:27 -0500 Subject: [PATCH 088/220] rename append_marker_to_isl_map_var_names()->append_mark_to_isl_map_var_names(); rename append_marker_to_strings()->append_mark_to_strings(); rename marker->mark; make mark argument required instead of having a default value --- loopy/schedule/checker/utils.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 9382d070a..3c3f5184f 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -106,8 +106,8 @@ def add_eq_isl_constraint_from_names(isl_map, var1, var2): {1: 0, var1: 1, var2: -1})) -def append_marker_to_isl_map_var_names(old_isl_map, dim_type, marker="'"): - """Return an :class:`islpy.Map` with a marker appended to the specified +def append_mark_to_isl_map_var_names(old_isl_map, dim_type, mark): + """Return an :class:`islpy.Map` with a mark appended to the specified dimension names. :arg old_isl_map: An :class:`islpy.Map`. @@ -115,24 +115,24 @@ def append_marker_to_isl_map_var_names(old_isl_map, dim_type, marker="'"): :arg dim_type: An :class:`islpy.dim_type`, i.e., an :class:`int`, specifying the dimension to be marked. - :arg marker: A :class:`str` to be appended to the specified dimension - names. If not provided, `marker` defaults to an apostrophe. + :arg mark: A :class:`str` to be appended to the specified dimension + names. If not provided, `mark` defaults to an apostrophe. :returns: An :class:`islpy.Map` matching `old_isl_map` with - `marker` appended to the `dim_type` dimension names. + `mark` appended to the `dim_type` dimension names. """ new_map = old_isl_map.copy() for i in range(len(old_isl_map.get_var_names(dim_type))): new_map = new_map.set_dim_name(dim_type, i, old_isl_map.get_dim_name( - dim_type, i)+marker) + dim_type, i)+mark) return new_map -def append_marker_to_strings(strings, marker="'"): +def append_mark_to_strings(strings, mark): assert isinstance(strings, list) - return [s+marker for s in strings] + return [s+mark for s in strings] def sorted_union_of_names_in_isl_sets( From 70aa8fc6f6595b90e67e53988f21699bebea29c5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 5 Apr 2021 05:54:34 -0500 Subject: [PATCH 089/220] (includes function signature changes) reorder args in get_lex_order_set(); remove redundant n_dims arg from create_lex_order_map(); rename marker->mark; make make mark argument required instead of having a default value --- .../checker/lexicographic_order_map.py | 56 ++++++++----------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 20f889975..0a01f888c 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -25,7 +25,7 @@ def get_statement_ordering_map( - sched_before, sched_after, lex_map, before_marker="'"): + sched_before, sched_after, lex_map, before_mark): """Return a statement ordering represented as a map from each statement instance to all statement instances occurring later. @@ -47,7 +47,7 @@ def get_statement_ordering_map( i0' < i0 or (i0' = i0 and i1' < i1) or (i0' = i0 and i1' = i1 and i2' < i2) ...} - :arg before_marker: A :class:`str` to be appended to the names of the + :arg before_mark: A :class:`str` to be appended to the names of the map dimensions representing the 'before' statement in the 'happens before' relationship. @@ -63,18 +63,18 @@ def get_statement_ordering_map( sio = sched_before.apply_range( lex_map).apply_range(sched_after.reverse()) - # Append marker to in_ dims + # Append mark to in_ dims from loopy.schedule.checker.utils import ( - append_marker_to_isl_map_var_names, + append_mark_to_isl_map_var_names, ) - return append_marker_to_isl_map_var_names( - sio, isl.dim_type.in_, before_marker) + return append_mark_to_isl_map_var_names( + sio, isl.dim_type.in_, before_mark) def get_lex_order_set( dim_names, + in_dim_mark, islvars=None, - in_dim_marker="'", ): """Return an :class:`islpy.Set` representing a lexicographic ordering over a space with the number of dimensions provided in `dim_names` @@ -85,26 +85,26 @@ def get_lex_order_set( to describe lexicographic space dimensions for a point in a lexicographic ordering. (see example below) + :arg in_dim_mark: A :class:`str` to be appended to dimension names to + distinguish corresponding dimensions in before-after pairs of points. + (see example below) + :arg islvars: A dictionary mapping variable names in `dim_names` to :class:`islpy.PwAff` instances that represent each of the variables (islvars may be produced by `islpy.make_zero_and_vars`). The key '0' is also include and represents a :class:`islpy.PwAff` zero constant. This dictionary defines the space to be used for the set and - must also include versions of `dim_names` with the `in_dim_marker` + must also include versions of `dim_names` with the `in_dim_mark` appended. If no value is passed, the dictionary will be made using - `dim_names` and `dim_names` with the `in_dim_marker` appended. - - :arg in_dim_marker: A :class:`str` to be appended to dimension names to - distinguish corresponding dimensions in before-after pairs of points. - (see example below) + `dim_names` and `dim_names` with the `in_dim_mark` appended. :returns: An :class:`islpy.Set` representing a big-endian lexicographic ordering with the number of dimensions provided in `dim_names`. The set has two dimensions for each name in `dim_names`, one identified by the - given name and another identified by the same name with `in_dim_marker` + given name and another identified by the same name with `in_dim_mark` appended. The set contains all points which meet a 'happens before' constraint defining the lexicographic ordering. E.g., if - `dim_names = [i0, i1, i2]` and `in_dim_marker="'"`, + `dim_names = [i0, i1, i2]` and `in_dim_mark="'"`, return the set containing all points in a 3-dimensional, big-endian lexicographic ordering such that point `[i0', i1', i2']` happens before `[i0, i1, i2]`. I.e., return:: @@ -116,10 +116,10 @@ def get_lex_order_set( """ from loopy.schedule.checker.utils import ( - append_marker_to_strings, + append_mark_to_strings, ) - in_dim_names = append_marker_to_strings(dim_names, marker=in_dim_marker) + in_dim_names = append_mark_to_strings(dim_names, mark=in_dim_mark) # If no islvars passed, make them using the names provided # (make sure to pass var names in desired order of space dims) @@ -156,21 +156,16 @@ def get_lex_order_set( def create_lex_order_map( - n_dims=None, - dim_names=None, - in_dim_marker="'", + dim_names, + in_dim_mark, ): """Return a map from each point in a lexicographic ordering to every point that occurs later in the lexicographic ordering. - :arg n_dims: An :class:`int` representing the number of dimensions - in the lexicographic ordering. If not provided, `n_dims` will be - set to length of `dim_names`. - :arg dim_names: A list of :class:`str` variable names for the lexicographic space dimensions. - :arg in_dim_marker: A :class:`str` to be appended to `dim_names` to create + :arg in_dim_mark: A :class:`str` to be appended to `dim_names` to create the names for the input dimensions of the map, thereby distinguishing them from the corresponding output dimensions in before-after pairs of points. (see example below) @@ -178,7 +173,7 @@ def create_lex_order_map( :returns: An :class:`islpy.Map` representing a lexicographic ordering as a mapping from each point in lexicographic time to every point that occurs later in lexicographic time. - E.g., if `dim_names = [i0, i1, i2]` and `in_dim_marker = "'"`, + E.g., if `dim_names = [i0, i1, i2]` and `in_dim_mark = "'"`, return the map:: {[i0', i1', i2'] -> [i0, i1, i2] : @@ -187,18 +182,13 @@ def create_lex_order_map( """ - if dim_names is None: - dim_names = ["i%s" % (i) for i in range(n_dims)] - if n_dims is None: - n_dims = len(dim_names) - - assert len(dim_names) == n_dims + n_dims = len(dim_names) dim_type = isl.dim_type # First, get a set representing the lexicographic ordering. lex_order_set = get_lex_order_set( dim_names, - in_dim_marker=in_dim_marker, + in_dim_mark=in_dim_mark, ) # Now convert that set to a map. From 2ca1a8e383569e2c97049ed55a62f883826a24bc Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 5 Apr 2021 05:55:27 -0500 Subject: [PATCH 090/220] rename marker->mark and pass mark into funcs where it is now required --- loopy/schedule/checker/schedule.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 6b509f694..d9029bfdf 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -246,7 +246,7 @@ def get_pairwise_statement_orderings_inner( ) from loopy.schedule.checker.utils import ( add_and_name_isl_dims, - append_marker_to_strings, + append_mark_to_strings, add_eq_isl_constraint_from_names, sorted_union_of_names_in_isl_sets, create_symbolic_map_from_tuples, @@ -556,20 +556,21 @@ def _gather_blex_ordering_info(sync_kind): # Create names for the blex dimensions for sequential loops seq_blex_dim_names = [ LEX_VAR_PREFIX+str(i) for i in range(n_seq_blex_dims)] - seq_blex_dim_names_prime = append_marker_to_strings( - seq_blex_dim_names, marker=BEFORE_MARK) + seq_blex_dim_names_prime = append_mark_to_strings( + seq_blex_dim_names, mark=BEFORE_MARK) # Begin with the blex order map created as a standard lexicographical order blex_order_map = create_lex_order_map( dim_names=seq_blex_dim_names, - in_dim_marker=BEFORE_MARK, + in_dim_mark=BEFORE_MARK, ) # Add LID/GID dims to blex order map blex_order_map = add_and_name_isl_dims( blex_order_map, dt.out, all_par_lex_dim_names) blex_order_map = add_and_name_isl_dims( - blex_order_map, dt.in_, append_marker_to_strings(all_par_lex_dim_names)) + blex_order_map, dt.in_, + append_mark_to_strings(all_par_lex_dim_names, mark=BEFORE_MARK)) if sync_kind == "local": # For intra-group case, constrain GID 'before' to equal GID 'after' for var_name in gid_lex_dim_names: @@ -628,7 +629,7 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # Start with a set representing blex_order_map space blex_set = blex_set_template.copy() - # Add markers to inames in the 'before' tuple + # Add marks to inames in the 'before' tuple # (all strings should be inames) before_prime = tuple( v+BEFORE_MARK if isinstance(v, str) else v for v in before) @@ -845,14 +846,15 @@ def _get_map_for_stmt( # Create pairwise lex order map (pairwise only in the intra-thread case) lex_order_map = create_lex_order_map( dim_names=seq_lex_dim_names, - in_dim_marker=BEFORE_MARK, + in_dim_mark=BEFORE_MARK, ) # Add lid/gid dims to lex order map lex_order_map = add_and_name_isl_dims( lex_order_map, dt.out, all_par_lex_dim_names) lex_order_map = add_and_name_isl_dims( - lex_order_map, dt.in_, append_marker_to_strings(all_par_lex_dim_names)) + lex_order_map, dt.in_, + append_mark_to_strings(all_par_lex_dim_names, mark=BEFORE_MARK)) # Constrain lid/gid vars to be equal for var_name in all_par_lex_dim_names: lex_order_map = add_eq_isl_constraint_from_names( @@ -863,7 +865,7 @@ def _get_map_for_stmt( sio_intra_thread = get_statement_ordering_map( *intra_thread_sched_maps, # note, func accepts exactly two maps lex_order_map, - before_marker=BEFORE_MARK, + before_mark=BEFORE_MARK, ) # }}} @@ -890,7 +892,7 @@ def _get_sched_maps_and_sio( sio_par = get_statement_ordering_map( *par_sched_maps, # note, func accepts exactly two maps blex_order_map, - before_marker=BEFORE_MARK, + before_mark=BEFORE_MARK, ) return par_sched_maps, sio_par From 2b8156e915fac9a379772119bd42e0012cfae3af Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 5 Apr 2021 05:59:29 -0500 Subject: [PATCH 091/220] for legibility of tests, allow test map strings to use apostrophe as a placeholder for the before-mark even when BEFORE_MARK is set to something else (by replacing the placeholder with BEFORE_MARK in the strings before creating the maps) --- test/test_linearization_checker.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 7c2272c82..d61925414 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -80,13 +80,24 @@ def _lex_point_string(dim_vals, lid_inames=[], gid_inames=[]): ) -def _isl_map_with_marked_dims(s): +def _isl_map_with_marked_dims(s, placeholder_mark="'"): + # For creating legible tests, map strings may be created with a placeholder + # for the 'before' mark. Replace this placeholder with BEFORE_MARK before + # creating the map. + # ALSO, if BEFORE_MARK == "'", ISL will ignore this mark when creating + # variable names, so it must be added manually. from loopy.schedule.checker.utils import ( - append_marker_to_isl_map_var_names, + append_mark_to_isl_map_var_names, ) dt = isl.dim_type - # Isl ignores the apostrophes in map strings, until they are explicitly added - return append_marker_to_isl_map_var_names(isl.Map(s), dt.in_, BEFORE_MARK) + if BEFORE_MARK == "'": + # ISL will ignore the apostrophe; manually name the in_ vars + return append_mark_to_isl_map_var_names( + isl.Map(s.replace(placeholder_mark, BEFORE_MARK)), + dt.in_, + BEFORE_MARK) + else: + return isl.Map(s.replace(placeholder_mark, BEFORE_MARK)) def _check_orderings_for_stmt_pair( @@ -455,8 +466,8 @@ def test_lex_order_map_creation(): def _check_lex_map(exp_lex_order_map, n_dims): lex_order_map = create_lex_order_map( - n_dims=n_dims, dim_names=["%s%d" % (LEX_VAR_PREFIX, i) for i in range(n_dims)], + in_dim_mark=BEFORE_MARK, ) assert lex_order_map == exp_lex_order_map @@ -909,7 +920,8 @@ def test_sios_and_schedules_with_barriers(): ij_end_val, conc_iname_bound_str, conc_iname_bound_str_p, - )) + ) + ) wanted_pairs = ensure_dim_names_match_and_align( wanted_pairs, order_info.sio_intra_group) @@ -931,7 +943,8 @@ def test_sios_and_schedules_with_barriers(): ij_end_val, conc_iname_bound_str, conc_iname_bound_str_p, - )) + ) + ) unwanted_pairs = ensure_dim_names_match_and_align( unwanted_pairs, order_info.sio_intra_group) From d04d1b85d741472311e419ce30585769e0a45e52 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 10 Apr 2021 20:46:31 -0500 Subject: [PATCH 092/220] set dt=isl.dim_type to make code prettier --- loopy/schedule/checker/utils.py | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 3c3f5184f..401fd477a 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -21,6 +21,7 @@ """ import islpy as isl +dt = isl.dim_type def prettier_map_string(map_obj): @@ -62,10 +63,10 @@ def reorder_dims_by_name( """ - assert dim_type != isl.dim_type.param + assert dim_type != dt.param assert set(isl_set.get_var_names(dim_type)) == set(desired_dims_ordered) - other_dim_type = isl.dim_type.param + other_dim_type = dt.param other_dim_len = len(isl_set.get_var_names(other_dim_type)) new_set = isl_set.copy() @@ -89,7 +90,7 @@ def ensure_dim_names_match_and_align(obj_map, tgt_map): if not all( set(obj_map.get_var_names(dt)) == set(tgt_map.get_var_names(dt)) for dt in - [isl.dim_type.in_, isl.dim_type.out, isl.dim_type.param]): + [dt.in_, dt.out, dt.param]): raise ValueError( "Cannot align spaces; names don't match:\n%s\n%s" % (prettier_map_string(obj_map), prettier_map_string(tgt_map)) @@ -137,7 +138,7 @@ def append_mark_to_strings(strings, mark): def sorted_union_of_names_in_isl_sets( isl_sets, - set_dim=isl.dim_type.set): + set_dim=dt.set): r"""Return a sorted list of the union of all variable names found in the provided :class:`islpy.Set`\ s. """ @@ -176,16 +177,14 @@ def create_symbolic_map_from_tuples( """ # TODO allow None for domains - dim_type = isl.dim_type - - space_out_names = space.get_var_names(dim_type.out) - space_in_names = space.get_var_names(isl.dim_type.in_) + space_out_names = space.get_var_names(dt.out) + space_in_names = space.get_var_names(dt.in_) # Get islvars from space islvars = isl.affs_from_space( space.move_dims( - isl.dim_type.out, 0, - isl.dim_type.in_, 0, + dt.out, 0, + dt.in_, 0, len(space_in_names), ).range() ) @@ -205,7 +204,7 @@ def _conjunction_of_dim_eq_conditions(dim_names, values, islvars): union_of_maps = isl.Map.from_domain( islvars[0].eq_set(islvars[0]+1) # 0 == 1 (false) ).move_dims( - dim_type.out, 0, dim_type.in_, len(space_in_names), len(space_out_names)) + dt.out, 0, dt.in_, len(space_in_names), len(space_out_names)) # Loop through tuple pairs for (tup_in, tup_out), dom in tuple_pairs_with_domains: @@ -221,13 +220,13 @@ def _conjunction_of_dim_eq_conditions(dim_names, values, islvars): # Convert set to map by moving dimensions around map_from_set = isl.Map.from_domain(condition) map_from_set = map_from_set.move_dims( - dim_type.out, 0, dim_type.in_, + dt.out, 0, dt.in_, len(space_in_names), len(space_out_names)) # Align the *out* dims of dom with the space *in_* dims # in preparation for intersection dom_with_set_dim_aligned = reorder_dims_by_name( - dom, isl.dim_type.set, + dom, dt.set, space_in_names, ) From 28c6de6bfbf008c915a2e19ad295ab7f9e36215b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 14 Apr 2021 09:16:28 -0500 Subject: [PATCH 093/220] when determining iname domains for schedule map creation for a statement, project out inames except stmt.within_inames --- loopy/schedule/checker/schedule.py | 5 +-- test/test_linearization_checker.py | 60 ++++++++++++++++-------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index d9029bfdf..726256b45 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -743,10 +743,9 @@ def _get_map_for_stmt( stmt_id, lex_points, int_sid, lex_dim_names): # Get inames domain for statement instance (a BasicSet) + within_inames = knl.id_to_insn[stmt_id].within_inames dom = knl.get_inames_domain( - knl.id_to_insn[stmt_id].within_inames) - # (note that this domain may include inames that are - # not in stmt.within_inames) + within_inames).project_out_except(within_inames, [dt.set]) # Create map space (an isl space in current implementation) # {('statement', ) -> diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index d61925414..528f10944 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -785,8 +785,12 @@ def test_sios_and_schedules_with_barriers(): # Create expected maps and compare # Iname bound strings to facilitate creation of expected maps - iname_bound_str = "ij_start <= i,j< ij_end" - iname_bound_str_p = "ij_start <= i',j'< ij_end" + i_bound_str = "ij_start <= i < ij_end" + i_bound_str_p = "ij_start <= i' < ij_end" + j_bound_str = "ij_start <= j < ij_end" + j_bound_str_p = "ij_start <= j' < ij_end" + ij_bound_str = i_bound_str + " and " + j_bound_str + ij_bound_str_p = i_bound_str_p + " and " + j_bound_str_p conc_iname_bound_str = "0 <= l0,l1,g0 < lg_end" conc_iname_bound_str_p = "0 <= l0',l1',g0' < lg_end" @@ -802,7 +806,7 @@ def test_sios_and_schedules_with_barriers(): ["2", "i", "2", "j", "1"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], ), - iname_bound_str, + ij_bound_str, conc_iname_bound_str, ) ) @@ -829,7 +833,7 @@ def test_sios_and_schedules_with_barriers(): "and {4}" # param assumptions "}}".format( STATEMENT_VAR_NAME, - iname_bound_str_p, + ij_bound_str_p, conc_iname_bound_str, conc_iname_bound_str_p, assumptions, @@ -850,7 +854,7 @@ def test_sios_and_schedules_with_barriers(): ["1", "i", "1"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], ), - iname_bound_str, + ij_bound_str, conc_iname_bound_str, ) ) @@ -876,7 +880,7 @@ def test_sios_and_schedules_with_barriers(): "and {4}" # param assumptions "}}".format( STATEMENT_VAR_NAME, - iname_bound_str_p, + ij_bound_str_p, conc_iname_bound_str, conc_iname_bound_str_p, assumptions, @@ -975,7 +979,7 @@ def test_sios_and_schedules_with_barriers(): sched_stmt_i0_intra_group_exp = isl.Map( "[ij_start, ij_end, lg_end] -> {" - "[%s=1, i, j, l0, l1, g0] -> [%s] : " + "[%s=1, i, l0, l1, g0] -> [%s] : " "%s and %s}" # iname bounds % ( STATEMENT_VAR_NAME, @@ -983,21 +987,21 @@ def test_sios_and_schedules_with_barriers(): ["2", "i", "0", "0", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], ), - iname_bound_str, + i_bound_str, conc_iname_bound_str, ) ) sio_intra_group_exp = _isl_map_with_marked_dims( "[ij_start, ij_end, lg_end] -> {{ " - "[{0}'=0, l0', l1', g0'] -> [{0}=1, i, j, l0, l1, g0] : " + "[{0}'=0, l0', l1', g0'] -> [{0}=1, i, l0, l1, g0] : " "ij_start + 1 <= i < ij_end " # not first iteration of i "and g0 = g0' " # within a single group "and {1} and {2} and {3} " # iname bounds "and {4}" # param assumptions "}}".format( STATEMENT_VAR_NAME, - iname_bound_str, + i_bound_str, conc_iname_bound_str, conc_iname_bound_str_p, assumptions, @@ -1023,7 +1027,7 @@ def test_sios_and_schedules_with_barriers(): sched_stmt_i0_global_exp = isl.Map( "[ij_start, ij_end, lg_end] -> {" - "[%s=1, i, j, l0, l1, g0] -> [%s] : " + "[%s=1, i, l0, l1, g0] -> [%s] : " "%s and %s}" # iname bounds % ( STATEMENT_VAR_NAME, @@ -1031,20 +1035,20 @@ def test_sios_and_schedules_with_barriers(): ["1", "i", "0"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], ), - iname_bound_str, + i_bound_str, conc_iname_bound_str, ) ) sio_global_exp = _isl_map_with_marked_dims( "[ij_start, ij_end, lg_end] -> {{ " - "[{0}'=0, l0', l1', g0'] -> [{0}=1, i, j, l0, l1, g0] : " + "[{0}'=0, l0', l1', g0'] -> [{0}=1, i, l0, l1, g0] : " "ij_start + 1 <= i < ij_end " # not first iteration of i "and {1} and {2} and {3} " # iname bounds "and {4}" # param assumptions "}}".format( STATEMENT_VAR_NAME, - iname_bound_str, + i_bound_str, conc_iname_bound_str, conc_iname_bound_str_p, assumptions, @@ -1106,8 +1110,8 @@ def test_sios_and_schedules_with_vec_and_barriers(): # Create expected maps and compare # Iname bound strings to facilitate creation of expected maps - iname_bound_str = "0 <= i < 4 and 0 <= j < n" - iname_bound_str_p = "0 <= i' < 4 and 0 <= j' < n" + ij_bound_str = "0 <= i < 4 and 0 <= j < n" + ij_bound_str_p = "0 <= i' < 4 and 0 <= j' < n" conc_iname_bound_str = "0 <= l0 < 32" conc_iname_bound_str_p = "0 <= l0' < 32" @@ -1123,7 +1127,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): ["j", "0"], # lex points (initial matching dim gets removed) lid_inames=["l0"], ), - iname_bound_str, + ij_bound_str, conc_iname_bound_str, ) ) @@ -1138,7 +1142,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): ["j", "1"], # lex points (initial matching dim gets removed) lid_inames=["l0"], ), - iname_bound_str, + ij_bound_str, conc_iname_bound_str, ) ) @@ -1151,8 +1155,8 @@ def test_sios_and_schedules_with_vec_and_barriers(): "and {1} and {2} and {3} and {4}" # iname bounds "}}".format( STATEMENT_VAR_NAME, - iname_bound_str, - iname_bound_str_p, + ij_bound_str, + ij_bound_str_p, conc_iname_bound_str, conc_iname_bound_str_p, ) @@ -1176,7 +1180,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): ["1", "j", "0"], # lex points lid_inames=["l0"], ), - iname_bound_str, + ij_bound_str, conc_iname_bound_str, ) ) @@ -1191,7 +1195,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): ["1", "j", "1"], # lex points lid_inames=["l0"], ), - iname_bound_str, + ij_bound_str, conc_iname_bound_str, ) ) @@ -1203,8 +1207,8 @@ def test_sios_and_schedules_with_vec_and_barriers(): "and {1} and {2} and {3} and {4}" # iname bounds "}}".format( STATEMENT_VAR_NAME, - iname_bound_str, - iname_bound_str_p, + ij_bound_str, + ij_bound_str_p, conc_iname_bound_str, conc_iname_bound_str_p, ) @@ -1224,7 +1228,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): ["0"], # lex points lid_inames=["l0"], ), - iname_bound_str, + ij_bound_str, conc_iname_bound_str, ) ) @@ -1240,7 +1244,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): ["0"], # lex points lid_inames=["l0"], ), - iname_bound_str, + ij_bound_str, conc_iname_bound_str, ) ) @@ -1252,8 +1256,8 @@ def test_sios_and_schedules_with_vec_and_barriers(): "and {1} and {2} and {3} and {4}" # iname bounds "}}".format( STATEMENT_VAR_NAME, - iname_bound_str, - iname_bound_str_p, + ij_bound_str, + ij_bound_str_p, conc_iname_bound_str, conc_iname_bound_str_p, ) From 167060b823f199a7d621809ddd0d82e1ce3bf4ac Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 15 Apr 2021 10:35:49 -0500 Subject: [PATCH 094/220] fix doctest --- loopy/schedule/checker/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 5a492660b..190a29c27 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -85,8 +85,8 @@ def get_pairwise_statement_orderings( >>> print(str(sio_dict[("stmt_a", "stmt_b")].sio_intra_thread ... ).replace("{ ", "{\n").replace(" :", "\n:")) [pj, pk] -> { - [_lp_linchk_stmt' = 0, j', k'] -> [_lp_linchk_stmt = 1, j, k] - : 0 <= j' < pj and 0 <= k' < pk and 0 <= j < pj and 0 <= k < pk } + [_lp_linchk_stmt' = 0, j'] -> [_lp_linchk_stmt = 1, k] + : pj > 0 and pk > 0 and 0 <= j' < pj and 0 <= k < pk } """ From af7c26315340afc0d32ba64388383dd5d930ffa9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 17 Apr 2021 15:16:35 -0500 Subject: [PATCH 095/220] Before adding each parallel iname constraint to a statement's schedule, make sure the iname applies to this statement. (Even though all parallel thread dims are active throughout the whole kernel, they may be assigned (tagged) to one iname for one subset of statements and another iname for a different subset of statements.); Add test with parallel matmul. --- loopy/schedule/checker/schedule.py | 19 ++++++---- test/test_linearization_checker.py | 57 ++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 726256b45..05aea3bdf 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -366,14 +366,14 @@ def get_pairwise_statement_orderings_inner( # name in schedules, i.e., i = lid0, j = lid1, etc. lid_lex_dim_names = set() gid_lex_dim_names = set() - par_iname_constraint_dicts = [] + par_iname_constraint_dicts = {} for iname in knl.all_inames(): ltag = knl.iname_tags_of_type(iname, LocalIndexTag) if ltag: assert len(ltag) == 1 # (should always be true) ltag_var = LTAG_VAR_NAMES[ltag.pop().axis] lid_lex_dim_names.add(ltag_var) - par_iname_constraint_dicts.append({1: 0, iname: 1, ltag_var: -1}) + par_iname_constraint_dicts[iname] = {1: 0, iname: 1, ltag_var: -1} continue # Shouldn't be any GroupIndexTags @@ -382,7 +382,7 @@ def get_pairwise_statement_orderings_inner( assert len(gtag) == 1 # (should always be true) gtag_var = GTAG_VAR_NAMES[gtag.pop().axis] gid_lex_dim_names.add(gtag_var) - par_iname_constraint_dicts.append({1: 0, iname: 1, gtag_var: -1}) + par_iname_constraint_dicts[iname] = {1: 0, iname: 1, gtag_var: -1} # Sort for consistent dimension ordering lid_lex_dim_names = sorted(lid_lex_dim_names) @@ -786,9 +786,16 @@ def _get_map_for_stmt( ) # Set inames equal to relevant gid/lid var names - for constraint_dict in par_iname_constraint_dicts: - sched_map = sched_map.add_constraint( - isl.Constraint.eq_from_names(sched_map.space, constraint_dict)) + for iname, constraint_dict in par_iname_constraint_dicts.items(): + # Even though all parallel thread dims are active throughout the + # whole kernel, they may be assigned (tagged) to one iname for some + # subset of statements and another iname for a different subset of + # statements (e.g., tiled, paralle. matmul). + # So before adding each parallel iname constraint, make sure the + # iname applies to this statement: + if iname in dom_inames_ordered: + sched_map = sched_map.add_constraint( + isl.Constraint.eq_from_names(sched_map.space, constraint_dict)) return sched_map diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 528f10944..060e3326d 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -1283,6 +1283,63 @@ def test_sios_and_schedules_with_vec_and_barriers(): # }}} +# {{{ test_sios_with_matmul + +def test_sios_with_matmul(): + from loopy.schedule.checker import ( + get_pairwise_statement_orderings, + ) + # For now, this test just ensures all pairwise SIOs can be created + # for a complex parallel kernel without any errors/exceptions. Later PRs + # will examine this kernel's SIOs and related dependencies for accuracy. + + bsize = 16 + knl = lp.make_kernel( + "{[i,k,j]: 0<=i 1: exec(sys.argv[1]) From 39fe70508a67d35c2ac7410664fb36930dfc1bca Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 24 Apr 2021 23:19:11 -0500 Subject: [PATCH 096/220] reduce duplicated code in tests by adding _process_and_linearize(knl) function, which returns linearization items along with the preprocessed kernel and linearized kernel --- test/test_linearization_checker.py | 56 +++++++++++++----------------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 060e3326d..c4eb49fc2 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -138,6 +138,14 @@ def _check_orderings_for_stmt_pair( maps_to_compare = [(m1, m2) for m1, m2 in map_candidates if m1 is not None] _align_and_compare_maps(maps_to_compare) + +def _process_and_linearize(knl): + # Return linearization items along with the preprocessed kernel and + # linearized kernel + proc_knl = preprocess_kernel(knl) + lin_knl = get_one_linearized_kernel(proc_knl) + return lin_knl.linearization, proc_knl, lin_knl + # }}} @@ -182,9 +190,7 @@ def test_intra_thread_pairwise_schedule_creation(): knl = lp.prioritize_loops(knl, "i,j") # Get a linearization - proc_knl = preprocess_kernel(knl) - lin_knl = get_one_linearized_kernel(proc_knl) - linearization_items = lin_knl.linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) stmt_id_pairs = [ ("stmt_a", "stmt_b"), @@ -196,7 +202,7 @@ def test_intra_thread_pairwise_schedule_creation(): ] pworders = get_pairwise_statement_orderings( lin_knl, - linearization_items, + lin_items, stmt_id_pairs, ) @@ -406,16 +412,14 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): knl = lp.tag_inames(knl, {"j": "l.1", "jj": "l.0", "i": "g.0"}) # Get a linearization - proc_knl = preprocess_kernel(knl) - lin_knl = get_one_linearized_kernel(proc_knl) - linearization_items = lin_knl.linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) stmt_id_pairs = [ ("stmt_a", "stmt_b"), ] pworders = get_pairwise_statement_orderings( lin_knl, - linearization_items, + lin_items, stmt_id_pairs, ) @@ -544,9 +548,7 @@ def test_intra_thread_statement_instance_ordering(): knl = lp.prioritize_loops(knl, "i,j") # Get a linearization - knl = preprocess_kernel(knl) - knl = get_one_linearized_kernel(knl) - linearization_items = knl.linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) # Get pairwise schedules stmt_id_pairs = [ @@ -558,8 +560,8 @@ def test_intra_thread_statement_instance_ordering(): ("stmt_c", "stmt_d"), ] pworders = get_pairwise_statement_orderings( - knl, - linearization_items, + proc_knl, + lin_items, stmt_id_pairs, ) @@ -688,9 +690,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): knl = lp.tag_inames(knl, {"j": "l.1", "jj": "l.0", "i": "g.0"}) # Get a linearization - proc_knl = preprocess_kernel(knl) - lin_knl = get_one_linearized_kernel(proc_knl) - linearization_items = lin_knl.linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) # Get pairwise schedules stmt_id_pairs = [ @@ -698,7 +698,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): ] pworders = get_pairwise_statement_orderings( lin_knl, - linearization_items, + lin_items, stmt_id_pairs, ) @@ -772,13 +772,11 @@ def test_sios_and_schedules_with_barriers(): knl = lp.tag_inames(knl, {"l0": "l.0", "l1": "l.1", "g0": "g.0"}) # Get a linearization - proc_knl = preprocess_kernel(knl) - lin_knl = get_one_linearized_kernel(proc_knl) - linearization_items = lin_knl.linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) stmt_id_pairs = [("stmt_j1", "stmt_2"), ("stmt_1", "stmt_i0")] pworders = get_pairwise_statement_orderings( - lin_knl, linearization_items, stmt_id_pairs) + lin_knl, lin_items, stmt_id_pairs) # {{{ Relationship between stmt_j1 and stmt_2 @@ -1097,13 +1095,11 @@ def test_sios_and_schedules_with_vec_and_barriers(): knl = lp.tag_inames(knl, {"i": "vec", "l0": "l.0"}) # Get a linearization - proc_knl = preprocess_kernel(knl) - lin_knl = get_one_linearized_kernel(proc_knl) - linearization_items = lin_knl.linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) stmt_id_pairs = [("stmt_1", "stmt_2")] pworders = get_pairwise_statement_orderings( - lin_knl, linearization_items, stmt_id_pairs) + lin_knl, lin_items, stmt_id_pairs) # {{{ Relationship between stmt_1 and stmt_2 @@ -1316,17 +1312,13 @@ def test_sios_with_matmul(): knl, "b", ["j_inner", "k_inner"], default_tag="l.auto") knl = lp.prioritize_loops(knl, "k_outer,k_inner") - proc_knl = preprocess_kernel(knl) - # Get a linearization - proc_knl = preprocess_kernel(knl) - lin_knl = get_one_linearized_kernel(proc_knl) - linearization_items = lin_knl.linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) # Get ALL statement id pairs from loopy.schedule import RunInstruction all_stmt_ids = [ - lin_item.insn_id for lin_item in linearization_items + lin_item.insn_id for lin_item in lin_items if isinstance(lin_item, RunInstruction)] from itertools import product stmt_id_pairs = [] @@ -1335,7 +1327,7 @@ def test_sios_with_matmul(): # Generate pairwise ordering info for every pair get_pairwise_statement_orderings( - lin_knl, linearization_items, stmt_id_pairs) + lin_knl, lin_items, stmt_id_pairs) # }}} From 0680d4dff50ea9e62a6d9689e46b6a6af10e3330 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 14 Jul 2021 16:57:06 -0500 Subject: [PATCH 097/220] change empty list default args to empty tuples --- test/test_linearization_checker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 9a997e0b9..daa43cd95 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -65,7 +65,7 @@ def _align_and_compare_maps(maps): assert map1_aligned == map2 -def _lex_point_string(dim_vals, lid_inames=[], gid_inames=[]): +def _lex_point_string(dim_vals, lid_inames=(), gid_inames=()): # Return a string describing a point in a lex space # by assigning values to lex dimension variables # (used to create maps below) From 58556767314ca008adecdb79eb287ba269ad1c46 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 14 Jul 2021 17:16:09 -0500 Subject: [PATCH 098/220] rename IndexTag->InameTag --- loopy/schedule/checker/schedule.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index efc0b8047..0d7d9aec6 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -239,7 +239,7 @@ def get_pairwise_statement_orderings_inner( """ from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) - from loopy.kernel.data import (LocalIndexTag, GroupIndexTag) + from loopy.kernel.data import (LocalInameTag, GroupInameTag) from loopy.schedule.checker.lexicographic_order_map import ( create_lex_order_map, get_statement_ordering_map, @@ -368,16 +368,16 @@ def get_pairwise_statement_orderings_inner( gid_lex_dim_names = set() par_iname_constraint_dicts = {} for iname in knl.all_inames(): - ltag = knl.iname_tags_of_type(iname, LocalIndexTag) + ltag = knl.iname_tags_of_type(iname, LocalInameTag) if ltag: assert len(ltag) == 1 # (should always be true) ltag_var = LTAG_VAR_NAMES[ltag.pop().axis] lid_lex_dim_names.add(ltag_var) par_iname_constraint_dicts[iname] = {1: 0, iname: 1, ltag_var: -1} - continue # Shouldn't be any GroupIndexTags + continue # Shouldn't be any GroupInameTags - gtag = knl.iname_tags_of_type(iname, GroupIndexTag) + gtag = knl.iname_tags_of_type(iname, GroupInameTag) if gtag: assert len(gtag) == 1 # (should always be true) gtag_var = GTAG_VAR_NAMES[gtag.pop().axis] From e55048c8c2317b64955f1acc7aa342f4a9af158c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 15 Jul 2021 18:57:45 -0500 Subject: [PATCH 099/220] handle dependencies on barrier stmts by assigning them a lex point --- loopy/schedule/checker/schedule.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 0d7d9aec6..18f391c2b 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -532,6 +532,31 @@ def _gather_blex_ordering_info(sync_kind): if lin_item.synchronization_kind == sync_kind: next_blex_tuple[-1] += 1 + lp_stmt_id = lin_item.originating_insn_id + + if lp_stmt_id is None: + # Barriers without stmt ids were inserted as a result of a + # dependency. They don't themselves have dependencies. + # Don't map this barrier to a blex tuple. + continue + + # This barrier has a stmt id. + # If it was included in listed stmts, process it. + # Otherwise, there's nothing left to do (we've already + # incremented next_blex_tuple if necessary, and this barrier + # does not need to be assigned to a designated point in blex + # time) + if lp_stmt_id in all_stmt_ids: + # If sync scope matches, give this barrier its own point in + # lex time and update blex tuple after barrier. + # Otherwise, add stmt->blex pair to stmt_inst_to_blex, but + # don't update the blex tuple (just like with any other + # stmt) + if lin_item.synchronization_kind == sync_kind: + stmt_inst_to_blex[lp_stmt_id] = tuple(next_blex_tuple) + next_blex_tuple[-1] += 1 + else: + stmt_inst_to_blex[lp_stmt_id] = tuple(next_blex_tuple) else: from loopy.schedule import (CallKernel, ReturnFromKernel) # No action needed for these types of linearization item From f91338d81fb764de5061ad64915d21fc7a81663f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 15 Jul 2021 18:58:29 -0500 Subject: [PATCH 100/220] test pairwise SIOs where one of the statements is a barrier --- test/test_linearization_checker.py | 264 +++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index daa43cd95..de88d98fc 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -725,6 +725,270 @@ def test_statement_instance_ordering_with_hw_par_tags(): # }}} +# {{{ test_statement_instance_ordering_of_barriers() + +def test_statement_instance_ordering_of_barriers(): + from loopy.schedule.checker import ( + get_pairwise_statement_orderings, + ) + from loopy.schedule.checker.utils import ( + partition_inames_by_concurrency, + ) + + # Example kernel + knl = lp.make_kernel( + [ + "{[i,ii]: 0<=i,iitemp = b[i,ii,j,jj] {id=stmt_a,dep=gbar} + ... lbarrier {id=lbar0,dep=stmt_a} + a[i,ii,j,jj] = temp + 1 {id=stmt_b,dep=lbar0} + ... lbarrier {id=lbar1,dep=stmt_b} + end + end + end + end + <>temp2 = 0.5 {id=stmt_c,dep=lbar1} + """, + assumptions="pi,pj >= 1", + lang_version=(2018, 2) + ) + knl = lp.add_and_infer_dtypes(knl, {"a,b": np.float32}) + knl = lp.tag_inames(knl, {"j": "l.0", "i": "g.0"}) + knl = lp.prioritize_loops(knl, "ii,jj") + + # Get a linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) + + # Get pairwise schedules + stmt_id_pairs = [ + ("stmt_a", "stmt_b"), + ("gbar", "stmt_a"), + ("stmt_b", "lbar1"), + ("lbar1", "stmt_c"), + ] + pworders = get_pairwise_statement_orderings( + lin_knl, + lin_items, + stmt_id_pairs, + ) + + # Create string for representing parallel iname SAME condition in sio + conc_inames, _ = partition_inames_by_concurrency(knl["loopy_kernel"]) + par_iname_condition = " and ".join( + "{0} = {0}'".format(iname) for iname in conc_inames) + + # {{{ Intra-thread relationship between stmt_a and stmt_b + + sio_intra_thread_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii', j', jj'] -> [{0}=1, i, ii, j, jj] : " + "0 <= i,ii,i',ii' < pi and 0 <= j,jj,j',jj' < pj " + "and (ii > ii' or (ii = ii' and jj >= jj')) " + "and {1} " + "}}".format( + STATEMENT_VAR_NAME, + par_iname_condition, + ) + ) + + _check_orderings_for_stmt_pair( + "stmt_a", "stmt_b", pworders, + sio_intra_thread_exp=sio_intra_thread_exp) + + # }}} + + # {{{ Relationship between gbar and stmt_a + + # intra-thread case + + sio_intra_thread_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii'] -> [{0}=1, i, ii, j, jj] : " + "0 <= i,ii,i',ii' < pi and 0 <= j,jj < pj " # domains + "and i = i' " # parallel inames must be same + "and ii >= ii' " # before->after condtion + "}}".format( + STATEMENT_VAR_NAME, + ) + ) + + # intra-group case + # TODO figure out what this should be + """ + sio_intra_group_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii'] -> [{0}=1, i, ii, j, jj] : " + "0 <= i,ii,i',ii' < pi and 0 <= j,jj < pj " # domains + "and i = i' " # GID inames must be same + "and (ii > ii' or (ii = ii' and jj = 0))" # before->after condtion + "}}".format( + STATEMENT_VAR_NAME, + ) + ) + """ + + # global case + + sio_global_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii'] -> [{0}=1, i, ii, j, jj] : " + "0 <= i,ii,i',ii' < pi and 0 <= j,jj < pj " # domains + "and ii >= ii' " # before->after condtion + "}}".format( + STATEMENT_VAR_NAME, + ) + ) + + _check_orderings_for_stmt_pair( + "gbar", "stmt_a", pworders, + sio_intra_thread_exp=sio_intra_thread_exp, + # sio_intra_group_exp=sio_intra_group_exp, + sio_global_exp=sio_global_exp) + + # }}} + + # {{{ Relationship between stmt_b and lbar1 + + # intra thread case + + sio_intra_thread_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii', j', jj'] -> [{0}=1, i, ii, j, jj] : " + "0 <= i,ii,i',ii' < pi and 0 <= j,jj,j',jj' < pj " # domains + "and i = i' and j = j'" # parallel inames must be same + "and (ii > ii' or (ii = ii' and jj >= jj'))" # before->after condtion + "}}".format( + STATEMENT_VAR_NAME, + ) + ) + + # intra-group case + + sio_intra_group_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii', j', jj'] -> [{0}=1, i, ii, j, jj] : " + "0 <= i,ii,i',ii' < pi and 0 <= j,jj,j',jj' < pj " # domains + "and i = i' " # GID parallel inames must be same + "and (ii > ii' or (ii = ii' and jj >= jj'))" # before->after condtion + "}}".format( + STATEMENT_VAR_NAME, + ) + ) + + # global case + + sio_global_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii', j', jj'] -> [{0}=1, i, ii, j, jj] : " + "0 <= i,ii,i',ii' < pi and 0 <= j,jj,j',jj' < pj " # domains + "and ii > ii'" # before->after condtion + "}}".format( + STATEMENT_VAR_NAME, + ) + ) + + _check_orderings_for_stmt_pair( + "stmt_b", "lbar1", pworders, + sio_intra_thread_exp=sio_intra_thread_exp, + sio_intra_group_exp=sio_intra_group_exp, + sio_global_exp=sio_global_exp, + ) + + # }}} + + # {{{ Relationship between stmt_a and stmt_b + + # intra thread case + + sio_intra_thread_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii', j', jj'] -> [{0}=1, i, ii, j, jj] : " + "0 <= i,ii,i',ii' < pi and 0 <= j,jj,j',jj' < pj " # domains + "and i = i' and j = j'" # parallel inames must be same + "and (ii > ii' or (ii = ii' and jj >= jj'))" # before->after condtion + "}}".format( + STATEMENT_VAR_NAME, + ) + ) + + # intra-group case + + sio_intra_group_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii', j', jj'] -> [{0}=1, i, ii, j, jj] : " + "0 <= i,ii,i',ii' < pi and 0 <= j,jj,j',jj' < pj " # domains + "and i = i' " # GID parallel inames must be same + "and (ii > ii' or (ii = ii' and jj >= jj'))" # before->after condtion + "}}".format( + STATEMENT_VAR_NAME, + ) + ) + + _check_orderings_for_stmt_pair( + "stmt_a", "stmt_b", pworders, + sio_intra_thread_exp=sio_intra_thread_exp, + sio_intra_group_exp=sio_intra_group_exp, + ) + + # }}} + + # {{{ Relationship between lbar1 and stmt_c + + # intra thread case + + sio_intra_thread_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii', j', jj'] -> [{0}=1] : " + "0 <= i',ii' < pi and 0 <= j',jj' < pj " # domains + "}}".format( + STATEMENT_VAR_NAME, + ) + ) + + # intra-group case + + sio_intra_group_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii', j', jj'] -> [{0}=1] : " + "0 <= i',ii' < pi and 0 <= j',jj' < pj " # domains + "}}".format( + STATEMENT_VAR_NAME, + ) + ) + + # global case + + # (only happens before if not last iteration of ii + sio_global_exp = _isl_map_with_marked_dims( + "[pi, pj] -> {{ " + "[{0}'=0, i', ii', j', jj'] -> [{0}=1] : " + "0 <= i',ii' < pi and 0 <= j',jj' < pj " # domains + "and ii' < pi-1" + "}}".format( + STATEMENT_VAR_NAME, + ) + ) + + _check_orderings_for_stmt_pair( + "lbar1", "stmt_c", pworders, + sio_intra_thread_exp=sio_intra_thread_exp, + sio_intra_group_exp=sio_intra_group_exp, + sio_global_exp=sio_global_exp, + ) + + # }}} + +# }}} + + # {{{ test_sios_and_schedules_with_barriers() def test_sios_and_schedules_with_barriers(): From 814607ae29a66cdd3080e7e25ea9f7e8d766aeb7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 17 Jul 2021 17:31:46 -0500 Subject: [PATCH 101/220] fix doc indentation --- loopy/schedule/checker/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 401fd477a..0698faf21 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -265,7 +265,7 @@ def get_EnterLoop_inames(linearization_items): def create_elementwise_comparison_conjunction_set( names0, names1, islvars, op="eq"): """Create a set constrained by the conjunction of conditions comparing - `names0` to `names1`. + `names0` to `names1`. :arg names0: A list of :class:`str` representing variable names. From f099b8f3f8006ecd25b371f6c57e0e3201cb45e6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 17 Jul 2021 17:31:57 -0500 Subject: [PATCH 102/220] Update loopy/schedule/checker/schedule.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix doc indentation Co-authored-by: Andreas Klöckner --- loopy/schedule/checker/schedule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 18f391c2b..3529dd48d 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -151,7 +151,7 @@ def _simplify_lex_dims(tup0, tup1): class SpecialLexPointWRTLoop: """Strings identifying a particular point or set of points in a - lexicographic ordering of statements, specified relative to a loop. + lexicographic ordering of statements, specified relative to a loop. .. attribute:: PRE A :class:`str` indicating the last lexicographic point that From 7d34906dcc70f0bda26c754dd9e70af989f8cabc Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 17 Jul 2021 17:34:34 -0500 Subject: [PATCH 103/220] Update loopy/schedule/checker/__init__.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit more generic terminology in doc string Co-authored-by: Andreas Klöckner --- loopy/schedule/checker/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 4ca15fe7f..529573860 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -44,7 +44,7 @@ def get_pairwise_statement_orderings( this routine during linearization, a truncated (i.e. partial) linearization may be passed through this argument. - :arg stmt_id_pairs: A list containing pairs of statement identifiers. + :arg stmt_id_pairs: A sequence containing pairs of statement identifiers. :returns: A dictionary mapping each two-tuple of statement identifiers provided in `stmt_id_pairs` to a :class:`collections.namedtuple` From 4092ae66a8ad539896f5f3b010da0d8ad3b00409 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 17 Jul 2021 17:53:57 -0500 Subject: [PATCH 104/220] revise docstring for StatementOrdering --- loopy/schedule/checker/schedule.py | 31 +++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 3529dd48d..e91cd6ac8 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -224,18 +224,14 @@ def get_pairwise_statement_orderings_inner( access tags. :returns: A dictionary mapping each two-tuple of statement identifiers - provided in `stmt_id_pairs` to a :class:`collections.namedtuple` + provided in `stmt_id_pairs` to a :class:`StatementOrdering` containing the intra-thread SIO (`sio_intra_thread`), intra-group SIO - (`sio_intra_group`), and global SIO (`sio_global`), each realized - as an :class:`islpy.Map` from each instance of the first - statement to all instances of the second statement that occur later, - as well as the intra-thread pairwise schedule (`pwsched_intra_thread`), - intra-group pairwise schedule (`pwsched_intra_group`), and the global - pairwise schedule (`pwsched_global`), each containing a pair of - mappings from statement instances to points in a lexicographic - ordering, one for each statement. Note that a pairwise schedule - alone cannot be used to reproduce the corresponding SIO without the - corresponding (unique) lexicographic order map, which is not returned. + (`sio_intra_group`), global SIO (`sio_global`), intra-thread pairwise + schedule (`pwsched_intra_thread`), intra-group pairwise schedule + (`pwsched_intra_group`), and the global pairwise schedule + (`pwsched_global`). Note that a pairwise schedule alone cannot be used + to reproduce the corresponding SIO without the corresponding + lexicographic order map, which is not returned. """ from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) @@ -827,6 +823,19 @@ def _get_map_for_stmt( # }}} pairwise_sios = {} + + """Create :class:`StatementOrdering` containing the + intra-thread SIO (`sio_intra_thread`), + intra-group SIO (`sio_intra_group`), + global SIO (`sio_global`), + intra-thread pairwise schedule (`pwsched_intra_thread`), + intra-group pairwise schedule (`pwsched_intra_group`), + and the global pairwise schedule (`pwsched_global`), + Each SIO is realized as an :class:`islpy.Map` from each instance of the + first statement to all instances of the second statement that occur later. + Each pairwise schedule contains a pair of mappings from statement + instances to points in a lexicographic ordering, one for each statement. + """ from collections import namedtuple StatementOrdering = namedtuple( "StatementOrdering", From 4196adbf24957415f44922edd1585a9f83087a37 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 17 Jul 2021 19:08:14 -0500 Subject: [PATCH 105/220] promote StatementOrdering to top-level dataclass --- loopy/schedule/checker/schedule.py | 85 +++++++++++++++++------------- 1 file changed, 49 insertions(+), 36 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index e91cd6ac8..02ff14ae5 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -21,6 +21,7 @@ """ import islpy as isl +from dataclasses import dataclass dt = isl.dim_type.set @@ -154,28 +155,28 @@ class SpecialLexPointWRTLoop: lexicographic ordering of statements, specified relative to a loop. .. attribute:: PRE - A :class:`str` indicating the last lexicographic point that - precedes the loop. + A :class:`str` indicating the last lexicographic point that + precedes the loop. .. attribute:: FIRST - A :class:`str` indicating the first lexicographic point in the - first loop iteration (i.e., with the iname set to its min. val). + A :class:`str` indicating the first lexicographic point in the + first loop iteration (i.e., with the iname set to its min. val). .. attribute:: TOP - A :class:`str` indicating the first lexicographic point in - an arbitrary loop iteration. + A :class:`str` indicating the first lexicographic point in + an arbitrary loop iteration. .. attribute:: BOTTOM - A :class:`str` indicating the last lexicographic point in - an arbitrary loop iteration. + A :class:`str` indicating the last lexicographic point in + an arbitrary loop iteration. .. attribute:: LAST - A :class:`str` indicating the last lexicographic point in the - last loop iteration (i.e., with the iname set to its max val). + A :class:`str` indicating the last lexicographic point in the + last loop iteration (i.e., with the iname set to its max val). .. attribute:: POST - A :class:`str` indicating the first lexicographic point that - follows the loop. + A :class:`str` indicating the first lexicographic point that + follows the loop. """ PRE = "pre" @@ -188,6 +189,37 @@ class SpecialLexPointWRTLoop: # }}} +# {{{ class StatementOrdering + +@dataclass +class StatementOrdering: + r"""A container for mappings used to describe the ordering of statement + instances for a pair of statements. These include the intra-thread SIO + (`sio_intra_thread`), intra-group SIO (`sio_intra_group`), and global SIO + (`sio_global`), each realized as an :class:`islpy.Map` from each instance + of the first statement to all instances of the second statement that occur + later. + + Also included (mostly for testing and debugging) are the + intra-thread pairwise schedule (`pwsched_intra_thread`), intra-group + pairwise schedule (`pwsched_intra_group`), and global pairwise schedule + (`pwsched_global`), each containing a pair of mappings from statement + instances to points in a lexicographic ordering, one for each statement. + Each SIO is created by composing the two mappings in the corresponding + pairwise schedule with an associated mapping defining the ordering of + points in the lexicographical space (not included). + """ + + sio_intra_thread: isl.Map + sio_intra_group: isl.Map + sio_global: isl.Map + pwsched_intra_thread: tuple + pwsched_intra_group: tuple + pwsched_global: tuple + +# }}} + + # {{{ get_pairwise_statement_orderings_inner def get_pairwise_statement_orderings_inner( @@ -824,28 +856,6 @@ def _get_map_for_stmt( pairwise_sios = {} - """Create :class:`StatementOrdering` containing the - intra-thread SIO (`sio_intra_thread`), - intra-group SIO (`sio_intra_group`), - global SIO (`sio_global`), - intra-thread pairwise schedule (`pwsched_intra_thread`), - intra-group pairwise schedule (`pwsched_intra_group`), - and the global pairwise schedule (`pwsched_global`), - Each SIO is realized as an :class:`islpy.Map` from each instance of the - first statement to all instances of the second statement that occur later. - Each pairwise schedule contains a pair of mappings from statement - instances to points in a lexicographic ordering, one for each statement. - """ - from collections import namedtuple - StatementOrdering = namedtuple( - "StatementOrdering", - [ - "sio_intra_thread", "pwsched_intra_thread", - "sio_intra_group", "pwsched_intra_group", - "sio_global", "pwsched_global", - ]) - # ("sio" = statement instance ordering; "pwsched" = pairwise schedule) - for stmt_ids in stmt_id_pairs: # Determine integer IDs that will represent each statement in mapping # (dependency map creation assumes sid_before=0 and sid_after=1, unless @@ -928,6 +938,9 @@ def _get_sched_maps_and_sio( in zip(stmt_ids, blex_tuples_padded, int_sids) ] + # Note that for the intra-group case, we already constrained GID + # 'before' to equal GID 'after' earlier in _gather_blex_ordering_info() + # Create statement instance ordering sio_par = get_statement_ordering_map( *par_sched_maps, # note, func accepts exactly two maps @@ -947,10 +960,10 @@ def _get_sched_maps_and_sio( # Store sched maps along with SIOs pairwise_sios[tuple(stmt_ids)] = StatementOrdering( sio_intra_thread=sio_intra_thread, - pwsched_intra_thread=tuple(intra_thread_sched_maps), sio_intra_group=sio_intra_group, - pwsched_intra_group=tuple(pwsched_intra_group), sio_global=sio_global, + pwsched_intra_thread=tuple(intra_thread_sched_maps), + pwsched_intra_group=tuple(pwsched_intra_group), pwsched_global=tuple(pwsched_global), ) From 4e847a5c7581aafae126d74ca80328f2d02d1383 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 17 Jul 2021 19:10:37 -0500 Subject: [PATCH 106/220] add dataclass to install_requires in setup.py --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 2e907c1b9..2f04d2203 100644 --- a/setup.py +++ b/setup.py @@ -90,6 +90,7 @@ def write_git_revision(package_name): # https://github.com/inducer/loopy/pull/419 "numpy>=1.19", + "dataclasses>=0.7;python_version<='3.6'" "cgen>=2016.1", "islpy>=2019.1", From 9ecd66d4e5e4129dd6e8b2c8f713eb2221beae1b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 17 Jul 2021 19:41:37 -0500 Subject: [PATCH 107/220] fix docstring indentation --- loopy/schedule/checker/lexicographic_order_map.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 0a01f888c..896235b82 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -27,7 +27,7 @@ def get_statement_ordering_map( sched_before, sched_after, lex_map, before_mark): """Return a statement ordering represented as a map from each statement - instance to all statement instances occurring later. + instance to all statement instances occurring later. :arg sched_before: An :class:`islpy.Map` representing a schedule as a mapping from statement instances (for one particular statement) @@ -77,9 +77,9 @@ def get_lex_order_set( islvars=None, ): """Return an :class:`islpy.Set` representing a lexicographic ordering - over a space with the number of dimensions provided in `dim_names` - (the set itself will have twice this many dimensions in order to - represent the ordering as before-after pairs of points). + over a space with the number of dimensions provided in `dim_names` + (the set itself will have twice this many dimensions in order to + represent the ordering as before-after pairs of points). :arg dim_names: A list of :class:`str` variable names to be used to describe lexicographic space dimensions for a point in a lexicographic @@ -160,7 +160,7 @@ def create_lex_order_map( in_dim_mark, ): """Return a map from each point in a lexicographic ordering to every - point that occurs later in the lexicographic ordering. + point that occurs later in the lexicographic ordering. :arg dim_names: A list of :class:`str` variable names for the lexicographic space dimensions. From 7c4785a36352d3e1abaffc80a7cfe94a22de0bbb Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 17 Jul 2021 19:42:47 -0500 Subject: [PATCH 108/220] reorg and improve docstrings about SIOs a bit --- loopy/schedule/checker/__init__.py | 37 ++++++++++++++------------- loopy/schedule/checker/schedule.py | 40 ++++++++++++++++-------------- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 529573860..d24b7a2ea 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -30,10 +30,23 @@ def get_pairwise_statement_orderings( ): r"""For each statement pair in a subset of all statement pairs found in a linearized kernel, determine the (relative) order in which the statement - instances are executed. For each pair, represent this relative ordering as - a ``statement instance ordering`` (SIO): a map from each instance of the - first statement to all instances of the second statement that occur - later. + instances are executed. For each pair, represent this relative ordering + using three ``statement instance orderings`` (SIOs): + + - The intra-thread SIO: A :class:`islpy.Map` from each instance of the + first statement to all instances of the second statement that occur + later, such that both statement instances in each before-after pair are + executed within the same work-item (thread). + + - The intra-group SIO: A :class:`islpy.Map` from each instance of the first + statement to all instances of the second statement that occur later, such + that both statement instances in each before-after pair are executed + within the same work-group (though potentially by different work-items). + + - The global SIO: A :class:`islpy.Map` from each instance of the first + statement to all instances of the second statement that occur later, even + if the two statement instances in a given before-after pair are executed + within different work-groups. :arg knl: A preprocessed :class:`loopy.kernel.LoopKernel` containing the linearization items that will be used to create the SIOs. @@ -47,18 +60,8 @@ def get_pairwise_statement_orderings( :arg stmt_id_pairs: A sequence containing pairs of statement identifiers. :returns: A dictionary mapping each two-tuple of statement identifiers - provided in `stmt_id_pairs` to a :class:`collections.namedtuple` - containing the intra-thread SIO (`sio_intra_thread`), intra-group SIO - (`sio_intra_group`), and global SIO (`sio_global`), each realized - as an :class:`islpy.Map` from each instance of the first - statement to all instances of the second statement that occur later, - as well as the intra-thread pairwise schedule (`pwsched_intra_thread`), - intra-group pairwise schedule (`pwsched_intra_group`), and the global - pairwise schedule (`pwsched_global`), each containing a pair of - mappings from statement instances to points in a lexicographic - ordering, one for each statement. Note that a pairwise schedule - alone cannot be used to reproduce the corresponding SIO without the - corresponding (unique) lexicographic order map, which is not returned. + provided in `stmt_id_pairs` to a :class:`StatementOrdering`, which + contains the three SIOs described above. .. doctest: @@ -124,7 +127,7 @@ def get_pairwise_statement_orderings( # }}} - # {{{ Create two mappings from {statement instance: lex point} + # {{{ Create the SIOs from loopy.schedule.checker.schedule import ( get_pairwise_statement_orderings_inner diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 02ff14ae5..85e1c8429 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -193,12 +193,9 @@ class SpecialLexPointWRTLoop: @dataclass class StatementOrdering: - r"""A container for mappings used to describe the ordering of statement - instances for a pair of statements. These include the intra-thread SIO - (`sio_intra_thread`), intra-group SIO (`sio_intra_group`), and global SIO - (`sio_global`), each realized as an :class:`islpy.Map` from each instance - of the first statement to all instances of the second statement that occur - later. + r"""A container for the three statement instance orderings (described + below) used to formalize the ordering of statement instances for a pair of + statements. Also included (mostly for testing and debugging) are the intra-thread pairwise schedule (`pwsched_intra_thread`), intra-group @@ -230,10 +227,23 @@ def get_pairwise_statement_orderings_inner( ): r"""For each statement pair in a subset of all statement pairs found in a linearized kernel, determine the (relative) order in which the statement - instances are executed. For each pair, represent this relative ordering as - a ``statement instance ordering`` (SIO): a map from each instance of the - first statement to all instances of the second statement that occur - later. + instances are executed. For each pair, represent this relative ordering + using three ``statement instance orderings`` (SIOs): + + - The intra-thread SIO: A :class:`islpy.Map` from each instance of the + first statement to all instances of the second statement that occur + later, such that both statement instances in each before-after pair are + executed within the same work-item (thread). + + - The intra-group SIO: A :class:`islpy.Map` from each instance of the first + statement to all instances of the second statement that occur later, such + that both statement instances in each before-after pair are executed + within the same work-group (though potentially by different work-items). + + - The global SIO: A :class:`islpy.Map` from each instance of the first + statement to all instances of the second statement that occur later, even + if the two statement instances in a given before-after pair are executed + within different work-groups. :arg knl: A preprocessed :class:`loopy.kernel.LoopKernel` containing the linearization items that will be used to create the SIOs. This @@ -256,14 +266,8 @@ def get_pairwise_statement_orderings_inner( access tags. :returns: A dictionary mapping each two-tuple of statement identifiers - provided in `stmt_id_pairs` to a :class:`StatementOrdering` - containing the intra-thread SIO (`sio_intra_thread`), intra-group SIO - (`sio_intra_group`), global SIO (`sio_global`), intra-thread pairwise - schedule (`pwsched_intra_thread`), intra-group pairwise schedule - (`pwsched_intra_group`), and the global pairwise schedule - (`pwsched_global`). Note that a pairwise schedule alone cannot be used - to reproduce the corresponding SIO without the corresponding - lexicographic order map, which is not returned. + provided in `stmt_id_pairs` to a :class:`StatementOrdering`, which + contains the three SIOs described above. """ from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) From 7614ab88b9d1b0a81ee07a8168f589f3a3d98f67 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 17 Jul 2021 20:05:01 -0500 Subject: [PATCH 109/220] consistent naming of funcs --- loopy/schedule/checker/lexicographic_order_map.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 896235b82..f0ae65f98 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -71,7 +71,7 @@ def get_statement_ordering_map( sio, isl.dim_type.in_, before_mark) -def get_lex_order_set( +def _create_lex_order_set( dim_names, in_dim_mark, islvars=None, @@ -186,7 +186,7 @@ def create_lex_order_map( dim_type = isl.dim_type # First, get a set representing the lexicographic ordering. - lex_order_set = get_lex_order_set( + lex_order_set = _create_lex_order_set( dim_names, in_dim_mark=in_dim_mark, ) From 9963c9b73944fee1c278a85bd79af7ad604e184c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 17 Jul 2021 20:10:14 -0500 Subject: [PATCH 110/220] docstring grammar typo --- loopy/schedule/checker/lexicographic_order_map.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index f0ae65f98..aac4ac8c7 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -92,7 +92,7 @@ def _create_lex_order_set( :arg islvars: A dictionary mapping variable names in `dim_names` to :class:`islpy.PwAff` instances that represent each of the variables (islvars may be produced by `islpy.make_zero_and_vars`). - The key '0' is also include and represents a :class:`islpy.PwAff` zero + The key '0' is also included and represents a :class:`islpy.PwAff` zero constant. This dictionary defines the space to be used for the set and must also include versions of `dim_names` with the `in_dim_mark` appended. If no value is passed, the dictionary will be made using From 9668335ff93ccf92df09accb93b797c303b20e9b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 19 Jul 2021 12:40:16 -0500 Subject: [PATCH 111/220] fix typo in setup.py --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2f04d2203..701f796d5 100644 --- a/setup.py +++ b/setup.py @@ -90,7 +90,7 @@ def write_git_revision(package_name): # https://github.com/inducer/loopy/pull/419 "numpy>=1.19", - "dataclasses>=0.7;python_version<='3.6'" + "dataclasses>=0.7;python_version<='3.6'", "cgen>=2016.1", "islpy>=2019.1", From 74b3f4bfb21c4f07f401bd1b07bcc0d0d2d89222 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 19 Jul 2021 12:50:56 -0500 Subject: [PATCH 112/220] rename islvars->var_name_to_pwaff --- .../checker/lexicographic_order_map.py | 25 +++++----- loopy/schedule/checker/utils.py | 48 +++++++++---------- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index aac4ac8c7..5821202cb 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -74,7 +74,7 @@ def get_statement_ordering_map( def _create_lex_order_set( dim_names, in_dim_mark, - islvars=None, + var_name_to_pwaff=None, ): """Return an :class:`islpy.Set` representing a lexicographic ordering over a space with the number of dimensions provided in `dim_names` @@ -89,9 +89,9 @@ def _create_lex_order_set( distinguish corresponding dimensions in before-after pairs of points. (see example below) - :arg islvars: A dictionary mapping variable names in `dim_names` to + :arg var_name_to_pwaff: A dictionary mapping variable names in `dim_names` to :class:`islpy.PwAff` instances that represent each of the variables - (islvars may be produced by `islpy.make_zero_and_vars`). + (var_name_to_pwaff may be produced by `islpy.make_zero_and_vars`). The key '0' is also included and represents a :class:`islpy.PwAff` zero constant. This dictionary defines the space to be used for the set and must also include versions of `dim_names` with the `in_dim_mark` @@ -121,33 +121,36 @@ def _create_lex_order_set( in_dim_names = append_mark_to_strings(dim_names, mark=in_dim_mark) - # If no islvars passed, make them using the names provided + # If no var_name_to_pwaff passed, make them using the names provided # (make sure to pass var names in desired order of space dims) - if islvars is None: - islvars = isl.make_zero_and_vars( + if var_name_to_pwaff is None: + var_name_to_pwaff = isl.make_zero_and_vars( in_dim_names+dim_names, []) # Initialize set with constraint i0' < i0 - lex_order_set = islvars[in_dim_names[0]].lt_set(islvars[dim_names[0]]) + lex_order_set = var_name_to_pwaff[in_dim_names[0]].lt_set( + var_name_to_pwaff[dim_names[0]]) # For each dim d, starting with d=1, equality_conj_set will be constrained # by d equalities, e.g., (i0' = i0 and i1' = i1 and ... i(d-1)' = i(d-1)). - equality_conj_set = islvars[0].eq_set(islvars[0]) # initialize to 'true' + equality_conj_set = var_name_to_pwaff[0].eq_set( + var_name_to_pwaff[0]) # initialize to 'true' for i in range(1, len(in_dim_names)): # Add the next equality constraint to equality_conj_set equality_conj_set = equality_conj_set & \ - islvars[in_dim_names[i-1]].eq_set(islvars[dim_names[i-1]]) + var_name_to_pwaff[in_dim_names[i-1]].eq_set( + var_name_to_pwaff[dim_names[i-1]]) # Create a set constrained by adding a less-than constraint for this dim, # e.g., (i1' < i1), to the current equality conjunction set. # For each dim d, starting with d=1, this full conjunction will have # d equalities and one inequality, e.g., # (i0' = i0 and i1' = i1 and ... i(d-1)' = i(d-1) and id' < id) - full_conj_set = islvars[in_dim_names[i]].lt_set( - islvars[dim_names[i]]) & equality_conj_set + full_conj_set = var_name_to_pwaff[in_dim_names[i]].lt_set( + var_name_to_pwaff[dim_names[i]]) & equality_conj_set # Union this new constraint with the current lex_order_set lex_order_set = lex_order_set | full_conj_set diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 0698faf21..94f2fbd0c 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -175,13 +175,24 @@ def create_symbolic_map_from_tuples( on these values. """ - # TODO allow None for domains + # FIXME allow None for domains space_out_names = space.get_var_names(dt.out) space_in_names = space.get_var_names(dt.in_) + def _conjunction_of_dim_eq_conditions(dim_names, values, var_name_to_pwaff): + condition = var_name_to_pwaff[0].eq_set(var_name_to_pwaff[0]) + for dim_name, val in zip(dim_names, values): + if isinstance(val, int): + condition = condition \ + & var_name_to_pwaff[dim_name].eq_set(var_name_to_pwaff[0]+val) + else: + condition = condition \ + & var_name_to_pwaff[dim_name].eq_set(var_name_to_pwaff[val]) + return condition + # Get islvars from space - islvars = isl.affs_from_space( + var_name_to_pwaff = isl.affs_from_space( space.move_dims( dt.out, 0, dt.in_, 0, @@ -189,20 +200,9 @@ def create_symbolic_map_from_tuples( ).range() ) - def _conjunction_of_dim_eq_conditions(dim_names, values, islvars): - condition = islvars[0].eq_set(islvars[0]) - for dim_name, val in zip(dim_names, values): - if isinstance(val, int): - condition = condition \ - & islvars[dim_name].eq_set(islvars[0]+val) - else: - condition = condition \ - & islvars[dim_name].eq_set(islvars[val]) - return condition - # Initialize union of maps to empty union_of_maps = isl.Map.from_domain( - islvars[0].eq_set(islvars[0]+1) # 0 == 1 (false) + var_name_to_pwaff[0].eq_set(var_name_to_pwaff[0]+1) # 0 == 1 (false) ).move_dims( dt.out, 0, dt.in_, len(space_in_names), len(space_out_names)) @@ -211,11 +211,11 @@ def _conjunction_of_dim_eq_conditions(dim_names, values, islvars): # Set values for 'in' dimension using tuple vals condition = _conjunction_of_dim_eq_conditions( - space_in_names, tup_in, islvars) + space_in_names, tup_in, var_name_to_pwaff) # Set values for 'out' dimension using tuple vals condition = condition & _conjunction_of_dim_eq_conditions( - space_out_names, tup_out, islvars) + space_out_names, tup_out, var_name_to_pwaff) # Convert set to map by moving dimensions around map_from_set = isl.Map.from_domain(condition) @@ -263,7 +263,7 @@ def get_EnterLoop_inames(linearization_items): def create_elementwise_comparison_conjunction_set( - names0, names1, islvars, op="eq"): + names0, names1, var_name_to_pwaff, op="eq"): """Create a set constrained by the conjunction of conditions comparing `names0` to `names1`. @@ -271,27 +271,27 @@ def create_elementwise_comparison_conjunction_set( :arg names1: A list of :class:`str` representing variable names. - :arg islvars: A dictionary from variable names to :class:`islpy.PwAff` + :arg var_name_to_pwaff: A dictionary from variable names to :class:`islpy.PwAff` instances that represent each of the variables - (islvars may be produced by `islpy.make_zero_and_vars`). The key + (var_name_to_pwaff may be produced by `islpy.make_zero_and_vars`). The key '0' is also include and represents a :class:`islpy.PwAff` zero constant. :arg op: A :class:`str` describing the operator to use when creating the set constraints. Options: `eq` for `=`, `lt` for `<` - :returns: A set involving `islvars` cosntrained by the constraints + :returns: A set involving `var_name_to_pwaff` cosntrained by the constraints `{names0[0] names1[0] and names0[1] names1[1] and ...}`. """ # initialize set with constraint that is always true - conj_set = islvars[0].eq_set(islvars[0]) + conj_set = var_name_to_pwaff[0].eq_set(var_name_to_pwaff[0]) for n0, n1 in zip(names0, names1): if op == "eq": - conj_set = conj_set & islvars[n0].eq_set(islvars[n1]) + conj_set = conj_set & var_name_to_pwaff[n0].eq_set(var_name_to_pwaff[n1]) elif op == "ne": - conj_set = conj_set & islvars[n0].ne_set(islvars[n1]) + conj_set = conj_set & var_name_to_pwaff[n0].ne_set(var_name_to_pwaff[n1]) elif op == "lt": - conj_set = conj_set & islvars[n0].lt_set(islvars[n1]) + conj_set = conj_set & var_name_to_pwaff[n0].lt_set(var_name_to_pwaff[n1]) return conj_set From 2ef18166d3a10019520687ad7fdd3d385f857ead Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 19 Jul 2021 13:06:18 -0500 Subject: [PATCH 113/220] add foldmethod=maker line for vim --- loopy/schedule/checker/__init__.py | 2 ++ loopy/schedule/checker/schedule.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index d24b7a2ea..b994d8768 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -142,3 +142,5 @@ def get_pairwise_statement_orderings( # }}} # }}} + +# vim: foldmethod=marker diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 85e1c8429..c7c545964 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -976,3 +976,5 @@ def _get_sched_maps_and_sio( return pairwise_sios # }}} + +# vim: foldmethod=marker From 0e8be5b5f23ca236074911051a432b286908dc1b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 19 Jul 2021 13:25:49 -0500 Subject: [PATCH 114/220] clarify comment --- loopy/schedule/checker/schedule.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index c7c545964..5940059c9 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -512,7 +512,8 @@ def _gather_blex_ordering_info(sync_kind): slex.TOP: tuple(next_blex_tuple), slex.FIRST: tuple(first_iter_blex_pt), } - # (make sure ^these are copies) + # (copy these three blex points when creating dict because + # the lists will continue to be updated) # Store any new params found blex_order_map_params |= set(lbound.get_var_names(dt.param)) @@ -548,7 +549,8 @@ def _gather_blex_ordering_info(sync_kind): last_iter_blex_pt) blex_exclusion_info[leave_iname][slex.POST] = tuple( next_blex_tuple) - # (make sure ^these are copies) + # (copy these three blex points when creating dict because + # the lists will continue to be updated) # Store any new params found blex_order_map_params |= set(ubound.get_var_names(dt.param)) From d4623c6e539d37a31f31fdc0f1cbb737bcfc859f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 19 Jul 2021 18:09:12 -0500 Subject: [PATCH 115/220] promote _gather_blex_ordering_info() to top level (step 1, temporarily keep old version for sanity check) --- loopy/schedule/checker/schedule.py | 374 ++++++++++++++++++++++++++++- 1 file changed, 371 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 5940059c9..deb53a264 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -217,6 +217,344 @@ class StatementOrdering: # }}} +# {{{ _gather_blex_ordering_info + +def _gather_blex_ordering_info( + sync_kind, + lin_items, loops_with_barriers, loops_to_ignore, + all_stmt_ids, iname_bounds_pwaff, + all_par_lex_dim_names, gid_lex_dim_names, + ): + """For the given sync_kind ("local" or "global"), create a mapping from + statement instances to blex space (dict), as well as a mapping + defining the blex ordering (isl map from blex space -> blex space) + + Note that, unlike in the intra-thread case, there will be a single + blex ordering map defining the blex ordering for all statement pairs, + rather than separate (smaller) lex ordering maps for each pair + """ + from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) + from loopy.schedule.checker.lexicographic_order_map import ( + create_lex_order_map, + ) + from loopy.schedule.checker.utils import ( + add_and_name_isl_dims, + append_mark_to_strings, + add_eq_isl_constraint_from_names, + ) + slex = SpecialLexPointWRTLoop + + # {{{ First, create map from stmt instances to blex space. + + # At the same time, gather information necessary to create the + # blex ordering map, i.e., for each loop, gather the 6 lex order tuples + # defined above in SpecialLexPointWRTLoop that will be required to + # create sub-maps which will be *excluded* (subtracted) from a standard + # lexicographic ordering in order to create the blex ordering + + stmt_inst_to_blex = {} # Map stmt instances to blex space + iname_to_blex_dim = {} # Map from inames to corresponding blex space dim + blex_exclusion_info = {} # Info for creating maps to exclude from blex order + blex_order_map_params = set() # Params needed in blex order map + n_seq_blex_dims = 1 # Num dims representing sequential order in blex space + next_blex_tuple = [0] # Next tuple of points in blex order + + for lin_item in lin_items: + if isinstance(lin_item, EnterLoop): + enter_iname = lin_item.iname + if enter_iname in loops_with_barriers[sync_kind] - loops_to_ignore: + pre_loop_blex_pt = next_blex_tuple[:] + + # Increment next_blex_tuple[-1] for statements in the section + # of code between this EnterLoop and the matching LeaveLoop. + next_blex_tuple[-1] += 1 + + # Upon entering a loop, add one blex dimension for the loop + # iteration, add second blex dim to enumerate sections of + # code within new loop + next_blex_tuple.append(enter_iname) + next_blex_tuple.append(0) + + # Store 3 tuples that will be used later to create pairs + # that will later be subtracted from the blex order map + lbound = iname_bounds_pwaff[enter_iname][0] + first_iter_blex_pt = next_blex_tuple[:] + first_iter_blex_pt[-2] = lbound + blex_exclusion_info[enter_iname] = { + slex.PRE: tuple(pre_loop_blex_pt), + slex.TOP: tuple(next_blex_tuple), + slex.FIRST: tuple(first_iter_blex_pt), + } + # (copy these three blex points when creating dict because + # the lists will continue to be updated) + + # Store any new params found + blex_order_map_params |= set(lbound.get_var_names(dt.param)) + + elif isinstance(lin_item, LeaveLoop): + leave_iname = lin_item.iname + if leave_iname in loops_with_barriers[sync_kind] - loops_to_ignore: + + # Update max blex dims + n_seq_blex_dims = max(n_seq_blex_dims, len(next_blex_tuple)) + + # Record the blex dim for this loop iname + iname_to_blex_dim[leave_iname] = len(next_blex_tuple)-2 + + # Update next blex pt + pre_end_loop_blex_pt = next_blex_tuple[:] + # Upon leaving a loop: + # - Pop lex dim for enumerating code sections within this loop + # - Pop lex dim for the loop iteration + # - Increment lex dim val enumerating items in current section + next_blex_tuple.pop() + next_blex_tuple.pop() + next_blex_tuple[-1] += 1 + + # Store 3 tuples that will be used later to create pairs + # that will later be subtracted from the blex order map + ubound = iname_bounds_pwaff[leave_iname][1] + last_iter_blex_pt = pre_end_loop_blex_pt[:] + last_iter_blex_pt[-2] = ubound + blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( + pre_end_loop_blex_pt) + blex_exclusion_info[leave_iname][slex.LAST] = tuple( + last_iter_blex_pt) + blex_exclusion_info[leave_iname][slex.POST] = tuple( + next_blex_tuple) + # (copy these three blex points when creating dict because + # the lists will continue to be updated) + + # Store any new params found + blex_order_map_params |= set(ubound.get_var_names(dt.param)) + + elif isinstance(lin_item, RunInstruction): + # Add stmt->blex pair to stmt_inst_to_blex + stmt_inst_to_blex[lin_item.insn_id] = tuple(next_blex_tuple) + + # (Don't increment blex dim val) + + elif isinstance(lin_item, Barrier): + # Increment blex dim val if the sync scope matches + if lin_item.synchronization_kind == sync_kind: + next_blex_tuple[-1] += 1 + + lp_stmt_id = lin_item.originating_insn_id + + if lp_stmt_id is None: + # Barriers without stmt ids were inserted as a result of a + # dependency. They don't themselves have dependencies. + # Don't map this barrier to a blex tuple. + continue + + # This barrier has a stmt id. + # If it was included in listed stmts, process it. + # Otherwise, there's nothing left to do (we've already + # incremented next_blex_tuple if necessary, and this barrier + # does not need to be assigned to a designated point in blex + # time) + if lp_stmt_id in all_stmt_ids: + # If sync scope matches, give this barrier its own point in + # lex time and update blex tuple after barrier. + # Otherwise, add stmt->blex pair to stmt_inst_to_blex, but + # don't update the blex tuple (just like with any other + # stmt) + if lin_item.synchronization_kind == sync_kind: + stmt_inst_to_blex[lp_stmt_id] = tuple(next_blex_tuple) + next_blex_tuple[-1] += 1 + else: + stmt_inst_to_blex[lp_stmt_id] = tuple(next_blex_tuple) + else: + from loopy.schedule import (CallKernel, ReturnFromKernel) + # No action needed for these types of linearization item + assert isinstance( + lin_item, (CallKernel, ReturnFromKernel)) + pass + + blex_order_map_params = sorted(blex_order_map_params) + + # At this point, some blex tuples may have more dimensions than others; + # the missing dims are the fastest-updating dims, and their values should + # be zero. Add them. + for stmt, tup in stmt_inst_to_blex.items(): + stmt_inst_to_blex[stmt] = _pad_tuple_with_zeros(tup, n_seq_blex_dims) + + # }}} + + # {{{ Second, create the blex order map + + # {{{ Create the initial (pre-subtraction) blex order map + + # Create names for the blex dimensions for sequential loops + seq_blex_dim_names = [ + LEX_VAR_PREFIX+str(i) for i in range(n_seq_blex_dims)] + seq_blex_dim_names_prime = append_mark_to_strings( + seq_blex_dim_names, mark=BEFORE_MARK) + + # Begin with the blex order map created as a standard lexicographical order + blex_order_map = create_lex_order_map( + dim_names=seq_blex_dim_names, + in_dim_mark=BEFORE_MARK, + ) + + # Add LID/GID dims to blex order map + blex_order_map = add_and_name_isl_dims( + blex_order_map, dt.out, all_par_lex_dim_names) + blex_order_map = add_and_name_isl_dims( + blex_order_map, dt.in_, + append_mark_to_strings(all_par_lex_dim_names, mark=BEFORE_MARK)) + if sync_kind == "local": + # For intra-group case, constrain GID 'before' to equal GID 'after' + for var_name in gid_lex_dim_names: + blex_order_map = add_eq_isl_constraint_from_names( + blex_order_map, var_name, var_name+BEFORE_MARK) + # (if sync_kind == "global", don't need constraints on LID/GID vars) + + # }}} + + # {{{ Subtract unwanted pairs from happens-before blex map + + # Create map from iname to corresponding blex dim name + iname_to_blex_var = {} + for iname, dim in iname_to_blex_dim.items(): + iname_to_blex_var[iname] = seq_blex_dim_names[dim] + iname_to_blex_var[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] + + # Add bounds params needed in blex map + blex_order_map = add_and_name_isl_dims( + blex_order_map, dt.param, blex_order_map_params) + + # Get a set representing blex_order_map space + n_blex_dims = n_seq_blex_dims + len(all_par_lex_dim_names) + blex_set_template = isl.align_spaces( + isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map + ).move_dims( + dt.in_, n_blex_dims, dt.out, 0, n_blex_dims + ).domain() + blex_set_affs = isl.affs_from_space(blex_set_template.space) + + # {{{ _create_excluded_map_for_iname + + def _create_excluded_map_for_iname(iname, key_lex_tuples): + """Create the blex->blex pairs that must be subtracted from the + initial blex order map for this particular loop using the 6 blex + tuples in the key_lex_tuples: + PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST + """ + + # Note: + # only key_lex_tuples[slex.FIRST] & key_lex_tuples[slex.LAST] are pwaffs + + # {{{ _create_blex_set_from_tuple_pair + + def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): + """Given a before->after tuple pair in the key_lex_tuples, which may + have dim vals described by ints, strings (inames), and pwaffs, + create an ISL set in blex space that can be converted into + the ISL map to be subtracted + """ + # (Vars from outside func used here: + # iname, blex_set_affs, blex_set_template, iname_to_blex_var, + # n_seq_blex_dims, seq_blex_dim_names, + # seq_blex_dim_names_prime) + + # Start with a set representing blex_order_map space + blex_set = blex_set_template.copy() + + # Add marks to inames in the 'before' tuple + # (all strings should be inames) + before_prime = tuple( + v+BEFORE_MARK if isinstance(v, str) else v for v in before) + before_padded = _pad_tuple_with_zeros(before_prime, n_seq_blex_dims) + after_padded = _pad_tuple_with_zeros(after, n_seq_blex_dims) + + # Assign vals in the tuple to dims in the ISL set + for dim_name, dim_val in zip( + seq_blex_dim_names_prime+seq_blex_dim_names, + before_padded+after_padded): + + if isinstance(dim_val, int): + # Set idx to int val + blex_set &= blex_set_affs[dim_name].eq_set( + blex_set_affs[0]+dim_val) + elif isinstance(dim_val, str): + # This is an iname, set idx to corresponding blex var + blex_set &= blex_set_affs[dim_name].eq_set( + blex_set_affs[iname_to_blex_var[dim_val]]) + else: + # This is a pwaff iname bound, align and intersect + assert isinstance(dim_val, isl.PwAff) + pwaff_aligned = isl.align_spaces(dim_val, blex_set_affs[0]) + # (doesn't matter which blex_set_affs item we align to^) + blex_set &= blex_set_affs[dim_name].eq_set(pwaff_aligned) + + if wrap_cond: + # This is the BOTTOM->TOP pair, add condition i = i' + 1 + blex_set &= blex_set_affs[iname_to_blex_var[iname]].eq_set( + blex_set_affs[iname_to_blex_var[iname+BEFORE_MARK]] + 1) + + return blex_set + + # }}} end _create_blex_set_from_tuple_pair() + + # Create pairs to be subtracted + # (set will be converted to map) + + # Enter loop case: PRE->FIRST + full_blex_set = _create_blex_set_from_tuple_pair( + key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST]) + # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) + full_blex_set |= _create_blex_set_from_tuple_pair( + key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], + wrap_cond=True) + # Leave loop case: LAST->POST + full_blex_set |= _create_blex_set_from_tuple_pair( + key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST]) + + # Add condition to fix iteration value for *surrounding* loops (j = j') + for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: + s_blex_var = iname_to_blex_var[surrounding_iname] + full_blex_set &= blex_set_affs[s_blex_var].eq_set( + blex_set_affs[s_blex_var+BEFORE_MARK]) + + # Convert blex set back to map + return isl.Map.from_domain(full_blex_set).move_dims( + dt.out, 0, dt.in_, n_blex_dims, n_blex_dims) + + # }}} end _create_excluded_map_for_iname() + + # Create map to subtract for each iname + maps_to_subtract = [] + for iname, subdict in blex_exclusion_info.items(): + maps_to_subtract.append(_create_excluded_map_for_iname(iname, subdict)) + + if maps_to_subtract: + + # Get union of maps + map_to_subtract = maps_to_subtract[0] + for other_map in maps_to_subtract[1:]: + map_to_subtract |= other_map + + # Get transitive closure of maps + map_to_subtract, closure_exact = map_to_subtract.transitive_closure() + assert closure_exact # TODO warn instead? + + # Subtract closure from blex order map + blex_order_map = blex_order_map - map_to_subtract + + # }}} + + # }}} + + return ( + stmt_inst_to_blex, # map stmt instances to blex space + blex_order_map, + seq_blex_dim_names, + ) + +# }}} + + # {{{ get_pairwise_statement_orderings_inner def get_pairwise_statement_orderings_inner( @@ -461,7 +799,7 @@ def get_pairwise_statement_orderings_inner( # {{{ _gather_blex_ordering_info(sync_kind): gather blex info for sync_kind - def _gather_blex_ordering_info(sync_kind): + def _gather_blex_ordering_info_orig(sync_kind): """For the given sync_kind ("local" or "global"), create a mapping from statement instances to blex space (dict), as well as a mapping defining the blex ordering (isl map from blex space -> blex space) @@ -781,14 +1119,44 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # }}} end _gather_blex_ordering_info(sync_kind) + # TODO remove old function call after comparing results for sanity check + + # Get the blex schedule blueprint (dict will become a map below) and + # blex order map w.r.t. local and global barriers + (_stmt_inst_to_lblex, + _lblex_order_map, + _seq_lblex_dim_names) = _gather_blex_ordering_info_orig("local") + (_stmt_inst_to_gblex, + _gblex_order_map, + _seq_gblex_dim_names) = _gather_blex_ordering_info_orig("global") + # Get the blex schedule blueprint (dict will become a map below) and # blex order map w.r.t. local and global barriers (stmt_inst_to_lblex, lblex_order_map, - seq_lblex_dim_names) = _gather_blex_ordering_info("local") + seq_lblex_dim_names) = _gather_blex_ordering_info( + "local", + lin_items, loops_with_barriers, loops_to_ignore, + all_stmt_ids, iname_bounds_pwaff, + all_par_lex_dim_names, gid_lex_dim_names, + ) (stmt_inst_to_gblex, gblex_order_map, - seq_gblex_dim_names) = _gather_blex_ordering_info("global") + seq_gblex_dim_names) = _gather_blex_ordering_info( + "global", + lin_items, loops_with_barriers, loops_to_ignore, + all_stmt_ids, iname_bounds_pwaff, + all_par_lex_dim_names, gid_lex_dim_names, + ) + + assert _stmt_inst_to_lblex == stmt_inst_to_lblex + assert _lblex_order_map == lblex_order_map + assert _lblex_order_map.get_var_dict() == lblex_order_map.get_var_dict() + assert _seq_lblex_dim_names == seq_lblex_dim_names + assert _stmt_inst_to_gblex == stmt_inst_to_gblex + assert _gblex_order_map == gblex_order_map + assert _gblex_order_map.get_var_dict() == gblex_order_map.get_var_dict() + assert _seq_gblex_dim_names == seq_gblex_dim_names # }}} From 6fab4bc3084ac922c07adf3af971889da54de8ee Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 19 Jul 2021 18:15:19 -0500 Subject: [PATCH 116/220] remove sanity check and old version of _gather_blex_ordering_info() after promoting func to top level --- loopy/schedule/checker/schedule.py | 343 ----------------------------- 1 file changed, 343 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index deb53a264..f9dad40e1 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -622,7 +622,6 @@ def get_pairwise_statement_orderings_inner( create_symbolic_map_from_tuples, insert_and_name_isl_dims, ) - slex = SpecialLexPointWRTLoop all_stmt_ids = set().union(*stmt_id_pairs) @@ -797,339 +796,6 @@ def get_pairwise_statement_orderings_inner( all_par_lex_dim_names = lid_lex_dim_names + gid_lex_dim_names - # {{{ _gather_blex_ordering_info(sync_kind): gather blex info for sync_kind - - def _gather_blex_ordering_info_orig(sync_kind): - """For the given sync_kind ("local" or "global"), create a mapping from - statement instances to blex space (dict), as well as a mapping - defining the blex ordering (isl map from blex space -> blex space) - - Note that, unlike in the intra-thread case, there will be a single - blex ordering map defining the blex ordering for all statement pairs, - rather than separate (smaller) lex ordering maps for each pair - """ - - # {{{ First, create map from stmt instances to blex space. - - # At the same time, gather information necessary to create the - # blex ordering map, i.e., for each loop, gather the 6 lex order tuples - # defined above in SpecialLexPointWRTLoop that will be required to - # create sub-maps which will be *excluded* (subtracted) from a standard - # lexicographic ordering in order to create the blex ordering - - stmt_inst_to_blex = {} # Map stmt instances to blex space - iname_to_blex_dim = {} # Map from inames to corresponding blex space dim - blex_exclusion_info = {} # Info for creating maps to exclude from blex order - blex_order_map_params = set() # Params needed in blex order map - n_seq_blex_dims = 1 # Num dims representing sequential order in blex space - next_blex_tuple = [0] # Next tuple of points in blex order - - for lin_item in lin_items: - if isinstance(lin_item, EnterLoop): - enter_iname = lin_item.iname - if enter_iname in loops_with_barriers[sync_kind] - loops_to_ignore: - pre_loop_blex_pt = next_blex_tuple[:] - - # Increment next_blex_tuple[-1] for statements in the section - # of code between this EnterLoop and the matching LeaveLoop. - next_blex_tuple[-1] += 1 - - # Upon entering a loop, add one blex dimension for the loop - # iteration, add second blex dim to enumerate sections of - # code within new loop - next_blex_tuple.append(enter_iname) - next_blex_tuple.append(0) - - # Store 3 tuples that will be used later to create pairs - # that will later be subtracted from the blex order map - lbound = iname_bounds_pwaff[enter_iname][0] - first_iter_blex_pt = next_blex_tuple[:] - first_iter_blex_pt[-2] = lbound - blex_exclusion_info[enter_iname] = { - slex.PRE: tuple(pre_loop_blex_pt), - slex.TOP: tuple(next_blex_tuple), - slex.FIRST: tuple(first_iter_blex_pt), - } - # (copy these three blex points when creating dict because - # the lists will continue to be updated) - - # Store any new params found - blex_order_map_params |= set(lbound.get_var_names(dt.param)) - - elif isinstance(lin_item, LeaveLoop): - leave_iname = lin_item.iname - if leave_iname in loops_with_barriers[sync_kind] - loops_to_ignore: - - # Update max blex dims - n_seq_blex_dims = max(n_seq_blex_dims, len(next_blex_tuple)) - - # Record the blex dim for this loop iname - iname_to_blex_dim[leave_iname] = len(next_blex_tuple)-2 - - # Update next blex pt - pre_end_loop_blex_pt = next_blex_tuple[:] - # Upon leaving a loop: - # - Pop lex dim for enumerating code sections within this loop - # - Pop lex dim for the loop iteration - # - Increment lex dim val enumerating items in current section - next_blex_tuple.pop() - next_blex_tuple.pop() - next_blex_tuple[-1] += 1 - - # Store 3 tuples that will be used later to create pairs - # that will later be subtracted from the blex order map - ubound = iname_bounds_pwaff[leave_iname][1] - last_iter_blex_pt = pre_end_loop_blex_pt[:] - last_iter_blex_pt[-2] = ubound - blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( - pre_end_loop_blex_pt) - blex_exclusion_info[leave_iname][slex.LAST] = tuple( - last_iter_blex_pt) - blex_exclusion_info[leave_iname][slex.POST] = tuple( - next_blex_tuple) - # (copy these three blex points when creating dict because - # the lists will continue to be updated) - - # Store any new params found - blex_order_map_params |= set(ubound.get_var_names(dt.param)) - - elif isinstance(lin_item, RunInstruction): - # Add stmt->blex pair to stmt_inst_to_blex - stmt_inst_to_blex[lin_item.insn_id] = tuple(next_blex_tuple) - - # (Don't increment blex dim val) - - elif isinstance(lin_item, Barrier): - # Increment blex dim val if the sync scope matches - if lin_item.synchronization_kind == sync_kind: - next_blex_tuple[-1] += 1 - - lp_stmt_id = lin_item.originating_insn_id - - if lp_stmt_id is None: - # Barriers without stmt ids were inserted as a result of a - # dependency. They don't themselves have dependencies. - # Don't map this barrier to a blex tuple. - continue - - # This barrier has a stmt id. - # If it was included in listed stmts, process it. - # Otherwise, there's nothing left to do (we've already - # incremented next_blex_tuple if necessary, and this barrier - # does not need to be assigned to a designated point in blex - # time) - if lp_stmt_id in all_stmt_ids: - # If sync scope matches, give this barrier its own point in - # lex time and update blex tuple after barrier. - # Otherwise, add stmt->blex pair to stmt_inst_to_blex, but - # don't update the blex tuple (just like with any other - # stmt) - if lin_item.synchronization_kind == sync_kind: - stmt_inst_to_blex[lp_stmt_id] = tuple(next_blex_tuple) - next_blex_tuple[-1] += 1 - else: - stmt_inst_to_blex[lp_stmt_id] = tuple(next_blex_tuple) - else: - from loopy.schedule import (CallKernel, ReturnFromKernel) - # No action needed for these types of linearization item - assert isinstance( - lin_item, (CallKernel, ReturnFromKernel)) - pass - - blex_order_map_params = sorted(blex_order_map_params) - - # At this point, some blex tuples may have more dimensions than others; - # the missing dims are the fastest-updating dims, and their values should - # be zero. Add them. - for stmt, tup in stmt_inst_to_blex.items(): - stmt_inst_to_blex[stmt] = _pad_tuple_with_zeros(tup, n_seq_blex_dims) - - # }}} - - # {{{ Second, create the blex order map - - # {{{ Create the initial (pre-subtraction) blex order map - - # Create names for the blex dimensions for sequential loops - seq_blex_dim_names = [ - LEX_VAR_PREFIX+str(i) for i in range(n_seq_blex_dims)] - seq_blex_dim_names_prime = append_mark_to_strings( - seq_blex_dim_names, mark=BEFORE_MARK) - - # Begin with the blex order map created as a standard lexicographical order - blex_order_map = create_lex_order_map( - dim_names=seq_blex_dim_names, - in_dim_mark=BEFORE_MARK, - ) - - # Add LID/GID dims to blex order map - blex_order_map = add_and_name_isl_dims( - blex_order_map, dt.out, all_par_lex_dim_names) - blex_order_map = add_and_name_isl_dims( - blex_order_map, dt.in_, - append_mark_to_strings(all_par_lex_dim_names, mark=BEFORE_MARK)) - if sync_kind == "local": - # For intra-group case, constrain GID 'before' to equal GID 'after' - for var_name in gid_lex_dim_names: - blex_order_map = add_eq_isl_constraint_from_names( - blex_order_map, var_name, var_name+BEFORE_MARK) - # (if sync_kind == "global", don't need constraints on LID/GID vars) - - # }}} - - # {{{ Subtract unwanted pairs from happens-before blex map - - # Create map from iname to corresponding blex dim name - iname_to_blex_var = {} - for iname, dim in iname_to_blex_dim.items(): - iname_to_blex_var[iname] = seq_blex_dim_names[dim] - iname_to_blex_var[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] - - # Add bounds params needed in blex map - blex_order_map = add_and_name_isl_dims( - blex_order_map, dt.param, blex_order_map_params) - - # Get a set representing blex_order_map space - n_blex_dims = n_seq_blex_dims + len(all_par_lex_dim_names) - blex_set_template = isl.align_spaces( - isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map - ).move_dims( - dt.in_, n_blex_dims, dt.out, 0, n_blex_dims - ).domain() - blex_set_affs = isl.affs_from_space(blex_set_template.space) - - # {{{ _create_excluded_map_for_iname - - def _create_excluded_map_for_iname(iname, key_lex_tuples): - """Create the blex->blex pairs that must be subtracted from the - initial blex order map for this particular loop using the 6 blex - tuples in the key_lex_tuples: - PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST - """ - - # Note: - # only key_lex_tuples[slex.FIRST] & key_lex_tuples[slex.LAST] are pwaffs - - # {{{ _create_blex_set_from_tuple_pair - - def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): - """Given a before->after tuple pair in the key_lex_tuples, which may - have dim vals described by ints, strings (inames), and pwaffs, - create an ISL set in blex space that can be converted into - the ISL map to be subtracted - """ - # (Vars from outside func used here: - # iname, blex_set_affs, blex_set_template, iname_to_blex_var, - # n_seq_blex_dims, seq_blex_dim_names, - # seq_blex_dim_names_prime) - - # Start with a set representing blex_order_map space - blex_set = blex_set_template.copy() - - # Add marks to inames in the 'before' tuple - # (all strings should be inames) - before_prime = tuple( - v+BEFORE_MARK if isinstance(v, str) else v for v in before) - before_padded = _pad_tuple_with_zeros(before_prime, n_seq_blex_dims) - after_padded = _pad_tuple_with_zeros(after, n_seq_blex_dims) - - # Assign vals in the tuple to dims in the ISL set - for dim_name, dim_val in zip( - seq_blex_dim_names_prime+seq_blex_dim_names, - before_padded+after_padded): - - if isinstance(dim_val, int): - # Set idx to int val - blex_set &= blex_set_affs[dim_name].eq_set( - blex_set_affs[0]+dim_val) - elif isinstance(dim_val, str): - # This is an iname, set idx to corresponding blex var - blex_set &= blex_set_affs[dim_name].eq_set( - blex_set_affs[iname_to_blex_var[dim_val]]) - else: - # This is a pwaff iname bound, align and intersect - assert isinstance(dim_val, isl.PwAff) - pwaff_aligned = isl.align_spaces(dim_val, blex_set_affs[0]) - # (doesn't matter which blex_set_affs item we align to^) - blex_set &= blex_set_affs[dim_name].eq_set(pwaff_aligned) - - if wrap_cond: - # This is the BOTTOM->TOP pair, add condition i = i' + 1 - blex_set &= blex_set_affs[iname_to_blex_var[iname]].eq_set( - blex_set_affs[iname_to_blex_var[iname+BEFORE_MARK]] + 1) - - return blex_set - - # }}} end _create_blex_set_from_tuple_pair() - - # Create pairs to be subtracted - # (set will be converted to map) - - # Enter loop case: PRE->FIRST - full_blex_set = _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST]) - # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) - full_blex_set |= _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], - wrap_cond=True) - # Leave loop case: LAST->POST - full_blex_set |= _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST]) - - # Add condition to fix iteration value for *surrounding* loops (j = j') - for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: - s_blex_var = iname_to_blex_var[surrounding_iname] - full_blex_set &= blex_set_affs[s_blex_var].eq_set( - blex_set_affs[s_blex_var+BEFORE_MARK]) - - # Convert blex set back to map - return isl.Map.from_domain(full_blex_set).move_dims( - dt.out, 0, dt.in_, n_blex_dims, n_blex_dims) - - # }}} end _create_excluded_map_for_iname() - - # Create map to subtract for each iname - maps_to_subtract = [] - for iname, subdict in blex_exclusion_info.items(): - maps_to_subtract.append(_create_excluded_map_for_iname(iname, subdict)) - - if maps_to_subtract: - - # Get union of maps - map_to_subtract = maps_to_subtract[0] - for other_map in maps_to_subtract[1:]: - map_to_subtract |= other_map - - # Get transitive closure of maps - map_to_subtract, closure_exact = map_to_subtract.transitive_closure() - assert closure_exact # TODO warn instead? - - # Subtract closure from blex order map - blex_order_map = blex_order_map - map_to_subtract - - # }}} - - # }}} - - return ( - stmt_inst_to_blex, # map stmt instances to blex space - blex_order_map, - seq_blex_dim_names, - ) - - # }}} end _gather_blex_ordering_info(sync_kind) - - # TODO remove old function call after comparing results for sanity check - - # Get the blex schedule blueprint (dict will become a map below) and - # blex order map w.r.t. local and global barriers - (_stmt_inst_to_lblex, - _lblex_order_map, - _seq_lblex_dim_names) = _gather_blex_ordering_info_orig("local") - (_stmt_inst_to_gblex, - _gblex_order_map, - _seq_gblex_dim_names) = _gather_blex_ordering_info_orig("global") - # Get the blex schedule blueprint (dict will become a map below) and # blex order map w.r.t. local and global barriers (stmt_inst_to_lblex, @@ -1149,15 +815,6 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): all_par_lex_dim_names, gid_lex_dim_names, ) - assert _stmt_inst_to_lblex == stmt_inst_to_lblex - assert _lblex_order_map == lblex_order_map - assert _lblex_order_map.get_var_dict() == lblex_order_map.get_var_dict() - assert _seq_lblex_dim_names == seq_lblex_dim_names - assert _stmt_inst_to_gblex == stmt_inst_to_gblex - assert _gblex_order_map == gblex_order_map - assert _gblex_order_map.get_var_dict() == gblex_order_map.get_var_dict() - assert _seq_gblex_dim_names == seq_gblex_dim_names - # }}} # }}} end intra-group and global blex order creation From 109d34fbf2de231fd7f78a0979d40548d534f2ed Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 20 Jul 2021 14:32:46 -0500 Subject: [PATCH 117/220] eliminate _create_excluded_map_for_iname() since it is only called once; make it inline instead (step 1, temporarily keep old func for sanity check) --- loopy/schedule/checker/schedule.py | 105 ++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index f9dad40e1..23acf15f5 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -441,6 +441,10 @@ def _create_excluded_map_for_iname(iname, key_lex_tuples): tuples in the key_lex_tuples: PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST """ + # (Vars from outside func used here: + # blex_set_affs, blex_set_template, iname_to_blex_var, + # n_seq_blex_dims, seq_blex_dim_names, + # seq_blex_dim_names_prime) # Note: # only key_lex_tuples[slex.FIRST] & key_lex_tuples[slex.LAST] are pwaffs @@ -525,8 +529,104 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # Create map to subtract for each iname maps_to_subtract = [] - for iname, subdict in blex_exclusion_info.items(): - maps_to_subtract.append(_create_excluded_map_for_iname(iname, subdict)) + for iname, key_lex_tuples in blex_exclusion_info.items(): + # TODO remove after sanity check + _old_map_to_subtract = _create_excluded_map_for_iname(iname, key_lex_tuples) + + # {{{ _create_excluded_map_for_iname + + """Create the blex->blex pairs that must be subtracted from the + initial blex order map for this particular loop using the 6 blex + tuples in the key_lex_tuples: + PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST + """ + + # Note: + # only key_lex_tuples[slex.FIRST] & key_lex_tuples[slex.LAST] are pwaffs + + # {{{ _create_blex_set_from_tuple_pair + + def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): + """Given a before->after tuple pair in the key_lex_tuples, which may + have dim vals described by ints, strings (inames), and pwaffs, + create an ISL set in blex space that can be converted into + the ISL map to be subtracted + """ + # (Vars from outside func used here: + # iname, blex_set_affs, blex_set_template, iname_to_blex_var, + # n_seq_blex_dims, seq_blex_dim_names, + # seq_blex_dim_names_prime) + + # Start with a set representing blex_order_map space + blex_set = blex_set_template.copy() + + # Add marks to inames in the 'before' tuple + # (all strings should be inames) + before_prime = tuple( + v+BEFORE_MARK if isinstance(v, str) else v for v in before) + before_padded = _pad_tuple_with_zeros(before_prime, n_seq_blex_dims) + after_padded = _pad_tuple_with_zeros(after, n_seq_blex_dims) + + # Assign vals in the tuple to dims in the ISL set + for dim_name, dim_val in zip( + seq_blex_dim_names_prime+seq_blex_dim_names, + before_padded+after_padded): + + if isinstance(dim_val, int): + # Set idx to int val + blex_set &= blex_set_affs[dim_name].eq_set( + blex_set_affs[0]+dim_val) + elif isinstance(dim_val, str): + # This is an iname, set idx to corresponding blex var + blex_set &= blex_set_affs[dim_name].eq_set( + blex_set_affs[iname_to_blex_var[dim_val]]) + else: + # This is a pwaff iname bound, align and intersect + assert isinstance(dim_val, isl.PwAff) + pwaff_aligned = isl.align_spaces(dim_val, blex_set_affs[0]) + # (doesn't matter which blex_set_affs item we align to^) + blex_set &= blex_set_affs[dim_name].eq_set(pwaff_aligned) + + if wrap_cond: + # This is the BOTTOM->TOP pair, add condition i = i' + 1 + blex_set &= blex_set_affs[iname_to_blex_var[iname]].eq_set( + blex_set_affs[iname_to_blex_var[iname+BEFORE_MARK]] + 1) + + return blex_set + + # }}} end _create_blex_set_from_tuple_pair() + + # Create pairs to be subtracted + # (set will be converted to map) + + # Enter loop case: PRE->FIRST + full_blex_set = _create_blex_set_from_tuple_pair( + key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST]) + # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) + full_blex_set |= _create_blex_set_from_tuple_pair( + key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], + wrap_cond=True) + # Leave loop case: LAST->POST + full_blex_set |= _create_blex_set_from_tuple_pair( + key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST]) + + # Add condition to fix iteration value for *surrounding* loops (j = j') + for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: + s_blex_var = iname_to_blex_var[surrounding_iname] + full_blex_set &= blex_set_affs[s_blex_var].eq_set( + blex_set_affs[s_blex_var+BEFORE_MARK]) + + # Convert blex set back to map + map_to_subtract = isl.Map.from_domain(full_blex_set).move_dims( + dt.out, 0, dt.in_, n_blex_dims, n_blex_dims) + + # }}} end _create_excluded_map_for_iname() + + # TODO remove sanity check + assert map_to_subtract == _old_map_to_subtract + assert map_to_subtract.get_var_dict() == _old_map_to_subtract.get_var_dict() + + maps_to_subtract.append(map_to_subtract) if maps_to_subtract: @@ -537,6 +637,7 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # Get transitive closure of maps map_to_subtract, closure_exact = map_to_subtract.transitive_closure() + assert closure_exact # TODO warn instead? # Subtract closure from blex order map From aa2c475f8b407cf965182758c7d7ca38e40d67eb Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 20 Jul 2021 14:45:24 -0500 Subject: [PATCH 118/220] eliminate _create_excluded_map_for_iname() since it is only called once; make it inline instead (step 2, after finishing sanity check) --- loopy/schedule/checker/schedule.py | 115 +++-------------------------- 1 file changed, 10 insertions(+), 105 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 23acf15f5..ab9af51df 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -433,111 +433,16 @@ def _gather_blex_ordering_info( ).domain() blex_set_affs = isl.affs_from_space(blex_set_template.space) - # {{{ _create_excluded_map_for_iname + # {{{ Create blex map to subtract for each iname in blex_exclusion_info - def _create_excluded_map_for_iname(iname, key_lex_tuples): - """Create the blex->blex pairs that must be subtracted from the - initial blex order map for this particular loop using the 6 blex - tuples in the key_lex_tuples: - PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST - """ - # (Vars from outside func used here: - # blex_set_affs, blex_set_template, iname_to_blex_var, - # n_seq_blex_dims, seq_blex_dim_names, - # seq_blex_dim_names_prime) - - # Note: - # only key_lex_tuples[slex.FIRST] & key_lex_tuples[slex.LAST] are pwaffs - - # {{{ _create_blex_set_from_tuple_pair - - def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): - """Given a before->after tuple pair in the key_lex_tuples, which may - have dim vals described by ints, strings (inames), and pwaffs, - create an ISL set in blex space that can be converted into - the ISL map to be subtracted - """ - # (Vars from outside func used here: - # iname, blex_set_affs, blex_set_template, iname_to_blex_var, - # n_seq_blex_dims, seq_blex_dim_names, - # seq_blex_dim_names_prime) - - # Start with a set representing blex_order_map space - blex_set = blex_set_template.copy() - - # Add marks to inames in the 'before' tuple - # (all strings should be inames) - before_prime = tuple( - v+BEFORE_MARK if isinstance(v, str) else v for v in before) - before_padded = _pad_tuple_with_zeros(before_prime, n_seq_blex_dims) - after_padded = _pad_tuple_with_zeros(after, n_seq_blex_dims) - - # Assign vals in the tuple to dims in the ISL set - for dim_name, dim_val in zip( - seq_blex_dim_names_prime+seq_blex_dim_names, - before_padded+after_padded): - - if isinstance(dim_val, int): - # Set idx to int val - blex_set &= blex_set_affs[dim_name].eq_set( - blex_set_affs[0]+dim_val) - elif isinstance(dim_val, str): - # This is an iname, set idx to corresponding blex var - blex_set &= blex_set_affs[dim_name].eq_set( - blex_set_affs[iname_to_blex_var[dim_val]]) - else: - # This is a pwaff iname bound, align and intersect - assert isinstance(dim_val, isl.PwAff) - pwaff_aligned = isl.align_spaces(dim_val, blex_set_affs[0]) - # (doesn't matter which blex_set_affs item we align to^) - blex_set &= blex_set_affs[dim_name].eq_set(pwaff_aligned) - - if wrap_cond: - # This is the BOTTOM->TOP pair, add condition i = i' + 1 - blex_set &= blex_set_affs[iname_to_blex_var[iname]].eq_set( - blex_set_affs[iname_to_blex_var[iname+BEFORE_MARK]] + 1) - - return blex_set - - # }}} end _create_blex_set_from_tuple_pair() - - # Create pairs to be subtracted - # (set will be converted to map) - - # Enter loop case: PRE->FIRST - full_blex_set = _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST]) - # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) - full_blex_set |= _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], - wrap_cond=True) - # Leave loop case: LAST->POST - full_blex_set |= _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST]) - - # Add condition to fix iteration value for *surrounding* loops (j = j') - for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: - s_blex_var = iname_to_blex_var[surrounding_iname] - full_blex_set &= blex_set_affs[s_blex_var].eq_set( - blex_set_affs[s_blex_var+BEFORE_MARK]) - - # Convert blex set back to map - return isl.Map.from_domain(full_blex_set).move_dims( - dt.out, 0, dt.in_, n_blex_dims, n_blex_dims) - - # }}} end _create_excluded_map_for_iname() - - # Create map to subtract for each iname maps_to_subtract = [] for iname, key_lex_tuples in blex_exclusion_info.items(): - # TODO remove after sanity check - _old_map_to_subtract = _create_excluded_map_for_iname(iname, key_lex_tuples) - # {{{ _create_excluded_map_for_iname + # {{{ Create blex map to subract for one iname """Create the blex->blex pairs that must be subtracted from the initial blex order map for this particular loop using the 6 blex - tuples in the key_lex_tuples: + tuples in key_lex_tuples: PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST """ @@ -620,14 +525,14 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): map_to_subtract = isl.Map.from_domain(full_blex_set).move_dims( dt.out, 0, dt.in_, n_blex_dims, n_blex_dims) - # }}} end _create_excluded_map_for_iname() - - # TODO remove sanity check - assert map_to_subtract == _old_map_to_subtract - assert map_to_subtract.get_var_dict() == _old_map_to_subtract.get_var_dict() + # }}} maps_to_subtract.append(map_to_subtract) + # }}} + + # {{{ Subtract transitive closure of union of blex maps to subtract + if maps_to_subtract: # Get union of maps @@ -636,12 +541,12 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): map_to_subtract |= other_map # Get transitive closure of maps - map_to_subtract, closure_exact = map_to_subtract.transitive_closure() + map_to_subtract_closure, closure_exact = map_to_subtract.transitive_closure() assert closure_exact # TODO warn instead? # Subtract closure from blex order map - blex_order_map = blex_order_map - map_to_subtract + blex_order_map = blex_order_map - map_to_subtract_closure # }}} From f719cfb541e3f0938be21e3da1d892e0b1a968ef Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 5 Aug 2021 17:03:36 -0500 Subject: [PATCH 119/220] add map_domain to loopy init --- loopy/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loopy/__init__.py b/loopy/__init__.py index a73f83bb9..177fae61c 100644 --- a/loopy/__init__.py +++ b/loopy/__init__.py @@ -76,7 +76,7 @@ affine_map_inames, find_unused_axis_tag, make_reduction_inames_unique, has_schedulable_iname_nesting, get_iname_duplication_options, - add_inames_to_insn, add_inames_for_unused_hw_axes) + add_inames_to_insn, add_inames_for_unused_hw_axes, map_domain) from loopy.transform.instruction import ( find_instructions, map_instructions, @@ -202,7 +202,7 @@ "affine_map_inames", "find_unused_axis_tag", "make_reduction_inames_unique", "has_schedulable_iname_nesting", "get_iname_duplication_options", - "add_inames_to_insn", "add_inames_for_unused_hw_axes", + "add_inames_to_insn", "add_inames_for_unused_hw_axes", "map_domain", "add_prefetch", "change_arg_to_image", "tag_array_axes", "tag_data_axes", From 2780237507258383eb99442e039c9df99fa363d3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 5 Aug 2021 17:06:09 -0500 Subject: [PATCH 120/220] copy in map_domain funcs from old branch (add-map-domain-transformation) --- loopy/transform/iname.py | 323 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 323 insertions(+) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index c3b4a42ee..33b52b913 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -72,6 +72,8 @@ .. autofunction:: add_inames_to_insn +.. autofunction:: map_domain + .. autofunction:: add_inames_for_unused_hw_axes """ @@ -1832,6 +1834,327 @@ def add_inames_to_insn(kernel, inames, insn_match): # }}} +# {{{ map_domain + +class _MapDomainMapper(RuleAwareIdentityMapper): + def __init__(self, rule_mapping_context, within, new_inames, substitutions): + super(_MapDomainMapper, self).__init__(rule_mapping_context) + + self.within = within + + self.old_inames = frozenset(substitutions) + self.new_inames = new_inames + + self.substitutions = substitutions + + def map_reduction(self, expr, expn_state): + red_overlap = frozenset(expr.inames) & self.old_inames + arg_ctx_overlap = frozenset(expn_state.arg_context) & self.old_inames + if (red_overlap + and self.within( + expn_state.kernel, + expn_state.instruction)): + if len(red_overlap) != len(self.old_inames): + raise LoopyError("reduction '%s' involves a part " + "of the map domain inames. Reductions must " + "either involve all or none of the map domain " + "inames." % str(expr)) + + if arg_ctx_overlap: + if arg_ctx_overlap == red_overlap: + # All variables are shadowed by context, that's OK. + return super(_MapDomainMapper, self).map_reduction( + expr, expn_state) + else: + raise LoopyError("reduction '%s' has" + "some of the reduction variables affected " + "by the map_domain shadowed by context. " + "Either all or none must be shadowed." + % str(expr)) + + new_inames = list(expr.inames) + for old_iname in self.old_inames: + new_inames.remove(old_iname) + new_inames.extend(self.new_inames) + + from loopy.symbolic import Reduction + return Reduction(expr.operation, tuple(new_inames), + self.rec(expr.expr, expn_state), + expr.allow_simultaneous) + else: + return super(_MapDomainMapper, self).map_reduction(expr, expn_state) + + def map_variable(self, expr, expn_state): + if (expr.name in self.old_inames + and expr.name not in expn_state.arg_context + and self.within( + expn_state.kernel, + expn_state.instruction)): + return self.substitutions[expr.name] + else: + return super(_MapDomainMapper, self).map_variable(expr, expn_state) + + +def _find_aff_subst_from_map(iname, isl_map): + if not isinstance(isl_map, isl.BasicMap): + raise RuntimeError("isl_map must be a BasicMap") + + dt, dim_idx = isl_map.get_var_dict()[iname] + + assert dt == dim_type.in_ + + # Force isl to solve for only this iname on its side of the map, by + # projecting out all other "in" variables. + isl_map = isl_map.project_out(dt, dim_idx+1, isl_map.dim(dt)-(dim_idx+1)) + isl_map = isl_map.project_out(dt, 0, dim_idx) + dim_idx = 0 + + # Convert map to set to avoid "domain of affine expression should be a set". + # The old "in" variable will be the last of the out_dims. + new_dim_idx = isl_map.dim(dim_type.out) + isl_map = isl_map.move_dims( + dim_type.out, isl_map.dim(dim_type.out), + dt, dim_idx, 1) + isl_map = isl_map.range() # now a set + dt = dim_type.set + dim_idx = new_dim_idx + del new_dim_idx + + for cns in isl_map.get_constraints(): + if cns.is_equality() and cns.involves_dims(dt, dim_idx, 1): + coeff = cns.get_coefficient_val(dt, dim_idx) + cns_zeroed = cns.set_coefficient_val(dt, dim_idx, 0) + if cns_zeroed.involves_dims(dt, dim_idx, 1): + # not suitable, constraint still involves dim, perhaps in a div + continue + + if coeff.is_one(): + return -cns_zeroed.get_aff() + elif coeff.is_negone(): + return cns_zeroed.get_aff() + else: + # not suitable, coefficient does not have unit coefficient + continue + + raise LoopyError("no suitable equation for '%s' found" % iname) + + +# TODO to match convention elsewhere, swap 'dt' and 'dim_type' identifiers +# (use dt to abbreviate islpy.dim_type, and use dim_type for variables +# containing a specific dim_type) + +def _find_and_rename_dim(old_map, dim_types, old_name, new_name): + # (This function is only used once here, but do not inline it; it is used many + # times in child branch update-dependencies-during-transformations.) + new_map = old_map.copy() + for dt in dim_types: + new_map = new_map.set_dim_name( + dt, new_map.find_dim_by_name(dt, old_name), new_name) + return new_map + + +@for_each_kernel +def map_domain(kernel, isl_map, within=None): + # FIXME: Express _split_iname_backend in terms of this + # Missing/deleted for now: + # - slab processing + # - priorities processing + # FIXME: Process priorities + # FIXME: Express affine_map_inames in terms of this, deprecate + # FIXME: Document + + # FIXME: Support within + # FIXME: Right now, this requires all inames in a domain (or none) to + # be mapped. That makes this awkward to use. + + # {{{ within processing (disabled for now) + if within is not None: + raise NotImplementedError("within") + + from loopy.match import parse_match + within = parse_match(within) + + # {{{ return the same kernel if no kernel matches + + if not any(within(kernel, insn) for insn in kernel.instructions): + return kernel + + # }}} + + # }}} + + if not isl_map.is_bijective(): + raise LoopyError("isl_map must be bijective") + + new_inames = frozenset(isl_map.get_var_dict(dim_type.out)) + old_inames = frozenset(isl_map.get_var_dict(dim_type.in_)) + + # {{{ solve for representation of old inames in terms of new + + substitutions = {} + var_substitutions = {} + applied_iname_rewrites = kernel.applied_iname_rewrites[:] + + from loopy.symbolic import aff_to_expr + from pymbolic import var + for iname in old_inames: + substitutions[iname] = aff_to_expr( + _find_aff_subst_from_map(iname, isl_map)) + var_substitutions[var(iname)] = aff_to_expr( + _find_aff_subst_from_map(iname, isl_map)) + + applied_iname_rewrites.append(var_substitutions) + del var_substitutions + + # }}} + + from loopy.schedule.checker.utils import ( + add_and_name_isl_dims, + ) + + def process_set(s): + var_dict = s.get_var_dict() + + overlap = old_inames & frozenset(var_dict) + + if not overlap: + # inames in s are not present in transform map, don't change s + return s + + if len(overlap) != len(old_inames): + raise LoopyError("loop domain '%s' involves a part " + "of the map domain inames. Domains must " + "either involve all or none of the map domain " + "inames." % s) + + from loopy.schedule.checker.utils import ( + add_eq_isl_constraint_from_names, + ) + + # {{{ align dims of isl_map and s + + # FIXME: Make this less gross + # FIXME: Make an exported/documented interface of this in islpy + from islpy import _align_dim_type + + map_with_s_domain = isl.Map.from_domain(s) + + # {{{ deal with dims missing from transform map (isl_map) + + # If dims in s are missing from transform map, they need to be added + # so that intersect_domain doesn't remove them. + # Order doesn't matter here because dims will be aligned in the next step. + dims_missing_from_transform_map = list( + set(s.get_var_names(dim_type.set)) - + set(isl_map.get_var_names(dim_type.in_))) + augmented_isl_map = add_and_name_isl_dims( + isl_map, dim_type.in_, dims_missing_from_transform_map) + + # We want these missing inames to map to themselves so that the transform + # has no effect on them. Unfortunatley isl will break if the + # names of the out dims aren't unique, so we will temporariliy rename them + # and then change the names back afterward. + + # FIXME: need better way to make sure proxy dim names are unique + dims_missing_from_transform_map_proxies = [ + d+"__prox" for d in dims_missing_from_transform_map] + assert not set(dims_missing_from_transform_map_proxies) & set( + augmented_isl_map.get_var_dict().keys()) + + augmented_isl_map = add_and_name_isl_dims( + augmented_isl_map, dim_type.out, dims_missing_from_transform_map_proxies) + + # Set proxy iname equal to real iname + for proxy_iname, real_iname in zip( + dims_missing_from_transform_map_proxies, + dims_missing_from_transform_map): + augmented_isl_map = add_eq_isl_constraint_from_names( + augmented_isl_map, proxy_iname, real_iname) + + # }}} + + dim_types = [dim_type.param, dim_type.in_, dim_type.out] + s_names = [ + map_with_s_domain.get_dim_name(dt, i) + for dt in dim_types + for i in range(map_with_s_domain.dim(dt)) + ] + map_names = [ + augmented_isl_map.get_dim_name(dt, i) + for dt in dim_types + for i in range(augmented_isl_map.dim(dt)) + ] + + # (order doesn't matter in s_names/map_names, + # _align_dim_type just converts these to sets + # to determine which names are in both the obj and template, + # not sure why this isn't just handled inside _align_dim_type) + aligned_map = _align_dim_type( + dim_type.param, + augmented_isl_map, map_with_s_domain, False, + map_names, s_names) + aligned_map = _align_dim_type( + dim_type.in_, + aligned_map, map_with_s_domain, False, + map_names, s_names) + + # }}} + + new_s = aligned_map.intersect_domain(s).range() + + # Now rename the proxy dims back to their original names + for proxy_iname, real_iname in zip( + dims_missing_from_transform_map_proxies, + dims_missing_from_transform_map): + new_s = _find_and_rename_dim( + new_s, [dim_type.set], proxy_iname, real_iname) + + return new_s + + # FIXME: Revive _project_out_only_if_all_instructions_in_within + + new_domains = [process_set(dom) for dom in kernel.domains] + + # {{{ update within_inames + + new_insns = [] + for insn in kernel.instructions: + overlap = old_inames & insn.within_inames + if overlap and within(kernel, insn): + if len(overlap) != len(old_inames): + raise LoopyError("instruction '%s' is within only a part " + "of the map domain inames. Instructions must " + "either be within all or none of the map domain " + "inames." % insn.id) + + insn = insn.copy( + within_inames=(insn.within_inames - old_inames) | new_inames) + else: + # leave insn unmodified + pass + + new_insns.append(insn) + + # }}} + + kernel = kernel.copy( + domains=new_domains, + instructions=new_insns, + applied_iname_rewrites=applied_iname_rewrites) + + rule_mapping_context = SubstitutionRuleMappingContext( + kernel.substitutions, kernel.get_var_name_generator()) + ins = _MapDomainMapper(rule_mapping_context, within, + new_inames, substitutions) + + kernel = ins.map_kernel(kernel) + kernel = rule_mapping_context.finish_kernel(kernel) + + return kernel + +# }}} + + @for_each_kernel def add_inames_for_unused_hw_axes(kernel, within=None): """ From e5edf400ca070ca98fd9aed30673383eeac35996 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 5 Aug 2021 17:17:23 -0500 Subject: [PATCH 121/220] define add_and_name_isl_dims and add_eq_isl_constraint_from_names locally for now (previously were defined in schedule checking utils before this code was moved to independent branch) --- loopy/transform/iname.py | 44 +++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 33b52b913..25cd6e4db 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -1939,10 +1939,38 @@ def _find_aff_subst_from_map(iname, isl_map): raise LoopyError("no suitable equation for '%s' found" % iname) -# TODO to match convention elsewhere, swap 'dt' and 'dim_type' identifiers +# FIXME to match convention elsewhere, swap 'dt' and 'dim_type' identifiers # (use dt to abbreviate islpy.dim_type, and use dim_type for variables # containing a specific dim_type) +def _add_and_name_isl_dims(isl_map, dt, names): + # (This function is also defined in independent, unmerged branch + # statement-instance-order-and-lex-order-map, and used in child branches + # thereof. Once these branches are all merged, it may make sense to move + # this function to a location for more general-purpose machinery. In the + # other branches, this function's name excludes the leading underscore.) + new_idx_start = isl_map.dim(dt) + new_map = isl_map.add_dims(dt, len(names)) + for i, name in enumerate(names): + new_map = new_map.set_dim_name(dt, new_idx_start+i, name) + return new_map + + +def _add_eq_isl_constraint_from_names(isl_map, var1, var2): + # (This function is also defined in independent, unmerged branch + # statement-instance-order-and-lex-order-map, and used in child branches + # thereof. Once these branches are all merged, it may make sense to move + # this function to a location for more general-purpose machinery. In the + # other branches, this function's name excludes the leading underscore.) + + # add constraint var1 = var2 + + return isl_map.add_constraint( + isl.Constraint.eq_from_names( + isl_map.space, + {1: 0, var1: 1, var2: -1})) + + def _find_and_rename_dim(old_map, dim_types, old_name, new_name): # (This function is only used once here, but do not inline it; it is used many # times in child branch update-dependencies-during-transformations.) @@ -2008,10 +2036,6 @@ def map_domain(kernel, isl_map, within=None): # }}} - from loopy.schedule.checker.utils import ( - add_and_name_isl_dims, - ) - def process_set(s): var_dict = s.get_var_dict() @@ -2027,10 +2051,6 @@ def process_set(s): "either involve all or none of the map domain " "inames." % s) - from loopy.schedule.checker.utils import ( - add_eq_isl_constraint_from_names, - ) - # {{{ align dims of isl_map and s # FIXME: Make this less gross @@ -2047,7 +2067,7 @@ def process_set(s): dims_missing_from_transform_map = list( set(s.get_var_names(dim_type.set)) - set(isl_map.get_var_names(dim_type.in_))) - augmented_isl_map = add_and_name_isl_dims( + augmented_isl_map = _add_and_name_isl_dims( isl_map, dim_type.in_, dims_missing_from_transform_map) # We want these missing inames to map to themselves so that the transform @@ -2061,14 +2081,14 @@ def process_set(s): assert not set(dims_missing_from_transform_map_proxies) & set( augmented_isl_map.get_var_dict().keys()) - augmented_isl_map = add_and_name_isl_dims( + augmented_isl_map = _add_and_name_isl_dims( augmented_isl_map, dim_type.out, dims_missing_from_transform_map_proxies) # Set proxy iname equal to real iname for proxy_iname, real_iname in zip( dims_missing_from_transform_map_proxies, dims_missing_from_transform_map): - augmented_isl_map = add_eq_isl_constraint_from_names( + augmented_isl_map = _add_eq_isl_constraint_from_names( augmented_isl_map, proxy_iname, real_iname) # }}} From c6320d849eb981ddc6511794c7d2093c6b283fe1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 5 Aug 2021 17:29:44 -0500 Subject: [PATCH 122/220] define ensure_dim_names_match_and_align locally for now (previously was defined in schedule checking utils before this code was moved to independent branch) --- test/test_transform.py | 242 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) diff --git a/test/test_transform.py b/test/test_transform.py index 51e7c2636..91db5ceeb 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -594,6 +594,248 @@ def test_nested_substs_in_insns(ctx_factory): lp.auto_test_vs_ref(ref_prg, ctx, t_unit) +# {{{ test_map_domain_vs_split_iname + +def _ensure_dim_names_match_and_align(obj_map, tgt_map): + # (This function is also defined in independent, unmerged branch + # new-dependency-and-nest-constraint-semantics-development, and used in + # child branches thereof. Once these branches are all merged, it may make + # sense to move this function to a location for more general-purpose + # machinery. In the other branches, this function's name excludes the + # leading underscore.) + from islpy import align_spaces + from islpy import dim_type as dt + + # first make sure names match + if not all( + set(obj_map.get_var_names(dt)) == set(tgt_map.get_var_names(dt)) + for dt in + [dt.in_, dt.out, dt.param]): + raise ValueError( + "Cannot align spaces; names don't match:\n%s\n%s" + % (obj_map, tgt_map)) + + return align_spaces(obj_map, tgt_map) + + +def test_map_domain_vs_split_iname(): + + # {{{ Make kernel + + knl = lp.make_kernel( + [ + "[nx,nt] -> {[x, t]: 0 <= x < nx and 0 <= t < nt}", + "[ni] -> {[i]: 0 <= i < ni}", + ], + """ + a[x,t] = b[x,t] {id=stmta} + c[x,t] = d[x,t] {id=stmtc} + e[i] = f[i] + """, + lang_version=(2018, 2), + ) + knl = lp.add_and_infer_dtypes(knl, {"b,d,f": np.float32}) + ref_knl = knl + + # }}} + + # {{{ Apply domain change mapping + + knl_map_dom = ref_knl # loop priority goes away, deps stay + + # Create map_domain mapping: + import islpy as isl + transform_map = isl.BasicMap( + "[nt] -> {[t] -> [t_outer, t_inner]: " + "0 <= t_inner < 32 and " + "32*t_outer + t_inner = t and " + "0 <= 32*t_outer + t_inner < nt}") + + # Call map_domain to transform kernel + knl_map_dom = lp.map_domain(knl_map_dom, transform_map) + + # Prioritize loops (prio should eventually be updated in map_domain?) + knl_map_dom = lp.prioritize_loops(knl_map_dom, "x, t_outer, t_inner") + + # Get a linearization + proc_knl_map_dom = lp.preprocess_kernel(knl_map_dom) + lin_knl_map_dom = lp.get_one_linearized_kernel( + proc_knl_map_dom["loopy_kernel"], proc_knl_map_dom.callables_table) + + # }}} + + # {{{ Split iname and see if we get the same result + + knl_split_iname = ref_knl + knl_split_iname = lp.split_iname(knl_split_iname, "t", 32) + knl_split_iname = lp.prioritize_loops(knl_split_iname, "x, t_outer, t_inner") + proc_knl_split_iname = lp.preprocess_kernel(knl_split_iname) + lin_knl_split_iname = lp.get_one_linearized_kernel( + proc_knl_split_iname["loopy_kernel"], proc_knl_split_iname.callables_table) + + for d_map_domain, d_split_iname in zip( + knl_map_dom["loopy_kernel"].domains, + knl_split_iname["loopy_kernel"].domains): + d_map_domain_aligned = _ensure_dim_names_match_and_align( + d_map_domain, d_split_iname) + assert d_map_domain_aligned == d_split_iname + + for litem_map_domain, litem_split_iname in zip( + lin_knl_map_dom.linearization, lin_knl_split_iname.linearization): + assert litem_map_domain == litem_split_iname + + # Can't easily compare instructions because equivalent subscript + # expressions may have different orders + + # }}} + +# }}} + + +# {{{ test_map_domain_with_transform_map_missing_dims + +def test_map_domain_with_transform_map_missing_dims(): + # Make sure map_domain works correctly when the mapping doesn't include + # all the dims in the domain. + + # {{{ Make kernel + + knl = lp.make_kernel( + [ + "[nx,nt] -> {[x, y, z, t]: 0 <= x,y,z < nx and 0 <= t < nt}", + ], + """ + a[y,x,t,z] = b[y,x,t,z] {id=stmta} + """, + lang_version=(2018, 2), + ) + knl = lp.add_and_infer_dtypes(knl, {"b": np.float32}) + ref_knl = knl + + # }}} + + # {{{ Apply domain change mapping + + knl_map_dom = ref_knl # loop priority goes away, deps stay + + # Create map_domain mapping that only includes t and y + # (x and z should be unaffected) + import islpy as isl + transform_map = isl.BasicMap( + "[nx,nt] -> {[t, y] -> [t_outer, t_inner, y_new]: " + "0 <= t_inner < 32 and " + "32*t_outer + t_inner = t and " + "0 <= 32*t_outer + t_inner < nt and " + "y = y_new" + "}") + + # Call map_domain to transform kernel + knl_map_dom = lp.map_domain(knl_map_dom, transform_map) + + # Prioritize loops (prio should eventually be updated in map_domain?) + try: + # Use constrain_loop_nesting if it's available + desired_prio = "x, t_outer, t_inner, z, y_new" + knl_map_dom = lp.constrain_loop_nesting(knl_map_dom, desired_prio) + except AttributeError: + # For some reason, prioritize_loops can't handle the ordering above + # when linearizing knl_split_iname below + desired_prio = "z, y_new, x, t_outer, t_inner" + knl_map_dom = lp.prioritize_loops(knl_map_dom, desired_prio) + + # Get a linearization + proc_knl_map_dom = lp.preprocess_kernel(knl_map_dom) + lin_knl_map_dom = lp.get_one_linearized_kernel( + proc_knl_map_dom["loopy_kernel"], proc_knl_map_dom.callables_table) + + # }}} + + # {{{ Split iname and see if we get the same result + + knl_split_iname = ref_knl + knl_split_iname = lp.split_iname(knl_split_iname, "t", 32) + knl_split_iname = lp.rename_iname(knl_split_iname, "y", "y_new") + try: + # Use constrain_loop_nesting if it's available + knl_split_iname = lp.constrain_loop_nesting(knl_split_iname, desired_prio) + except AttributeError: + knl_split_iname = lp.prioritize_loops(knl_split_iname, desired_prio) + proc_knl_split_iname = lp.preprocess_kernel(knl_split_iname) + lin_knl_split_iname = lp.get_one_linearized_kernel( + proc_knl_split_iname["loopy_kernel"], proc_knl_split_iname.callables_table) + + for d_map_domain, d_split_iname in zip( + knl_map_dom["loopy_kernel"].domains, + knl_split_iname["loopy_kernel"].domains): + d_map_domain_aligned = _ensure_dim_names_match_and_align( + d_map_domain, d_split_iname) + assert d_map_domain_aligned == d_split_iname + + for litem_map_domain, litem_split_iname in zip( + lin_knl_map_dom.linearization, lin_knl_split_iname.linearization): + assert litem_map_domain == litem_split_iname + + # Can't easily compare instructions because equivalent subscript + # expressions may have different orders + + # }}} + +# }}} + + +def test_diamond_tiling(ctx_factory, interactive=False): + ctx = ctx_factory() + queue = cl.CommandQueue(ctx) + + ref_knl = lp.make_kernel( + "[nx,nt] -> {[ix, it]: 1<=ix {[ix, it] -> [tx, tt, tparity, itt, itx]: " + "16*(tx - tt) + itx - itt = ix - it and " + "16*(tx + tt + tparity) + itt + itx = ix + it and " + "0<=tparity<2 and 0 <= itx - itt < 16 and 0 <= itt+itx < 16}") + knl = lp.map_domain(knl_for_transform, m) + knl = lp.prioritize_loops(knl, "tt,tparity,tx,itt,itx") + + if interactive: + nx = 43 + u = np.zeros((nx, 200)) + x = np.linspace(-1, 1, nx) + dx = x[1] - x[0] + u[:, 0] = u[:, 1] = np.exp(-100*x**2) + + u_dev = cl.array.to_device(queue, u) + knl(queue, u=u_dev, dx=dx, dt=dx) + + u = u_dev.get() + import matplotlib.pyplot as plt + plt.imshow(u.T) + plt.show() + else: + types = {"dt,dx,u": np.float64} + knl = lp.add_and_infer_dtypes(knl, types) + ref_knl = lp.add_and_infer_dtypes(ref_knl, types) + + lp.auto_test_vs_ref(ref_knl, ctx, knl, + parameters={ + "nx": 200, "nt": 300, + "dx": 1, "dt": 1 + }) + + def test_extract_subst_with_iname_deps_in_templ(ctx_factory): knl = lp.make_kernel( "{[i, j, k]: 0<=i<100 and 0<=j,k<5}", From 10a92b41011f8d347becf6b10155db29f1bf7026 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 8 Aug 2021 17:10:14 -0500 Subject: [PATCH 123/220] (WIP) compute lexmax/min to get bounds for trangular domains --- loopy/schedule/checker/schedule.py | 56 +++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index ab9af51df..f7ef78210 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -650,12 +650,18 @@ def get_pairwise_statement_orderings_inner( # this information will be used later when creating *intra-group* and # *global* lexicographic orderings loops_with_barriers = {"local": set(), "global": set()} - current_inames = set() + current_inames = [] + + # While we're passing through, also determine the values of the active + # inames on the first and last iteration of each loop that contains + # barriers. We will need these later on when creating the FIRST and LAST + # blex points. + loop_bounds = {} for lin_item in lin_items: if isinstance(lin_item, EnterLoop): iname = lin_item.iname - current_inames.add(iname) + current_inames.append(iname) if iname in loops_to_ignore: continue @@ -674,7 +680,7 @@ def get_pairwise_statement_orderings_inner( elif isinstance(lin_item, LeaveLoop): iname = lin_item.iname - current_inames.remove(iname) + current_inames.pop() if iname in loops_to_ignore: continue @@ -704,7 +710,39 @@ def get_pairwise_statement_orderings_inner( elif isinstance(lin_item, Barrier): lp_stmt_id = lin_item.originating_insn_id - loops_with_barriers[lin_item.synchronization_kind] |= current_inames + loops_with_barriers[lin_item.synchronization_kind] |= set(current_inames) + + # {{{ Store bounds for inames containing barriers + + # (only compute the ones we haven't already stored; bounds finding + # will only happen once for each barrier-containing loop) + for depth, iname in enumerate(current_inames): + + # If we haven't already stored bounds for this iname, do so + if iname not in loop_bounds: + + # Get set of inames nested outside this one (including this iname) + inames_involved_in_bound = set(current_inames[:depth+1]) + + # Get inames domain + dom = knl.get_inames_domain( + inames_involved_in_bound).project_out_except( + inames_involved_in_bound, [dt.set]) + + # {{{ Move domain dims for surrounding inames to parameters + # (keeping them in order, which might come in handy later...) + + # Move those inames to params + for outer_iname in current_inames[:depth]: + outer_iname_idx = dom.find_dim_by_name(dt.set, outer_iname) + dom = dom.move_dims( + dt.param, dom.n_param(), dt.set, outer_iname_idx, 1) + + # }}} + + loop_bounds[iname] = (dom.lexmin(), dom.lexmax()) + + # }}} if lp_stmt_id is None: # Barriers without stmt ids were inserted as a result of a @@ -731,6 +769,16 @@ def get_pairwise_statement_orderings_inner( lin_item, (CallKernel, ReturnFromKernel)) pass + # Debugging.... (TODO remove) + from loopy.schedule.checker.utils import prettier_map_string + for iname, (lbound, ubound) in loop_bounds.items(): + print(iname) + print(prettier_map_string(lbound)) + print(prettier_map_string(ubound)) + + 1/0 + # TODO left off here + # }}} # {{{ Create lex dim names representing parallel axes From 3ba708257bfeb34a78ea55eecb1936a2183149bd Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 8 Aug 2021 17:10:57 -0500 Subject: [PATCH 124/220] (WIP) add test for SIO creation when domain is traingular --- test/test_linearization_checker.py | 80 ++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index de88d98fc..d6f0baf8e 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -1591,6 +1591,86 @@ def test_sios_with_matmul(): # }}} +# {{{ test_sios_with_triangular_domain + +def test_sios_with_triangular_domain(): + + from loopy.schedule.checker import ( + get_pairwise_statement_orderings, + ) + + ''' + assumptions = "i_end >= i_start + 1 and j_end >= j_start + 1 and k_end >= 1" + knl = lp.make_kernel( + [ + "{[i,j,k]: i_start<=itemp0 = 0 {id=stmt_k0} + ... lbarrier {id=stmt_b0,dep=stmt_k0} + <>temp1 = 1 {id=stmt_k1,dep=stmt_b0} + for i + <>tempi0 = 0 {id=stmt_i0,dep=stmt_k1} + ... lbarrier {id=stmt_ib0,dep=stmt_i0} + ... gbarrier {id=stmt_ibb0,dep=stmt_i0} + <>tempi1 = 0 {id=stmt_i1,dep=stmt_ib0} + <>tempi2 = 0 {id=stmt_i2,dep=stmt_i1} + for j + <>tempj0 = 0 {id=stmt_j0,dep=stmt_i2} + ... lbarrier {id=stmt_jb0,dep=stmt_j0} + <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} + end + end + <>temp2 = 0 {id=stmt_k2,dep=stmt_i0} + end + """, + assumptions=assumptions, + lang_version=(2018, 2) + ) + ''' + assumptions = "ij_end >= i_start + 1 and k_end >= 1" + knl = lp.make_kernel( + [ + "{[i,j,k]: i_start<=itemp0 = 0 {id=stmt_k0} + ... lbarrier {id=stmt_b0,dep=stmt_k0} + <>temp1 = 1 {id=stmt_k1,dep=stmt_b0} + for i + <>tempi0 = 0 {id=stmt_i0,dep=stmt_k1} + ... lbarrier {id=stmt_ib0,dep=stmt_i0} + ... gbarrier {id=stmt_ibb0,dep=stmt_i0} + <>tempi1 = 0 {id=stmt_i1,dep=stmt_ib0} + <>tempi2 = 0 {id=stmt_i2,dep=stmt_i1} + for j + <>tempj0 = 0 {id=stmt_j0,dep=stmt_i2} + ... lbarrier {id=stmt_jb0,dep=stmt_j0} + <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} + end + end + <>temp2 = 0 {id=stmt_k2,dep=stmt_i0} + end + """, + assumptions=assumptions, + lang_version=(2018, 2) + ) + + # Get a linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) + + stmt_id_pairs = [("stmt_j1", "stmt_k2"), ("stmt_k1", "stmt_i0")] + pworders = get_pairwise_statement_orderings( + lin_knl, lin_items, stmt_id_pairs) + + 1/0 + # TODO left off here + +# }}} + + if __name__ == "__main__": if len(sys.argv) > 1: exec(sys.argv[1]) From 34b7d8fd6a34ed91b432766cfd1b00d14f3acdc6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 10 Aug 2021 13:06:54 -0500 Subject: [PATCH 125/220] remove FIXME now that dim_type usage is consistent --- loopy/transform/iname.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 25cd6e4db..131056eab 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -1939,10 +1939,6 @@ def _find_aff_subst_from_map(iname, isl_map): raise LoopyError("no suitable equation for '%s' found" % iname) -# FIXME to match convention elsewhere, swap 'dt' and 'dim_type' identifiers -# (use dt to abbreviate islpy.dim_type, and use dim_type for variables -# containing a specific dim_type) - def _add_and_name_isl_dims(isl_map, dt, names): # (This function is also defined in independent, unmerged branch # statement-instance-order-and-lex-order-map, and used in child branches From 62d711b6c55cd6b135ad6c6d3eb7b36464ed601d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 10 Aug 2021 16:59:59 -0500 Subject: [PATCH 126/220] add better encapsulation for case where domain map has fewer dims than domains (with _apply_identity_for_missing_map_dims func) --- loopy/transform/iname.py | 84 ++++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 131056eab..f3369cea8 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -1977,6 +1977,40 @@ def _find_and_rename_dim(old_map, dim_types, old_name, new_name): return new_map +def _apply_identity_for_missing_map_dims(mapping, desired_dims): + + # If dims in s are missing from transform map, they need to be added + # so that, e.g, intersect_domain doesn't remove them. + # (assume ordering will be handled afterward) + + missing_dims = list( + set(desired_dims) - set(mapping.get_var_names(dim_type.in_))) + augmented_mapping = _add_and_name_isl_dims( + mapping, dim_type.in_, missing_dims) + + # We want these missing inames to map to themselves so that the map + # has no effect on them. Unfortunatley isl will break if the + # names of the out dims aren't unique, so we will temporariliy rename them + # (and then plan to change the names back afterward). + + # FIXME: need better way to make sure proxy dim names are unique within map + missing_dims_proxies = [d+"__prox" for d in missing_dims] + assert not set(missing_dims_proxies) & set( + augmented_mapping.get_var_dict().keys()) + + augmented_mapping = _add_and_name_isl_dims( + augmented_mapping, dim_type.out, missing_dims_proxies) + + proxy_name_pairs = list(zip(missing_dims, missing_dims_proxies)) + + # Set proxy iname equal to real iname with equality constraint + for real_iname, proxy_iname in proxy_name_pairs: + augmented_mapping = _add_eq_isl_constraint_from_names( + augmented_mapping, proxy_iname, real_iname) + + return augmented_mapping, proxy_name_pairs + + @for_each_kernel def map_domain(kernel, isl_map, within=None): # FIXME: Express _split_iname_backend in terms of this @@ -2049,46 +2083,22 @@ def process_set(s): # {{{ align dims of isl_map and s - # FIXME: Make this less gross - # FIXME: Make an exported/documented interface of this in islpy from islpy import _align_dim_type map_with_s_domain = isl.Map.from_domain(s) - # {{{ deal with dims missing from transform map (isl_map) - - # If dims in s are missing from transform map, they need to be added - # so that intersect_domain doesn't remove them. - # Order doesn't matter here because dims will be aligned in the next step. - dims_missing_from_transform_map = list( - set(s.get_var_names(dim_type.set)) - - set(isl_map.get_var_names(dim_type.in_))) - augmented_isl_map = _add_and_name_isl_dims( - isl_map, dim_type.in_, dims_missing_from_transform_map) - - # We want these missing inames to map to themselves so that the transform - # has no effect on them. Unfortunatley isl will break if the - # names of the out dims aren't unique, so we will temporariliy rename them - # and then change the names back afterward. - - # FIXME: need better way to make sure proxy dim names are unique - dims_missing_from_transform_map_proxies = [ - d+"__prox" for d in dims_missing_from_transform_map] - assert not set(dims_missing_from_transform_map_proxies) & set( - augmented_isl_map.get_var_dict().keys()) - - augmented_isl_map = _add_and_name_isl_dims( - augmented_isl_map, dim_type.out, dims_missing_from_transform_map_proxies) - - # Set proxy iname equal to real iname - for proxy_iname, real_iname in zip( - dims_missing_from_transform_map_proxies, - dims_missing_from_transform_map): - augmented_isl_map = _add_eq_isl_constraint_from_names( - augmented_isl_map, proxy_iname, real_iname) - - # }}} + # If there are dims in s that are not mapped by isl_map, add them + # to the in/out space of isl_map so that they remain unchanged. + # (temporary proxy dim names are needed in out space of transform + # map because isl won't allow any dim names to match, i.e., instead + # of just mapping {[unused_iname]->[unused_iname]}, we have to map + # {[unused_name]->[unused_name__prox] : unused_name__prox = unused_name}, + # and then rename unused_name__prox afterward.) + augmented_isl_map, proxy_name_pairs = _apply_identity_for_missing_map_dims( + isl_map, s.get_var_names(dim_type.set)) + # FIXME: Make this less gross + # FIXME: Make an exported/documented interface of this in islpy dim_types = [dim_type.param, dim_type.in_, dim_type.out] s_names = [ map_with_s_domain.get_dim_name(dt, i) @@ -2119,9 +2129,7 @@ def process_set(s): new_s = aligned_map.intersect_domain(s).range() # Now rename the proxy dims back to their original names - for proxy_iname, real_iname in zip( - dims_missing_from_transform_map_proxies, - dims_missing_from_transform_map): + for real_iname, proxy_iname in proxy_name_pairs: new_s = _find_and_rename_dim( new_s, [dim_type.set], proxy_iname, real_iname) From 05acfbee1f4626e16d458893cb09a9ee23ecc94c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 10 Aug 2021 18:05:28 -0500 Subject: [PATCH 127/220] improve var names and error message related to mismatching of transform map and inames domain --- loopy/transform/iname.py | 41 ++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index f3369cea8..0d5228275 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2022,8 +2022,6 @@ def map_domain(kernel, isl_map, within=None): # FIXME: Document # FIXME: Support within - # FIXME: Right now, this requires all inames in a domain (or none) to - # be mapped. That makes this awkward to use. # {{{ within processing (disabled for now) if within is not None: @@ -2044,8 +2042,8 @@ def map_domain(kernel, isl_map, within=None): if not isl_map.is_bijective(): raise LoopyError("isl_map must be bijective") - new_inames = frozenset(isl_map.get_var_dict(dim_type.out)) - old_inames = frozenset(isl_map.get_var_dict(dim_type.in_)) + transform_map_out_dims = frozenset(isl_map.get_var_dict(dim_type.out)) + transform_map_in_dims = frozenset(isl_map.get_var_dict(dim_type.in_)) # {{{ solve for representation of old inames in terms of new @@ -2055,7 +2053,7 @@ def map_domain(kernel, isl_map, within=None): from loopy.symbolic import aff_to_expr from pymbolic import var - for iname in old_inames: + for iname in transform_map_in_dims: substitutions[iname] = aff_to_expr( _find_aff_subst_from_map(iname, isl_map)) var_substitutions[var(iname)] = aff_to_expr( @@ -2066,20 +2064,27 @@ def map_domain(kernel, isl_map, within=None): # }}} - def process_set(s): + def process_iname_dom(s): + # Make sure the inames we're transforming are all present in the domain + # if not transform_map_in_dims.issubset(frozenset(s.get_var_dict())): + # raise LoopyError("transform map %s attempts to map inames " + # "not present in domain %s. Transform map input inames " + # "must be a subset of the domain inames." + # % (isl_map, s)) + var_dict = s.get_var_dict() - overlap = old_inames & frozenset(var_dict) + overlap = transform_map_in_dims & frozenset(var_dict) if not overlap: # inames in s are not present in transform map, don't change s return s - if len(overlap) != len(old_inames): - raise LoopyError("loop domain '%s' involves a part " - "of the map domain inames. Domains must " - "either involve all or none of the map domain " - "inames." % s) + if len(overlap) != len(transform_map_in_dims): + raise LoopyError( + "Transform map %s attempts to map variables that are not present " + "in domain %s. This is only allowed if *none* of the mapped " + "variables are found in the domain." % (isl_map, s)) # {{{ align dims of isl_map and s @@ -2137,22 +2142,22 @@ def process_set(s): # FIXME: Revive _project_out_only_if_all_instructions_in_within - new_domains = [process_set(dom) for dom in kernel.domains] + new_domains = [process_iname_dom(dom) for dom in kernel.domains] # {{{ update within_inames new_insns = [] for insn in kernel.instructions: - overlap = old_inames & insn.within_inames + overlap = transform_map_in_dims & insn.within_inames if overlap and within(kernel, insn): - if len(overlap) != len(old_inames): + if len(overlap) != len(transform_map_in_dims): raise LoopyError("instruction '%s' is within only a part " "of the map domain inames. Instructions must " "either be within all or none of the map domain " "inames." % insn.id) - insn = insn.copy( - within_inames=(insn.within_inames - old_inames) | new_inames) + insn = insn.copy(within_inames=( + insn.within_inames - transform_map_in_dims) | transform_map_out_dims) else: # leave insn unmodified pass @@ -2169,7 +2174,7 @@ def process_set(s): rule_mapping_context = SubstitutionRuleMappingContext( kernel.substitutions, kernel.get_var_name_generator()) ins = _MapDomainMapper(rule_mapping_context, within, - new_inames, substitutions) + transform_map_out_dims, substitutions) kernel = ins.map_kernel(kernel) kernel = rule_mapping_context.finish_kernel(kernel) From 8b3195fb3809594ddbe190a9a4c983f1099bade9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 10 Aug 2021 18:07:12 -0500 Subject: [PATCH 128/220] test map_domain cases where there is a mismatch between the inames in the transform map and the inames in a domain --- test/test_transform.py | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/test/test_transform.py b/test/test_transform.py index 91db5ceeb..a07d31d81 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -780,6 +780,64 @@ def test_map_domain_with_transform_map_missing_dims(): # }}} + # {{{ Make sure there's an error if transform map contains *extra* dims + # Note, this is only okay if transform map 'in' dims don't match *any* + # domain inames, in which case nothing happens. + + # Not bijective + transform_map = isl.BasicMap( + "[nx,nt] -> {[t, y, rogue] -> [t_new, y_new]: " + "y = y_new and t = t_new" + "}") + + from loopy.diagnostic import LoopyError + knl_map_dom = ref_knl + try: + knl_map_dom = lp.map_domain(knl_map_dom, transform_map) + raise AssertionError() + except LoopyError as err: + assert "map must be bijective" in str(err) + + # Bijective and rogue dim + # (with some inames missing from in-dims, which would otherwise be okay) + transform_map = isl.BasicMap( + "[nx,nt] -> {[t, y, rogue] -> [t_new, y_new, rogue_new]: " + "y = y_new and t = t_new and rogue = rogue_new" + "}") + + try: + knl_map_dom = lp.map_domain(knl_map_dom, transform_map) + raise AssertionError() + except LoopyError as err: + assert ( + "attempts to map variables that are not present in domain" in str(err)) + + # Bijective and rogue dim + # (with all inames present in in-dims) + transform_map = isl.BasicMap( + "[nx,nt] -> {[t, y, x, z, rogue] -> [t_new, y_new, x_new, z_new, rogue_new]:" + "y = y_new and t = t_new and x = x_new and z = z_new and rogue = rogue_new" + "}") + + try: + knl_map_dom = lp.map_domain(knl_map_dom, transform_map) + raise AssertionError() + except LoopyError as err: + assert ( + "attempts to map variables that are not present in domain" in str(err)) + + # Bijective and rogue dim with *no* inames present in domain + # (allowed but does nothing) + transform_map = isl.BasicMap( + "[nx,nt] -> {[rogue] -> [rogue_new]: " + "rogue = rogue_new" + "}") + + # This should not raise an error + knl_map_dom = lp.map_domain(knl_map_dom, transform_map) + + # }}} + # }}} From 6ee3cf036e3b79080aa0c394438b76022e73ab62 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 11 Aug 2021 17:19:28 -0500 Subject: [PATCH 129/220] enforce that transform map in map_domain must apply to exactly one domain --- loopy/transform/iname.py | 41 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 0d5228275..c11746799 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2064,27 +2064,16 @@ def map_domain(kernel, isl_map, within=None): # }}} - def process_iname_dom(s): - # Make sure the inames we're transforming are all present in the domain - # if not transform_map_in_dims.issubset(frozenset(s.get_var_dict())): - # raise LoopyError("transform map %s attempts to map inames " - # "not present in domain %s. Transform map input inames " - # "must be a subset of the domain inames." - # % (isl_map, s)) + def process_set(s): + """Return the transformed set if transformation is possible, otherwise + return the original set. Also return an int representing + the number of sets that were transformed (0 or 1)""" - var_dict = s.get_var_dict() - - overlap = transform_map_in_dims & frozenset(var_dict) - - if not overlap: - # inames in s are not present in transform map, don't change s - return s - - if len(overlap) != len(transform_map_in_dims): - raise LoopyError( - "Transform map %s attempts to map variables that are not present " - "in domain %s. This is only allowed if *none* of the mapped " - "variables are found in the domain." % (isl_map, s)) + # Make sure the inames we're transforming are all present in the set + # (okay if map only transforms a *subset* of the inames in the set) + if not transform_map_in_dims.issubset(frozenset(s.get_var_dict())): + # Don't transform this set + return s, 0 # {{{ align dims of isl_map and s @@ -2138,11 +2127,19 @@ def process_iname_dom(s): new_s = _find_and_rename_dim( new_s, [dim_type.set], proxy_iname, real_iname) - return new_s + return new_s, 1 # FIXME: Revive _project_out_only_if_all_instructions_in_within - new_domains = [process_iname_dom(dom) for dom in kernel.domains] + new_doms_and_transform_ct = [process_set(dom) for dom in kernel.domains] + new_domains, transform_ct = zip(*new_doms_and_transform_ct) + if sum(transform_ct) != 1: + raise LoopyError( + "Transform map %s was applicable to %d domains. " + "Transform map must be applicable to exactly one domain. " + "A transform map is applicable to a domain if its input " + "inames are a subset of the domain inames." + % (isl_map, sum(transform_ct))) # {{{ update within_inames From f5b2257db8f0692ddb46e69787d57b938e4d9a5f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 11 Aug 2021 17:19:53 -0500 Subject: [PATCH 130/220] test map validity checking/errors in map_domain --- test/test_transform.py | 90 +++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/test/test_transform.py b/test/test_transform.py index a07d31d81..85911c028 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -692,20 +692,22 @@ def test_map_domain_vs_split_iname(): # }}} -# {{{ test_map_domain_with_transform_map_missing_dims +# {{{ test_map_domain_transform_map_validity_and_errors -def test_map_domain_with_transform_map_missing_dims(): - # Make sure map_domain works correctly when the mapping doesn't include - # all the dims in the domain. +def test_map_domain_transform_map_validity_and_errors(): # {{{ Make kernel knl = lp.make_kernel( [ "[nx,nt] -> {[x, y, z, t]: 0 <= x,y,z < nx and 0 <= t < nt}", + "[m] -> {[j]: 0 <= j < m}", ], """ a[y,x,t,z] = b[y,x,t,z] {id=stmta} + for j + <>temp = j {dep=stmta} + end """, lang_version=(2018, 2), ) @@ -714,6 +716,9 @@ def test_map_domain_with_transform_map_missing_dims(): # }}} + # Make sure map_domain works correctly when the mapping doesn't include + # all the dims in the domain. + # {{{ Apply domain change mapping knl_map_dom = ref_knl # loop priority goes away, deps stay @@ -729,10 +734,10 @@ def test_map_domain_with_transform_map_missing_dims(): "y = y_new" "}") - # Call map_domain to transform kernel + # Call map_domain to transform kernel; this should not produce an error knl_map_dom = lp.map_domain(knl_map_dom, transform_map) - # Prioritize loops (prio should eventually be updated in map_domain?) + # Prioritize loops (prio should eventually be updated in map_domain) try: # Use constrain_loop_nesting if it's available desired_prio = "x, t_outer, t_inner, z, y_new" @@ -780,9 +785,7 @@ def test_map_domain_with_transform_map_missing_dims(): # }}} - # {{{ Make sure there's an error if transform map contains *extra* dims - # Note, this is only okay if transform map 'in' dims don't match *any* - # domain inames, in which case nothing happens. + # {{{ Make sure we error on a map that is not bijective # Not bijective transform_map = isl.BasicMap( @@ -798,43 +801,42 @@ def test_map_domain_with_transform_map_missing_dims(): except LoopyError as err: assert "map must be bijective" in str(err) - # Bijective and rogue dim - # (with some inames missing from in-dims, which would otherwise be okay) - transform_map = isl.BasicMap( - "[nx,nt] -> {[t, y, rogue] -> [t_new, y_new, rogue_new]: " - "y = y_new and t = t_new and rogue = rogue_new" - "}") - - try: - knl_map_dom = lp.map_domain(knl_map_dom, transform_map) - raise AssertionError() - except LoopyError as err: - assert ( - "attempts to map variables that are not present in domain" in str(err)) - - # Bijective and rogue dim - # (with all inames present in in-dims) - transform_map = isl.BasicMap( - "[nx,nt] -> {[t, y, x, z, rogue] -> [t_new, y_new, x_new, z_new, rogue_new]:" - "y = y_new and t = t_new and x = x_new and z = z_new and rogue = rogue_new" - "}") - - try: - knl_map_dom = lp.map_domain(knl_map_dom, transform_map) - raise AssertionError() - except LoopyError as err: - assert ( - "attempts to map variables that are not present in domain" in str(err)) + # }}} - # Bijective and rogue dim with *no* inames present in domain - # (allowed but does nothing) - transform_map = isl.BasicMap( - "[nx,nt] -> {[rogue] -> [rogue_new]: " - "rogue = rogue_new" - "}") + # {{{ Make sure there's an error if transform map does not apply to + # exactly one domain. + + test_maps = [ + # Map where some inames match exactly one domain but there's also a + # rogue dim + isl.BasicMap( + "[nx,nt] -> {[t, y, rogue] -> [t_new, y_new, rogue_new]: " + "y = y_new and t = t_new and rogue = rogue_new" + "}"), + # Map where all inames match exactly one domain but there's also a + # rogue dim + isl.BasicMap( + "[nx,nt] -> {[t, y, x, z, rogue] -> " + "[t_new, y_new, x_new, z_new, rogue_new]: " + "y = y_new and t = t_new and x = x_new and z = z_new " + "and rogue = rogue_new" + "}"), + # Map where no inames match any domain + isl.BasicMap( + "[nx,nt] -> {[rogue] -> [rogue_new]: " + "rogue = rogue_new" + "}"), + ] - # This should not raise an error - knl_map_dom = lp.map_domain(knl_map_dom, transform_map) + for transform_map in test_maps: + try: + knl_map_dom = lp.map_domain(knl_map_dom, transform_map) + raise AssertionError() + except LoopyError as err: + assert ( + "was applicable to 0 domains. " + "Transform map must be applicable to exactly one domain." + in str(err)) # }}} From fddd305f1e0c0e2fda1423222194b03a693388b7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 11 Aug 2021 18:05:09 -0500 Subject: [PATCH 131/220] remove map applicability logic from process_set --- loopy/transform/iname.py | 63 ++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 18 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index c11746799..594ee0032 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2065,15 +2065,8 @@ def map_domain(kernel, isl_map, within=None): # }}} def process_set(s): - """Return the transformed set if transformation is possible, otherwise - return the original set. Also return an int representing - the number of sets that were transformed (0 or 1)""" - - # Make sure the inames we're transforming are all present in the set - # (okay if map only transforms a *subset* of the inames in the set) - if not transform_map_in_dims.issubset(frozenset(s.get_var_dict())): - # Don't transform this set - return s, 0 + """Return the transformed set. Assume that map is applicable to this + set.""" # {{{ align dims of isl_map and s @@ -2127,19 +2120,53 @@ def process_set(s): new_s = _find_and_rename_dim( new_s, [dim_type.set], proxy_iname, real_iname) - return new_s, 1 + return new_s # FIXME: Revive _project_out_only_if_all_instructions_in_within - new_doms_and_transform_ct = [process_set(dom) for dom in kernel.domains] - new_domains, transform_ct = zip(*new_doms_and_transform_ct) - if sum(transform_ct) != 1: + # {{{ Apply the transform map to exactly one domain + + map_applied_to_one_dom = False + new_domains = [] + transform_map_rules = ( + "Transform map must be applicable to exactly one domain. " + "A transform map is applicable to a domain if its input " + "inames are a subset of the domain inames.") + + for old_domain in kernel.domains: + + # Make sure transform map is applicable to this set. Then transform. + + if not transform_map_in_dims.issubset( + frozenset(old_domain.get_var_dict())): + + # Map transforms inames that are not all present in the set. + # Don't transform. + new_domains.append(old_domain) + continue + + elif map_applied_to_one_dom: + + # Map is applicable to this domain, but this map was + # already applied. Error. + raise LoopyError( + "Transform map %s was applicable to more than one domain. %s" + % (isl_map, transform_map_rules)) + + else: + + # Map is applicable to this domain, and this map has not yet + # been applied. Transform. + new_domains.append(process_set(old_domain)) + map_applied_to_one_dom = True + + # If the map could not be applied to any domain, error. + if not map_applied_to_one_dom: raise LoopyError( - "Transform map %s was applicable to %d domains. " - "Transform map must be applicable to exactly one domain. " - "A transform map is applicable to a domain if its input " - "inames are a subset of the domain inames." - % (isl_map, sum(transform_ct))) + "Transform map %s was not applicable to any domain. %s" + % (isl_map, transform_map_rules)) + + # }}} # {{{ update within_inames From be524ff23e20d01885d930920601cfcb9e14b7b4 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 11 Aug 2021 18:05:29 -0500 Subject: [PATCH 132/220] update expected error string for map_domain test --- test/test_transform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_transform.py b/test/test_transform.py index 85911c028..d72d35ba2 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -834,7 +834,7 @@ def test_map_domain_transform_map_validity_and_errors(): raise AssertionError() except LoopyError as err: assert ( - "was applicable to 0 domains. " + "was not applicable to any domain. " "Transform map must be applicable to exactly one domain." in str(err)) From d8bc177d325ae5096ea4b9c9b837581b50ee5c2a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 12 Aug 2021 13:02:01 -0500 Subject: [PATCH 133/220] (WIP) print out the loop bounds that I think we want to use to create the blex space (bounds that came from lexmax/lexmin, which work for triangular domains) --- loopy/schedule/checker/schedule.py | 44 +++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index f7ef78210..6e3fd81b9 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -221,7 +221,7 @@ class StatementOrdering: def _gather_blex_ordering_info( sync_kind, - lin_items, loops_with_barriers, loops_to_ignore, + lin_items, loops_with_barriers, loop_bounds, loops_to_ignore, all_stmt_ids, iname_bounds_pwaff, all_par_lex_dim_names, gid_lex_dim_names, ): @@ -259,6 +259,7 @@ def _gather_blex_ordering_info( n_seq_blex_dims = 1 # Num dims representing sequential order in blex space next_blex_tuple = [0] # Next tuple of points in blex order + print() # Debugging. TODO remove for lin_item in lin_items: if isinstance(lin_item, EnterLoop): enter_iname = lin_item.iname @@ -277,6 +278,9 @@ def _gather_blex_ordering_info( # Store 3 tuples that will be used later to create pairs # that will later be subtracted from the blex order map + + # {{{ OLD version without lexmin/lexmax: + lbound = iname_bounds_pwaff[enter_iname][0] first_iter_blex_pt = next_blex_tuple[:] first_iter_blex_pt[-2] = lbound @@ -285,6 +289,19 @@ def _gather_blex_ordering_info( slex.TOP: tuple(next_blex_tuple), slex.FIRST: tuple(first_iter_blex_pt), } + + # }}} + + # {{{ NEW version with lexmin/lexmax + + from loopy.schedule.checker.utils import prettier_map_string + print("Iname %s" % (enter_iname)) + print("OLD FIRST:", tuple(first_iter_blex_pt)) + print("lexmin:") + print(prettier_map_string(loop_bounds[enter_iname][0])) + + # }}} + # (copy these three blex points when creating dict because # the lists will continue to be updated) @@ -313,6 +330,9 @@ def _gather_blex_ordering_info( # Store 3 tuples that will be used later to create pairs # that will later be subtracted from the blex order map + + # {{{ NEW version without lexmin/lexmax: + ubound = iname_bounds_pwaff[leave_iname][1] last_iter_blex_pt = pre_end_loop_blex_pt[:] last_iter_blex_pt[-2] = ubound @@ -322,6 +342,19 @@ def _gather_blex_ordering_info( last_iter_blex_pt) blex_exclusion_info[leave_iname][slex.POST] = tuple( next_blex_tuple) + + # }}} + + # {{{ NEW version with lexmin/lexmax + + from loopy.schedule.checker.utils import prettier_map_string + print("Iname %s" % (leave_iname)) + print("OLD LAST:", tuple(last_iter_blex_pt)) + print("lexmax:") + print(prettier_map_string(loop_bounds[leave_iname][1])) + + # }}} + # (copy these three blex points when creating dict because # the lists will continue to be updated) @@ -721,7 +754,7 @@ def get_pairwise_statement_orderings_inner( # If we haven't already stored bounds for this iname, do so if iname not in loop_bounds: - # Get set of inames nested outside this one (including this iname) + # Get set of inames nested outside (including this iname) inames_involved_in_bound = set(current_inames[:depth+1]) # Get inames domain @@ -776,9 +809,6 @@ def get_pairwise_statement_orderings_inner( print(prettier_map_string(lbound)) print(prettier_map_string(ubound)) - 1/0 - # TODO left off here - # }}} # {{{ Create lex dim names representing parallel axes @@ -856,7 +886,7 @@ def get_pairwise_statement_orderings_inner( lblex_order_map, seq_lblex_dim_names) = _gather_blex_ordering_info( "local", - lin_items, loops_with_barriers, loops_to_ignore, + lin_items, loops_with_barriers, loop_bounds, loops_to_ignore, all_stmt_ids, iname_bounds_pwaff, all_par_lex_dim_names, gid_lex_dim_names, ) @@ -864,7 +894,7 @@ def get_pairwise_statement_orderings_inner( gblex_order_map, seq_gblex_dim_names) = _gather_blex_ordering_info( "global", - lin_items, loops_with_barriers, loops_to_ignore, + lin_items, loops_with_barriers, loop_bounds, loops_to_ignore, all_stmt_ids, iname_bounds_pwaff, all_par_lex_dim_names, gid_lex_dim_names, ) From 885ef5e0d942aa46f2c997d851d14e909e67118d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 12 Aug 2021 13:59:24 -0500 Subject: [PATCH 134/220] temporarilly committing broken test --- test/test_linearization_checker.py | 76 ++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index d6f0baf8e..627434001 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -150,6 +150,82 @@ def _process_and_linearize(knl, knl_name="loopy_kernel"): # }}} + + +from loopy.schedule.checker import ( + get_pairwise_statement_orderings, +) + +''' +assumptions = "i_end >= i_start + 1 and j_end >= j_start + 1 and k_end >= 1" +knl = lp.make_kernel( + [ + "{[i,j,k]: i_start<=itemp0 = 0 {id=stmt_k0} + ... lbarrier {id=stmt_b0,dep=stmt_k0} + <>temp1 = 1 {id=stmt_k1,dep=stmt_b0} + for i + <>tempi0 = 0 {id=stmt_i0,dep=stmt_k1} + ... lbarrier {id=stmt_ib0,dep=stmt_i0} + ... gbarrier {id=stmt_ibb0,dep=stmt_i0} + <>tempi1 = 0 {id=stmt_i1,dep=stmt_ib0} + <>tempi2 = 0 {id=stmt_i2,dep=stmt_i1} + for j + <>tempj0 = 0 {id=stmt_j0,dep=stmt_i2} + ... lbarrier {id=stmt_jb0,dep=stmt_j0} + <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} + end + end + <>temp2 = 0 {id=stmt_k2,dep=stmt_i0} + end + """, + assumptions=assumptions, + lang_version=(2018, 2) + ) +''' +assumptions = "ij_end >= i_start + 1 and k_end >= 1" +knl = lp.make_kernel( + [ + "{[i,j,k]: i_start<=itemp0 = 0 {id=stmt_k0} + ... lbarrier {id=stmt_b0,dep=stmt_k0} + <>temp1 = 1 {id=stmt_k1,dep=stmt_b0} + for i + <>tempi0 = 0 {id=stmt_i0,dep=stmt_k1} + ... lbarrier {id=stmt_ib0,dep=stmt_i0} + ... gbarrier {id=stmt_ibb0,dep=stmt_i0} + <>tempi1 = 0 {id=stmt_i1,dep=stmt_ib0} + <>tempi2 = 0 {id=stmt_i2,dep=stmt_i1} + for j + <>tempj0 = 0 {id=stmt_j0,dep=stmt_i2} + ... lbarrier {id=stmt_jb0,dep=stmt_j0} + <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} + end + end + <>temp2 = 0 {id=stmt_k2,dep=stmt_i0} + end + """, + assumptions=assumptions, + lang_version=(2018, 2) + ) + +# Get a linearization +lin_items, proc_knl, lin_knl = _process_and_linearize(knl) + +stmt_id_pairs = [("stmt_j1", "stmt_k2"), ("stmt_k1", "stmt_i0")] +pworders = get_pairwise_statement_orderings( + lin_knl, lin_items, stmt_id_pairs) + +1/0 + + + # {{{ test_intra_thread_pairwise_schedule_creation() def test_intra_thread_pairwise_schedule_creation(): From e5b765c23e725ab690b829338be2164b16d24201 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 13 Aug 2021 14:19:43 -0500 Subject: [PATCH 135/220] remove arg from map_domain --- loopy/transform/iname.py | 38 ++++++-------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 594ee0032..8d1f06d7b 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -1837,11 +1837,9 @@ def add_inames_to_insn(kernel, inames, insn_match): # {{{ map_domain class _MapDomainMapper(RuleAwareIdentityMapper): - def __init__(self, rule_mapping_context, within, new_inames, substitutions): + def __init__(self, rule_mapping_context, new_inames, substitutions): super(_MapDomainMapper, self).__init__(rule_mapping_context) - self.within = within - self.old_inames = frozenset(substitutions) self.new_inames = new_inames @@ -1850,10 +1848,7 @@ def __init__(self, rule_mapping_context, within, new_inames, substitutions): def map_reduction(self, expr, expn_state): red_overlap = frozenset(expr.inames) & self.old_inames arg_ctx_overlap = frozenset(expn_state.arg_context) & self.old_inames - if (red_overlap - and self.within( - expn_state.kernel, - expn_state.instruction)): + if red_overlap: if len(red_overlap) != len(self.old_inames): raise LoopyError("reduction '%s' involves a part " "of the map domain inames. Reductions must " @@ -1886,10 +1881,7 @@ def map_reduction(self, expr, expn_state): def map_variable(self, expr, expn_state): if (expr.name in self.old_inames - and expr.name not in expn_state.arg_context - and self.within( - expn_state.kernel, - expn_state.instruction)): + and expr.name not in expn_state.arg_context): return self.substitutions[expr.name] else: return super(_MapDomainMapper, self).map_variable(expr, expn_state) @@ -2012,7 +2004,7 @@ def _apply_identity_for_missing_map_dims(mapping, desired_dims): @for_each_kernel -def map_domain(kernel, isl_map, within=None): +def map_domain(kernel, isl_map): # FIXME: Express _split_iname_backend in terms of this # Missing/deleted for now: # - slab processing @@ -2021,24 +2013,6 @@ def map_domain(kernel, isl_map, within=None): # FIXME: Express affine_map_inames in terms of this, deprecate # FIXME: Document - # FIXME: Support within - - # {{{ within processing (disabled for now) - if within is not None: - raise NotImplementedError("within") - - from loopy.match import parse_match - within = parse_match(within) - - # {{{ return the same kernel if no kernel matches - - if not any(within(kernel, insn) for insn in kernel.instructions): - return kernel - - # }}} - - # }}} - if not isl_map.is_bijective(): raise LoopyError("isl_map must be bijective") @@ -2173,7 +2147,7 @@ def process_set(s): new_insns = [] for insn in kernel.instructions: overlap = transform_map_in_dims & insn.within_inames - if overlap and within(kernel, insn): + if overlap: if len(overlap) != len(transform_map_in_dims): raise LoopyError("instruction '%s' is within only a part " "of the map domain inames. Instructions must " @@ -2197,7 +2171,7 @@ def process_set(s): rule_mapping_context = SubstitutionRuleMappingContext( kernel.substitutions, kernel.get_var_name_generator()) - ins = _MapDomainMapper(rule_mapping_context, within, + ins = _MapDomainMapper(rule_mapping_context, transform_map_out_dims, substitutions) kernel = ins.map_kernel(kernel) From c0a613c5d1f0722cdaca71893387b05c97927b36 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 13 Aug 2021 15:13:53 -0500 Subject: [PATCH 136/220] in map_domain, error if there are any loop priorities/nest constraints involving the mapped inames --- loopy/transform/iname.py | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 8d1f06d7b..a4e5fcee6 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2003,22 +2003,53 @@ def _apply_identity_for_missing_map_dims(mapping, desired_dims): return augmented_mapping, proxy_name_pairs +def _error_if_any_iname_in_constraint( + inames, nest_constraints, + constraint_descriptor_str): + for constraint in nest_constraints: + for tier in constraint: + for iname in inames: + if tier.contains(iname): + raise ValueError( + "%s constraint %s contains iname(s) " + "transformed by map in map_domain." + % (constraint_descriptor_str, constraint)) + + @for_each_kernel def map_domain(kernel, isl_map): # FIXME: Express _split_iname_backend in terms of this # Missing/deleted for now: # - slab processing # - priorities processing - # FIXME: Process priorities # FIXME: Express affine_map_inames in terms of this, deprecate # FIXME: Document + # Make sure the map is bijective if not isl_map.is_bijective(): raise LoopyError("isl_map must be bijective") transform_map_out_dims = frozenset(isl_map.get_var_dict(dim_type.out)) transform_map_in_dims = frozenset(isl_map.get_var_dict(dim_type.in_)) + # {{{ Make sure that none of the mapped inames are involved in loop priorities + + if hasattr(kernel, "loop_priority") and kernel.loop_priority: + for prio in kernel.loop_priority: + if set(prio) & transform_map_in_dims: + raise ValueError( + "Loop priority %s contains iname(s) transformed by " + "map %s in map_domain." % (prio, isl_map)) + if hasattr(kernel, "loop_nest_constraints") and kernel.loop_nest_constraints: + _error_if_any_iname_in_constraint( + transform_map_in_dims, + kernel.loop_nest_constraints.must_nest, "Must-nest") + _error_if_any_iname_in_constraint( + transform_map_in_dims, + kernel.loop_nest_constraints.must_not_nest, "Must-not-nest") + + # }}} + # {{{ solve for representation of old inames in terms of new substitutions = {} From 88ebe1afa225840efaef2f06babebb96f005397e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 13 Aug 2021 15:17:32 -0500 Subject: [PATCH 137/220] add test for map_domain error when there are any loop priorities/nest constraints involving the mapped inames --- test/test_transform.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/test/test_transform.py b/test/test_transform.py index d72d35ba2..516d676c3 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -794,9 +794,9 @@ def test_map_domain_transform_map_validity_and_errors(): "}") from loopy.diagnostic import LoopyError - knl_map_dom = ref_knl + knl = ref_knl try: - knl_map_dom = lp.map_domain(knl_map_dom, transform_map) + knl = lp.map_domain(knl, transform_map) raise AssertionError() except LoopyError as err: assert "map must be bijective" in str(err) @@ -830,7 +830,7 @@ def test_map_domain_transform_map_validity_and_errors(): for transform_map in test_maps: try: - knl_map_dom = lp.map_domain(knl_map_dom, transform_map) + knl = lp.map_domain(knl, transform_map) raise AssertionError() except LoopyError as err: assert ( @@ -840,6 +840,24 @@ def test_map_domain_transform_map_validity_and_errors(): # }}} + # {{{ Make sure there's an error if we try to map inames in priorities + + knl = ref_knl + knl = lp.prioritize_loops(knl, "y, z") + knl = lp.prioritize_loops(knl, "x, z") + try: + transform_map = isl.BasicMap( + "[nx,nt] -> {[t, y] -> [t_new, y_new]: " + "y = y_new and t = t_new }") + knl = lp.map_domain(knl, transform_map) + raise AssertionError() + except ValueError as err: + assert ( + "Loop priority ('y', 'z') contains iname(s) " + "transformed by map" in str(err)) + + # }}} + # }}} From acd0803bd7751d9ece7da52df75ff5f4c4c8d2a2 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 13 Aug 2021 16:31:54 -0500 Subject: [PATCH 138/220] use dim_type to abbreviate isl.dim_type class and dt to refer to a particular dim type --- loopy/schedule/checker/schedule.py | 24 +++++------ loopy/schedule/checker/utils.py | 66 +++++++++++++++--------------- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index ab9af51df..fd0b1a6aa 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -22,7 +22,7 @@ import islpy as isl from dataclasses import dataclass -dt = isl.dim_type.set +dim_type = isl.dim_type # {{{ Constants @@ -289,7 +289,7 @@ def _gather_blex_ordering_info( # the lists will continue to be updated) # Store any new params found - blex_order_map_params |= set(lbound.get_var_names(dt.param)) + blex_order_map_params |= set(lbound.get_var_names(dim_type.param)) elif isinstance(lin_item, LeaveLoop): leave_iname = lin_item.iname @@ -326,7 +326,7 @@ def _gather_blex_ordering_info( # the lists will continue to be updated) # Store any new params found - blex_order_map_params |= set(ubound.get_var_names(dt.param)) + blex_order_map_params |= set(ubound.get_var_names(dim_type.param)) elif isinstance(lin_item, RunInstruction): # Add stmt->blex pair to stmt_inst_to_blex @@ -399,9 +399,9 @@ def _gather_blex_ordering_info( # Add LID/GID dims to blex order map blex_order_map = add_and_name_isl_dims( - blex_order_map, dt.out, all_par_lex_dim_names) + blex_order_map, dim_type.out, all_par_lex_dim_names) blex_order_map = add_and_name_isl_dims( - blex_order_map, dt.in_, + blex_order_map, dim_type.in_, append_mark_to_strings(all_par_lex_dim_names, mark=BEFORE_MARK)) if sync_kind == "local": # For intra-group case, constrain GID 'before' to equal GID 'after' @@ -422,14 +422,14 @@ def _gather_blex_ordering_info( # Add bounds params needed in blex map blex_order_map = add_and_name_isl_dims( - blex_order_map, dt.param, blex_order_map_params) + blex_order_map, dim_type.param, blex_order_map_params) # Get a set representing blex_order_map space n_blex_dims = n_seq_blex_dims + len(all_par_lex_dim_names) blex_set_template = isl.align_spaces( isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map ).move_dims( - dt.in_, n_blex_dims, dt.out, 0, n_blex_dims + dim_type.in_, n_blex_dims, dim_type.out, 0, n_blex_dims ).domain() blex_set_affs = isl.affs_from_space(blex_set_template.space) @@ -523,7 +523,7 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # Convert blex set back to map map_to_subtract = isl.Map.from_domain(full_blex_set).move_dims( - dt.out, 0, dt.in_, n_blex_dims, n_blex_dims) + dim_type.out, 0, dim_type.in_, n_blex_dims, n_blex_dims) # }}} @@ -835,7 +835,7 @@ def _get_map_for_stmt( # Get inames domain for statement instance (a BasicSet) within_inames = knl.id_to_insn[stmt_id].within_inames dom = knl.get_inames_domain( - within_inames).project_out_except(within_inames, [dt.set]) + within_inames).project_out_except(within_inames, [dim_type.set]) # Create map space (an isl space in current implementation) # {('statement', ) -> @@ -853,7 +853,7 @@ def _get_map_for_stmt( # Insert 'statement' dim into domain so that its space allows # for intersection with sched map later dom_to_intersect = insert_and_name_isl_dims( - dom, dt.set, [STATEMENT_VAR_NAME], 0) + dom, dim_type.set, [STATEMENT_VAR_NAME], 0) # Each map will map statement instances -> lex time. # At this point, statement instance tuples consist of single int. @@ -938,9 +938,9 @@ def _get_map_for_stmt( # Add lid/gid dims to lex order map lex_order_map = add_and_name_isl_dims( - lex_order_map, dt.out, all_par_lex_dim_names) + lex_order_map, dim_type.out, all_par_lex_dim_names) lex_order_map = add_and_name_isl_dims( - lex_order_map, dt.in_, + lex_order_map, dim_type.in_, append_mark_to_strings(all_par_lex_dim_names, mark=BEFORE_MARK)) # Constrain lid/gid vars to be equal for var_name in all_par_lex_dim_names: diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 94f2fbd0c..0f9877bac 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -21,7 +21,7 @@ """ import islpy as isl -dt = isl.dim_type +dim_type = isl.dim_type def prettier_map_string(map_obj): @@ -29,30 +29,30 @@ def prettier_map_string(map_obj): ).replace("{ ", "{\n").replace(" }", "\n}").replace("; ", ";\n") -def insert_and_name_isl_dims(isl_set, dim_type, names, new_idx_start): - new_set = isl_set.insert_dims(dim_type, new_idx_start, len(names)) +def insert_and_name_isl_dims(isl_set, dt, names, new_idx_start): + new_set = isl_set.insert_dims(dt, new_idx_start, len(names)) for i, name in enumerate(names): - new_set = new_set.set_dim_name(dim_type, new_idx_start+i, name) + new_set = new_set.set_dim_name(dt, new_idx_start+i, name) return new_set -def add_and_name_isl_dims(isl_map, dim_type, names): - new_idx_start = isl_map.dim(dim_type) - new_map = isl_map.add_dims(dim_type, len(names)) +def add_and_name_isl_dims(isl_map, dt, names): + new_idx_start = isl_map.dim(dt) + new_map = isl_map.add_dims(dt, len(names)) for i, name in enumerate(names): - new_map = new_map.set_dim_name(dim_type, new_idx_start+i, name) + new_map = new_map.set_dim_name(dt, new_idx_start+i, name) return new_map def reorder_dims_by_name( - isl_set, dim_type, desired_dims_ordered): - """Return an isl_set with the dimensions of the specified dim_type + isl_set, dt, desired_dims_ordered): + """Return an isl_set with the dimensions of the specified dim type in the specified order. :arg isl_set: A :class:`islpy.Set` whose dimensions are to be reordered. - :arg dim_type: A :class:`islpy.dim_type`, i.e., an :class:`int`, + :arg dt: A :class:`islpy.dim_type`, i.e., an :class:`int`, specifying the dimension to be reordered. :arg desired_dims_ordered: A :class:`list` of :class:`str` elements @@ -63,23 +63,23 @@ def reorder_dims_by_name( """ - assert dim_type != dt.param - assert set(isl_set.get_var_names(dim_type)) == set(desired_dims_ordered) + assert dt != dim_type.param + assert set(isl_set.get_var_names(dt)) == set(desired_dims_ordered) - other_dim_type = dt.param - other_dim_len = len(isl_set.get_var_names(other_dim_type)) + other_dt = dim_type.param + other_dim_len = len(isl_set.get_var_names(other_dt)) new_set = isl_set.copy() for desired_idx, name in enumerate(desired_dims_ordered): - current_idx = new_set.find_dim_by_name(dim_type, name) + current_idx = new_set.find_dim_by_name(dt, name) if current_idx != desired_idx: # First move to other dim because isl is stupid new_set = new_set.move_dims( - other_dim_type, other_dim_len, dim_type, current_idx, 1) + other_dt, other_dim_len, dt, current_idx, 1) # Now move it where we actually want it new_set = new_set.move_dims( - dim_type, desired_idx, other_dim_type, other_dim_len, 1) + dt, desired_idx, other_dt, other_dim_len, 1) return new_set @@ -90,7 +90,7 @@ def ensure_dim_names_match_and_align(obj_map, tgt_map): if not all( set(obj_map.get_var_names(dt)) == set(tgt_map.get_var_names(dt)) for dt in - [dt.in_, dt.out, dt.param]): + [dim_type.in_, dim_type.out, dim_type.param]): raise ValueError( "Cannot align spaces; names don't match:\n%s\n%s" % (prettier_map_string(obj_map), prettier_map_string(tgt_map)) @@ -107,27 +107,27 @@ def add_eq_isl_constraint_from_names(isl_map, var1, var2): {1: 0, var1: 1, var2: -1})) -def append_mark_to_isl_map_var_names(old_isl_map, dim_type, mark): +def append_mark_to_isl_map_var_names(old_isl_map, dt, mark): """Return an :class:`islpy.Map` with a mark appended to the specified dimension names. :arg old_isl_map: An :class:`islpy.Map`. - :arg dim_type: An :class:`islpy.dim_type`, i.e., an :class:`int`, + :arg dt: An :class:`islpy.dim_type`, i.e., an :class:`int`, specifying the dimension to be marked. :arg mark: A :class:`str` to be appended to the specified dimension names. If not provided, `mark` defaults to an apostrophe. :returns: An :class:`islpy.Map` matching `old_isl_map` with - `mark` appended to the `dim_type` dimension names. + `mark` appended to the `dt` dimension names. """ new_map = old_isl_map.copy() - for i in range(len(old_isl_map.get_var_names(dim_type))): - new_map = new_map.set_dim_name(dim_type, i, old_isl_map.get_dim_name( - dim_type, i)+mark) + for i in range(len(old_isl_map.get_var_names(dt))): + new_map = new_map.set_dim_name(dt, i, old_isl_map.get_dim_name( + dt, i)+mark) return new_map @@ -138,7 +138,7 @@ def append_mark_to_strings(strings, mark): def sorted_union_of_names_in_isl_sets( isl_sets, - set_dim=dt.set): + set_dim=dim_type.set): r"""Return a sorted list of the union of all variable names found in the provided :class:`islpy.Set`\ s. """ @@ -177,8 +177,8 @@ def create_symbolic_map_from_tuples( """ # FIXME allow None for domains - space_out_names = space.get_var_names(dt.out) - space_in_names = space.get_var_names(dt.in_) + space_out_names = space.get_var_names(dim_type.out) + space_in_names = space.get_var_names(dim_type.in_) def _conjunction_of_dim_eq_conditions(dim_names, values, var_name_to_pwaff): condition = var_name_to_pwaff[0].eq_set(var_name_to_pwaff[0]) @@ -194,8 +194,8 @@ def _conjunction_of_dim_eq_conditions(dim_names, values, var_name_to_pwaff): # Get islvars from space var_name_to_pwaff = isl.affs_from_space( space.move_dims( - dt.out, 0, - dt.in_, 0, + dim_type.out, 0, + dim_type.in_, 0, len(space_in_names), ).range() ) @@ -204,7 +204,7 @@ def _conjunction_of_dim_eq_conditions(dim_names, values, var_name_to_pwaff): union_of_maps = isl.Map.from_domain( var_name_to_pwaff[0].eq_set(var_name_to_pwaff[0]+1) # 0 == 1 (false) ).move_dims( - dt.out, 0, dt.in_, len(space_in_names), len(space_out_names)) + dim_type.out, 0, dim_type.in_, len(space_in_names), len(space_out_names)) # Loop through tuple pairs for (tup_in, tup_out), dom in tuple_pairs_with_domains: @@ -220,13 +220,13 @@ def _conjunction_of_dim_eq_conditions(dim_names, values, var_name_to_pwaff): # Convert set to map by moving dimensions around map_from_set = isl.Map.from_domain(condition) map_from_set = map_from_set.move_dims( - dt.out, 0, dt.in_, + dim_type.out, 0, dim_type.in_, len(space_in_names), len(space_out_names)) # Align the *out* dims of dom with the space *in_* dims # in preparation for intersection dom_with_set_dim_aligned = reorder_dims_by_name( - dom, dt.set, + dom, dim_type.set, space_in_names, ) From 619b15791f2107565d1d678857fa22054fc8003d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 13 Aug 2021 16:44:00 -0500 Subject: [PATCH 139/220] use dim_type to abbreviate isl.dim_type class and dt to refer to a particular dim type --- loopy/schedule/checker/schedule.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index c627fa5ba..955f129ad 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -760,16 +760,18 @@ def get_pairwise_statement_orderings_inner( # Get inames domain dom = knl.get_inames_domain( inames_involved_in_bound).project_out_except( - inames_involved_in_bound, [dt.set]) + inames_involved_in_bound, [dim_type.set]) # {{{ Move domain dims for surrounding inames to parameters # (keeping them in order, which might come in handy later...) # Move those inames to params for outer_iname in current_inames[:depth]: - outer_iname_idx = dom.find_dim_by_name(dt.set, outer_iname) + outer_iname_idx = dom.find_dim_by_name( + dim_type.set, outer_iname) dom = dom.move_dims( - dt.param, dom.n_param(), dt.set, outer_iname_idx, 1) + dim_type.param, dom.n_param(), dim_type.set, + outer_iname_idx, 1) # }}} From 13356df6dce015acc7bd48593649e1e59e2d588b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 14 Aug 2021 16:47:36 -0500 Subject: [PATCH 140/220] in map_domain, rename isl_map->transform_map; add docstring --- loopy/transform/iname.py | 48 ++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index a4e5fcee6..0c6b27f1e 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2017,20 +2017,29 @@ def _error_if_any_iname_in_constraint( @for_each_kernel -def map_domain(kernel, isl_map): +def map_domain(kernel, transform_map): + """Transform an iname domain by applying a mapping from existing inames to + new inames. + + :arg transform_map: A bijective :class:`islpy.Map` from existing inames to + new inames. To be applicable to a kernel domain, all input inames in + the map must be found in the domain. The map must be applicable to + exactly one domain found in *kernel.domains*. + + """ + # FIXME: Express _split_iname_backend in terms of this # Missing/deleted for now: # - slab processing # - priorities processing # FIXME: Express affine_map_inames in terms of this, deprecate - # FIXME: Document # Make sure the map is bijective - if not isl_map.is_bijective(): - raise LoopyError("isl_map must be bijective") + if not transform_map.is_bijective(): + raise LoopyError("transform_map must be bijective") - transform_map_out_dims = frozenset(isl_map.get_var_dict(dim_type.out)) - transform_map_in_dims = frozenset(isl_map.get_var_dict(dim_type.in_)) + transform_map_out_dims = frozenset(transform_map.get_var_dict(dim_type.out)) + transform_map_in_dims = frozenset(transform_map.get_var_dict(dim_type.in_)) # {{{ Make sure that none of the mapped inames are involved in loop priorities @@ -2039,7 +2048,7 @@ def map_domain(kernel, isl_map): if set(prio) & transform_map_in_dims: raise ValueError( "Loop priority %s contains iname(s) transformed by " - "map %s in map_domain." % (prio, isl_map)) + "map %s in map_domain." % (prio, transform_map)) if hasattr(kernel, "loop_nest_constraints") and kernel.loop_nest_constraints: _error_if_any_iname_in_constraint( transform_map_in_dims, @@ -2060,9 +2069,9 @@ def map_domain(kernel, isl_map): from pymbolic import var for iname in transform_map_in_dims: substitutions[iname] = aff_to_expr( - _find_aff_subst_from_map(iname, isl_map)) + _find_aff_subst_from_map(iname, transform_map)) var_substitutions[var(iname)] = aff_to_expr( - _find_aff_subst_from_map(iname, isl_map)) + _find_aff_subst_from_map(iname, transform_map)) applied_iname_rewrites.append(var_substitutions) del var_substitutions @@ -2073,21 +2082,22 @@ def process_set(s): """Return the transformed set. Assume that map is applicable to this set.""" - # {{{ align dims of isl_map and s + # {{{ align dims of transform_map and s from islpy import _align_dim_type map_with_s_domain = isl.Map.from_domain(s) - # If there are dims in s that are not mapped by isl_map, add them - # to the in/out space of isl_map so that they remain unchanged. + # If there are dims in s that are not mapped by transform_map, add them + # to the in/out space of transform_map so that they remain unchanged. # (temporary proxy dim names are needed in out space of transform # map because isl won't allow any dim names to match, i.e., instead # of just mapping {[unused_iname]->[unused_iname]}, we have to map # {[unused_name]->[unused_name__prox] : unused_name__prox = unused_name}, # and then rename unused_name__prox afterward.) - augmented_isl_map, proxy_name_pairs = _apply_identity_for_missing_map_dims( - isl_map, s.get_var_names(dim_type.set)) + augmented_transform_map, proxy_name_pairs = \ + _apply_identity_for_missing_map_dims( + transform_map, s.get_var_names(dim_type.set)) # FIXME: Make this less gross # FIXME: Make an exported/documented interface of this in islpy @@ -2098,9 +2108,9 @@ def process_set(s): for i in range(map_with_s_domain.dim(dt)) ] map_names = [ - augmented_isl_map.get_dim_name(dt, i) + augmented_transform_map.get_dim_name(dt, i) for dt in dim_types - for i in range(augmented_isl_map.dim(dt)) + for i in range(augmented_transform_map.dim(dt)) ] # (order doesn't matter in s_names/map_names, @@ -2109,7 +2119,7 @@ def process_set(s): # not sure why this isn't just handled inside _align_dim_type) aligned_map = _align_dim_type( dim_type.param, - augmented_isl_map, map_with_s_domain, False, + augmented_transform_map, map_with_s_domain, False, map_names, s_names) aligned_map = _align_dim_type( dim_type.in_, @@ -2156,7 +2166,7 @@ def process_set(s): # already applied. Error. raise LoopyError( "Transform map %s was applicable to more than one domain. %s" - % (isl_map, transform_map_rules)) + % (transform_map, transform_map_rules)) else: @@ -2169,7 +2179,7 @@ def process_set(s): if not map_applied_to_one_dom: raise LoopyError( "Transform map %s was not applicable to any domain. %s" - % (isl_map, transform_map_rules)) + % (transform_map, transform_map_rules)) # }}} From 716f4a2ba0c217103a85569761ff52dc85776552 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 14 Aug 2021 17:12:00 -0500 Subject: [PATCH 141/220] (WIP) make test kernel for tringular domain doubly triangular --- test/test_linearization_checker.py | 148 +++++------------------------ 1 file changed, 23 insertions(+), 125 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 627434001..6ee57d8a8 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -150,82 +150,52 @@ def _process_and_linearize(knl, knl_name="loopy_kernel"): # }}} - - +# (WIP Testing/debugging; TODO make this into an official test) from loopy.schedule.checker import ( get_pairwise_statement_orderings, ) -''' -assumptions = "i_end >= i_start + 1 and j_end >= j_start + 1 and k_end >= 1" -knl = lp.make_kernel( - [ - "{[i,j,k]: i_start<=itemp0 = 0 {id=stmt_k0} - ... lbarrier {id=stmt_b0,dep=stmt_k0} - <>temp1 = 1 {id=stmt_k1,dep=stmt_b0} - for i - <>tempi0 = 0 {id=stmt_i0,dep=stmt_k1} - ... lbarrier {id=stmt_ib0,dep=stmt_i0} - ... gbarrier {id=stmt_ibb0,dep=stmt_i0} - <>tempi1 = 0 {id=stmt_i1,dep=stmt_ib0} - <>tempi2 = 0 {id=stmt_i2,dep=stmt_i1} - for j - <>tempj0 = 0 {id=stmt_j0,dep=stmt_i2} - ... lbarrier {id=stmt_jb0,dep=stmt_j0} - <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} - end - end - <>temp2 = 0 {id=stmt_k2,dep=stmt_i0} - end - """, - assumptions=assumptions, - lang_version=(2018, 2) - ) -''' -assumptions = "ij_end >= i_start + 1 and k_end >= 1" +assumptions = "ijk_end >= i_start + 1" knl = lp.make_kernel( [ - "{[i,j,k]: i_start<=itemp0 = 0 {id=stmt_k0} - ... lbarrier {id=stmt_b0,dep=stmt_k0} - <>temp1 = 1 {id=stmt_k1,dep=stmt_b0} - for i - <>tempi0 = 0 {id=stmt_i0,dep=stmt_k1} - ... lbarrier {id=stmt_ib0,dep=stmt_i0} - ... gbarrier {id=stmt_ibb0,dep=stmt_i0} - <>tempi1 = 0 {id=stmt_i1,dep=stmt_ib0} - <>tempi2 = 0 {id=stmt_i2,dep=stmt_i1} - for j - <>tempj0 = 0 {id=stmt_j0,dep=stmt_i2} - ... lbarrier {id=stmt_jb0,dep=stmt_j0} - <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} + for i + <>temp0 = 0 {id=stmt_i0} + ... lbarrier {id=stmt_b0,dep=stmt_i0} + <>temp1 = 1 {id=stmt_i1,dep=stmt_b0} + for j + <>tempj0 = 0 {id=stmt_j0,dep=stmt_i1} + ... lbarrier {id=stmt_jb0,dep=stmt_j0} + ... gbarrier {id=stmt_jbb0,dep=stmt_j0} + <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} + <>tempj2 = 0 {id=stmt_j2,dep=stmt_j1} + for k + <>tempk0 = 0 {id=stmt_k0,dep=stmt_j2} + ... lbarrier {id=stmt_kb0,dep=stmt_k0} + <>tempk1 = 0 {id=stmt_k1,dep=stmt_kb0} end end - <>temp2 = 0 {id=stmt_k2,dep=stmt_i0} + <>temp2 = 0 {id=stmt_i2,dep=stmt_j0} end """, assumptions=assumptions, lang_version=(2018, 2) ) +# TODO what happens if i+j<=ktemp0 = 0 {id=stmt_k0} - ... lbarrier {id=stmt_b0,dep=stmt_k0} - <>temp1 = 1 {id=stmt_k1,dep=stmt_b0} - for i - <>tempi0 = 0 {id=stmt_i0,dep=stmt_k1} - ... lbarrier {id=stmt_ib0,dep=stmt_i0} - ... gbarrier {id=stmt_ibb0,dep=stmt_i0} - <>tempi1 = 0 {id=stmt_i1,dep=stmt_ib0} - <>tempi2 = 0 {id=stmt_i2,dep=stmt_i1} - for j - <>tempj0 = 0 {id=stmt_j0,dep=stmt_i2} - ... lbarrier {id=stmt_jb0,dep=stmt_j0} - <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} - end - end - <>temp2 = 0 {id=stmt_k2,dep=stmt_i0} - end - """, - assumptions=assumptions, - lang_version=(2018, 2) - ) - ''' - assumptions = "ij_end >= i_start + 1 and k_end >= 1" - knl = lp.make_kernel( - [ - "{[i,j,k]: i_start<=itemp0 = 0 {id=stmt_k0} - ... lbarrier {id=stmt_b0,dep=stmt_k0} - <>temp1 = 1 {id=stmt_k1,dep=stmt_b0} - for i - <>tempi0 = 0 {id=stmt_i0,dep=stmt_k1} - ... lbarrier {id=stmt_ib0,dep=stmt_i0} - ... gbarrier {id=stmt_ibb0,dep=stmt_i0} - <>tempi1 = 0 {id=stmt_i1,dep=stmt_ib0} - <>tempi2 = 0 {id=stmt_i2,dep=stmt_i1} - for j - <>tempj0 = 0 {id=stmt_j0,dep=stmt_i2} - ... lbarrier {id=stmt_jb0,dep=stmt_j0} - <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} - end - end - <>temp2 = 0 {id=stmt_k2,dep=stmt_i0} - end - """, - assumptions=assumptions, - lang_version=(2018, 2) - ) - - # Get a linearization - lin_items, proc_knl, lin_knl = _process_and_linearize(knl) - - stmt_id_pairs = [("stmt_j1", "stmt_k2"), ("stmt_k1", "stmt_i0")] - pworders = get_pairwise_statement_orderings( - lin_knl, lin_items, stmt_id_pairs) - - 1/0 - # TODO left off here +# def test_sios_with_triangular_domain(): +# TODO make this test # }}} From 59754079e7270a2b3cd4f6ea2e862bc27b13885c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Aug 2021 19:01:47 -0500 Subject: [PATCH 142/220] (WIP) add all stmt ids in triangular-domain blex example to ensure all loops are represented --- test/test_linearization_checker.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 6ee57d8a8..a1da9d790 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -189,7 +189,16 @@ def _process_and_linearize(knl, knl_name="loopy_kernel"): # Get a linearization lin_items, proc_knl, lin_knl = _process_and_linearize(knl) -stmt_id_pairs = [("stmt_k1", "stmt_i2"), ("stmt_i1", "stmt_j0")] +#stmt_id_pairs = [("stmt_k1", "stmt_i2"), ("stmt_i1", "stmt_j0")] +stmt_id_pairs = [ + ("stmt_i0", "stmt_i1"), + ("stmt_i1", "stmt_j0"), + ("stmt_j0", "stmt_j1"), + ("stmt_j1", "stmt_j2"), + ("stmt_j2", "stmt_k0"), + ("stmt_k0", "stmt_k1"), + ("stmt_k1", "stmt_i2"), + ] pworders = get_pairwise_statement_orderings( lin_knl, lin_items, stmt_id_pairs) From a4434857d5c61aafa8d9b88810f77a3782f9a355 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Aug 2021 19:05:42 -0500 Subject: [PATCH 143/220] (WIP) use lexmax/min_multi_pw_aff instead of lexmax/lexmin, use new bounds when building desired blex tuples (WIP), also keep old map construction code alongside new code temporarily for comparison --- loopy/schedule/checker/schedule.py | 197 ++++++++++++++++++++++++----- 1 file changed, 166 insertions(+), 31 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 955f129ad..13b94bc37 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -254,7 +254,10 @@ def _gather_blex_ordering_info( stmt_inst_to_blex = {} # Map stmt instances to blex space iname_to_blex_dim = {} # Map from inames to corresponding blex space dim + # OLD blex_exclusion_info, TODO remove + _blex_exclusion_info = {} # Info for creating maps to exclude from blex order blex_exclusion_info = {} # Info for creating maps to exclude from blex order + _blex_order_map_params = set() # TODO remove blex_order_map_params = set() # Params needed in blex order map n_seq_blex_dims = 1 # Num dims representing sequential order in blex space next_blex_tuple = [0] # Next tuple of points in blex order @@ -281,24 +284,32 @@ def _gather_blex_ordering_info( # {{{ OLD version without lexmin/lexmax: - lbound = iname_bounds_pwaff[enter_iname][0] - first_iter_blex_pt = next_blex_tuple[:] - first_iter_blex_pt[-2] = lbound - blex_exclusion_info[enter_iname] = { + _lbound = iname_bounds_pwaff[enter_iname][0] + _first_iter_blex_pt = next_blex_tuple[:] + _first_iter_blex_pt[-2] = _lbound + _blex_exclusion_info[enter_iname] = { slex.PRE: tuple(pre_loop_blex_pt), slex.TOP: tuple(next_blex_tuple), - slex.FIRST: tuple(first_iter_blex_pt), + slex.FIRST: tuple(_first_iter_blex_pt), } # }}} # {{{ NEW version with lexmin/lexmax - from loopy.schedule.checker.utils import prettier_map_string print("Iname %s" % (enter_iname)) - print("OLD FIRST:", tuple(first_iter_blex_pt)) + print("OLD FIRST:", tuple(_first_iter_blex_pt)) print("lexmin:") - print(prettier_map_string(loop_bounds[enter_iname][0])) + print(loop_bounds[enter_iname][0]) + + lbound = loop_bounds[enter_iname][0] # pwaff + first_iter_blex_pt = next_blex_tuple[:] + first_iter_blex_pt[-2] = lbound + blex_exclusion_info[enter_iname] = { + slex.PRE: tuple(pre_loop_blex_pt), + slex.TOP: tuple(next_blex_tuple), + slex.FIRST: tuple(first_iter_blex_pt), + } # }}} @@ -306,6 +317,7 @@ def _gather_blex_ordering_info( # the lists will continue to be updated) # Store any new params found + _blex_order_map_params |= set(_lbound.get_var_names(dim_type.param)) # TODO remove blex_order_map_params |= set(lbound.get_var_names(dim_type.param)) elif isinstance(lin_item, LeaveLoop): @@ -331,27 +343,36 @@ def _gather_blex_ordering_info( # Store 3 tuples that will be used later to create pairs # that will later be subtracted from the blex order map - # {{{ NEW version without lexmin/lexmax: + # {{{ OLD version without lexmin/lexmax: - ubound = iname_bounds_pwaff[leave_iname][1] - last_iter_blex_pt = pre_end_loop_blex_pt[:] - last_iter_blex_pt[-2] = ubound - blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( + _ubound = iname_bounds_pwaff[leave_iname][1] + _last_iter_blex_pt = pre_end_loop_blex_pt[:] + _last_iter_blex_pt[-2] = _ubound + _blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( pre_end_loop_blex_pt) - blex_exclusion_info[leave_iname][slex.LAST] = tuple( - last_iter_blex_pt) - blex_exclusion_info[leave_iname][slex.POST] = tuple( + _blex_exclusion_info[leave_iname][slex.LAST] = tuple( + _last_iter_blex_pt) + _blex_exclusion_info[leave_iname][slex.POST] = tuple( next_blex_tuple) # }}} # {{{ NEW version with lexmin/lexmax - from loopy.schedule.checker.utils import prettier_map_string print("Iname %s" % (leave_iname)) - print("OLD LAST:", tuple(last_iter_blex_pt)) + print("OLD LAST:", tuple(_last_iter_blex_pt)) print("lexmax:") - print(prettier_map_string(loop_bounds[leave_iname][1])) + print(loop_bounds[leave_iname][1]) + + ubound = loop_bounds[leave_iname][1] + last_iter_blex_pt = pre_end_loop_blex_pt[:] + last_iter_blex_pt[-2] = ubound + blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( + pre_end_loop_blex_pt) + blex_exclusion_info[leave_iname][slex.LAST] = tuple( + last_iter_blex_pt) + blex_exclusion_info[leave_iname][slex.POST] = tuple( + next_blex_tuple) # }}} @@ -359,6 +380,7 @@ def _gather_blex_ordering_info( # the lists will continue to be updated) # Store any new params found + _blex_order_map_params |= set(_ubound.get_var_names(dim_type.param)) # TODO remove blex_order_map_params |= set(ubound.get_var_names(dim_type.param)) elif isinstance(lin_item, RunInstruction): @@ -404,6 +426,7 @@ def _gather_blex_ordering_info( lin_item, (CallKernel, ReturnFromKernel)) pass + _blex_order_map_params = sorted(_blex_order_map_params) # TODO remove blex_order_map_params = sorted(blex_order_map_params) # At this point, some blex tuples may have more dimensions than others; @@ -454,6 +477,8 @@ def _gather_blex_ordering_info( iname_to_blex_var[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] # Add bounds params needed in blex map + _blex_order_map = add_and_name_isl_dims( # TODO remove + blex_order_map, dim_type.param, _blex_order_map_params) blex_order_map = add_and_name_isl_dims( blex_order_map, dim_type.param, blex_order_map_params) @@ -466,10 +491,22 @@ def _gather_blex_ordering_info( ).domain() blex_set_affs = isl.affs_from_space(blex_set_template.space) + # TODO remove: + _blex_set_template = isl.align_spaces( + isl.Map("[ ] -> { [ ] -> [ ] }"), _blex_order_map + ).move_dims( + dim_type.in_, n_blex_dims, dim_type.out, 0, n_blex_dims + ).domain() + _blex_set_affs = isl.affs_from_space(_blex_set_template.space) + # {{{ Create blex map to subtract for each iname in blex_exclusion_info maps_to_subtract = [] for iname, key_lex_tuples in blex_exclusion_info.items(): + _iname = iname # TODO remove + _key_lex_tuples = _blex_exclusion_info[_iname] # TODO remove + print("") + print(iname) # {{{ Create blex map to subract for one iname @@ -484,7 +521,9 @@ def _gather_blex_ordering_info( # {{{ _create_blex_set_from_tuple_pair - def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): + # def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): + def _create_blex_set_from_tuple_pair( + before, after, _before, _after, wrap_cond=False): # TODO switch back """Given a before->after tuple pair in the key_lex_tuples, which may have dim vals described by ints, strings (inames), and pwaffs, create an ISL set in blex space that can be converted into @@ -496,6 +535,7 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # seq_blex_dim_names_prime) # Start with a set representing blex_order_map space + _blex_set = _blex_set_template.copy() # TODO remove blex_set = blex_set_template.copy() # Add marks to inames in the 'before' tuple @@ -505,10 +545,20 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): before_padded = _pad_tuple_with_zeros(before_prime, n_seq_blex_dims) after_padded = _pad_tuple_with_zeros(after, n_seq_blex_dims) + # TODO remove: + _before_prime = tuple( + v+BEFORE_MARK if isinstance(v, str) else v for v in _before) + _before_padded = _pad_tuple_with_zeros(_before_prime, n_seq_blex_dims) + _after_padded = _pad_tuple_with_zeros(_after, n_seq_blex_dims) + # Assign vals in the tuple to dims in the ISL set - for dim_name, dim_val in zip( + #for dim_name, dim_val in zip( + # seq_blex_dim_names_prime+seq_blex_dim_names, + # before_padded+after_padded): + for dim_name, dim_val, _dim_val in zip( # TODO remove seq_blex_dim_names_prime+seq_blex_dim_names, - before_padded+after_padded): + before_padded+after_padded, + _before_padded+_after_padded): if isinstance(dim_val, int): # Set idx to int val @@ -520,17 +570,57 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): blex_set_affs[iname_to_blex_var[dim_val]]) else: # This is a pwaff iname bound, align and intersect - assert isinstance(dim_val, isl.PwAff) - pwaff_aligned = isl.align_spaces(dim_val, blex_set_affs[0]) + assert isinstance(dim_val, isl.PwMultiAff) + if dim_val.n_piece() != 1: + raise NotImplementedError( + "lexmin_pw_multi_aff() of inames domain for %s and surrounding " + "loops has more than one piece.") + dim_val_pwaff = dim_val.get_pw_aff(0) + assert isinstance(dim_val_pwaff, isl.PwAff) + pwaff_aligned = isl.align_spaces(dim_val_pwaff, blex_set_affs[0]) # (doesn't matter which blex_set_affs item we align to^) blex_set &= blex_set_affs[dim_name].eq_set(pwaff_aligned) + # TODO LEFT OFF HERE: + # Problem: loop lexmin/max set in terms of inames but need + # to use corresponding blex dim names in blex map, + # rename set(/aff?) dims accordingly; + # ALSO TODO: don't put inames into blex params. + # dim_val_pwaff might have inames as params, and if it + # does, we also (earlier) added those inames to + # blex_set_affs. Blex map does not use inames for var names + # (uses corresponding lex dim names), and these parameters + # probably shouldn't be in the blex map. Figure out at what + # point it makes sense to remove these params. + # ALSO TODO see whether we should even be dealing with affs + # in the first place, we could have used lexmin/lexmax to + # get a set instead of a PwMultiAff and then delt with that + # differently? + + # TODO remove + if isinstance(_dim_val, int): + # Set idx to int val + _blex_set &= _blex_set_affs[dim_name].eq_set( + _blex_set_affs[0]+_dim_val) + elif isinstance(_dim_val, str): + # This is an iname, set idx to corresponding blex var + _blex_set &= _blex_set_affs[dim_name].eq_set( + _blex_set_affs[iname_to_blex_var[_dim_val]]) + else: + # This is a pwaff iname bound, align and intersect + assert isinstance(_dim_val, isl.PwAff) + _pwaff_aligned = isl.align_spaces(_dim_val, _blex_set_affs[0]) + # (doesn't matter which blex_set_affs item we align to^) + _blex_set &= _blex_set_affs[dim_name].eq_set(_pwaff_aligned) + if wrap_cond: # This is the BOTTOM->TOP pair, add condition i = i' + 1 + _blex_set &= _blex_set_affs[iname_to_blex_var[_iname]].eq_set( # TODO remove + _blex_set_affs[iname_to_blex_var[_iname+BEFORE_MARK]] + 1) blex_set &= blex_set_affs[iname_to_blex_var[iname]].eq_set( blex_set_affs[iname_to_blex_var[iname+BEFORE_MARK]] + 1) - return blex_set + return blex_set, _blex_set # }}} end _create_blex_set_from_tuple_pair() @@ -538,15 +628,44 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # (set will be converted to map) # Enter loop case: PRE->FIRST - full_blex_set = _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST]) + #full_blex_set = _create_blex_set_from_tuple_pair( + # key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST]) + full_blex_set, _full_blex_set = _create_blex_set_from_tuple_pair( # TODO remove + key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST], + _key_lex_tuples[slex.PRE], _key_lex_tuples[slex.FIRST]) + from loopy.schedule.checker.utils import prettier_map_string + print("PRE->FIRST") + print("full_blex_set before:") + print(prettier_map_string(_full_blex_set)) + print("full_blex_set new:") + print(prettier_map_string(full_blex_set)) # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) - full_blex_set |= _create_blex_set_from_tuple_pair( + #full_blex_set |= _create_blex_set_from_tuple_pair( + # key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], + # wrap_cond=True) + # TODO remove: + temp, _temp = _create_blex_set_from_tuple_pair( key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], + _key_lex_tuples[slex.BOTTOM], _key_lex_tuples[slex.TOP], wrap_cond=True) + _full_blex_set |= _temp + full_blex_set |= temp + # Leave loop case: LAST->POST - full_blex_set |= _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST]) + #full_blex_set |= _create_blex_set_from_tuple_pair( + # key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST]) + # TODO remove + temp, _temp = _create_blex_set_from_tuple_pair( + key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST], + _key_lex_tuples[slex.LAST], _key_lex_tuples[slex.POST], + ) + _full_blex_set |= _temp + full_blex_set |= temp + print("LAST->POST") + print("full_blex_set before:") + print(prettier_map_string(_temp)) + print("full_blex_set new:") + print(prettier_map_string(temp)) # Add condition to fix iteration value for *surrounding* loops (j = j') for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: @@ -554,15 +673,28 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): full_blex_set &= blex_set_affs[s_blex_var].eq_set( blex_set_affs[s_blex_var+BEFORE_MARK]) + # TODO remove: + for _surrounding_iname in _key_lex_tuples[slex.PRE][1::2]: + _s_blex_var = iname_to_blex_var[_surrounding_iname] + _full_blex_set &= _blex_set_affs[_s_blex_var].eq_set( + _blex_set_affs[_s_blex_var+BEFORE_MARK]) + # Convert blex set back to map map_to_subtract = isl.Map.from_domain(full_blex_set).move_dims( dim_type.out, 0, dim_type.in_, n_blex_dims, n_blex_dims) + # TODO remove: + _map_to_subtract = isl.Map.from_domain(_full_blex_set).move_dims( + dim_type.out, 0, dim_type.in_, n_blex_dims, n_blex_dims) + # }}} + # TODO no more comparison of old vs new after this point + maps_to_subtract.append(map_to_subtract) # }}} + 1/0 # {{{ Subtract transitive closure of union of blex maps to subtract @@ -585,6 +717,8 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # }}} + # }}} + return ( stmt_inst_to_blex, # map stmt instances to blex space blex_order_map, @@ -775,7 +909,8 @@ def get_pairwise_statement_orderings_inner( # }}} - loop_bounds[iname] = (dom.lexmin(), dom.lexmax()) + #loop_bounds[iname] = (dom.lexmin(), dom.lexmax()) + loop_bounds[iname] = (dom.lexmin_pw_multi_aff(), dom.lexmax_pw_multi_aff()) # }}} From 9783409e5d5b24397ef9d9c284cf03e46ae25a17 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 18 Aug 2021 19:37:28 -0500 Subject: [PATCH 144/220] create rename_dims function --- loopy/schedule/checker/utils.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 0f9877bac..dec63af59 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -84,6 +84,18 @@ def reorder_dims_by_name( return new_set +def rename_dims( + isl_set, rename_map, + dts=(dim_type.in_, dim_type.out, dim_type.param)): + new_isl_set = isl_set.copy() + for dt in dts: + for idx, old_name in enumerate(isl_set.get_var_names(dt)): + if old_name in rename_map: + new_isl_set = new_isl_set.set_dim_name( + dt, idx, rename_map[old_name]) + return new_isl_set + + def ensure_dim_names_match_and_align(obj_map, tgt_map): # first make sure names match From a35fd08de7e21cf08f99514a7b9c3b3027db0366 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 18 Aug 2021 19:38:59 -0500 Subject: [PATCH 145/220] just use lexmin instead of lexmin_pw_multi_aff when finding FIRST and LAST points for loop; deal with sets instead of pwaffs; once lexmin/max is found, remove inames from set params, rename them to corresponding blex vars, and align with blex map so they can be intersected --- loopy/schedule/checker/schedule.py | 52 ++++++++++++++++++------------ 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 13b94bc37..2b68285cd 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -233,6 +233,7 @@ def _gather_blex_ordering_info( blex ordering map defining the blex ordering for all statement pairs, rather than separate (smaller) lex ordering maps for each pair """ + # TODO just pass in loops_with_barriers for the appropriate sync kind from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.schedule.checker.lexicographic_order_map import ( create_lex_order_map, @@ -318,7 +319,7 @@ def _gather_blex_ordering_info( # Store any new params found _blex_order_map_params |= set(_lbound.get_var_names(dim_type.param)) # TODO remove - blex_order_map_params |= set(lbound.get_var_names(dim_type.param)) + blex_order_map_params |= set(lbound.get_var_names(dim_type.param)) # might include inames elif isinstance(lin_item, LeaveLoop): leave_iname = lin_item.iname @@ -427,7 +428,11 @@ def _gather_blex_ordering_info( pass _blex_order_map_params = sorted(_blex_order_map_params) # TODO remove - blex_order_map_params = sorted(blex_order_map_params) + #blex_order_map_params = sorted(blex_order_map_params) + # Don't want inames in blex map params, remove them + # TODO: could we have introduced inames other than loops_with_barriers? + blex_order_map_params = sorted(blex_order_map_params - loops_with_barriers[sync_kind]) + # At this point, some blex tuples may have more dimensions than others; # the missing dims are the fastest-updating dims, and their values should @@ -569,6 +574,7 @@ def _create_blex_set_from_tuple_pair( blex_set &= blex_set_affs[dim_name].eq_set( blex_set_affs[iname_to_blex_var[dim_val]]) else: + """ # This is a pwaff iname bound, align and intersect assert isinstance(dim_val, isl.PwMultiAff) if dim_val.n_piece() != 1: @@ -580,22 +586,27 @@ def _create_blex_set_from_tuple_pair( pwaff_aligned = isl.align_spaces(dim_val_pwaff, blex_set_affs[0]) # (doesn't matter which blex_set_affs item we align to^) blex_set &= blex_set_affs[dim_name].eq_set(pwaff_aligned) - - # TODO LEFT OFF HERE: - # Problem: loop lexmin/max set in terms of inames but need - # to use corresponding blex dim names in blex map, - # rename set(/aff?) dims accordingly; - # ALSO TODO: don't put inames into blex params. - # dim_val_pwaff might have inames as params, and if it - # does, we also (earlier) added those inames to - # blex_set_affs. Blex map does not use inames for var names - # (uses corresponding lex dim names), and these parameters - # probably shouldn't be in the blex map. Figure out at what - # point it makes sense to remove these params. - # ALSO TODO see whether we should even be dealing with affs - # in the first place, we could have used lexmin/lexmax to - # get a set instead of a PwMultiAff and then delt with that - # differently? + """ + # TODO figure out best place to do this: + # Rename dims and align dim_val so it can intersect w/blex_set + + # There might be inames as params in dim_val, move them to set dim + dim_val_pre_aligned = dim_val.copy() # maybe we can remove this copy + for var_name in dim_val_pre_aligned.get_var_names(dim_type.param): + if var_name in iname_to_blex_var: + idx = dim_val_pre_aligned.find_dim_by_name( + dim_type.param, var_name) # (might have moved since loop start) + dim_val_pre_aligned = dim_val_pre_aligned.move_dims( + dim_type.out, 0, dim_type.param, idx, 1) + + # Rename inames to corresponding blex var names + # TODO does this catch all potential inames? + from loopy.schedule.checker.utils import rename_dims + dim_val_renamed = rename_dims( + dim_val_pre_aligned, iname_to_blex_var, [dim_type.set]) + + dim_val_aligned = isl.align_spaces(dim_val_renamed, blex_set_template) + blex_set &= dim_val_aligned # TODO remove if isinstance(_dim_val, int): @@ -694,7 +705,6 @@ def _create_blex_set_from_tuple_pair( maps_to_subtract.append(map_to_subtract) # }}} - 1/0 # {{{ Subtract transitive closure of union of blex maps to subtract @@ -909,8 +919,8 @@ def get_pairwise_statement_orderings_inner( # }}} - #loop_bounds[iname] = (dom.lexmin(), dom.lexmax()) - loop_bounds[iname] = (dom.lexmin_pw_multi_aff(), dom.lexmax_pw_multi_aff()) + loop_bounds[iname] = (dom.lexmin(), dom.lexmax()) + #loop_bounds[iname] = (dom.lexmin_pw_multi_aff(), dom.lexmax_pw_multi_aff()) # }}} From b558496bcbad7b714c8cca0b7484918d81116165 Mon Sep 17 00:00:00 2001 From: Alexandru Fikl Date: Thu, 19 Aug 2021 10:45:56 -0500 Subject: [PATCH 146/220] add failing test for real inputs --- test/test_expression.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/test_expression.py b/test/test_expression.py index 91c4dcc0e..7b81f6360 100644 --- a/test/test_expression.py +++ b/test/test_expression.py @@ -548,6 +548,25 @@ def test_complex_support(ctx_factory, target): (0.5*n*(n-1) - 0.5*n*(n-1)*1j) ** 2) +@pytest.mark.parametrize("dtype", [np.float32, np.float64]) +def test_real_with_real_argument(ctx_factory, dtype): + ctx = ctx_factory() + queue = cl.CommandQueue(ctx) + + knl = lp.make_kernel( + "{[i]: 0 <= i < nresult}", + "result[i] = real(ary[i])", + ) + + rng = np.random.default_rng() + ary = cl.array.to_device(queue, rng.random(128).astype(dtype)) + + _, (result,) = knl(queue, ary=ary) + + assert result.dtype == ary.dtype + np.testing.assert_allclose(result.get(), np.real(ary.get())) + + def test_bool_type_context(ctx_factory): # Checks if a boolean type context is correctly handled in codegen phase. # See https://github.com/inducer/loopy/pull/258 From c33406c9098879737bf476380b7e1c53c7c87c78 Mon Sep 17 00:00:00 2001 From: Alexandru Fikl Date: Thu, 19 Aug 2021 14:22:03 -0500 Subject: [PATCH 147/220] add support for real/imag with real arguments to pyopencl target --- loopy/target/pyopencl.py | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/loopy/target/pyopencl.py b/loopy/target/pyopencl.py index afd457dbe..d54730e9c 100644 --- a/loopy/target/pyopencl.py +++ b/loopy/target/pyopencl.py @@ -51,7 +51,7 @@ def with_types(self, arg_id_to_dtype, callables_table): for id in arg_id_to_dtype: # since all the below functions are single arg. if not -1 <= id <= 0: - raise LoopyError("%s can only take one argument." % name) + raise LoopyError(f"{name} can only take one argument") if 0 not in arg_id_to_dtype or arg_id_to_dtype[0] is None: # the types provided aren't mature enough to specialize the @@ -69,7 +69,7 @@ def with_types(self, arg_id_to_dtype, callables_table): elif dtype.numpy_dtype == np.complex128: tpname = "cdouble" else: - raise LoopyTypeError("unexpected complex type '%s'" % dtype) + raise LoopyTypeError(f"unexpected complex type '{dtype}'") return ( self.copy(name_in_target=f"{tpname}_{name}", @@ -77,6 +77,15 @@ def with_types(self, arg_id_to_dtype, callables_table): np.dtype(dtype.numpy_dtype.type(0).real))}), callables_table) + if name in ["real", "imag"]: + if not dtype.is_complex(): + tpname = dtype.numpy_dtype.type.__name__ + return ( + self.copy( + name_in_target=f"lpy_{name}_{tpname}", + arg_id_to_dtype={0: dtype, -1: dtype}), + callables_table) + if name in ["sqrt", "exp", "log", "sin", "cos", "tan", "sinh", "cosh", "tanh", @@ -110,6 +119,23 @@ def with_types(self, arg_id_to_dtype, callables_table): self.copy(arg_id_to_dtype=arg_id_to_dtype), callables_table) + def generate_preambles(self, target): + name = self.name_in_target + if name.startswith("lpy_real") or name.startswith("lpy_imag"): + if name.startswith("lpy_real"): + ret = "x" + else: + ret = "0" + + dtype = self.arg_id_to_dtype[-1] + ctype = target.dtype_to_typename(dtype) + + yield(f"40_{name}", f""" + static inline {ctype} {name}({ctype} x) {{ + return {ret}; + }} + """) + def get_pyopencl_callables(): pyopencl_ids = ["sqrt", "exp", "log", "sin", "cos", "tan", "sinh", "cosh", From 73098bbbefb82b631f07a30f1411208c579b01c6 Mon Sep 17 00:00:00 2001 From: Kaushik Kulkarni Date: Mon, 23 Aug 2021 18:48:48 -0500 Subject: [PATCH 148/220] [pyopencl target]: fix host code for zero-strided outputs --- loopy/target/pyopencl_execution.py | 2 +- test/test_loopy.py | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/loopy/target/pyopencl_execution.py b/loopy/target/pyopencl_execution.py index 1b90add01..87e13faa2 100644 --- a/loopy/target/pyopencl_execution.py +++ b/loopy/target/pyopencl_execution.py @@ -101,7 +101,7 @@ def handle_alloc(self, gen, arg, kernel_arg, strify, skip_arg_checks): if not skip_arg_checks: for i in range(num_axes): - gen("assert _lpy_ustrides_%d > 0, " + gen("assert _lpy_ustrides_%d >= 0, " "\"'%s' has negative stride in axis %d\"" % (i, arg.name, i)) diff --git a/test/test_loopy.py b/test/test_loopy.py index 7f7644f9a..2bd6fb874 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -3216,6 +3216,21 @@ def test_get_return_from_kernel_mapping(): assert ret_from_knl_idx[9] == 10 +def test_zero_stride_array(ctx_factory): + ctx = ctx_factory() + cq = cl.CommandQueue(ctx) + + knl = lp.make_kernel( + ["{[i]: 0<=i<10}", + "{[j]: 1=0}"], + """ + y[i, j] = 1 + """, [lp.GlobalArg("y", shape=(10, 0))]) + + evt, (out,) = knl(cq) + assert out.shape == (10, 0) + + if __name__ == "__main__": if len(sys.argv) > 1: exec(sys.argv[1]) From 3a1778df190649df67bc754c651935b091f7396e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 24 Aug 2021 20:37:33 -0500 Subject: [PATCH 149/220] add isl helper function add_int_bounds_to_isl_var() --- loopy/schedule/checker/utils.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 0f9877bac..41d3ed89b 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -107,6 +107,17 @@ def add_eq_isl_constraint_from_names(isl_map, var1, var2): {1: 0, var1: 1, var2: -1})) +def add_int_bounds_to_isl_var(isl_map, var, lbound, ubound): + # NOTE: these are inclusive bounds + # add constraint var1 = var2 + return isl_map.add_constraint( + isl.Constraint.ineq_from_names( + isl_map.space, {1: -1*lbound, var: 1}) + ).add_constraint( + isl.Constraint.ineq_from_names( + isl_map.space, {1: ubound, var: -1})) + + def append_mark_to_isl_map_var_names(old_isl_map, dt, mark): """Return an :class:`islpy.Map` with a mark appended to the specified dimension names. From be9b9bba0877c48a8b1c56674699309ed22f0952 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 24 Aug 2021 20:40:20 -0500 Subject: [PATCH 150/220] (WIP) working on bounding blex dims and determining whether blex map is transitive; also moved the step where we add the dims representing concurrent inames to the blex map to *after* the subtraction step --- loopy/schedule/checker/schedule.py | 133 +++++++++++++++++++++++++---- 1 file changed, 115 insertions(+), 18 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index fd0b1a6aa..38fcadd85 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -22,6 +22,7 @@ import islpy as isl from dataclasses import dataclass +from loopy.schedule.checker.utils import prettier_map_string # noqa dim_type = isl.dim_type @@ -65,7 +66,8 @@ """ -LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" +#LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" +LIN_CHECK_IDENTIFIER_PREFIX = "__" # TODO change back after debug LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) LTAG_VAR_NAMES = [] @@ -259,6 +261,10 @@ def _gather_blex_ordering_info( n_seq_blex_dims = 1 # Num dims representing sequential order in blex space next_blex_tuple = [0] # Next tuple of points in blex order + known_blex_dim_ubounds = [0, ] # Place to store bounds for non-iname blex dims + # TODO handle case where one non-iname blex dim is used in multiple + # separate loops? + for lin_item in lin_items: if isinstance(lin_item, EnterLoop): enter_iname = lin_item.iname @@ -274,6 +280,8 @@ def _gather_blex_ordering_info( # code within new loop next_blex_tuple.append(enter_iname) next_blex_tuple.append(0) + known_blex_dim_ubounds.append(None) + known_blex_dim_ubounds.append(0) # Store 3 tuples that will be used later to create pairs # that will later be subtracted from the blex order map @@ -295,11 +303,17 @@ def _gather_blex_ordering_info( leave_iname = lin_item.iname if leave_iname in loops_with_barriers[sync_kind] - loops_to_ignore: + curr_blex_dim_ct = len(next_blex_tuple) + # Update max blex dims - n_seq_blex_dims = max(n_seq_blex_dims, len(next_blex_tuple)) + n_seq_blex_dims = max(n_seq_blex_dims, curr_blex_dim_ct) # Record the blex dim for this loop iname - iname_to_blex_dim[leave_iname] = len(next_blex_tuple)-2 + iname_to_blex_dim[leave_iname] = curr_blex_dim_ct-2 + + # Record the max value for the non-iname blex dim + known_blex_dim_ubounds[curr_blex_dim_ct-1] = max( + next_blex_tuple[-1], known_blex_dim_ubounds[curr_blex_dim_ct-1]) # Update next blex pt pre_end_loop_blex_pt = next_blex_tuple[:] @@ -371,6 +385,10 @@ def _gather_blex_ordering_info( lin_item, (CallKernel, ReturnFromKernel)) pass + # Record the max value for the 0th non-iname blex dim + known_blex_dim_ubounds[0] = max( + next_blex_tuple[-1], known_blex_dim_ubounds[0]) + blex_order_map_params = sorted(blex_order_map_params) # At this point, some blex tuples may have more dimensions than others; @@ -397,24 +415,26 @@ def _gather_blex_ordering_info( in_dim_mark=BEFORE_MARK, ) - # Add LID/GID dims to blex order map - blex_order_map = add_and_name_isl_dims( - blex_order_map, dim_type.out, all_par_lex_dim_names) - blex_order_map = add_and_name_isl_dims( - blex_order_map, dim_type.in_, - append_mark_to_strings(all_par_lex_dim_names, mark=BEFORE_MARK)) - if sync_kind == "local": - # For intra-group case, constrain GID 'before' to equal GID 'after' - for var_name in gid_lex_dim_names: - blex_order_map = add_eq_isl_constraint_from_names( - blex_order_map, var_name, var_name+BEFORE_MARK) - # (if sync_kind == "global", don't need constraints on LID/GID vars) + # Bound the non-iname blex variables + from loopy.schedule.checker.utils import add_int_bounds_to_isl_var + for idx in range(0, len(seq_blex_dim_names), 2): + #print(prettier_map_string(blex_order_map)) + blex_order_map = add_int_bounds_to_isl_var( + blex_order_map, seq_blex_dim_names[idx], 0, known_blex_dim_ubounds[idx]) + #print(prettier_map_string(blex_order_map)) + blex_order_map = add_int_bounds_to_isl_var( + blex_order_map, seq_blex_dim_names_prime[idx], 0, known_blex_dim_ubounds[idx]) + #print(prettier_map_string(blex_order_map)) + # TODO do prime bounds need to be shifted 1 from non-primes? + + # Bound the iname blex variables + # TODO # }}} # {{{ Subtract unwanted pairs from happens-before blex map - # Create map from iname to corresponding blex dim name + # Create mapping (dict) from iname to corresponding blex dim name iname_to_blex_var = {} for iname, dim in iname_to_blex_dim.items(): iname_to_blex_var[iname] = seq_blex_dim_names[dim] @@ -425,7 +445,7 @@ def _gather_blex_ordering_info( blex_order_map, dim_type.param, blex_order_map_params) # Get a set representing blex_order_map space - n_blex_dims = n_seq_blex_dims + len(all_par_lex_dim_names) + n_blex_dims = n_seq_blex_dims blex_set_template = isl.align_spaces( isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map ).move_dims( @@ -438,7 +458,7 @@ def _gather_blex_ordering_info( maps_to_subtract = [] for iname, key_lex_tuples in blex_exclusion_info.items(): - # {{{ Create blex map to subract for one iname + # {{{ Create blex map to subtract for one iname """Create the blex->blex pairs that must be subtracted from the initial blex order map for this particular loop using the 6 blex @@ -525,6 +545,12 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): map_to_subtract = isl.Map.from_domain(full_blex_set).move_dims( dim_type.out, 0, dim_type.in_, n_blex_dims, n_blex_dims) + # Bound the blex dims by intersecting with the full blex map, which + # contains all the bound constraints + pu.db + assert map_to_subtract.is_subset(blex_order_map) + map_to_subtract &= blex_order_map + # }}} maps_to_subtract.append(map_to_subtract) @@ -540,16 +566,87 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): for other_map in maps_to_subtract[1:]: map_to_subtract |= other_map + """ + print(blex_order_map.space) + print(map_to_subtract.space) + #print(blex_order_map - map_to_subtract) + assert map_to_subtract.is_subset(blex_order_map) # TODO why not subset? + """ + # Get transitive closure of maps map_to_subtract_closure, closure_exact = map_to_subtract.transitive_closure() assert closure_exact # TODO warn instead? + #""" + # {{{ Check some assumptions related to result of subtraction being transitive + from copy import deepcopy + + # Make sure blex order map is transitive + closure_test = deepcopy(blex_order_map) + closure_test, closure_exact = closure_test.transitive_closure() + assert closure_exact + print("IS FULL BLEX MAP TRANSITIVE?") + assert closure_test == blex_order_map + print("yes") + + closure_test = deepcopy(map_to_subtract_closure) + closure_test, closure_exact = closure_test.transitive_closure() + assert closure_exact + print("IS SUBTRACTION MAP TRANSITIVE?") + assert closure_test == map_to_subtract_closure + print("yes") + + assert map_to_subtract.is_subset(blex_order_map) + print("IS SUBTRACTION MAP A SUBSET OF FULL BLEX ORDER MAP?") + assert map_to_subtract_closure.is_subset(blex_order_map) + print("yes") + # }}} + + #""" + + print("blex_order_map FULL") + print(prettier_map_string(blex_order_map)) + #print(blex_order_map) + # Subtract closure from blex order map blex_order_map = blex_order_map - map_to_subtract_closure + #""" + # TODO check if map_to_subtract/map_to_subtract_closure is indeed subset of blex_order_map + print("subtraction map for %s barriers" % (sync_kind)) + print(prettier_map_string(map_to_subtract_closure)) + #print(map_to_subtract_closure) + print("blex_order_map FINAL = blex_order_map FULL - map_to_subtract_closure") + print(prettier_map_string(blex_order_map)) + closure_test = deepcopy(blex_order_map) + closure_test, closure_exact = closure_test.transitive_closure() + + print("closure(blex_order_map FINAL)") + print(prettier_map_string(closure_test)) + + + assert closure_exact # passes + print("IS RESULT OF SUBTRACTION TRANSITIVE?") + assert closure_test == blex_order_map + print("yes") + #""" + # }}} + # Add LID/GID dims to blex order map + blex_order_map = add_and_name_isl_dims( + blex_order_map, dim_type.out, all_par_lex_dim_names) + blex_order_map = add_and_name_isl_dims( + blex_order_map, dim_type.in_, + append_mark_to_strings(all_par_lex_dim_names, mark=BEFORE_MARK)) + if sync_kind == "local": + # For intra-group case, constrain GID 'before' to equal GID 'after' + for var_name in gid_lex_dim_names: + blex_order_map = add_eq_isl_constraint_from_names( + blex_order_map, var_name, var_name+BEFORE_MARK) + # (if sync_kind == "global", don't need constraints on LID/GID vars) + # }}} return ( From 1978a719a8277cb0e202c5df502300da1dfd34d0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 27 Aug 2021 08:41:29 -0500 Subject: [PATCH 151/220] remove redundant import --- loopy/schedule/checker/schedule.py | 1 - 1 file changed, 1 deletion(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 420559cc7..0e6939918 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -663,7 +663,6 @@ def _create_blex_set_from_tuple_pair( full_blex_set, _full_blex_set = _create_blex_set_from_tuple_pair( # TODO remove key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST], _key_lex_tuples[slex.PRE], _key_lex_tuples[slex.FIRST]) - from loopy.schedule.checker.utils import prettier_map_string print("PRE->FIRST") print("full_blex_set before:") print(prettier_map_string(_full_blex_set)) From ab6076ad00bdea35a0d7a2935bdd299dc120df70 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 27 Aug 2021 09:37:56 -0500 Subject: [PATCH 152/220] clean up code for map_domain; clarify error message a bit --- loopy/transform/iname.py | 54 +++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 0c6b27f1e..bdc94d8d5 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2059,7 +2059,7 @@ def map_domain(kernel, transform_map): # }}} - # {{{ solve for representation of old inames in terms of new + # {{{ Solve for representation of old inames in terms of new substitutions = {} var_substitutions = {} @@ -2078,13 +2078,13 @@ def map_domain(kernel, transform_map): # }}} + # {{{ Function for applying mapping to one set + def process_set(s): """Return the transformed set. Assume that map is applicable to this set.""" - # {{{ align dims of transform_map and s - - from islpy import _align_dim_type + # {{{ Align dims of transform_map and s so that map can be applied map_with_s_domain = isl.Map.from_domain(s) @@ -2117,6 +2117,8 @@ def process_set(s): # _align_dim_type just converts these to sets # to determine which names are in both the obj and template, # not sure why this isn't just handled inside _align_dim_type) + + from islpy import _align_dim_type aligned_map = _align_dim_type( dim_type.param, augmented_transform_map, map_with_s_domain, False, @@ -2139,6 +2141,8 @@ def process_set(s): # FIXME: Revive _project_out_only_if_all_instructions_in_within + # }}} + # {{{ Apply the transform map to exactly one domain map_applied_to_one_dom = False @@ -2155,8 +2159,8 @@ def process_set(s): if not transform_map_in_dims.issubset( frozenset(old_domain.get_var_dict())): - # Map transforms inames that are not all present in the set. - # Don't transform. + # Map not applicable to this set because map transforms at least + # one iname that is not present in the set. Don't transform. new_domains.append(old_domain) continue @@ -2175,7 +2179,8 @@ def process_set(s): new_domains.append(process_set(old_domain)) map_applied_to_one_dom = True - # If the map could not be applied to any domain, error. + # If we get this far, either the map has been applied to 1 domain (good) + # or the map could not be applied to any domain, which should produce an error. if not map_applied_to_one_dom: raise LoopyError( "Transform map %s was not applicable to any domain. %s" @@ -2183,31 +2188,40 @@ def process_set(s): # }}} - # {{{ update within_inames + # {{{ Update within_inames for each statement - new_insns = [] - for insn in kernel.instructions: - overlap = transform_map_in_dims & insn.within_inames + # If we get this far, we know that the map was applied to exactly one domain, + # and that all the inames in transform_map_in_dims were transformed to + # inames in transform_map_out_dims. However, it's still possible that for some + # statements, stmt.within_inames will contain at least one but not all of the + # transformed inames (transform_map_in_dims). + # In this case, it's not clear what within_inames should be. Therefore, we + # require that if any transformed inames are found in stmt.within_inames, + # ALL transformed inames must be found in stmt.within_inames. + + new_stmts = [] + for stmt in kernel.instructions: + overlap = transform_map_in_dims & stmt.within_inames if overlap: if len(overlap) != len(transform_map_in_dims): - raise LoopyError("instruction '%s' is within only a part " - "of the map domain inames. Instructions must " - "either be within all or none of the map domain " - "inames." % insn.id) + raise LoopyError("Statement '%s' is within only a part " + "of the mapped inames in transformation map %s. " + "Statements must be within all or none of the mapped " + "inames." % (stmt.id, transform_map)) - insn = insn.copy(within_inames=( - insn.within_inames - transform_map_in_dims) | transform_map_out_dims) + stmt = stmt.copy(within_inames=( + stmt.within_inames - transform_map_in_dims) | transform_map_out_dims) else: - # leave insn unmodified + # Leave stmt unmodified pass - new_insns.append(insn) + new_stmts.append(stmt) # }}} kernel = kernel.copy( domains=new_domains, - instructions=new_insns, + instructions=new_stmts, applied_iname_rewrites=applied_iname_rewrites) rule_mapping_context = SubstitutionRuleMappingContext( From d710f8d3918d60debbd6c62bb8ac4776603bf762 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 27 Aug 2021 09:38:31 -0500 Subject: [PATCH 153/220] add map_domain test for handling of case where stmt.within_inames contains some but not all mapped inames --- test/test_transform.py | 46 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/test/test_transform.py b/test/test_transform.py index 516d676c3..152f8b5de 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -858,6 +858,52 @@ def test_map_domain_transform_map_validity_and_errors(): # }}} + # {{{ Make sure we error when stmt.within_inames contains at least one but + # not all mapped inames + + # {{{ Make kernel + + knl = lp.make_kernel( + [ + "[n, m] -> { [i, j]: 0 <= i < n and 0 <= j < m }", + "[ell] -> { [k]: 0 <= k < ell }", + ], + """ + for i + <>t0 = i {id=stmt0} + for j + <>t1 = j {id=stmt1, dep=stmt0} + end + <>t2 = i + 1 {id=stmt2, dep=stmt1} + end + for k + <>t3 = k {id=stmt3, dep=stmt2} + end + """, + lang_version=(2018, 2), + ) + + # }}} + + # This should fail: + try: + transform_map = isl.BasicMap( + "[n, m] -> {[i, j] -> [i_new, j_new]: " + "i_new = i + j and j_new = 2 + i }") + knl = lp.map_domain(knl, transform_map) + raise AssertionError() + except LoopyError as err: + assert ( + "Statements must be within all or none of the mapped inames" + in str(err)) + + # This should succeed: + transform_map = isl.BasicMap( + "[n, m] -> {[i] -> [i_new]: i_new = i + 2 }") + knl = lp.map_domain(knl, transform_map) + + # }}} + # }}} From 48e2c9a632c72edf4c8122aa434e7b85d5a4742a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 27 Aug 2021 09:48:24 -0500 Subject: [PATCH 154/220] clarify comment in map_domain --- loopy/transform/iname.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index bdc94d8d5..1fca57fbc 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2090,11 +2090,12 @@ def process_set(s): # If there are dims in s that are not mapped by transform_map, add them # to the in/out space of transform_map so that they remain unchanged. - # (temporary proxy dim names are needed in out space of transform - # map because isl won't allow any dim names to match, i.e., instead - # of just mapping {[unused_iname]->[unused_iname]}, we have to map + # We cannot just map {[unused_iname]->[unused_iname]} because isl won't + # allow any dim names to match, so temporary proxy dim names are needed + # in out space of transform map. I.e., we apply mapping # {[unused_name]->[unused_name__prox] : unused_name__prox = unused_name}, - # and then rename unused_name__prox afterward.) + # and then rename unused_name__prox afterward. + augmented_transform_map, proxy_name_pairs = \ _apply_identity_for_missing_map_dims( transform_map, s.get_var_names(dim_type.set)) From 6e7951a47a033ab24a4f19f6ffabe8b88421c352 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 28 Aug 2021 15:04:24 -0500 Subject: [PATCH 155/220] remove fixme --- test/test_transform.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_transform.py b/test/test_transform.py index 152f8b5de..86b7738a0 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -920,7 +920,6 @@ def test_diamond_tiling(ctx_factory, interactive=False): - u[ix, it]) """) - # FIXME: Handle priorities in map_domain knl_for_transform = ref_knl ref_knl = lp.prioritize_loops(ref_knl, "it, ix") From 061a8ecc8ec34747a7eca22ec51374337ef7bf36 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 28 Aug 2021 15:48:34 -0500 Subject: [PATCH 156/220] clean up and document _apply_identity_for_missing_map_dims --- loopy/transform/iname.py | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 1fca57fbc..0cffb6edd 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -1970,23 +1970,35 @@ def _find_and_rename_dim(old_map, dim_types, old_name, new_name): def _apply_identity_for_missing_map_dims(mapping, desired_dims): + """For every variable v in *desired_dims* that is not found in the + input space for *mapping*, add input dimension v, output dimension + v_'proxy'_, and constraint v = v_'proxy'_ to the mapping. Also return a + list of the (v, v_'proxy'_) pairs. + """ + + # If the transform map in map_domain (below) does not contain all the + # inames in the iname domain (set) to which it is applied, the missing + # inames must be added to the transform map so that intersect_domain() + # doesn't remove them from the iname domain when the map is applied. + + # No two map dimension names can match, so we create a unique name for each + # new variable in the output dimension by appending _'proxy'_, and return a + # list of the (v, v_'proxy'_) pairs so that the proxy dims can be + # identified and replaced later. - # If dims in s are missing from transform map, they need to be added - # so that, e.g, intersect_domain doesn't remove them. - # (assume ordering will be handled afterward) + # (Apostrophes are not allowed in inames, so this suffix + # will not match any existing inames. This function is also used on + # dependency maps, which may contain variable names consisting of an iname + # suffixed with a single apostrophe.) + + # {{{ Find any missing vars and add them to the input and output space missing_dims = list( set(desired_dims) - set(mapping.get_var_names(dim_type.in_))) augmented_mapping = _add_and_name_isl_dims( mapping, dim_type.in_, missing_dims) - # We want these missing inames to map to themselves so that the map - # has no effect on them. Unfortunatley isl will break if the - # names of the out dims aren't unique, so we will temporariliy rename them - # (and then plan to change the names back afterward). - - # FIXME: need better way to make sure proxy dim names are unique within map - missing_dims_proxies = [d+"__prox" for d in missing_dims] + missing_dims_proxies = [d+"_'prox'_" for d in missing_dims] assert not set(missing_dims_proxies) & set( augmented_mapping.get_var_dict().keys()) @@ -1995,11 +2007,16 @@ def _apply_identity_for_missing_map_dims(mapping, desired_dims): proxy_name_pairs = list(zip(missing_dims, missing_dims_proxies)) - # Set proxy iname equal to real iname with equality constraint + # }}} + + # {{{ Add identity constraint (v = v_'proxy'_) for each new pair of dims + for real_iname, proxy_iname in proxy_name_pairs: augmented_mapping = _add_eq_isl_constraint_from_names( augmented_mapping, proxy_iname, real_iname) + # }}} + return augmented_mapping, proxy_name_pairs From fc0e265c79d55a3db175edaa3b649db2ac302ad4 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 28 Aug 2021 15:51:32 -0500 Subject: [PATCH 157/220] document _error_if_any_iname_in_constraint --- loopy/transform/iname.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 0cffb6edd..b83543b40 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2021,8 +2021,13 @@ def _apply_identity_for_missing_map_dims(mapping, desired_dims): def _error_if_any_iname_in_constraint( - inames, nest_constraints, - constraint_descriptor_str): + inames, nest_constraints, constraint_descriptor_str): + """Raise informative error if any iname in *inames* is constrained by any + nest constraint in *nest_constraints*. + """ + # (This function is only used when new machinery from + # new-loop-nest-constraints branch is detected.) + for constraint in nest_constraints: for tier in constraint: for iname in inames: From aee9c8313b7f6bd347e42b8b3d0f17083d285742 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 28 Aug 2021 15:57:18 -0500 Subject: [PATCH 158/220] minor changes to error messages in _MapDomainMapper and _find_aff_subst_from_map --- loopy/transform/iname.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index b83543b40..848d5d74a 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -1850,7 +1850,7 @@ def map_reduction(self, expr, expn_state): arg_ctx_overlap = frozenset(expn_state.arg_context) & self.old_inames if red_overlap: if len(red_overlap) != len(self.old_inames): - raise LoopyError("reduction '%s' involves a part " + raise LoopyError("Reduction '%s' involves a part " "of the map domain inames. Reductions must " "either involve all or none of the map domain " "inames." % str(expr)) @@ -1861,7 +1861,7 @@ def map_reduction(self, expr, expn_state): return super(_MapDomainMapper, self).map_reduction( expr, expn_state) else: - raise LoopyError("reduction '%s' has" + raise LoopyError("Reduction '%s' has" "some of the reduction variables affected " "by the map_domain shadowed by context. " "Either all or none must be shadowed." @@ -1928,7 +1928,7 @@ def _find_aff_subst_from_map(iname, isl_map): # not suitable, coefficient does not have unit coefficient continue - raise LoopyError("no suitable equation for '%s' found" % iname) + raise LoopyError("No suitable equation for '%s' found" % iname) def _add_and_name_isl_dims(isl_map, dt, names): From 468819d7e792e4160ac2527135b3d0f6ea510b1e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 28 Aug 2021 16:02:52 -0500 Subject: [PATCH 159/220] vim fold markers for map_domain and associated functions --- loopy/transform/iname.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 848d5d74a..78db2ded5 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -1834,7 +1834,9 @@ def add_inames_to_insn(kernel, inames, insn_match): # }}} -# {{{ map_domain +# {{{ map_domain and associated functions + +# {{{ _MapDomainMapper class _MapDomainMapper(RuleAwareIdentityMapper): def __init__(self, rule_mapping_context, new_inames, substitutions): @@ -1886,6 +1888,10 @@ def map_variable(self, expr, expn_state): else: return super(_MapDomainMapper, self).map_variable(expr, expn_state) +# }}} + + +# {{{ _find_aff_subst_from_map(iname, isl_map) def _find_aff_subst_from_map(iname, isl_map): if not isinstance(isl_map, isl.BasicMap): @@ -1930,6 +1936,10 @@ def _find_aff_subst_from_map(iname, isl_map): raise LoopyError("No suitable equation for '%s' found" % iname) +# }}} + + +# {{{ ISL map wrangling helper functions def _add_and_name_isl_dims(isl_map, dt, names): # (This function is also defined in independent, unmerged branch @@ -1968,6 +1978,10 @@ def _find_and_rename_dim(old_map, dim_types, old_name, new_name): dt, new_map.find_dim_by_name(dt, old_name), new_name) return new_map +# }}} + + +# {{{ _apply_identity_for_missing_map_dims(mapping, desired_dims) def _apply_identity_for_missing_map_dims(mapping, desired_dims): """For every variable v in *desired_dims* that is not found in the @@ -2019,6 +2033,10 @@ def _apply_identity_for_missing_map_dims(mapping, desired_dims): return augmented_mapping, proxy_name_pairs +# }}} + + +# {{{ _error_if_any_iname_in_constraint def _error_if_any_iname_in_constraint( inames, nest_constraints, constraint_descriptor_str): @@ -2037,6 +2055,10 @@ def _error_if_any_iname_in_constraint( "transformed by map in map_domain." % (constraint_descriptor_str, constraint)) +# }}} + + +# {{{ map_domain @for_each_kernel def map_domain(kernel, transform_map): @@ -2259,6 +2281,8 @@ def process_set(s): # }}} +# }}} + @for_each_kernel def add_inames_for_unused_hw_axes(kernel, within=None): From 1073f994a9d628a71b360ab67c644fc40d3c2738 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 28 Aug 2021 16:24:54 -0500 Subject: [PATCH 160/220] final cleanup of map_domain functions --- loopy/transform/iname.py | 46 +++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 78db2ded5..59b534f2d 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2087,6 +2087,8 @@ def map_domain(kernel, transform_map): # {{{ Make sure that none of the mapped inames are involved in loop priorities + # kernel.loop_priority is being replaced with kernel.loop_nest_constraints, + # handle both attributes. if hasattr(kernel, "loop_priority") and kernel.loop_priority: for prio in kernel.loop_priority: if set(prio) & transform_map_in_dims: @@ -2122,7 +2124,7 @@ def map_domain(kernel, transform_map): # }}} - # {{{ Function for applying mapping to one set + # {{{ Function to apply mapping to one set def process_set(s): """Return the transformed set. Assume that map is applicable to this @@ -2130,38 +2132,41 @@ def process_set(s): # {{{ Align dims of transform_map and s so that map can be applied + # Create a map whose input space matches the set map_with_s_domain = isl.Map.from_domain(s) - # If there are dims in s that are not mapped by transform_map, add them - # to the in/out space of transform_map so that they remain unchanged. - # We cannot just map {[unused_iname]->[unused_iname]} because isl won't - # allow any dim names to match, so temporary proxy dim names are needed - # in out space of transform map. I.e., we apply mapping - # {[unused_name]->[unused_name__prox] : unused_name__prox = unused_name}, - # and then rename unused_name__prox afterward. + # {{{ Check for missing map dims and add them + + # For every iname v in the domain that is *not* found in the input + # space of the transform map, add input dimension v, output dimension + # v_'proxy'_, and constraint v = v_'proxy'_ to the transform map. + # Otherwise, v will be dropped from the domain when the map is applied. augmented_transform_map, proxy_name_pairs = \ _apply_identity_for_missing_map_dims( transform_map, s.get_var_names(dim_type.set)) - # FIXME: Make this less gross + # }}} + + # {{{ Align transform map input dims with set dims + # FIXME: Make an exported/documented interface of this in islpy + dim_types = [dim_type.param, dim_type.in_, dim_type.out] - s_names = [ + # Variables found in iname domain set + s_names = { map_with_s_domain.get_dim_name(dt, i) for dt in dim_types for i in range(map_with_s_domain.dim(dt)) - ] - map_names = [ + } + # Variables found in transform map + map_names = { augmented_transform_map.get_dim_name(dt, i) for dt in dim_types for i in range(augmented_transform_map.dim(dt)) - ] - - # (order doesn't matter in s_names/map_names, - # _align_dim_type just converts these to sets - # to determine which names are in both the obj and template, - # not sure why this isn't just handled inside _align_dim_type) + } + # (_align_dim_type uses these two sets to determine which names are in + # both the obj and template) from islpy import _align_dim_type aligned_map = _align_dim_type( @@ -2175,9 +2180,12 @@ def process_set(s): # }}} + # }}} + + # Apply the transform map to the domain new_s = aligned_map.intersect_domain(s).range() - # Now rename the proxy dims back to their original names + # Now rename any proxy dims back to their original names for real_iname, proxy_iname in proxy_name_pairs: new_s = _find_and_rename_dim( new_s, [dim_type.set], proxy_iname, real_iname) From e2ff759f0e7048ff207bcc9b20aec7a308d48637 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 16:46:31 -0500 Subject: [PATCH 161/220] Update loopy/transform/iname.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit update arg without copy in _find_and_rename_dim Co-authored-by: Andreas Klöckner --- loopy/transform/iname.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 59b534f2d..c8fcdcb32 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -1969,14 +1969,13 @@ def _add_eq_isl_constraint_from_names(isl_map, var1, var2): {1: 0, var1: 1, var2: -1})) -def _find_and_rename_dim(old_map, dim_types, old_name, new_name): +def _find_and_rename_dim(map, dim_types, old_name, new_name): # (This function is only used once here, but do not inline it; it is used many # times in child branch update-dependencies-during-transformations.) - new_map = old_map.copy() for dt in dim_types: - new_map = new_map.set_dim_name( - dt, new_map.find_dim_by_name(dt, old_name), new_name) - return new_map + map = map.set_dim_name( + dt, map.find_dim_by_name(dt, old_name), new_name) + return map # }}} From 4ce6c7a39111915eb8d93ef244c4e88eda6f6066 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 16:51:47 -0500 Subject: [PATCH 162/220] Update loopy/transform/iname.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit in map_domain, use <= instead of issubset Co-authored-by: Andreas Klöckner --- loopy/transform/iname.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index c8fcdcb32..7b62f0bcc 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2208,8 +2208,7 @@ def process_set(s): # Make sure transform map is applicable to this set. Then transform. - if not transform_map_in_dims.issubset( - frozenset(old_domain.get_var_dict())): + if not transform_map_in_dims <= frozenset(old_domain.get_var_dict()): # Map not applicable to this set because map transforms at least # one iname that is not present in the set. Don't transform. From 906ef55e55a24c961525a36f598b936ed07e0626 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 17:14:18 -0500 Subject: [PATCH 163/220] allow second val in add_eq_isl_constraint_from_names to be an integer --- loopy/schedule/checker/utils.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index f6df1921b..9d181de73 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -115,10 +115,19 @@ def ensure_dim_names_match_and_align(obj_map, tgt_map): def add_eq_isl_constraint_from_names(isl_map, var1, var2): # add constraint var1 = var2 - return isl_map.add_constraint( - isl.Constraint.eq_from_names( - isl_map.space, - {1: 0, var1: 1, var2: -1})) + assert isinstance(var1, str) + # var2 may be an int or a string + if isinstance(var2, str): + return isl_map.add_constraint( + isl.Constraint.eq_from_names( + isl_map.space, + {1: 0, var1: 1, var2: -1})) + else: + assert isinstance(var2, int) + return isl_map.add_constraint( + isl.Constraint.eq_from_names( + isl_map.space, + {1: var2, var1: -1})) def add_int_bounds_to_isl_var(isl_map, var, lbound, ubound): From 89afc213ae1082c41bdda708d8ff26de99788497 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 17:16:22 -0500 Subject: [PATCH 164/220] (WIP) begin construction of full blex map as union of individual per-blex-tuple maps --- loopy/schedule/checker/schedule.py | 145 ++++++++++++++++++----------- 1 file changed, 93 insertions(+), 52 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 0e6939918..12a833d87 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -235,7 +235,6 @@ def _gather_blex_ordering_info( blex ordering map defining the blex ordering for all statement pairs, rather than separate (smaller) lex ordering maps for each pair """ - # TODO just pass in loops_with_barriers for the appropriate sync kind from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.schedule.checker.lexicographic_order_map import ( create_lex_order_map, @@ -255,6 +254,76 @@ def _gather_blex_ordering_info( # create sub-maps which will be *excluded* (subtracted) from a standard # lexicographic ordering in order to create the blex ordering + + # {{{ Determine the number of blex dims we will need + + max_nested_loops = 0 + cur_nested_loops = 0 + # TODO for effiency, this pass could be combined with an earlier pass + for lin_item in lin_items: + if isinstance(lin_item, EnterLoop): + if lin_item.iname in loops_with_barriers - loops_to_ignore: + cur_nested_loops += 1 + elif isinstance(lin_item, LeaveLoop): + if lin_item.iname in loops_with_barriers - loops_to_ignore: + max_nested_loops = max(cur_nested_loops, max_nested_loops) + cur_nested_loops -= 1 + else: + pass + n_seq_blex_dims = max_nested_loops*2 + 1 + + # }}} + + # {{{ Create the initial (pre-subtraction) blex order map + + # Create names for the blex dimensions for sequential loops + seq_blex_dim_names = [ + LEX_VAR_PREFIX+str(i) for i in range(n_seq_blex_dims)] + seq_blex_dim_names_prime = append_mark_to_strings( + seq_blex_dim_names, mark=BEFORE_MARK) + + # Begin with the blex order map created as a standard lexicographical order + blex_order_map = create_lex_order_map( + dim_names=seq_blex_dim_names, + in_dim_mark=BEFORE_MARK, + ) + + # Bound the non-iname blex variables (TODO by creating set of all blex points below) + """ + from loopy.schedule.checker.utils import add_int_bounds_to_isl_var + for idx in range(0, len(seq_blex_dim_names), 2): + #print(prettier_map_string(blex_order_map)) + blex_order_map = add_int_bounds_to_isl_var( + blex_order_map, seq_blex_dim_names[idx], 0, known_blex_dim_ubounds[idx]) + #print(prettier_map_string(blex_order_map)) + blex_order_map = add_int_bounds_to_isl_var( + blex_order_map, seq_blex_dim_names_prime[idx], 0, known_blex_dim_ubounds[idx]) + #print(prettier_map_string(blex_order_map)) + + """ + # Bound the iname blex variables (TODO by creating set of all blex points below) + + # }}} + + # {{{ Create a template set for the space of all blex points + + blex_set_template = isl.align_spaces( + isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map).range() + + # Create set of all blex points by starting with (0, 0, 0, ...) + # and then unioning this with each new set of blex points we find + all_blex_points = blex_set_template.copy() # TODO do we need to copy? + for var_name in seq_blex_dim_names: + all_blex_points = add_eq_isl_constraint_from_names( + all_blex_points, var_name, 0) + + # }}} + + print(prettier_map_string(all_blex_points)) + 1/0 + + + # TODO may be able to remove some of this stuff now: stmt_inst_to_blex = {} # Map stmt instances to blex space iname_to_blex_dim = {} # Map from inames to corresponding blex space dim # OLD blex_exclusion_info, TODO remove @@ -262,7 +331,7 @@ def _gather_blex_ordering_info( blex_exclusion_info = {} # Info for creating maps to exclude from blex order _blex_order_map_params = set() # TODO remove blex_order_map_params = set() # Params needed in blex order map - n_seq_blex_dims = 1 # Num dims representing sequential order in blex space + _n_seq_blex_dims = 1 # TODO remove Num dims representing sequential order in blex space next_blex_tuple = [0] # Next tuple of points in blex order print() # Debugging. TODO remove @@ -273,7 +342,7 @@ def _gather_blex_ordering_info( for lin_item in lin_items: if isinstance(lin_item, EnterLoop): enter_iname = lin_item.iname - if enter_iname in loops_with_barriers[sync_kind] - loops_to_ignore: + if enter_iname in loops_with_barriers - loops_to_ignore: pre_loop_blex_pt = next_blex_tuple[:] # Increment next_blex_tuple[-1] for statements in the section @@ -320,6 +389,8 @@ def _gather_blex_ordering_info( slex.FIRST: tuple(first_iter_blex_pt), } + # Create the set of blex points to add + # }}} # (copy these three blex points when creating dict because @@ -331,12 +402,12 @@ def _gather_blex_ordering_info( elif isinstance(lin_item, LeaveLoop): leave_iname = lin_item.iname - if leave_iname in loops_with_barriers[sync_kind] - loops_to_ignore: + if leave_iname in loops_with_barriers - loops_to_ignore: curr_blex_dim_ct = len(next_blex_tuple) # Update max blex dims - n_seq_blex_dims = max(n_seq_blex_dims, curr_blex_dim_ct) + _n_seq_blex_dims = max(_n_seq_blex_dims, curr_blex_dim_ct) # Record the blex dim for this loop iname iname_to_blex_dim[leave_iname] = curr_blex_dim_ct-2 @@ -441,6 +512,8 @@ def _gather_blex_ordering_info( lin_item, (CallKernel, ReturnFromKernel)) pass + assert n_seq_blex_dims == _n_seq_blex_dims # TODO remove + # Record the max value for the 0th non-iname blex dim known_blex_dim_ubounds[0] = max( next_blex_tuple[-1], known_blex_dim_ubounds[0]) @@ -449,7 +522,7 @@ def _gather_blex_ordering_info( #blex_order_map_params = sorted(blex_order_map_params) # Don't want inames in blex map params, remove them # TODO: could we have introduced inames other than loops_with_barriers? - blex_order_map_params = sorted(blex_order_map_params - loops_with_barriers[sync_kind]) + blex_order_map_params = sorted(blex_order_map_params - loops_with_barriers) # At this point, some blex tuples may have more dimensions than others; # the missing dims are the fastest-updating dims, and their values should @@ -461,37 +534,6 @@ def _gather_blex_ordering_info( # {{{ Second, create the blex order map - # {{{ Create the initial (pre-subtraction) blex order map - - # Create names for the blex dimensions for sequential loops - seq_blex_dim_names = [ - LEX_VAR_PREFIX+str(i) for i in range(n_seq_blex_dims)] - seq_blex_dim_names_prime = append_mark_to_strings( - seq_blex_dim_names, mark=BEFORE_MARK) - - # Begin with the blex order map created as a standard lexicographical order - blex_order_map = create_lex_order_map( - dim_names=seq_blex_dim_names, - in_dim_mark=BEFORE_MARK, - ) - - # Bound the non-iname blex variables - from loopy.schedule.checker.utils import add_int_bounds_to_isl_var - for idx in range(0, len(seq_blex_dim_names), 2): - #print(prettier_map_string(blex_order_map)) - blex_order_map = add_int_bounds_to_isl_var( - blex_order_map, seq_blex_dim_names[idx], 0, known_blex_dim_ubounds[idx]) - #print(prettier_map_string(blex_order_map)) - blex_order_map = add_int_bounds_to_isl_var( - blex_order_map, seq_blex_dim_names_prime[idx], 0, known_blex_dim_ubounds[idx]) - #print(prettier_map_string(blex_order_map)) - # TODO do prime bounds need to be shifted 1 from non-primes? - - # Bound the iname blex variables - # TODO - - # }}} - # {{{ Subtract unwanted pairs from happens-before blex map # Create mapping (dict) from iname to corresponding blex dim name @@ -507,21 +549,20 @@ def _gather_blex_ordering_info( blex_order_map, dim_type.param, blex_order_map_params) # Get a set representing blex_order_map space - n_blex_dims = n_seq_blex_dims - blex_set_template = isl.align_spaces( + blex_mapset_template = isl.align_spaces( isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map ).move_dims( - dim_type.in_, n_blex_dims, dim_type.out, 0, n_blex_dims + dim_type.in_, n_seq_blex_dims, dim_type.out, 0, n_seq_blex_dims ).domain() - blex_set_affs = isl.affs_from_space(blex_set_template.space) + blex_set_affs = isl.affs_from_space(blex_mapset_template.space) # TODO remove: - _blex_set_template = isl.align_spaces( + _blex_mapset_template = isl.align_spaces( isl.Map("[ ] -> { [ ] -> [ ] }"), _blex_order_map ).move_dims( - dim_type.in_, n_blex_dims, dim_type.out, 0, n_blex_dims + dim_type.in_, n_seq_blex_dims, dim_type.out, 0, n_seq_blex_dims ).domain() - _blex_set_affs = isl.affs_from_space(_blex_set_template.space) + _blex_set_affs = isl.affs_from_space(_blex_mapset_template.space) # {{{ Create blex map to subtract for each iname in blex_exclusion_info @@ -554,13 +595,13 @@ def _create_blex_set_from_tuple_pair( the ISL map to be subtracted """ # (Vars from outside func used here: - # iname, blex_set_affs, blex_set_template, iname_to_blex_var, + # iname, blex_set_affs, blex_mapset_template, iname_to_blex_var, # n_seq_blex_dims, seq_blex_dim_names, # seq_blex_dim_names_prime) # Start with a set representing blex_order_map space - _blex_set = _blex_set_template.copy() # TODO remove - blex_set = blex_set_template.copy() + _blex_set = _blex_mapset_template.copy() # TODO remove + blex_set = blex_mapset_template.copy() # Add marks to inames in the 'before' tuple # (all strings should be inames) @@ -624,7 +665,7 @@ def _create_blex_set_from_tuple_pair( dim_val_renamed = rename_dims( dim_val_pre_aligned, iname_to_blex_var, [dim_type.set]) - dim_val_aligned = isl.align_spaces(dim_val_renamed, blex_set_template) + dim_val_aligned = isl.align_spaces(dim_val_renamed, blex_mapset_template) blex_set &= dim_val_aligned # TODO remove @@ -710,11 +751,11 @@ def _create_blex_set_from_tuple_pair( # Convert blex set back to map map_to_subtract = isl.Map.from_domain(full_blex_set).move_dims( - dim_type.out, 0, dim_type.in_, n_blex_dims, n_blex_dims) + dim_type.out, 0, dim_type.in_, n_seq_blex_dims, n_seq_blex_dims) # TODO remove: _map_to_subtract = isl.Map.from_domain(_full_blex_set).move_dims( - dim_type.out, 0, dim_type.in_, n_blex_dims, n_blex_dims) + dim_type.out, 0, dim_type.in_, n_seq_blex_dims, n_seq_blex_dims) # Bound the blex dims by intersecting with the full blex map, which # contains all the bound constraints @@ -1134,7 +1175,7 @@ def get_pairwise_statement_orderings_inner( lblex_order_map, seq_lblex_dim_names) = _gather_blex_ordering_info( "local", - lin_items, loops_with_barriers, loop_bounds, loops_to_ignore, + lin_items, loops_with_barriers["local"], loop_bounds, loops_to_ignore, all_stmt_ids, iname_bounds_pwaff, all_par_lex_dim_names, gid_lex_dim_names, ) @@ -1142,7 +1183,7 @@ def get_pairwise_statement_orderings_inner( gblex_order_map, seq_gblex_dim_names) = _gather_blex_ordering_info( "global", - lin_items, loops_with_barriers, loop_bounds, loops_to_ignore, + lin_items, loops_with_barriers["global"], loop_bounds, loops_to_ignore, all_stmt_ids, iname_bounds_pwaff, all_par_lex_dim_names, gid_lex_dim_names, ) From a1534bd5dfab4ca9cdae3a6fd9696f9056f7f938 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 17:24:14 -0500 Subject: [PATCH 165/220] move add_and_name_isl_dims, add_eq_isl_constraint_from_names, and find_and_rename_dim into isl_helpers --- loopy/isl_helpers.py | 50 +++++++++++++++++++++++++++++++++++++ loopy/transform/iname.py | 54 +++++++--------------------------------- 2 files changed, 59 insertions(+), 45 deletions(-) diff --git a/loopy/isl_helpers.py b/loopy/isl_helpers.py index d67df1154..448a62367 100644 --- a/loopy/isl_helpers.py +++ b/loopy/isl_helpers.py @@ -767,4 +767,54 @@ def subst_into_pwaff(new_space, pwaff, subst_dict): # }}} + +# {{{ add_and_name_isl_dims + +def add_and_name_isl_dims(isl_map, dt, names): + # (This function is also defined in independent, unmerged branch + # statement-instance-order-and-lex-order-map, and used in child branches + # thereof. Once these branches are all merged, it may make sense to move + # this function to a location for more general-purpose machinery. In the + # other branches, this function's name excludes the leading underscore.) + new_idx_start = isl_map.dim(dt) + new_map = isl_map.add_dims(dt, len(names)) + for i, name in enumerate(names): + new_map = new_map.set_dim_name(dt, new_idx_start+i, name) + return new_map + +# }}} + + +# {{{ add_eq_isl_constraint_from_names + +def add_eq_isl_constraint_from_names(isl_map, var1, var2): + # (This function is also defined in independent, unmerged branch + # statement-instance-order-and-lex-order-map, and used in child branches + # thereof. Once these branches are all merged, it may make sense to move + # this function to a location for more general-purpose machinery. In the + # other branches, this function's name excludes the leading underscore.) + + # add constraint var1 = var2 + + return isl_map.add_constraint( + isl.Constraint.eq_from_names( + isl_map.space, + {1: 0, var1: 1, var2: -1})) + +# }}} + + +# {{{ find_and_rename_dim + +def find_and_rename_dim(map, dim_types, old_name, new_name): + # (This function is only used once here, but do not inline it; it is used many + # times in child branch update-dependencies-during-transformations.) + for dt in dim_types: + map = map.set_dim_name( + dt, map.find_dim_by_name(dt, old_name), new_name) + return map + +# }}} + + # vim: foldmethod=marker diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 7b62f0bcc..a94b2cb82 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -1939,47 +1939,6 @@ def _find_aff_subst_from_map(iname, isl_map): # }}} -# {{{ ISL map wrangling helper functions - -def _add_and_name_isl_dims(isl_map, dt, names): - # (This function is also defined in independent, unmerged branch - # statement-instance-order-and-lex-order-map, and used in child branches - # thereof. Once these branches are all merged, it may make sense to move - # this function to a location for more general-purpose machinery. In the - # other branches, this function's name excludes the leading underscore.) - new_idx_start = isl_map.dim(dt) - new_map = isl_map.add_dims(dt, len(names)) - for i, name in enumerate(names): - new_map = new_map.set_dim_name(dt, new_idx_start+i, name) - return new_map - - -def _add_eq_isl_constraint_from_names(isl_map, var1, var2): - # (This function is also defined in independent, unmerged branch - # statement-instance-order-and-lex-order-map, and used in child branches - # thereof. Once these branches are all merged, it may make sense to move - # this function to a location for more general-purpose machinery. In the - # other branches, this function's name excludes the leading underscore.) - - # add constraint var1 = var2 - - return isl_map.add_constraint( - isl.Constraint.eq_from_names( - isl_map.space, - {1: 0, var1: 1, var2: -1})) - - -def _find_and_rename_dim(map, dim_types, old_name, new_name): - # (This function is only used once here, but do not inline it; it is used many - # times in child branch update-dependencies-during-transformations.) - for dt in dim_types: - map = map.set_dim_name( - dt, map.find_dim_by_name(dt, old_name), new_name) - return map - -# }}} - - # {{{ _apply_identity_for_missing_map_dims(mapping, desired_dims) def _apply_identity_for_missing_map_dims(mapping, desired_dims): @@ -2004,18 +1963,21 @@ def _apply_identity_for_missing_map_dims(mapping, desired_dims): # dependency maps, which may contain variable names consisting of an iname # suffixed with a single apostrophe.) + from loopy.isl_helpers import ( + add_and_name_isl_dims, add_eq_isl_constraint_from_names) + # {{{ Find any missing vars and add them to the input and output space missing_dims = list( set(desired_dims) - set(mapping.get_var_names(dim_type.in_))) - augmented_mapping = _add_and_name_isl_dims( + augmented_mapping = add_and_name_isl_dims( mapping, dim_type.in_, missing_dims) missing_dims_proxies = [d+"_'prox'_" for d in missing_dims] assert not set(missing_dims_proxies) & set( augmented_mapping.get_var_dict().keys()) - augmented_mapping = _add_and_name_isl_dims( + augmented_mapping = add_and_name_isl_dims( augmented_mapping, dim_type.out, missing_dims_proxies) proxy_name_pairs = list(zip(missing_dims, missing_dims_proxies)) @@ -2025,7 +1987,7 @@ def _apply_identity_for_missing_map_dims(mapping, desired_dims): # {{{ Add identity constraint (v = v_'proxy'_) for each new pair of dims for real_iname, proxy_iname in proxy_name_pairs: - augmented_mapping = _add_eq_isl_constraint_from_names( + augmented_mapping = add_eq_isl_constraint_from_names( augmented_mapping, proxy_iname, real_iname) # }}} @@ -2185,8 +2147,10 @@ def process_set(s): new_s = aligned_map.intersect_domain(s).range() # Now rename any proxy dims back to their original names + + from loopy.isl_helpers import find_and_rename_dim for real_iname, proxy_iname in proxy_name_pairs: - new_s = _find_and_rename_dim( + new_s = find_and_rename_dim( new_s, [dim_type.set], proxy_iname, real_iname) return new_s From 3281b76ff2f8247b8cee83395b3a36a436161c21 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 17:30:03 -0500 Subject: [PATCH 166/220] rename isl_map to isl_obj when sets are also allowed; remove comments about functions defined in other branches --- loopy/isl_helpers.py | 44 ++++++++++++++-------------------------- loopy/transform/iname.py | 8 ++++---- 2 files changed, 19 insertions(+), 33 deletions(-) diff --git a/loopy/isl_helpers.py b/loopy/isl_helpers.py index 448a62367..1be92d6f7 100644 --- a/loopy/isl_helpers.py +++ b/loopy/isl_helpers.py @@ -768,37 +768,25 @@ def subst_into_pwaff(new_space, pwaff, subst_dict): # }}} -# {{{ add_and_name_isl_dims - -def add_and_name_isl_dims(isl_map, dt, names): - # (This function is also defined in independent, unmerged branch - # statement-instance-order-and-lex-order-map, and used in child branches - # thereof. Once these branches are all merged, it may make sense to move - # this function to a location for more general-purpose machinery. In the - # other branches, this function's name excludes the leading underscore.) - new_idx_start = isl_map.dim(dt) - new_map = isl_map.add_dims(dt, len(names)) +# {{{ add_and_name_dims + +def add_and_name_dims(isl_obj, dt, names): + new_idx_start = isl_obj.dim(dt) + new_obj = isl_obj.add_dims(dt, len(names)) for i, name in enumerate(names): - new_map = new_map.set_dim_name(dt, new_idx_start+i, name) - return new_map + new_obj = new_obj.set_dim_name(dt, new_idx_start+i, name) + return new_obj # }}} -# {{{ add_eq_isl_constraint_from_names - -def add_eq_isl_constraint_from_names(isl_map, var1, var2): - # (This function is also defined in independent, unmerged branch - # statement-instance-order-and-lex-order-map, and used in child branches - # thereof. Once these branches are all merged, it may make sense to move - # this function to a location for more general-purpose machinery. In the - # other branches, this function's name excludes the leading underscore.) +# {{{ add_eq_constraint_from_names +def add_eq_constraint_from_names(isl_obj, var1, var2): # add constraint var1 = var2 - - return isl_map.add_constraint( + return isl_obj.add_constraint( isl.Constraint.eq_from_names( - isl_map.space, + isl_obj.space, {1: 0, var1: 1, var2: -1})) # }}} @@ -806,13 +794,11 @@ def add_eq_isl_constraint_from_names(isl_map, var1, var2): # {{{ find_and_rename_dim -def find_and_rename_dim(map, dim_types, old_name, new_name): - # (This function is only used once here, but do not inline it; it is used many - # times in child branch update-dependencies-during-transformations.) +def find_and_rename_dim(isl_obj, dim_types, old_name, new_name): for dt in dim_types: - map = map.set_dim_name( - dt, map.find_dim_by_name(dt, old_name), new_name) - return map + isl_obj = isl_obj.set_dim_name( + dt, isl_obj.find_dim_by_name(dt, old_name), new_name) + return isl_obj # }}} diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index a94b2cb82..d71b17dbb 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -1964,20 +1964,20 @@ def _apply_identity_for_missing_map_dims(mapping, desired_dims): # suffixed with a single apostrophe.) from loopy.isl_helpers import ( - add_and_name_isl_dims, add_eq_isl_constraint_from_names) + add_and_name_dims, add_eq_constraint_from_names) # {{{ Find any missing vars and add them to the input and output space missing_dims = list( set(desired_dims) - set(mapping.get_var_names(dim_type.in_))) - augmented_mapping = add_and_name_isl_dims( + augmented_mapping = add_and_name_dims( mapping, dim_type.in_, missing_dims) missing_dims_proxies = [d+"_'prox'_" for d in missing_dims] assert not set(missing_dims_proxies) & set( augmented_mapping.get_var_dict().keys()) - augmented_mapping = add_and_name_isl_dims( + augmented_mapping = add_and_name_dims( augmented_mapping, dim_type.out, missing_dims_proxies) proxy_name_pairs = list(zip(missing_dims, missing_dims_proxies)) @@ -1987,7 +1987,7 @@ def _apply_identity_for_missing_map_dims(mapping, desired_dims): # {{{ Add identity constraint (v = v_'proxy'_) for each new pair of dims for real_iname, proxy_iname in proxy_name_pairs: - augmented_mapping = add_eq_isl_constraint_from_names( + augmented_mapping = add_eq_constraint_from_names( augmented_mapping, proxy_iname, real_iname) # }}} From c7ac1f25c134983545ac7c63bc3173c1bf08d79f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 17:58:58 -0500 Subject: [PATCH 167/220] docstrings for add_and_name_isl_dims, add_eq_isl_constraint_from_names, and find_and_rename_dim --- loopy/isl_helpers.py | 52 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/loopy/isl_helpers.py b/loopy/isl_helpers.py index 1be92d6f7..585bd4dcd 100644 --- a/loopy/isl_helpers.py +++ b/loopy/isl_helpers.py @@ -771,6 +771,23 @@ def subst_into_pwaff(new_space, pwaff, subst_dict): # {{{ add_and_name_dims def add_and_name_dims(isl_obj, dt, names): + """Append dimensions of the specified dimension type to the provided ISL + object, and set their names. + + :arg isl_obj: An :class:`islpy.Set` or :class:`islpy.Map` to which + new dimensions will be added. + + :arg dt: An :class:`islpy.dim_type`, i.e., an :class:`int`, specifying the + dimension type for the new dimensions. + + :arg names: An iterable of :class:`str` values specifying the names of the + new dimensions to be added. + + :returns: An object of the same type as *isl_obj* with the new dimensions + added and named. + + """ + new_idx_start = isl_obj.dim(dt) new_obj = isl_obj.add_dims(dt, len(names)) for i, name in enumerate(names): @@ -783,7 +800,21 @@ def add_and_name_dims(isl_obj, dt, names): # {{{ add_eq_constraint_from_names def add_eq_constraint_from_names(isl_obj, var1, var2): - # add constraint var1 = var2 + """Add constraint *var1* = *var2* to an ISL object. + + :arg isl_obj: An :class:`islpy.Set` or :class:`islpy.Map` to which + a new constraint will be added. + + :arg var1: A :class:`str` specifying the name of the first variable + involved in constraint *var1* = *var2*. + + :arg var2: A :class:`str` specifying the name of the second variable + involved in constraint *var1* = *var2*. + + :returns: An object of the same type as *isl_obj* with the constraint + *var1* = *var2*. + + """ return isl_obj.add_constraint( isl.Constraint.eq_from_names( isl_obj.space, @@ -795,6 +826,25 @@ def add_eq_constraint_from_names(isl_obj, var1, var2): # {{{ find_and_rename_dim def find_and_rename_dim(isl_obj, dim_types, old_name, new_name): + """Rename a dimension in an ISL object. + + :arg isl_obj: An :class:`islpy.Set` or :class:`islpy.Map` containing the + dimension to be renamed. + + :arg dim_types: An iterable of :class:`islpy.dim_type` values (i.e., + :class:`int` values) specifying the dimension types for any dimensions + to be renamed. + + :arg old_name: A :class:`str` specifying the name of the dimension to be + renamed. + + :arg new_name: A :class:`str` specifying the new name of the dimension to + be renamed. + + :returns: An object of the same type as *isl_obj* with the dimension + *old_name* renamed to *new_name*. + + """ for dt in dim_types: isl_obj = isl_obj.set_dim_name( dt, isl_obj.find_dim_by_name(dt, old_name), new_name) From 693ee86b63ec5639152e500cf0e0d87c188abe7b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 18:02:51 -0500 Subject: [PATCH 168/220] remove unnecessary variable renaming in add_and_name_dims --- loopy/isl_helpers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/loopy/isl_helpers.py b/loopy/isl_helpers.py index 585bd4dcd..bcad428ba 100644 --- a/loopy/isl_helpers.py +++ b/loopy/isl_helpers.py @@ -789,10 +789,10 @@ def add_and_name_dims(isl_obj, dt, names): """ new_idx_start = isl_obj.dim(dt) - new_obj = isl_obj.add_dims(dt, len(names)) + isl_obj = isl_obj.add_dims(dt, len(names)) for i, name in enumerate(names): - new_obj = new_obj.set_dim_name(dt, new_idx_start+i, name) - return new_obj + isl_obj = isl_obj.set_dim_name(dt, new_idx_start+i, name) + return isl_obj # }}} From b8c3400250d79b49076e9185d8b6357700581726 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 18:08:32 -0500 Subject: [PATCH 169/220] since find_and_rename_dim is only used for one dim type at a time, make it only accept a single dim type arg --- loopy/isl_helpers.py | 11 ++++------- loopy/transform/iname.py | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/loopy/isl_helpers.py b/loopy/isl_helpers.py index bcad428ba..57183109b 100644 --- a/loopy/isl_helpers.py +++ b/loopy/isl_helpers.py @@ -825,15 +825,14 @@ def add_eq_constraint_from_names(isl_obj, var1, var2): # {{{ find_and_rename_dim -def find_and_rename_dim(isl_obj, dim_types, old_name, new_name): +def find_and_rename_dim(isl_obj, dt, old_name, new_name): """Rename a dimension in an ISL object. :arg isl_obj: An :class:`islpy.Set` or :class:`islpy.Map` containing the dimension to be renamed. - :arg dim_types: An iterable of :class:`islpy.dim_type` values (i.e., - :class:`int` values) specifying the dimension types for any dimensions - to be renamed. + :arg dt: An :class:`islpy.dim_type` (i.e., :class:`int`) specifying the + dimension type containing the dimension to be renamed. :arg old_name: A :class:`str` specifying the name of the dimension to be renamed. @@ -845,10 +844,8 @@ def find_and_rename_dim(isl_obj, dim_types, old_name, new_name): *old_name* renamed to *new_name*. """ - for dt in dim_types: - isl_obj = isl_obj.set_dim_name( + return isl_obj.set_dim_name( dt, isl_obj.find_dim_by_name(dt, old_name), new_name) - return isl_obj # }}} diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index d71b17dbb..ccd0ea556 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2151,7 +2151,7 @@ def process_set(s): from loopy.isl_helpers import find_and_rename_dim for real_iname, proxy_iname in proxy_name_pairs: new_s = find_and_rename_dim( - new_s, [dim_type.set], proxy_iname, real_iname) + new_s, dim_type.set, proxy_iname, real_iname) return new_s From 9801d1cffb4b20c61818f7716203986ca5d104d4 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 18:19:27 -0500 Subject: [PATCH 170/220] more detailed documentation for _apply_identity_for_missing_map_dims --- loopy/transform/iname.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index ccd0ea556..5127d92c0 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -1946,6 +1946,16 @@ def _apply_identity_for_missing_map_dims(mapping, desired_dims): input space for *mapping*, add input dimension v, output dimension v_'proxy'_, and constraint v = v_'proxy'_ to the mapping. Also return a list of the (v, v_'proxy'_) pairs. + + :arg mapping: An :class:`islpy.Map`. + + :arg desired_dims: An iterable of :class:`str` specifying the names of the + desired map input dimensions. + + :returns: A two-tuple containing the mapping with the new dimensions and + constraints added, and a list of two-tuples of :class:`str` values + specifying the (v, v_'proxy'_) pairs. + """ # If the transform map in map_domain (below) does not contain all the From 09703eb041c7132fd8427085269ad14b7059aeb7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 18:27:12 -0500 Subject: [PATCH 171/220] in map_domain, don't recompute subst_from_map for no reason --- loopy/transform/iname.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 5127d92c0..548f9ec01 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2085,10 +2085,10 @@ def map_domain(kernel, transform_map): from loopy.symbolic import aff_to_expr from pymbolic import var for iname in transform_map_in_dims: - substitutions[iname] = aff_to_expr( - _find_aff_subst_from_map(iname, transform_map)) - var_substitutions[var(iname)] = aff_to_expr( - _find_aff_subst_from_map(iname, transform_map)) + subst_from_map = aff_to_expr( + _find_aff_subst_from_map(iname, transform_map)) + substitutions[iname] = subst_from_map + var_substitutions[var(iname)] = subst_from_map applied_iname_rewrites.append(var_substitutions) del var_substitutions From 3d24d437f6d291e4a40050164b1b33c1c7b0a23c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 18:36:56 -0500 Subject: [PATCH 172/220] use auto_test_vs_ref in test_map_domain_vs_split_iname --- test/test_transform.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/test_transform.py b/test/test_transform.py index 86b7738a0..38a15fe04 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -618,7 +618,7 @@ def _ensure_dim_names_match_and_align(obj_map, tgt_map): return align_spaces(obj_map, tgt_map) -def test_map_domain_vs_split_iname(): +def test_map_domain_vs_split_iname(ctx_factory): # {{{ Make kernel @@ -687,6 +687,9 @@ def test_map_domain_vs_split_iname(): # Can't easily compare instructions because equivalent subscript # expressions may have different orders + lp.auto_test_vs_ref(proc_knl_split_iname, ctx_factory(), proc_knl_map_dom, + parameters={"nx": 256, "nt": 256, "ni": 256}) + # }}} # }}} From 6594873494979511fd9c4aabcf547bc90f517ffd Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 18:55:00 -0500 Subject: [PATCH 173/220] use get_attr instead of try/except to check for loop_nest_constraints attribute in kernel; also clarify purpose of some tests --- test/test_transform.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/test/test_transform.py b/test/test_transform.py index 38a15fe04..a8c03d761 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -641,7 +641,7 @@ def test_map_domain_vs_split_iname(ctx_factory): # {{{ Apply domain change mapping - knl_map_dom = ref_knl # loop priority goes away, deps stay + knl_map_dom = ref_knl # Create map_domain mapping: import islpy as isl @@ -688,7 +688,7 @@ def test_map_domain_vs_split_iname(ctx_factory): # expressions may have different orders lp.auto_test_vs_ref(proc_knl_split_iname, ctx_factory(), proc_knl_map_dom, - parameters={"nx": 256, "nt": 256, "ni": 256}) + parameters={"nx": 128, "nt": 128, "ni": 128}) # }}} @@ -697,7 +697,7 @@ def test_map_domain_vs_split_iname(ctx_factory): # {{{ test_map_domain_transform_map_validity_and_errors -def test_map_domain_transform_map_validity_and_errors(): +def test_map_domain_transform_map_validity_and_errors(ctx_factory): # {{{ Make kernel @@ -719,12 +719,14 @@ def test_map_domain_transform_map_validity_and_errors(): # }}} - # Make sure map_domain works correctly when the mapping doesn't include - # all the dims in the domain. + # {{{ Make sure map_domain succeeds when we apply a map that includes 2 of 4 + # dims in the domain. - # {{{ Apply domain change mapping + # {{{ Apply domain change mapping that splits t and renames y; (similar to + # split_iname test above, but doesn't hurt to test this slightly different + # scenario) - knl_map_dom = ref_knl # loop priority goes away, deps stay + knl_map_dom = ref_knl # Create map_domain mapping that only includes t and y # (x and z should be unaffected) @@ -737,15 +739,17 @@ def test_map_domain_transform_map_validity_and_errors(): "y = y_new" "}") - # Call map_domain to transform kernel; this should not produce an error + # Call map_domain to transform kernel; this should *not* produce an error knl_map_dom = lp.map_domain(knl_map_dom, transform_map) - # Prioritize loops (prio should eventually be updated in map_domain) - try: - # Use constrain_loop_nesting if it's available + # Prioritize loops + + # Use constrain_loop_nesting if it's available + cln_attr = getattr(lp, "constrain_loop_nesting", None) + if cln_attr is not None: desired_prio = "x, t_outer, t_inner, z, y_new" knl_map_dom = lp.constrain_loop_nesting(knl_map_dom, desired_prio) - except AttributeError: + else: # For some reason, prioritize_loops can't handle the ordering above # when linearizing knl_split_iname below desired_prio = "z, y_new, x, t_outer, t_inner" @@ -758,7 +762,7 @@ def test_map_domain_transform_map_validity_and_errors(): # }}} - # {{{ Split iname and see if we get the same result + # {{{ Use split_iname, and rename_iname, and make sure we get the same result knl_split_iname = ref_knl knl_split_iname = lp.split_iname(knl_split_iname, "t", 32) @@ -786,6 +790,11 @@ def test_map_domain_transform_map_validity_and_errors(): # Can't easily compare instructions because equivalent subscript # expressions may have different orders + lp.auto_test_vs_ref(proc_knl_split_iname, ctx_factory(), proc_knl_map_dom, + parameters={"nx": 64, "nt": 64, "m": 64}) + + # }}} + # }}} # {{{ Make sure we error on a map that is not bijective From 94045941e8eaad77623b29ff5acacddd8b9e991b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 18:57:16 -0500 Subject: [PATCH 174/220] shrink problem size to make test_map_domain_transform_map_validity_and_errors run faster --- test/test_transform.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test_transform.py b/test/test_transform.py index a8c03d761..29a6e2802 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -733,9 +733,9 @@ def test_map_domain_transform_map_validity_and_errors(ctx_factory): import islpy as isl transform_map = isl.BasicMap( "[nx,nt] -> {[t, y] -> [t_outer, t_inner, y_new]: " - "0 <= t_inner < 32 and " - "32*t_outer + t_inner = t and " - "0 <= 32*t_outer + t_inner < nt and " + "0 <= t_inner < 16 and " + "16*t_outer + t_inner = t and " + "0 <= 16*t_outer + t_inner < nt and " "y = y_new" "}") @@ -765,7 +765,7 @@ def test_map_domain_transform_map_validity_and_errors(ctx_factory): # {{{ Use split_iname, and rename_iname, and make sure we get the same result knl_split_iname = ref_knl - knl_split_iname = lp.split_iname(knl_split_iname, "t", 32) + knl_split_iname = lp.split_iname(knl_split_iname, "t", 16) knl_split_iname = lp.rename_iname(knl_split_iname, "y", "y_new") try: # Use constrain_loop_nesting if it's available @@ -791,7 +791,7 @@ def test_map_domain_transform_map_validity_and_errors(ctx_factory): # expressions may have different orders lp.auto_test_vs_ref(proc_knl_split_iname, ctx_factory(), proc_knl_map_dom, - parameters={"nx": 64, "nt": 64, "m": 64}) + parameters={"nx": 32, "nt": 32, "m": 32}) # }}} From 81886490f1d7c7464257f1f0b903f54a98b8db33 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 19:00:17 -0500 Subject: [PATCH 175/220] use same loop prioritization regardless of whether we're using prioritize_loops() or constrain_loop_nesting() --- test/test_transform.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/test_transform.py b/test/test_transform.py index 29a6e2802..2eeea80ba 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -743,16 +743,13 @@ def test_map_domain_transform_map_validity_and_errors(ctx_factory): knl_map_dom = lp.map_domain(knl_map_dom, transform_map) # Prioritize loops + desired_prio = "x, t_outer, t_inner, z, y_new" # Use constrain_loop_nesting if it's available cln_attr = getattr(lp, "constrain_loop_nesting", None) if cln_attr is not None: - desired_prio = "x, t_outer, t_inner, z, y_new" knl_map_dom = lp.constrain_loop_nesting(knl_map_dom, desired_prio) else: - # For some reason, prioritize_loops can't handle the ordering above - # when linearizing knl_split_iname below - desired_prio = "z, y_new, x, t_outer, t_inner" knl_map_dom = lp.prioritize_loops(knl_map_dom, desired_prio) # Get a linearization From 434f04b13aabca268067ff9981d67b903258c6ac Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 19:07:42 -0500 Subject: [PATCH 176/220] further clarification in comments about purpose of some map-domain tests --- test/test_transform.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/test_transform.py b/test/test_transform.py index 2eeea80ba..56bd4f77f 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -655,7 +655,8 @@ def test_map_domain_vs_split_iname(ctx_factory): knl_map_dom = lp.map_domain(knl_map_dom, transform_map) # Prioritize loops (prio should eventually be updated in map_domain?) - knl_map_dom = lp.prioritize_loops(knl_map_dom, "x, t_outer, t_inner") + loop_priority = "x, t_outer, t_inner" + knl_map_dom = lp.prioritize_loops(knl_map_dom, loop_priority) # Get a linearization proc_knl_map_dom = lp.preprocess_kernel(knl_map_dom) @@ -668,7 +669,7 @@ def test_map_domain_vs_split_iname(ctx_factory): knl_split_iname = ref_knl knl_split_iname = lp.split_iname(knl_split_iname, "t", 32) - knl_split_iname = lp.prioritize_loops(knl_split_iname, "x, t_outer, t_inner") + knl_split_iname = lp.prioritize_loops(knl_split_iname, loop_priority) proc_knl_split_iname = lp.preprocess_kernel(knl_split_iname) lin_knl_split_iname = lp.get_one_linearized_kernel( proc_knl_split_iname["loopy_kernel"], proc_knl_split_iname.callables_table) @@ -719,8 +720,8 @@ def test_map_domain_transform_map_validity_and_errors(ctx_factory): # }}} - # {{{ Make sure map_domain succeeds when we apply a map that includes 2 of 4 - # dims in the domain. + # {{{ Make sure map_domain *succeeds* when map includes 2 of 4 dims in one + # domain. # {{{ Apply domain change mapping that splits t and renames y; (similar to # split_iname test above, but doesn't hurt to test this slightly different @@ -759,7 +760,7 @@ def test_map_domain_transform_map_validity_and_errors(ctx_factory): # }}} - # {{{ Use split_iname, and rename_iname, and make sure we get the same result + # {{{ Use split_iname and rename_iname, and make sure we get the same result knl_split_iname = ref_knl knl_split_iname = lp.split_iname(knl_split_iname, "t", 16) @@ -870,7 +871,7 @@ def test_map_domain_transform_map_validity_and_errors(ctx_factory): # {{{ Make sure we error when stmt.within_inames contains at least one but # not all mapped inames - # {{{ Make kernel + # {{{ Make potentially problematic kernel knl = lp.make_kernel( [ From 332ebf55e839c909b19f939be8a24cc7e921d8a9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 19:25:19 -0500 Subject: [PATCH 177/220] tell pylint to chill out about a missing attribute --- test/test_transform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_transform.py b/test/test_transform.py index 56bd4f77f..8c44a3f67 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -749,7 +749,7 @@ def test_map_domain_transform_map_validity_and_errors(ctx_factory): # Use constrain_loop_nesting if it's available cln_attr = getattr(lp, "constrain_loop_nesting", None) if cln_attr is not None: - knl_map_dom = lp.constrain_loop_nesting(knl_map_dom, desired_prio) + knl_map_dom = lp.constrain_loop_nesting(knl_map_dom, desired_prio) # noqa else: knl_map_dom = lp.prioritize_loops(knl_map_dom, desired_prio) From 6e1f1d9e7ce3fd56d53bd58841a1c04e7ffc0dba Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 19:25:19 -0500 Subject: [PATCH 178/220] tell pylint to chill out about a missing attribute --- test/test_transform.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/test_transform.py b/test/test_transform.py index 56bd4f77f..3df2d6c2c 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -749,7 +749,8 @@ def test_map_domain_transform_map_validity_and_errors(ctx_factory): # Use constrain_loop_nesting if it's available cln_attr = getattr(lp, "constrain_loop_nesting", None) if cln_attr is not None: - knl_map_dom = lp.constrain_loop_nesting(knl_map_dom, desired_prio) + knl_map_dom = lp.constrain_loop_nesting( # noqa pylint:disable=no-member + knl_map_dom, desired_prio) else: knl_map_dom = lp.prioritize_loops(knl_map_dom, desired_prio) From 84da857c13866f774c35b1bb1710271e085114cb Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 2 Sep 2021 12:28:57 -0500 Subject: [PATCH 179/220] (WIP) further construction of full blex map as union of individual per-blex-tuple maps --- loopy/schedule/checker/schedule.py | 174 +++++++++++++++++++++++------ 1 file changed, 141 insertions(+), 33 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 12a833d87..313ff8c29 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -22,7 +22,12 @@ import islpy as isl from dataclasses import dataclass -from loopy.schedule.checker.utils import prettier_map_string # noqa +from loopy.schedule.checker.utils import ( + add_and_name_isl_dims, + add_eq_isl_constraint_from_names, + append_mark_to_isl_map_var_names, + prettier_map_string, # noqa +) dim_type = isl.dim_type @@ -67,8 +72,9 @@ """ #LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" -LIN_CHECK_IDENTIFIER_PREFIX = "__" # TODO change back after debug -LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) +#LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) +LIN_CHECK_IDENTIFIER_PREFIX = "" # TODO change back after debug +LEX_VAR_PREFIX = "%slx" % (LIN_CHECK_IDENTIFIER_PREFIX) # TODO change back after debug STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) LTAG_VAR_NAMES = [] GTAG_VAR_NAMES = [] @@ -221,7 +227,61 @@ class StatementOrdering: # {{{ _gather_blex_ordering_info +def _find_and_rename_dim(isl_obj, dt, old_name, new_name): + # TODO remove this func once it's merged into isl_helpers + return isl_obj.set_dim_name( + dt, isl_obj.find_dim_by_name(dt, old_name), new_name) + + +def _add_one_blex_tuple( + all_blex_points, blex_tuple, seq_blex_dim_names, knl): + + # blex_tuple contains 1 dim plus 2 dims for each *current* loop, so it may + # be shorter than seq_blex_dim_names, which contains *all* the blex dim + # names + current_inames = blex_tuple[1::2] + + # Get set of inames nested outside (including this iname) + seq_within_inames = set(current_inames) + + # Get inames domain for current inames + # TODO it's possible that we can project out more inames, + # how do we figure out which ones to project out? + # TODO what if this iname bound also depends on a concurrent iname? + dom = knl.get_inames_domain( + seq_within_inames).project_out_except( + seq_within_inames, [dim_type.set]) + + # Rename iname dims to blex dims + for depth, iname in enumerate(current_inames): + blex_dim_name = seq_blex_dim_names[1 + 2*depth] + dom = _find_and_rename_dim(dom, dim_type.set, iname, blex_dim_name) + + # Add any new params to all_blex_points + current_params = all_blex_points.get_var_names(dim_type.param) + needed_params = dom.get_var_names(dim_type.param) + missing_params = set(needed_params) - set(current_params) + all_blex_points = add_and_name_isl_dims( + all_blex_points, dim_type.param, missing_params) + + # Add missing blex dims and align + dom = isl.align_spaces(dom, all_blex_points) + + # Set values for non-iname blex dims + for blex_dim_name, blex_val in zip(seq_blex_dim_names[::2], blex_tuple[::2]): + dom = add_eq_isl_constraint_from_names(dom, blex_dim_name, blex_val) + # Set any unused (rightmost, fastest-updating) blex dims to zero + for blex_dim_name in seq_blex_dim_names[len(blex_tuple):]: + dom = add_eq_isl_constraint_from_names(dom, blex_dim_name, 0) + + # Add this blex set to full set of blex points + all_blex_points |= dom + + return all_blex_points + + def _gather_blex_ordering_info( + knl, sync_kind, lin_items, loops_with_barriers, loop_bounds, loops_to_ignore, all_stmt_ids, iname_bounds_pwaff, @@ -274,7 +334,7 @@ def _gather_blex_ordering_info( # }}} - # {{{ Create the initial (pre-subtraction) blex order map + # {{{ Create the initial (pre-subtraction) blex order map, initially without bounds # Create names for the blex dimensions for sequential loops seq_blex_dim_names = [ @@ -283,6 +343,8 @@ def _gather_blex_ordering_info( seq_blex_dim_names, mark=BEFORE_MARK) # Begin with the blex order map created as a standard lexicographical order + # (bounds will be applied later by intersecting this with map containing + # all blex points) blex_order_map = create_lex_order_map( dim_names=seq_blex_dim_names, in_dim_mark=BEFORE_MARK, @@ -307,6 +369,7 @@ def _gather_blex_ordering_info( # {{{ Create a template set for the space of all blex points + # TODO if we only use this template once, don't save it blex_set_template = isl.align_spaces( isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map).range() @@ -320,8 +383,6 @@ def _gather_blex_ordering_info( # }}} print(prettier_map_string(all_blex_points)) - 1/0 - # TODO may be able to remove some of this stuff now: stmt_inst_to_blex = {} # Map stmt instances to blex space @@ -400,6 +461,14 @@ def _gather_blex_ordering_info( _blex_order_map_params |= set(_lbound.get_var_names(dim_type.param)) # TODO remove blex_order_map_params |= set(lbound.get_var_names(dim_type.param)) # might include inames + # {{{ NEW NEW stuff: create the blex set for this blex point + + all_blex_points = _add_one_blex_tuple( + all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) + + # }}} + + elif isinstance(lin_item, LeaveLoop): leave_iname = lin_item.iname if leave_iname in loops_with_barriers - loops_to_ignore: @@ -469,6 +538,13 @@ def _gather_blex_ordering_info( _blex_order_map_params |= set(_ubound.get_var_names(dim_type.param)) # TODO remove blex_order_map_params |= set(ubound.get_var_names(dim_type.param)) + # {{{ NEW NEW stuff: create the blex set for this blex point + + all_blex_points = _add_one_blex_tuple( + all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) + + # }}} + elif isinstance(lin_item, RunInstruction): # Add stmt->blex pair to stmt_inst_to_blex stmt_inst_to_blex[lin_item.insn_id] = tuple(next_blex_tuple) @@ -480,6 +556,13 @@ def _gather_blex_ordering_info( if lin_item.synchronization_kind == sync_kind: next_blex_tuple[-1] += 1 + # {{{ NEW NEW stuff: create the blex set for this blex point + + all_blex_points = _add_one_blex_tuple( + all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) + + # }}} + lp_stmt_id = lin_item.originating_insn_id if lp_stmt_id is None: @@ -495,16 +578,21 @@ def _gather_blex_ordering_info( # does not need to be assigned to a designated point in blex # time) if lp_stmt_id in all_stmt_ids: - # If sync scope matches, give this barrier its own point in - # lex time and update blex tuple after barrier. - # Otherwise, add stmt->blex pair to stmt_inst_to_blex, but - # don't update the blex tuple (just like with any other - # stmt) + + # Assign a blex point to this barrier just as we would for an assignment stmt + stmt_inst_to_blex[lp_stmt_id] = tuple(next_blex_tuple) + + # If sync scope matches, give this barrier its *own* point in + # lex time by updating blex tuple after barrier. if lin_item.synchronization_kind == sync_kind: - stmt_inst_to_blex[lp_stmt_id] = tuple(next_blex_tuple) next_blex_tuple[-1] += 1 - else: - stmt_inst_to_blex[lp_stmt_id] = tuple(next_blex_tuple) + + # {{{ NEW NEW stuff: create the blex set for this blex point + + all_blex_points = _add_one_blex_tuple( + all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) + + # }}} else: from loopy.schedule import (CallKernel, ReturnFromKernel) # No action needed for these types of linearization item @@ -534,6 +622,15 @@ def _gather_blex_ordering_info( # {{{ Second, create the blex order map + # {{{ Bound the (pre-subtraction) blex order map + + all_blex_points_prime = append_mark_to_isl_map_var_names( + all_blex_points, dim_type.set, BEFORE_MARK) + blex_order_map = blex_order_map.intersect_domain( + all_blex_points_prime).intersect_range(all_blex_points) + + # }}} + # {{{ Subtract unwanted pairs from happens-before blex map # Create mapping (dict) from iname to corresponding blex dim name @@ -543,10 +640,13 @@ def _gather_blex_ordering_info( iname_to_blex_var[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] # Add bounds params needed in blex map + """ _blex_order_map = add_and_name_isl_dims( # TODO remove blex_order_map, dim_type.param, _blex_order_map_params) blex_order_map = add_and_name_isl_dims( blex_order_map, dim_type.param, blex_order_map_params) + """ + _blex_order_map = blex_order_map.copy() # TODO remove # Get a set representing blex_order_map space blex_mapset_template = isl.align_spaces( @@ -699,18 +799,18 @@ def _create_blex_set_from_tuple_pair( # (set will be converted to map) # Enter loop case: PRE->FIRST - #full_blex_set = _create_blex_set_from_tuple_pair( + #blex_set_to_subtract = _create_blex_set_from_tuple_pair( # key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST]) - full_blex_set, _full_blex_set = _create_blex_set_from_tuple_pair( # TODO remove + blex_set_to_subtract, _blex_set_to_subtract = _create_blex_set_from_tuple_pair( # TODO remove key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST], _key_lex_tuples[slex.PRE], _key_lex_tuples[slex.FIRST]) print("PRE->FIRST") - print("full_blex_set before:") - print(prettier_map_string(_full_blex_set)) - print("full_blex_set new:") - print(prettier_map_string(full_blex_set)) + print("blex_set_to_subtract before:") + print(prettier_map_string(_blex_set_to_subtract)) + print("blex_set_to_subtract new:") + print(prettier_map_string(blex_set_to_subtract)) # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) - #full_blex_set |= _create_blex_set_from_tuple_pair( + #blex_set_to_subtract |= _create_blex_set_from_tuple_pair( # key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], # wrap_cond=True) # TODO remove: @@ -718,49 +818,54 @@ def _create_blex_set_from_tuple_pair( key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], _key_lex_tuples[slex.BOTTOM], _key_lex_tuples[slex.TOP], wrap_cond=True) - _full_blex_set |= _temp - full_blex_set |= temp + _blex_set_to_subtract |= _temp + blex_set_to_subtract |= temp # Leave loop case: LAST->POST - #full_blex_set |= _create_blex_set_from_tuple_pair( + #blex_set_to_subtract |= _create_blex_set_from_tuple_pair( # key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST]) # TODO remove temp, _temp = _create_blex_set_from_tuple_pair( key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST], _key_lex_tuples[slex.LAST], _key_lex_tuples[slex.POST], ) - _full_blex_set |= _temp - full_blex_set |= temp + _blex_set_to_subtract |= _temp + blex_set_to_subtract |= temp print("LAST->POST") - print("full_blex_set before:") + print("blex_set_to_subtract before:") print(prettier_map_string(_temp)) - print("full_blex_set new:") + print("blex_set_to_subtract new:") print(prettier_map_string(temp)) # Add condition to fix iteration value for *surrounding* loops (j = j') for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: s_blex_var = iname_to_blex_var[surrounding_iname] - full_blex_set &= blex_set_affs[s_blex_var].eq_set( + blex_set_to_subtract &= blex_set_affs[s_blex_var].eq_set( blex_set_affs[s_blex_var+BEFORE_MARK]) # TODO remove: for _surrounding_iname in _key_lex_tuples[slex.PRE][1::2]: _s_blex_var = iname_to_blex_var[_surrounding_iname] - _full_blex_set &= _blex_set_affs[_s_blex_var].eq_set( + _blex_set_to_subtract &= _blex_set_affs[_s_blex_var].eq_set( _blex_set_affs[_s_blex_var+BEFORE_MARK]) # Convert blex set back to map - map_to_subtract = isl.Map.from_domain(full_blex_set).move_dims( + map_to_subtract = isl.Map.from_domain(blex_set_to_subtract).move_dims( dim_type.out, 0, dim_type.in_, n_seq_blex_dims, n_seq_blex_dims) # TODO remove: - _map_to_subtract = isl.Map.from_domain(_full_blex_set).move_dims( + _map_to_subtract = isl.Map.from_domain(_blex_set_to_subtract).move_dims( dim_type.out, 0, dim_type.in_, n_seq_blex_dims, n_seq_blex_dims) + # TODO left off here, something wrong... + print("FULL MAP_TO_SUBTRACT FOR LOOP", iname) + print(prettier_map_string(map_to_subtract)) # Bound the blex dims by intersecting with the full blex map, which # contains all the bound constraints assert map_to_subtract.is_subset(blex_order_map) map_to_subtract &= blex_order_map + print("CONSTRAINED MAP_TO_SUBTRACT FOR LOOP", iname) + print(prettier_map_string(map_to_subtract)) # }}} @@ -770,6 +875,8 @@ def _create_blex_set_from_tuple_pair( # }}} + 1/0 + # {{{ Subtract transitive closure of union of blex maps to subtract if maps_to_subtract: @@ -938,7 +1045,6 @@ def get_pairwise_statement_orderings_inner( from loopy.schedule.checker.utils import ( add_and_name_isl_dims, append_mark_to_strings, - add_eq_isl_constraint_from_names, sorted_union_of_names_in_isl_sets, create_symbolic_map_from_tuples, insert_and_name_isl_dims, @@ -1174,6 +1280,7 @@ def get_pairwise_statement_orderings_inner( (stmt_inst_to_lblex, lblex_order_map, seq_lblex_dim_names) = _gather_blex_ordering_info( + knl, "local", lin_items, loops_with_barriers["local"], loop_bounds, loops_to_ignore, all_stmt_ids, iname_bounds_pwaff, @@ -1182,6 +1289,7 @@ def get_pairwise_statement_orderings_inner( (stmt_inst_to_gblex, gblex_order_map, seq_gblex_dim_names) = _gather_blex_ordering_info( + knl, "global", lin_items, loops_with_barriers["global"], loop_bounds, loops_to_ignore, all_stmt_ids, iname_bounds_pwaff, From cff0046621542da75025fbed48a815b7b6c0094d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 4 Sep 2021 18:40:18 -0500 Subject: [PATCH 180/220] (WIP) fix bug so that inames inside sets found in a 'before' tuple also get primed apprpriately --- loopy/schedule/checker/schedule.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 313ff8c29..332dae49d 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -26,6 +26,7 @@ add_and_name_isl_dims, add_eq_isl_constraint_from_names, append_mark_to_isl_map_var_names, + rename_dims, prettier_map_string, # noqa ) dim_type = isl.dim_type @@ -635,7 +636,9 @@ def _gather_blex_ordering_info( # Create mapping (dict) from iname to corresponding blex dim name iname_to_blex_var = {} + iname_to_iname_prime = {} for iname, dim in iname_to_blex_dim.items(): + iname_to_iname_prime[iname] = iname+BEFORE_MARK iname_to_blex_var[iname] = seq_blex_dim_names[dim] iname_to_blex_var[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] @@ -705,8 +708,20 @@ def _create_blex_set_from_tuple_pair( # Add marks to inames in the 'before' tuple # (all strings should be inames) + before_prime = [] + for v in before: + if isinstance(v, int): + before_prime.append(v) + elif isinstance(v, str): + before_prime.append(v+BEFORE_MARK) + else: + assert isinstance(v, isl.Set) + before_prime.append(rename_dims(v, iname_to_iname_prime)) + before_prime = tuple(before_prime) + """ before_prime = tuple( v+BEFORE_MARK if isinstance(v, str) else v for v in before) + """ before_padded = _pad_tuple_with_zeros(before_prime, n_seq_blex_dims) after_padded = _pad_tuple_with_zeros(after, n_seq_blex_dims) @@ -761,7 +776,6 @@ def _create_blex_set_from_tuple_pair( # Rename inames to corresponding blex var names # TODO does this catch all potential inames? - from loopy.schedule.checker.utils import rename_dims dim_val_renamed = rename_dims( dim_val_pre_aligned, iname_to_blex_var, [dim_type.set]) @@ -862,7 +876,6 @@ def _create_blex_set_from_tuple_pair( print(prettier_map_string(map_to_subtract)) # Bound the blex dims by intersecting with the full blex map, which # contains all the bound constraints - assert map_to_subtract.is_subset(blex_order_map) map_to_subtract &= blex_order_map print("CONSTRAINED MAP_TO_SUBTRACT FOR LOOP", iname) print(prettier_map_string(map_to_subtract)) @@ -875,8 +888,6 @@ def _create_blex_set_from_tuple_pair( # }}} - 1/0 - # {{{ Subtract transitive closure of union of blex maps to subtract if maps_to_subtract: From 993242b140f3f0633c93c86b30725e7f0d94b99d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 4 Sep 2021 19:07:29 -0500 Subject: [PATCH 181/220] (WIP) remove debugging comparisons to old version of blex map --- loopy/schedule/checker/schedule.py | 208 +++++------------------------ 1 file changed, 34 insertions(+), 174 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 332dae49d..52b4961af 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -75,7 +75,7 @@ #LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" #LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) LIN_CHECK_IDENTIFIER_PREFIX = "" # TODO change back after debug -LEX_VAR_PREFIX = "%slx" % (LIN_CHECK_IDENTIFIER_PREFIX) # TODO change back after debug +LEX_VAR_PREFIX = "%slx" % (LIN_CHECK_IDENTIFIER_PREFIX) # TODO change back STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) LTAG_VAR_NAMES = [] GTAG_VAR_NAMES = [] @@ -315,7 +315,6 @@ def _gather_blex_ordering_info( # create sub-maps which will be *excluded* (subtracted) from a standard # lexicographic ordering in order to create the blex ordering - # {{{ Determine the number of blex dims we will need max_nested_loops = 0 @@ -335,7 +334,7 @@ def _gather_blex_ordering_info( # }}} - # {{{ Create the initial (pre-subtraction) blex order map, initially without bounds + # {{{ Create the initial (pre-subtraction) blex order map, initially w/o bounds # Create names for the blex dimensions for sequential loops seq_blex_dim_names = [ @@ -351,21 +350,6 @@ def _gather_blex_ordering_info( in_dim_mark=BEFORE_MARK, ) - # Bound the non-iname blex variables (TODO by creating set of all blex points below) - """ - from loopy.schedule.checker.utils import add_int_bounds_to_isl_var - for idx in range(0, len(seq_blex_dim_names), 2): - #print(prettier_map_string(blex_order_map)) - blex_order_map = add_int_bounds_to_isl_var( - blex_order_map, seq_blex_dim_names[idx], 0, known_blex_dim_ubounds[idx]) - #print(prettier_map_string(blex_order_map)) - blex_order_map = add_int_bounds_to_isl_var( - blex_order_map, seq_blex_dim_names_prime[idx], 0, known_blex_dim_ubounds[idx]) - #print(prettier_map_string(blex_order_map)) - - """ - # Bound the iname blex variables (TODO by creating set of all blex points below) - # }}} # {{{ Create a template set for the space of all blex points @@ -389,11 +373,8 @@ def _gather_blex_ordering_info( stmt_inst_to_blex = {} # Map stmt instances to blex space iname_to_blex_dim = {} # Map from inames to corresponding blex space dim # OLD blex_exclusion_info, TODO remove - _blex_exclusion_info = {} # Info for creating maps to exclude from blex order blex_exclusion_info = {} # Info for creating maps to exclude from blex order - _blex_order_map_params = set() # TODO remove blex_order_map_params = set() # Params needed in blex order map - _n_seq_blex_dims = 1 # TODO remove Num dims representing sequential order in blex space next_blex_tuple = [0] # Next tuple of points in blex order print() # Debugging. TODO remove @@ -422,23 +403,9 @@ def _gather_blex_ordering_info( # Store 3 tuples that will be used later to create pairs # that will later be subtracted from the blex order map - # {{{ OLD version without lexmin/lexmax: - - _lbound = iname_bounds_pwaff[enter_iname][0] - _first_iter_blex_pt = next_blex_tuple[:] - _first_iter_blex_pt[-2] = _lbound - _blex_exclusion_info[enter_iname] = { - slex.PRE: tuple(pre_loop_blex_pt), - slex.TOP: tuple(next_blex_tuple), - slex.FIRST: tuple(_first_iter_blex_pt), - } - - # }}} - # {{{ NEW version with lexmin/lexmax print("Iname %s" % (enter_iname)) - print("OLD FIRST:", tuple(_first_iter_blex_pt)) print("lexmin:") print(loop_bounds[enter_iname][0]) @@ -459,8 +426,8 @@ def _gather_blex_ordering_info( # the lists will continue to be updated) # Store any new params found - _blex_order_map_params |= set(_lbound.get_var_names(dim_type.param)) # TODO remove - blex_order_map_params |= set(lbound.get_var_names(dim_type.param)) # might include inames + # (might include inames) + blex_order_map_params |= set(lbound.get_var_names(dim_type.param)) # {{{ NEW NEW stuff: create the blex set for this blex point @@ -469,16 +436,12 @@ def _gather_blex_ordering_info( # }}} - elif isinstance(lin_item, LeaveLoop): leave_iname = lin_item.iname if leave_iname in loops_with_barriers - loops_to_ignore: curr_blex_dim_ct = len(next_blex_tuple) - # Update max blex dims - _n_seq_blex_dims = max(_n_seq_blex_dims, curr_blex_dim_ct) - # Record the blex dim for this loop iname iname_to_blex_dim[leave_iname] = curr_blex_dim_ct-2 @@ -499,24 +462,9 @@ def _gather_blex_ordering_info( # Store 3 tuples that will be used later to create pairs # that will later be subtracted from the blex order map - # {{{ OLD version without lexmin/lexmax: - - _ubound = iname_bounds_pwaff[leave_iname][1] - _last_iter_blex_pt = pre_end_loop_blex_pt[:] - _last_iter_blex_pt[-2] = _ubound - _blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( - pre_end_loop_blex_pt) - _blex_exclusion_info[leave_iname][slex.LAST] = tuple( - _last_iter_blex_pt) - _blex_exclusion_info[leave_iname][slex.POST] = tuple( - next_blex_tuple) - - # }}} - # {{{ NEW version with lexmin/lexmax print("Iname %s" % (leave_iname)) - print("OLD LAST:", tuple(_last_iter_blex_pt)) print("lexmax:") print(loop_bounds[leave_iname][1]) @@ -536,7 +484,6 @@ def _gather_blex_ordering_info( # the lists will continue to be updated) # Store any new params found - _blex_order_map_params |= set(_ubound.get_var_names(dim_type.param)) # TODO remove blex_order_map_params |= set(ubound.get_var_names(dim_type.param)) # {{{ NEW NEW stuff: create the blex set for this blex point @@ -580,7 +527,8 @@ def _gather_blex_ordering_info( # time) if lp_stmt_id in all_stmt_ids: - # Assign a blex point to this barrier just as we would for an assignment stmt + # Assign a blex point to this barrier just as we would for an + # assignment stmt stmt_inst_to_blex[lp_stmt_id] = tuple(next_blex_tuple) # If sync scope matches, give this barrier its *own* point in @@ -591,7 +539,7 @@ def _gather_blex_ordering_info( # {{{ NEW NEW stuff: create the blex set for this blex point all_blex_points = _add_one_blex_tuple( - all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) + all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) # }}} else: @@ -601,14 +549,10 @@ def _gather_blex_ordering_info( lin_item, (CallKernel, ReturnFromKernel)) pass - assert n_seq_blex_dims == _n_seq_blex_dims # TODO remove - # Record the max value for the 0th non-iname blex dim known_blex_dim_ubounds[0] = max( next_blex_tuple[-1], known_blex_dim_ubounds[0]) - _blex_order_map_params = sorted(_blex_order_map_params) # TODO remove - #blex_order_map_params = sorted(blex_order_map_params) # Don't want inames in blex map params, remove them # TODO: could we have introduced inames other than loops_with_barriers? blex_order_map_params = sorted(blex_order_map_params - loops_with_barriers) @@ -649,7 +593,6 @@ def _gather_blex_ordering_info( blex_order_map = add_and_name_isl_dims( blex_order_map, dim_type.param, blex_order_map_params) """ - _blex_order_map = blex_order_map.copy() # TODO remove # Get a set representing blex_order_map space blex_mapset_template = isl.align_spaces( @@ -659,20 +602,10 @@ def _gather_blex_ordering_info( ).domain() blex_set_affs = isl.affs_from_space(blex_mapset_template.space) - # TODO remove: - _blex_mapset_template = isl.align_spaces( - isl.Map("[ ] -> { [ ] -> [ ] }"), _blex_order_map - ).move_dims( - dim_type.in_, n_seq_blex_dims, dim_type.out, 0, n_seq_blex_dims - ).domain() - _blex_set_affs = isl.affs_from_space(_blex_mapset_template.space) - # {{{ Create blex map to subtract for each iname in blex_exclusion_info maps_to_subtract = [] for iname, key_lex_tuples in blex_exclusion_info.items(): - _iname = iname # TODO remove - _key_lex_tuples = _blex_exclusion_info[_iname] # TODO remove print("") print(iname) @@ -689,9 +622,7 @@ def _gather_blex_ordering_info( # {{{ _create_blex_set_from_tuple_pair - # def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): - def _create_blex_set_from_tuple_pair( - before, after, _before, _after, wrap_cond=False): # TODO switch back + def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): """Given a before->after tuple pair in the key_lex_tuples, which may have dim vals described by ints, strings (inames), and pwaffs, create an ISL set in blex space that can be converted into @@ -703,7 +634,6 @@ def _create_blex_set_from_tuple_pair( # seq_blex_dim_names_prime) # Start with a set representing blex_order_map space - _blex_set = _blex_mapset_template.copy() # TODO remove blex_set = blex_mapset_template.copy() # Add marks to inames in the 'before' tuple @@ -725,20 +655,10 @@ def _create_blex_set_from_tuple_pair( before_padded = _pad_tuple_with_zeros(before_prime, n_seq_blex_dims) after_padded = _pad_tuple_with_zeros(after, n_seq_blex_dims) - # TODO remove: - _before_prime = tuple( - v+BEFORE_MARK if isinstance(v, str) else v for v in _before) - _before_padded = _pad_tuple_with_zeros(_before_prime, n_seq_blex_dims) - _after_padded = _pad_tuple_with_zeros(_after, n_seq_blex_dims) - # Assign vals in the tuple to dims in the ISL set - #for dim_name, dim_val in zip( - # seq_blex_dim_names_prime+seq_blex_dim_names, - # before_padded+after_padded): - for dim_name, dim_val, _dim_val in zip( # TODO remove + for dim_name, dim_val in zip( seq_blex_dim_names_prime+seq_blex_dim_names, - before_padded+after_padded, - _before_padded+_after_padded): + before_padded+after_padded): if isinstance(dim_val, int): # Set idx to int val @@ -749,28 +669,17 @@ def _create_blex_set_from_tuple_pair( blex_set &= blex_set_affs[dim_name].eq_set( blex_set_affs[iname_to_blex_var[dim_val]]) else: - """ - # This is a pwaff iname bound, align and intersect - assert isinstance(dim_val, isl.PwMultiAff) - if dim_val.n_piece() != 1: - raise NotImplementedError( - "lexmin_pw_multi_aff() of inames domain for %s and surrounding " - "loops has more than one piece.") - dim_val_pwaff = dim_val.get_pw_aff(0) - assert isinstance(dim_val_pwaff, isl.PwAff) - pwaff_aligned = isl.align_spaces(dim_val_pwaff, blex_set_affs[0]) - # (doesn't matter which blex_set_affs item we align to^) - blex_set &= blex_set_affs[dim_name].eq_set(pwaff_aligned) - """ # TODO figure out best place to do this: # Rename dims and align dim_val so it can intersect w/blex_set - # There might be inames as params in dim_val, move them to set dim - dim_val_pre_aligned = dim_val.copy() # maybe we can remove this copy - for var_name in dim_val_pre_aligned.get_var_names(dim_type.param): + # There may be inames as params in dim_val, move them to set dim + dim_val_pre_aligned = dim_val.copy() # TODO maybe remove copy + for var_name in dim_val_pre_aligned.get_var_names( + dim_type.param): if var_name in iname_to_blex_var: + # Get idx of var_name (might have moved since loop start) idx = dim_val_pre_aligned.find_dim_by_name( - dim_type.param, var_name) # (might have moved since loop start) + dim_type.param, var_name) dim_val_pre_aligned = dim_val_pre_aligned.move_dims( dim_type.out, 0, dim_type.param, idx, 1) @@ -779,33 +688,16 @@ def _create_blex_set_from_tuple_pair( dim_val_renamed = rename_dims( dim_val_pre_aligned, iname_to_blex_var, [dim_type.set]) - dim_val_aligned = isl.align_spaces(dim_val_renamed, blex_mapset_template) + dim_val_aligned = isl.align_spaces( + dim_val_renamed, blex_mapset_template) blex_set &= dim_val_aligned - # TODO remove - if isinstance(_dim_val, int): - # Set idx to int val - _blex_set &= _blex_set_affs[dim_name].eq_set( - _blex_set_affs[0]+_dim_val) - elif isinstance(_dim_val, str): - # This is an iname, set idx to corresponding blex var - _blex_set &= _blex_set_affs[dim_name].eq_set( - _blex_set_affs[iname_to_blex_var[_dim_val]]) - else: - # This is a pwaff iname bound, align and intersect - assert isinstance(_dim_val, isl.PwAff) - _pwaff_aligned = isl.align_spaces(_dim_val, _blex_set_affs[0]) - # (doesn't matter which blex_set_affs item we align to^) - _blex_set &= _blex_set_affs[dim_name].eq_set(_pwaff_aligned) - if wrap_cond: # This is the BOTTOM->TOP pair, add condition i = i' + 1 - _blex_set &= _blex_set_affs[iname_to_blex_var[_iname]].eq_set( # TODO remove - _blex_set_affs[iname_to_blex_var[_iname+BEFORE_MARK]] + 1) blex_set &= blex_set_affs[iname_to_blex_var[iname]].eq_set( blex_set_affs[iname_to_blex_var[iname+BEFORE_MARK]] + 1) - return blex_set, _blex_set + return blex_set # }}} end _create_blex_set_from_tuple_pair() @@ -813,41 +705,26 @@ def _create_blex_set_from_tuple_pair( # (set will be converted to map) # Enter loop case: PRE->FIRST - #blex_set_to_subtract = _create_blex_set_from_tuple_pair( - # key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST]) - blex_set_to_subtract, _blex_set_to_subtract = _create_blex_set_from_tuple_pair( # TODO remove - key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST], - _key_lex_tuples[slex.PRE], _key_lex_tuples[slex.FIRST]) + blex_set_to_subtract = _create_blex_set_from_tuple_pair( + key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST]) print("PRE->FIRST") - print("blex_set_to_subtract before:") - print(prettier_map_string(_blex_set_to_subtract)) print("blex_set_to_subtract new:") print(prettier_map_string(blex_set_to_subtract)) # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) - #blex_set_to_subtract |= _create_blex_set_from_tuple_pair( - # key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], - # wrap_cond=True) - # TODO remove: - temp, _temp = _create_blex_set_from_tuple_pair( + # TODO union in place: + temp = _create_blex_set_from_tuple_pair( key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], - _key_lex_tuples[slex.BOTTOM], _key_lex_tuples[slex.TOP], wrap_cond=True) - _blex_set_to_subtract |= _temp blex_set_to_subtract |= temp # Leave loop case: LAST->POST #blex_set_to_subtract |= _create_blex_set_from_tuple_pair( # key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST]) - # TODO remove - temp, _temp = _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST], - _key_lex_tuples[slex.LAST], _key_lex_tuples[slex.POST], - ) - _blex_set_to_subtract |= _temp + # TODO union in place: + temp = _create_blex_set_from_tuple_pair( + key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST],) blex_set_to_subtract |= temp print("LAST->POST") - print("blex_set_to_subtract before:") - print(prettier_map_string(_temp)) print("blex_set_to_subtract new:") print(prettier_map_string(temp)) @@ -857,21 +734,10 @@ def _create_blex_set_from_tuple_pair( blex_set_to_subtract &= blex_set_affs[s_blex_var].eq_set( blex_set_affs[s_blex_var+BEFORE_MARK]) - # TODO remove: - for _surrounding_iname in _key_lex_tuples[slex.PRE][1::2]: - _s_blex_var = iname_to_blex_var[_surrounding_iname] - _blex_set_to_subtract &= _blex_set_affs[_s_blex_var].eq_set( - _blex_set_affs[_s_blex_var+BEFORE_MARK]) - # Convert blex set back to map map_to_subtract = isl.Map.from_domain(blex_set_to_subtract).move_dims( dim_type.out, 0, dim_type.in_, n_seq_blex_dims, n_seq_blex_dims) - # TODO remove: - _map_to_subtract = isl.Map.from_domain(_blex_set_to_subtract).move_dims( - dim_type.out, 0, dim_type.in_, n_seq_blex_dims, n_seq_blex_dims) - - # TODO left off here, something wrong... print("FULL MAP_TO_SUBTRACT FOR LOOP", iname) print(prettier_map_string(map_to_subtract)) # Bound the blex dims by intersecting with the full blex map, which @@ -882,8 +748,6 @@ def _create_blex_set_from_tuple_pair( # }}} - # TODO no more comparison of old vs new after this point - maps_to_subtract.append(map_to_subtract) # }}} @@ -909,8 +773,7 @@ def _create_blex_set_from_tuple_pair( assert closure_exact # TODO warn instead? - #""" - # {{{ Check some assumptions related to result of subtraction being transitive + # {{{ Check some assumptions about result of subtraction being transitive from copy import deepcopy # Make sure blex order map is transitive @@ -934,8 +797,6 @@ def _create_blex_set_from_tuple_pair( print("yes") # }}} - #""" - print("blex_order_map FULL") print(prettier_map_string(blex_order_map)) #print(blex_order_map) @@ -943,8 +804,6 @@ def _create_blex_set_from_tuple_pair( # Subtract closure from blex order map blex_order_map = blex_order_map - map_to_subtract_closure - #""" - # TODO check if map_to_subtract/map_to_subtract_closure is indeed subset of blex_order_map print("subtraction map for %s barriers" % (sync_kind)) print(prettier_map_string(map_to_subtract_closure)) #print(map_to_subtract_closure) @@ -962,9 +821,8 @@ def _create_blex_set_from_tuple_pair( "IS RESULT OF SUBTRACTION TRANSITIVE?", closure_test == blex_order_map ) - #assert closure_test == blex_order_map - #print("yes") - #""" + assert closure_test == blex_order_map + print("yes") # }}} @@ -1159,7 +1017,7 @@ def get_pairwise_statement_orderings_inner( # Get inames domain # TODO it's possible that we can project out more inames, # how do we figure out which ones to project out? - # TODO what if this iname bound also depends on a concurrent iname? + # TODO what if this iname bound depends on a concurrent iname? dom = knl.get_inames_domain( inames_involved_in_bound).project_out_except( inames_involved_in_bound, [dim_type.set]) @@ -1177,8 +1035,10 @@ def get_pairwise_statement_orderings_inner( # }}} - loop_bounds[iname] = (dom.lexmin(), dom.lexmax(), dom) # TODO adding dom for now - #loop_bounds[iname] = (dom.lexmin_pw_multi_aff(), dom.lexmax_pw_multi_aff()) + loop_bounds[iname] = (dom.lexmin(), dom.lexmax(), dom) + # TODO adding dom^ for now + #loop_bounds[iname] = ( + # dom.lexmin_pw_multi_aff(), dom.lexmax_pw_multi_aff()) # }}} From 41640fbbf3f1fdcd84d7ff375b7e910b439e9945 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 5 Sep 2021 20:12:23 -0500 Subject: [PATCH 182/220] (WIP) initial implementation of less messy machinery for producing the blex map to subtract --- loopy/schedule/checker/schedule.py | 280 +++++++++++++++++++++++++---- test/test_linearization_checker.py | 2 +- 2 files changed, 248 insertions(+), 34 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 52b4961af..9722c64c4 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -32,6 +32,22 @@ dim_type = isl.dim_type +# TODO delete this: +def _align_and_compare_maps(maps): + from loopy.schedule.checker.utils import ( + ensure_dim_names_match_and_align, + ) + + for map1, map2 in maps: + # Align maps and compare + map1_aligned = ensure_dim_names_match_and_align(map1, map2) + if map1_aligned != map2: + print("Maps not equal:") + print(prettier_map_string(map1_aligned)) + print(prettier_map_string(map2)) + assert map1_aligned == map2 + + # {{{ Constants __doc__ = """ @@ -234,11 +250,27 @@ def _find_and_rename_dim(isl_obj, dt, old_name, new_name): dt, isl_obj.find_dim_by_name(dt, old_name), new_name) +def _find_and_rename_dims(isl_obj, dt, rename_dict): + # TODO remove this func once it's merged into isl_helpers + for old_name, new_name in rename_dict.items(): + isl_obj = isl_obj.set_dim_name( + dt, isl_obj.find_dim_by_name(dt, old_name), new_name) + return isl_obj + + +def _add_eq_isl_constraints_for_ints_only(isl_obj, assignment_pairs): + for dim_name, val in assignment_pairs: + if isinstance(val, int): + isl_obj = add_eq_isl_constraint_from_names( + isl_obj, dim_name, val) + return isl_obj + + def _add_one_blex_tuple( - all_blex_points, blex_tuple, seq_blex_dim_names, knl): + all_blex_points, blex_tuple, all_seq_blex_dim_names, knl): # blex_tuple contains 1 dim plus 2 dims for each *current* loop, so it may - # be shorter than seq_blex_dim_names, which contains *all* the blex dim + # be shorter than all_seq_blex_dim_names, which contains *all* the blex dim # names current_inames = blex_tuple[1::2] @@ -255,7 +287,7 @@ def _add_one_blex_tuple( # Rename iname dims to blex dims for depth, iname in enumerate(current_inames): - blex_dim_name = seq_blex_dim_names[1 + 2*depth] + blex_dim_name = all_seq_blex_dim_names[1 + 2*depth] dom = _find_and_rename_dim(dom, dim_type.set, iname, blex_dim_name) # Add any new params to all_blex_points @@ -269,10 +301,10 @@ def _add_one_blex_tuple( dom = isl.align_spaces(dom, all_blex_points) # Set values for non-iname blex dims - for blex_dim_name, blex_val in zip(seq_blex_dim_names[::2], blex_tuple[::2]): + for blex_dim_name, blex_val in zip(all_seq_blex_dim_names[::2], blex_tuple[::2]): dom = add_eq_isl_constraint_from_names(dom, blex_dim_name, blex_val) # Set any unused (rightmost, fastest-updating) blex dims to zero - for blex_dim_name in seq_blex_dim_names[len(blex_tuple):]: + for blex_dim_name in all_seq_blex_dim_names[len(blex_tuple):]: dom = add_eq_isl_constraint_from_names(dom, blex_dim_name, 0) # Add this blex set to full set of blex points @@ -284,8 +316,9 @@ def _add_one_blex_tuple( def _gather_blex_ordering_info( knl, sync_kind, - lin_items, loops_with_barriers, loop_bounds, loops_to_ignore, - all_stmt_ids, iname_bounds_pwaff, + lin_items, loops_with_barriers, + loops_to_ignore, loop_bounds, new_loop_bounds, + all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, ): """For the given sync_kind ("local" or "global"), create a mapping from @@ -374,6 +407,7 @@ def _gather_blex_ordering_info( iname_to_blex_dim = {} # Map from inames to corresponding blex space dim # OLD blex_exclusion_info, TODO remove blex_exclusion_info = {} # Info for creating maps to exclude from blex order + new_blex_exclusion_info = {} # Info for creating maps to exclude from blex order blex_order_map_params = set() # Params needed in blex order map next_blex_tuple = [0] # Next tuple of points in blex order @@ -409,7 +443,7 @@ def _gather_blex_ordering_info( print("lexmin:") print(loop_bounds[enter_iname][0]) - lbound = loop_bounds[enter_iname][0] # pwaff + lbound = loop_bounds[enter_iname][0] first_iter_blex_pt = next_blex_tuple[:] first_iter_blex_pt[-2] = lbound blex_exclusion_info[enter_iname] = { @@ -418,6 +452,14 @@ def _gather_blex_ordering_info( slex.FIRST: tuple(first_iter_blex_pt), } + # TODO switch to this: + first_iter_blex_pt[-2] = enter_iname + new_blex_exclusion_info[enter_iname] = { + slex.PRE: tuple(pre_loop_blex_pt), + slex.TOP: tuple(next_blex_tuple), + slex.FIRST: tuple(first_iter_blex_pt), + } + # Create the set of blex points to add # }}} @@ -478,6 +520,15 @@ def _gather_blex_ordering_info( blex_exclusion_info[leave_iname][slex.POST] = tuple( next_blex_tuple) + # TODO switch to this: + last_iter_blex_pt[-2] = leave_iname + new_blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( + pre_end_loop_blex_pt) + new_blex_exclusion_info[leave_iname][slex.LAST] = tuple( + last_iter_blex_pt) + new_blex_exclusion_info[leave_iname][slex.POST] = tuple( + next_blex_tuple) + # }}} # (copy these three blex points when creating dict because @@ -602,10 +653,17 @@ def _gather_blex_ordering_info( ).domain() blex_set_affs = isl.affs_from_space(blex_mapset_template.space) + # New version + blex_map_template = isl.align_spaces( + isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map) + blex_set_template = blex_map_template.range() + #blex_set_template_prime = append_mark_to_isl_map_var_names(blex_set_template) + # {{{ Create blex map to subtract for each iname in blex_exclusion_info maps_to_subtract = [] for iname, key_lex_tuples in blex_exclusion_info.items(): + new_key_lex_tuples = new_blex_exclusion_info[iname] print("") print(iname) @@ -706,10 +764,56 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # Enter loop case: PRE->FIRST blex_set_to_subtract = _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST]) + key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST], + ) print("PRE->FIRST") print("blex_set_to_subtract new:") print(prettier_map_string(blex_set_to_subtract)) + + # {{{ New version: + + # {{{ PRE->FIRST + + # Values in PRE should be strings (inames) or ints. + # We actually already know which blex dims correspond to the inames + # due to their position, and their bounds will be set later by intersecting + # the subtraction map with the (bounded) full blex map. + # We only need to set the values for blex dims that will be ints, + # i.e., the intra-loop-section blex dims and any trailing zeros. + + # Values in FIRST will involve one of our lexmin bounds. + + first_tuple = new_key_lex_tuples[slex.FIRST] + first_tuple_padded = _pad_tuple_with_zeros(first_tuple, n_seq_blex_dims) + pre_tuple_padded = _pad_tuple_with_zeros( + new_key_lex_tuples[slex.PRE], n_seq_blex_dims) + # Assign int dims; all other dims will have any necessary bounds set + # later by intersecting with the (bounded) full blex map + pre_to_first_map = _add_eq_isl_constraints_for_ints_only( + blex_map_template, + zip( + seq_blex_dim_names_prime+seq_blex_dim_names, + pre_tuple_padded+first_tuple_padded)) + + loop_min_bound = new_loop_bounds[iname][0] + + # Rename iname dims to blex dims + # TODO could there be any other inames involved besides first_tuple[1::2]? + loop_min_bound = _find_and_rename_dims( + loop_min_bound, dim_type.set, + {k: iname_to_blex_var[k] for k in first_tuple[1::2]}) + # Align with blex space (adds needed dims) + loop_first_set = isl.align_spaces(loop_min_bound, blex_set_template) + + # Make PRE->FIRST pair by intersecting this with the range of our map + pre_to_first_map = pre_to_first_map.intersect_range(loop_first_set) + + # }}} + + # }}} + + print(prettier_map_string(pre_to_first_map)) + # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) # TODO union in place: temp = _create_blex_set_from_tuple_pair( @@ -717,38 +821,130 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): wrap_cond=True) blex_set_to_subtract |= temp + # {{{ New version: + + # {{{ BOTTOM->TOP + + # Values in BOTTOM/TOP should be strings (inames) or ints. + # We actually already know which blex dims correspond to the inames + # due to their position, and their bounds will be set later by intersecting + # the subtraction map with the (bounded) full blex map. + # We only need to set the values for blex dims that will be ints, + # i.e., the intra-loop-section blex dims and any trailing zeros. + bottom_tuple_padded = _pad_tuple_with_zeros( + new_key_lex_tuples[slex.BOTTOM], n_seq_blex_dims) + top_tuple_padded = _pad_tuple_with_zeros( + new_key_lex_tuples[slex.TOP], n_seq_blex_dims) + bottom_to_top_map = _add_eq_isl_constraints_for_ints_only( + blex_map_template, + zip( + seq_blex_dim_names_prime+seq_blex_dim_names, + bottom_tuple_padded+top_tuple_padded)) + + # Add constraint i = i' + 1 + blex_var_for_iname = iname_to_blex_var[iname] + bottom_to_top_map = bottom_to_top_map.add_constraint( + isl.Constraint.eq_from_names( + bottom_to_top_map.space, + {1: 1, blex_var_for_iname + BEFORE_MARK: 1, blex_var_for_iname: -1})) + + # }}} + + # }}} + + print(prettier_map_string(bottom_to_top_map)) + # Leave loop case: LAST->POST #blex_set_to_subtract |= _create_blex_set_from_tuple_pair( # key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST]) # TODO union in place: temp = _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST],) + key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST], + ) blex_set_to_subtract |= temp print("LAST->POST") print("blex_set_to_subtract new:") print(prettier_map_string(temp)) + # {{{ New version: + + # {{{ LAST->POST + + # Values in POST should be strings (inames) or ints. + # We actually already know which blex dims correspond to the inames + # due to their position, and their bounds will be set later by intersecting + # the subtraction map with the (bounded) full blex map. + # We only need to set the values for blex dims that will be ints, + # i.e., the intra-loop-section blex dims and any trailing zeros. + + # Values in last will involve one of our lexmax bounds. + + last_tuple = new_key_lex_tuples[slex.LAST] + last_tuple_padded = _pad_tuple_with_zeros(last_tuple, n_seq_blex_dims) + post_tuple_padded = _pad_tuple_with_zeros( + new_key_lex_tuples[slex.POST], n_seq_blex_dims) + # Assign int dims; all other dims will have any necessary bounds set + # later by intersecting with the (bounded) full blex map + last_to_post_map = _add_eq_isl_constraints_for_ints_only( + blex_map_template, + zip( + seq_blex_dim_names_prime+seq_blex_dim_names, + last_tuple_padded+post_tuple_padded)) + + loop_max_bound = new_loop_bounds[iname][1] + + # Rename iname dims to blex dims + # TODO could there be any other inames involved besides last_tuple[1::2]? + loop_max_bound = _find_and_rename_dims( + loop_max_bound, dim_type.set, + {k: iname_to_blex_var[k] for k in last_tuple[1::2]}) + # Align with blex space (adds needed dims) + loop_last_set = isl.align_spaces(loop_max_bound, blex_set_template) + # These blex vars should all have BEFORE_MARK but that will be added + # when we intersect_domain below + + # Make PRE->FIRST pair by intersecting this with the range of our map + last_to_post_map = last_to_post_map.intersect_domain(loop_last_set) + + # }}} + + # }}} + + print(prettier_map_string(last_to_post_map)) + blex_map_to_subtract = pre_to_first_map | bottom_to_top_map | last_to_post_map + # Add condition to fix iteration value for *surrounding* loops (j = j') + # (odd indices in key_lex_tuples[PRE] contain the sounding inames) + # TODO make sure this is still the right strategy given new approach for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: s_blex_var = iname_to_blex_var[surrounding_iname] blex_set_to_subtract &= blex_set_affs[s_blex_var].eq_set( blex_set_affs[s_blex_var+BEFORE_MARK]) + # Add condition to fix iteration value for *surrounding* loops (j = j') + # (odd indices in key_lex_tuples[PRE] contain the sounding inames) + for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: + s_blex_var = iname_to_blex_var[surrounding_iname] + blex_map_to_subtract = add_eq_isl_constraint_from_names( + blex_map_to_subtract, s_blex_var, s_blex_var+BEFORE_MARK) + # Convert blex set back to map map_to_subtract = isl.Map.from_domain(blex_set_to_subtract).move_dims( dim_type.out, 0, dim_type.in_, n_seq_blex_dims, n_seq_blex_dims) + _align_and_compare_maps([(blex_map_to_subtract, map_to_subtract)]) + print("FULL MAP_TO_SUBTRACT FOR LOOP", iname) print(prettier_map_string(map_to_subtract)) # Bound the blex dims by intersecting with the full blex map, which # contains all the bound constraints - map_to_subtract &= blex_order_map + blex_map_to_subtract &= blex_order_map print("CONSTRAINED MAP_TO_SUBTRACT FOR LOOP", iname) - print(prettier_map_string(map_to_subtract)) + print(prettier_map_string(blex_map_to_subtract)) # }}} - maps_to_subtract.append(map_to_subtract) + maps_to_subtract.append(blex_map_to_subtract) # }}} @@ -944,9 +1140,11 @@ def get_pairwise_statement_orderings_inner( # While we're passing through, also determine the values of the active # inames on the first and last iteration of each loop that contains - # barriers. We will need these later on when creating the FIRST and LAST - # blex points. + # barriers (dom.lexmin/lexmax). + # This information will be used later when creating *intra-group* and + # *global* lexicographic orderings loop_bounds = {} + new_loop_bounds = {} for lin_item in lin_items: if isinstance(lin_item, EnterLoop): @@ -1011,12 +1209,13 @@ def get_pairwise_statement_orderings_inner( # If we haven't already stored bounds for this iname, do so if iname not in loop_bounds: - # Get set of inames nested outside (including this iname) + # Get set of inames that might be involved in this bound + # (this iname plus any nested outside this iname) inames_involved_in_bound = set(current_inames[:depth+1]) # Get inames domain - # TODO it's possible that we can project out more inames, - # how do we figure out which ones to project out? + # (It's possible that we can project out more inames, + # but for now, don't.) # TODO what if this iname bound depends on a concurrent iname? dom = knl.get_inames_domain( inames_involved_in_bound).project_out_except( @@ -1040,6 +1239,24 @@ def get_pairwise_statement_orderings_inner( #loop_bounds[iname] = ( # dom.lexmin_pw_multi_aff(), dom.lexmax_pw_multi_aff()) + lmin = dom.lexmin() + lmax = dom.lexmax() + + # Now move param inames back to set dim + for outer_iname in current_inames[:depth]: + outer_iname_idx = lmin.find_dim_by_name( + dim_type.param, outer_iname) + lmin = lmin.move_dims( + dim_type.set, 0, dim_type.param, + outer_iname_idx, 1) + outer_iname_idx = lmax.find_dim_by_name( + dim_type.param, outer_iname) + lmax = lmax.move_dims( + dim_type.set, 0, dim_type.param, + outer_iname_idx, 1) + + new_loop_bounds[iname] = (lmin, lmax) + # }}} if lp_stmt_id is None: @@ -1068,13 +1285,18 @@ def get_pairwise_statement_orderings_inner( pass # Debugging.... (TODO remove) - from loopy.schedule.checker.utils import prettier_map_string for iname, (lbound, ubound, dom) in loop_bounds.items(): print(iname) print(prettier_map_string(lbound)) print(prettier_map_string(ubound)) print(prettier_map_string(dom)) + print() + for iname, (lbound, ubound) in new_loop_bounds.items(): + print(iname) + print(prettier_map_string(lbound)) + print(prettier_map_string(ubound)) + # }}} # {{{ Create lex dim names representing parallel axes @@ -1132,16 +1354,6 @@ def get_pairwise_statement_orderings_inner( lex order map, yielding the 'blex' order map. """ - # {{{ Get upper and lower bound for each loop that contains a barrier - - iname_bounds_pwaff = {} - for iname in loops_with_barriers["local"] | loops_with_barriers["global"]: - bounds = knl.get_iname_bounds(iname) - iname_bounds_pwaff[iname] = ( - bounds.lower_bound_pw_aff, bounds.upper_bound_pw_aff) - - # }}} - # {{{ Create blex order maps and blex tuples defining statement ordering (x2) all_par_lex_dim_names = lid_lex_dim_names + gid_lex_dim_names @@ -1153,8 +1365,9 @@ def get_pairwise_statement_orderings_inner( seq_lblex_dim_names) = _gather_blex_ordering_info( knl, "local", - lin_items, loops_with_barriers["local"], loop_bounds, loops_to_ignore, - all_stmt_ids, iname_bounds_pwaff, + lin_items, loops_with_barriers["local"], + loops_to_ignore, loop_bounds, new_loop_bounds, + all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, ) (stmt_inst_to_gblex, @@ -1162,8 +1375,9 @@ def get_pairwise_statement_orderings_inner( seq_gblex_dim_names) = _gather_blex_ordering_info( knl, "global", - lin_items, loops_with_barriers["global"], loop_bounds, loops_to_ignore, - all_stmt_ids, iname_bounds_pwaff, + lin_items, loops_with_barriers["global"], + loops_to_ignore, loop_bounds, new_loop_bounds, + all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, ) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 1ad715fc5..40ccc5118 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -214,7 +214,7 @@ def _process_and_linearize(knl, knl_name="loopy_kernel"): pworders = get_pairwise_statement_orderings( lin_knl, lin_items, stmt_id_pairs) -1/0 +#1/0 # {{{ test_intra_thread_pairwise_schedule_creation() From d273bfdb5b845af1cba55afd8fd6ac03e551d7b3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 5 Sep 2021 21:16:31 -0500 Subject: [PATCH 183/220] (WIP) remove a bunch of old code that has now been replaced; clean up new code a little; make transitivity checks an official option via boolean arg --- loopy/schedule/checker/schedule.py | 385 +++++------------------------ 1 file changed, 64 insertions(+), 321 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 9722c64c4..48113129a 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -26,7 +26,6 @@ add_and_name_isl_dims, add_eq_isl_constraint_from_names, append_mark_to_isl_map_var_names, - rename_dims, prettier_map_string, # noqa ) dim_type = isl.dim_type @@ -266,6 +265,12 @@ def _add_eq_isl_constraints_for_ints_only(isl_obj, assignment_pairs): return isl_obj +def _assert_exact_closure(mapping): + closure_test, closure_exact = mapping.transitive_closure() + assert closure_exact + assert closure_test == mapping + + def _add_one_blex_tuple( all_blex_points, blex_tuple, all_seq_blex_dim_names, knl): @@ -317,9 +322,10 @@ def _gather_blex_ordering_info( knl, sync_kind, lin_items, loops_with_barriers, - loops_to_ignore, loop_bounds, new_loop_bounds, + loops_to_ignore, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, + perform_closure_checks=False, ): """For the given sync_kind ("local" or "global"), create a mapping from statement instances to blex space (dict), as well as a mapping @@ -387,13 +393,10 @@ def _gather_blex_ordering_info( # {{{ Create a template set for the space of all blex points - # TODO if we only use this template once, don't save it - blex_set_template = isl.align_spaces( - isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map).range() - # Create set of all blex points by starting with (0, 0, 0, ...) # and then unioning this with each new set of blex points we find - all_blex_points = blex_set_template.copy() # TODO do we need to copy? + all_blex_points = isl.align_spaces( + isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map).range() for var_name in seq_blex_dim_names: all_blex_points = add_eq_isl_constraint_from_names( all_blex_points, var_name, 0) @@ -405,13 +408,9 @@ def _gather_blex_ordering_info( # TODO may be able to remove some of this stuff now: stmt_inst_to_blex = {} # Map stmt instances to blex space iname_to_blex_dim = {} # Map from inames to corresponding blex space dim - # OLD blex_exclusion_info, TODO remove blex_exclusion_info = {} # Info for creating maps to exclude from blex order - new_blex_exclusion_info = {} # Info for creating maps to exclude from blex order - blex_order_map_params = set() # Params needed in blex order map next_blex_tuple = [0] # Next tuple of points in blex order - print() # Debugging. TODO remove known_blex_dim_ubounds = [0, ] # Place to store bounds for non-iname blex dims # TODO handle case where one non-iname blex dim is used in multiple # separate loops? @@ -437,41 +436,17 @@ def _gather_blex_ordering_info( # Store 3 tuples that will be used later to create pairs # that will later be subtracted from the blex order map - # {{{ NEW version with lexmin/lexmax - - print("Iname %s" % (enter_iname)) - print("lexmin:") - print(loop_bounds[enter_iname][0]) - - lbound = loop_bounds[enter_iname][0] first_iter_blex_pt = next_blex_tuple[:] - first_iter_blex_pt[-2] = lbound - blex_exclusion_info[enter_iname] = { - slex.PRE: tuple(pre_loop_blex_pt), - slex.TOP: tuple(next_blex_tuple), - slex.FIRST: tuple(first_iter_blex_pt), - } - - # TODO switch to this: first_iter_blex_pt[-2] = enter_iname - new_blex_exclusion_info[enter_iname] = { + blex_exclusion_info[enter_iname] = { slex.PRE: tuple(pre_loop_blex_pt), slex.TOP: tuple(next_blex_tuple), slex.FIRST: tuple(first_iter_blex_pt), } - - # Create the set of blex points to add - - # }}} - # (copy these three blex points when creating dict because # the lists will continue to be updated) - # Store any new params found - # (might include inames) - blex_order_map_params |= set(lbound.get_var_names(dim_type.param)) - - # {{{ NEW NEW stuff: create the blex set for this blex point + # {{{ Create the blex set for this blex point all_blex_points = _add_one_blex_tuple( all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) @@ -504,40 +479,18 @@ def _gather_blex_ordering_info( # Store 3 tuples that will be used later to create pairs # that will later be subtracted from the blex order map - # {{{ NEW version with lexmin/lexmax - - print("Iname %s" % (leave_iname)) - print("lexmax:") - print(loop_bounds[leave_iname][1]) - - ubound = loop_bounds[leave_iname][1] last_iter_blex_pt = pre_end_loop_blex_pt[:] - last_iter_blex_pt[-2] = ubound + last_iter_blex_pt[-2] = leave_iname blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( pre_end_loop_blex_pt) blex_exclusion_info[leave_iname][slex.LAST] = tuple( last_iter_blex_pt) blex_exclusion_info[leave_iname][slex.POST] = tuple( next_blex_tuple) - - # TODO switch to this: - last_iter_blex_pt[-2] = leave_iname - new_blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( - pre_end_loop_blex_pt) - new_blex_exclusion_info[leave_iname][slex.LAST] = tuple( - last_iter_blex_pt) - new_blex_exclusion_info[leave_iname][slex.POST] = tuple( - next_blex_tuple) - - # }}} - # (copy these three blex points when creating dict because # the lists will continue to be updated) - # Store any new params found - blex_order_map_params |= set(ubound.get_var_names(dim_type.param)) - - # {{{ NEW NEW stuff: create the blex set for this blex point + # {{{ Create the blex set for this blex point all_blex_points = _add_one_blex_tuple( all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) @@ -555,7 +508,7 @@ def _gather_blex_ordering_info( if lin_item.synchronization_kind == sync_kind: next_blex_tuple[-1] += 1 - # {{{ NEW NEW stuff: create the blex set for this blex point + # {{{ Create the blex set for this blex point all_blex_points = _add_one_blex_tuple( all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) @@ -587,7 +540,7 @@ def _gather_blex_ordering_info( if lin_item.synchronization_kind == sync_kind: next_blex_tuple[-1] += 1 - # {{{ NEW NEW stuff: create the blex set for this blex point + # {{{ Create the blex set for this blex point all_blex_points = _add_one_blex_tuple( all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) @@ -600,14 +553,6 @@ def _gather_blex_ordering_info( lin_item, (CallKernel, ReturnFromKernel)) pass - # Record the max value for the 0th non-iname blex dim - known_blex_dim_ubounds[0] = max( - next_blex_tuple[-1], known_blex_dim_ubounds[0]) - - # Don't want inames in blex map params, remove them - # TODO: could we have introduced inames other than loops_with_barriers? - blex_order_map_params = sorted(blex_order_map_params - loops_with_barriers) - # At this point, some blex tuples may have more dimensions than others; # the missing dims are the fastest-updating dims, and their values should # be zero. Add them. @@ -637,33 +582,18 @@ def _gather_blex_ordering_info( iname_to_blex_var[iname] = seq_blex_dim_names[dim] iname_to_blex_var[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] - # Add bounds params needed in blex map - """ - _blex_order_map = add_and_name_isl_dims( # TODO remove - blex_order_map, dim_type.param, _blex_order_map_params) - blex_order_map = add_and_name_isl_dims( - blex_order_map, dim_type.param, blex_order_map_params) - """ - - # Get a set representing blex_order_map space - blex_mapset_template = isl.align_spaces( - isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map - ).move_dims( - dim_type.in_, n_seq_blex_dims, dim_type.out, 0, n_seq_blex_dims - ).domain() - blex_set_affs = isl.affs_from_space(blex_mapset_template.space) - - # New version + # Get a map representing blex_order_map space + # (Note that this template cannot be created until *after* the intersection + # of blex_order_map with all_blex_points above, otherwise the template will + # be missing necessary parameters) blex_map_template = isl.align_spaces( isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map) blex_set_template = blex_map_template.range() - #blex_set_template_prime = append_mark_to_isl_map_var_names(blex_set_template) # {{{ Create blex map to subtract for each iname in blex_exclusion_info maps_to_subtract = [] for iname, key_lex_tuples in blex_exclusion_info.items(): - new_key_lex_tuples = new_blex_exclusion_info[iname] print("") print(iname) @@ -675,103 +605,6 @@ def _gather_blex_ordering_info( PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST """ - # Note: - # only key_lex_tuples[slex.FIRST] & key_lex_tuples[slex.LAST] are pwaffs - - # {{{ _create_blex_set_from_tuple_pair - - def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): - """Given a before->after tuple pair in the key_lex_tuples, which may - have dim vals described by ints, strings (inames), and pwaffs, - create an ISL set in blex space that can be converted into - the ISL map to be subtracted - """ - # (Vars from outside func used here: - # iname, blex_set_affs, blex_mapset_template, iname_to_blex_var, - # n_seq_blex_dims, seq_blex_dim_names, - # seq_blex_dim_names_prime) - - # Start with a set representing blex_order_map space - blex_set = blex_mapset_template.copy() - - # Add marks to inames in the 'before' tuple - # (all strings should be inames) - before_prime = [] - for v in before: - if isinstance(v, int): - before_prime.append(v) - elif isinstance(v, str): - before_prime.append(v+BEFORE_MARK) - else: - assert isinstance(v, isl.Set) - before_prime.append(rename_dims(v, iname_to_iname_prime)) - before_prime = tuple(before_prime) - """ - before_prime = tuple( - v+BEFORE_MARK if isinstance(v, str) else v for v in before) - """ - before_padded = _pad_tuple_with_zeros(before_prime, n_seq_blex_dims) - after_padded = _pad_tuple_with_zeros(after, n_seq_blex_dims) - - # Assign vals in the tuple to dims in the ISL set - for dim_name, dim_val in zip( - seq_blex_dim_names_prime+seq_blex_dim_names, - before_padded+after_padded): - - if isinstance(dim_val, int): - # Set idx to int val - blex_set &= blex_set_affs[dim_name].eq_set( - blex_set_affs[0]+dim_val) - elif isinstance(dim_val, str): - # This is an iname, set idx to corresponding blex var - blex_set &= blex_set_affs[dim_name].eq_set( - blex_set_affs[iname_to_blex_var[dim_val]]) - else: - # TODO figure out best place to do this: - # Rename dims and align dim_val so it can intersect w/blex_set - - # There may be inames as params in dim_val, move them to set dim - dim_val_pre_aligned = dim_val.copy() # TODO maybe remove copy - for var_name in dim_val_pre_aligned.get_var_names( - dim_type.param): - if var_name in iname_to_blex_var: - # Get idx of var_name (might have moved since loop start) - idx = dim_val_pre_aligned.find_dim_by_name( - dim_type.param, var_name) - dim_val_pre_aligned = dim_val_pre_aligned.move_dims( - dim_type.out, 0, dim_type.param, idx, 1) - - # Rename inames to corresponding blex var names - # TODO does this catch all potential inames? - dim_val_renamed = rename_dims( - dim_val_pre_aligned, iname_to_blex_var, [dim_type.set]) - - dim_val_aligned = isl.align_spaces( - dim_val_renamed, blex_mapset_template) - blex_set &= dim_val_aligned - - if wrap_cond: - # This is the BOTTOM->TOP pair, add condition i = i' + 1 - blex_set &= blex_set_affs[iname_to_blex_var[iname]].eq_set( - blex_set_affs[iname_to_blex_var[iname+BEFORE_MARK]] + 1) - - return blex_set - - # }}} end _create_blex_set_from_tuple_pair() - - # Create pairs to be subtracted - # (set will be converted to map) - - # Enter loop case: PRE->FIRST - blex_set_to_subtract = _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.PRE], key_lex_tuples[slex.FIRST], - ) - print("PRE->FIRST") - print("blex_set_to_subtract new:") - print(prettier_map_string(blex_set_to_subtract)) - - # {{{ New version: - # {{{ PRE->FIRST # Values in PRE should be strings (inames) or ints. @@ -783,10 +616,10 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # Values in FIRST will involve one of our lexmin bounds. - first_tuple = new_key_lex_tuples[slex.FIRST] + first_tuple = key_lex_tuples[slex.FIRST] first_tuple_padded = _pad_tuple_with_zeros(first_tuple, n_seq_blex_dims) pre_tuple_padded = _pad_tuple_with_zeros( - new_key_lex_tuples[slex.PRE], n_seq_blex_dims) + key_lex_tuples[slex.PRE], n_seq_blex_dims) # Assign int dims; all other dims will have any necessary bounds set # later by intersecting with the (bounded) full blex map pre_to_first_map = _add_eq_isl_constraints_for_ints_only( @@ -795,7 +628,7 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): seq_blex_dim_names_prime+seq_blex_dim_names, pre_tuple_padded+first_tuple_padded)) - loop_min_bound = new_loop_bounds[iname][0] + loop_min_bound = loop_bounds[iname][0] # Rename iname dims to blex dims # TODO could there be any other inames involved besides first_tuple[1::2]? @@ -810,20 +643,11 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # }}} - # }}} - + print("PRE->FIRST") print(prettier_map_string(pre_to_first_map)) - # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) - # TODO union in place: - temp = _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP], - wrap_cond=True) - blex_set_to_subtract |= temp - - # {{{ New version: - # {{{ BOTTOM->TOP + # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) # Values in BOTTOM/TOP should be strings (inames) or ints. # We actually already know which blex dims correspond to the inames @@ -832,9 +656,9 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # We only need to set the values for blex dims that will be ints, # i.e., the intra-loop-section blex dims and any trailing zeros. bottom_tuple_padded = _pad_tuple_with_zeros( - new_key_lex_tuples[slex.BOTTOM], n_seq_blex_dims) + key_lex_tuples[slex.BOTTOM], n_seq_blex_dims) top_tuple_padded = _pad_tuple_with_zeros( - new_key_lex_tuples[slex.TOP], n_seq_blex_dims) + key_lex_tuples[slex.TOP], n_seq_blex_dims) bottom_to_top_map = _add_eq_isl_constraints_for_ints_only( blex_map_template, zip( @@ -850,24 +674,8 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # }}} - # }}} - print(prettier_map_string(bottom_to_top_map)) - # Leave loop case: LAST->POST - #blex_set_to_subtract |= _create_blex_set_from_tuple_pair( - # key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST]) - # TODO union in place: - temp = _create_blex_set_from_tuple_pair( - key_lex_tuples[slex.LAST], key_lex_tuples[slex.POST], - ) - blex_set_to_subtract |= temp - print("LAST->POST") - print("blex_set_to_subtract new:") - print(prettier_map_string(temp)) - - # {{{ New version: - # {{{ LAST->POST # Values in POST should be strings (inames) or ints. @@ -879,10 +687,10 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # Values in last will involve one of our lexmax bounds. - last_tuple = new_key_lex_tuples[slex.LAST] + last_tuple = key_lex_tuples[slex.LAST] last_tuple_padded = _pad_tuple_with_zeros(last_tuple, n_seq_blex_dims) post_tuple_padded = _pad_tuple_with_zeros( - new_key_lex_tuples[slex.POST], n_seq_blex_dims) + key_lex_tuples[slex.POST], n_seq_blex_dims) # Assign int dims; all other dims will have any necessary bounds set # later by intersecting with the (bounded) full blex map last_to_post_map = _add_eq_isl_constraints_for_ints_only( @@ -891,7 +699,7 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): seq_blex_dim_names_prime+seq_blex_dim_names, last_tuple_padded+post_tuple_padded)) - loop_max_bound = new_loop_bounds[iname][1] + loop_max_bound = loop_bounds[iname][1] # Rename iname dims to blex dims # TODO could there be any other inames involved besides last_tuple[1::2]? @@ -908,43 +716,29 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): # }}} - # }}} - + print("LAST->POST") print(prettier_map_string(last_to_post_map)) - blex_map_to_subtract = pre_to_first_map | bottom_to_top_map | last_to_post_map - # Add condition to fix iteration value for *surrounding* loops (j = j') - # (odd indices in key_lex_tuples[PRE] contain the sounding inames) - # TODO make sure this is still the right strategy given new approach - for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: - s_blex_var = iname_to_blex_var[surrounding_iname] - blex_set_to_subtract &= blex_set_affs[s_blex_var].eq_set( - blex_set_affs[s_blex_var+BEFORE_MARK]) + map_to_subtract = pre_to_first_map | bottom_to_top_map | last_to_post_map # Add condition to fix iteration value for *surrounding* loops (j = j') # (odd indices in key_lex_tuples[PRE] contain the sounding inames) for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: s_blex_var = iname_to_blex_var[surrounding_iname] - blex_map_to_subtract = add_eq_isl_constraint_from_names( - blex_map_to_subtract, s_blex_var, s_blex_var+BEFORE_MARK) - - # Convert blex set back to map - map_to_subtract = isl.Map.from_domain(blex_set_to_subtract).move_dims( - dim_type.out, 0, dim_type.in_, n_seq_blex_dims, n_seq_blex_dims) - - _align_and_compare_maps([(blex_map_to_subtract, map_to_subtract)]) + map_to_subtract = add_eq_isl_constraint_from_names( + map_to_subtract, s_blex_var, s_blex_var+BEFORE_MARK) print("FULL MAP_TO_SUBTRACT FOR LOOP", iname) print(prettier_map_string(map_to_subtract)) # Bound the blex dims by intersecting with the full blex map, which # contains all the bound constraints - blex_map_to_subtract &= blex_order_map + map_to_subtract &= blex_order_map print("CONSTRAINED MAP_TO_SUBTRACT FOR LOOP", iname) - print(prettier_map_string(blex_map_to_subtract)) + print(prettier_map_string(map_to_subtract)) # }}} - maps_to_subtract.append(blex_map_to_subtract) + maps_to_subtract.append(map_to_subtract) # }}} @@ -957,68 +751,35 @@ def _create_blex_set_from_tuple_pair(before, after, wrap_cond=False): for other_map in maps_to_subtract[1:]: map_to_subtract |= other_map - """ - print(blex_order_map.space) - print(map_to_subtract.space) - #print(blex_order_map - map_to_subtract) - assert map_to_subtract.is_subset(blex_order_map) # TODO why not subset? - """ - # Get transitive closure of maps map_to_subtract_closure, closure_exact = map_to_subtract.transitive_closure() assert closure_exact # TODO warn instead? - # {{{ Check some assumptions about result of subtraction being transitive - from copy import deepcopy - - # Make sure blex order map is transitive - closure_test = deepcopy(blex_order_map) - closure_test, closure_exact = closure_test.transitive_closure() - assert closure_exact - print("IS FULL BLEX MAP TRANSITIVE?") - assert closure_test == blex_order_map - print("yes") - - closure_test = deepcopy(map_to_subtract_closure) - closure_test, closure_exact = closure_test.transitive_closure() - assert closure_exact - print("IS SUBTRACTION MAP TRANSITIVE?") - assert closure_test == map_to_subtract_closure - print("yes") - - assert map_to_subtract.is_subset(blex_order_map) - print("IS SUBTRACTION MAP A SUBSET OF FULL BLEX ORDER MAP?") - assert map_to_subtract_closure.is_subset(blex_order_map) - print("yes") - # }}} + # {{{ Check assumptions about map transitivity - print("blex_order_map FULL") - print(prettier_map_string(blex_order_map)) - #print(blex_order_map) + if perform_closure_checks: + + # Make sure map_to_subtract_closure is subset of blex_order_map + assert map_to_subtract <= blex_order_map + assert map_to_subtract_closure <= blex_order_map + + # Make sure blex_order_map and map_to_subtract are closures + _assert_exact_closure(blex_order_map) + _assert_exact_closure(map_to_subtract_closure) + + # }}} # Subtract closure from blex order map blex_order_map = blex_order_map - map_to_subtract_closure - print("subtraction map for %s barriers" % (sync_kind)) - print(prettier_map_string(map_to_subtract_closure)) - #print(map_to_subtract_closure) - print("blex_order_map FINAL = blex_order_map FULL - map_to_subtract_closure") - print(prettier_map_string(blex_order_map)) - closure_test = deepcopy(blex_order_map) - closure_test, closure_exact = closure_test.transitive_closure() - - print("closure(blex_order_map FINAL)") - print(prettier_map_string(closure_test)) - print("exact?", closure_exact) - - #assert closure_exact # FAILS - print( - "IS RESULT OF SUBTRACTION TRANSITIVE?", - closure_test == blex_order_map - ) - assert closure_test == blex_order_map - print("yes") + # {{{ Check assumptions about map transitivity + + # Make sure blex_order_map is closure after subtraction + if perform_closure_checks: + _assert_exact_closure(blex_order_map) + + # }}} # }}} @@ -1055,6 +816,7 @@ def get_pairwise_statement_orderings_inner( lin_items, stmt_id_pairs, loops_to_ignore=frozenset(), + perform_closure_checks=False, ): r"""For each statement pair in a subset of all statement pairs found in a linearized kernel, determine the (relative) order in which the statement @@ -1144,7 +906,6 @@ def get_pairwise_statement_orderings_inner( # This information will be used later when creating *intra-group* and # *global* lexicographic orderings loop_bounds = {} - new_loop_bounds = {} for lin_item in lin_items: if isinstance(lin_item, EnterLoop): @@ -1234,11 +995,6 @@ def get_pairwise_statement_orderings_inner( # }}} - loop_bounds[iname] = (dom.lexmin(), dom.lexmax(), dom) - # TODO adding dom^ for now - #loop_bounds[iname] = ( - # dom.lexmin_pw_multi_aff(), dom.lexmax_pw_multi_aff()) - lmin = dom.lexmin() lmax = dom.lexmax() @@ -1247,15 +1003,13 @@ def get_pairwise_statement_orderings_inner( outer_iname_idx = lmin.find_dim_by_name( dim_type.param, outer_iname) lmin = lmin.move_dims( - dim_type.set, 0, dim_type.param, - outer_iname_idx, 1) + dim_type.set, 0, dim_type.param, outer_iname_idx, 1) outer_iname_idx = lmax.find_dim_by_name( dim_type.param, outer_iname) lmax = lmax.move_dims( - dim_type.set, 0, dim_type.param, - outer_iname_idx, 1) + dim_type.set, 0, dim_type.param, outer_iname_idx, 1) - new_loop_bounds[iname] = (lmin, lmax) + loop_bounds[iname] = (lmin, lmax) # }}} @@ -1284,19 +1038,6 @@ def get_pairwise_statement_orderings_inner( lin_item, (CallKernel, ReturnFromKernel)) pass - # Debugging.... (TODO remove) - for iname, (lbound, ubound, dom) in loop_bounds.items(): - print(iname) - print(prettier_map_string(lbound)) - print(prettier_map_string(ubound)) - print(prettier_map_string(dom)) - - print() - for iname, (lbound, ubound) in new_loop_bounds.items(): - print(iname) - print(prettier_map_string(lbound)) - print(prettier_map_string(ubound)) - # }}} # {{{ Create lex dim names representing parallel axes @@ -1366,9 +1107,10 @@ def get_pairwise_statement_orderings_inner( knl, "local", lin_items, loops_with_barriers["local"], - loops_to_ignore, loop_bounds, new_loop_bounds, + loops_to_ignore, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, + perform_closure_checks=perform_closure_checks, ) (stmt_inst_to_gblex, gblex_order_map, @@ -1376,9 +1118,10 @@ def get_pairwise_statement_orderings_inner( knl, "global", lin_items, loops_with_barriers["global"], - loops_to_ignore, loop_bounds, new_loop_bounds, + loops_to_ignore, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, + perform_closure_checks=perform_closure_checks, ) # }}} From dde6a77189a5ba93142131d01a492c2ee08f8d1f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 5 Sep 2021 21:16:58 -0500 Subject: [PATCH 184/220] pass along bool args for transitivity checks --- loopy/schedule/checker/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index b994d8768..eaaf7d52d 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -27,6 +27,7 @@ def get_pairwise_statement_orderings( knl, lin_items, stmt_id_pairs, + perform_closure_checks=False, ): r"""For each statement pair in a subset of all statement pairs found in a linearized kernel, determine the (relative) order in which the statement @@ -137,6 +138,7 @@ def get_pairwise_statement_orderings( lin_items, stmt_id_pairs, loops_to_ignore=conc_loop_inames, + perform_closure_checks=perform_closure_checks, ) # }}} From 7ad44fb5feb0ddba6daab42cc93defc3fc4b114c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 5 Sep 2021 21:17:43 -0500 Subject: [PATCH 185/220] pass bool args enabling transitivity checks into get_pairwise_statement_orderings --- test/test_linearization_checker.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 40ccc5118..54f91f33f 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -212,7 +212,7 @@ def _process_and_linearize(knl, knl_name="loopy_kernel"): ("stmt_k1", "stmt_i2"), ] pworders = get_pairwise_statement_orderings( - lin_knl, lin_items, stmt_id_pairs) + lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) #1/0 @@ -271,6 +271,7 @@ def test_intra_thread_pairwise_schedule_creation(): lin_knl, lin_items, stmt_id_pairs, + perform_closure_checks=True, ) # {{{ Relationship between stmt_a and stmt_b @@ -487,6 +488,7 @@ def test_pairwise_schedule_creation_with_hw_par_tags(): lin_knl, lin_items, stmt_id_pairs, + perform_closure_checks=True, ) # {{{ Relationship between stmt_a and stmt_b @@ -628,6 +630,7 @@ def test_intra_thread_statement_instance_ordering(): proc_knl, lin_items, stmt_id_pairs, + perform_closure_checks=True, ) # {{{ Relationship between stmt_a and stmt_b @@ -764,6 +767,7 @@ def test_statement_instance_ordering_with_hw_par_tags(): lin_knl, lin_items, stmt_id_pairs, + perform_closure_checks=True, ) # Create string for representing parallel iname condition in sio @@ -845,6 +849,7 @@ def test_statement_instance_ordering_of_barriers(): lin_knl, lin_items, stmt_id_pairs, + perform_closure_checks=True, ) # Create string for representing parallel iname SAME condition in sio @@ -1103,7 +1108,7 @@ def test_sios_and_schedules_with_barriers(): stmt_id_pairs = [("stmt_j1", "stmt_2"), ("stmt_1", "stmt_i0")] pworders = get_pairwise_statement_orderings( - lin_knl, lin_items, stmt_id_pairs) + lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) # {{{ Relationship between stmt_j1 and stmt_2 @@ -1426,7 +1431,7 @@ def test_sios_and_schedules_with_vec_and_barriers(): stmt_id_pairs = [("stmt_1", "stmt_2")] pworders = get_pairwise_statement_orderings( - lin_knl, lin_items, stmt_id_pairs) + lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) # {{{ Relationship between stmt_1 and stmt_2 @@ -1653,7 +1658,7 @@ def test_sios_with_matmul(): # Generate pairwise ordering info for every pair get_pairwise_statement_orderings( - lin_knl, lin_items, stmt_id_pairs) + lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) # }}} From 8f3ff97c581f60ab2ff0c04e42154141397179b4 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 6 Sep 2021 15:00:16 -0500 Subject: [PATCH 186/220] remove some unnecessary functions --- loopy/schedule/checker/schedule.py | 33 ++++-------------------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 48113129a..613c72b96 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -31,22 +31,6 @@ dim_type = isl.dim_type -# TODO delete this: -def _align_and_compare_maps(maps): - from loopy.schedule.checker.utils import ( - ensure_dim_names_match_and_align, - ) - - for map1, map2 in maps: - # Align maps and compare - map1_aligned = ensure_dim_names_match_and_align(map1, map2) - if map1_aligned != map2: - print("Maps not equal:") - print(prettier_map_string(map1_aligned)) - print(prettier_map_string(map2)) - assert map1_aligned == map2 - - # {{{ Constants __doc__ = """ @@ -243,12 +227,6 @@ class StatementOrdering: # {{{ _gather_blex_ordering_info -def _find_and_rename_dim(isl_obj, dt, old_name, new_name): - # TODO remove this func once it's merged into isl_helpers - return isl_obj.set_dim_name( - dt, isl_obj.find_dim_by_name(dt, old_name), new_name) - - def _find_and_rename_dims(isl_obj, dt, rename_dict): # TODO remove this func once it's merged into isl_helpers for old_name, new_name in rename_dict.items(): @@ -291,9 +269,9 @@ def _add_one_blex_tuple( seq_within_inames, [dim_type.set]) # Rename iname dims to blex dims - for depth, iname in enumerate(current_inames): - blex_dim_name = all_seq_blex_dim_names[1 + 2*depth] - dom = _find_and_rename_dim(dom, dim_type.set, iname, blex_dim_name) + dom = _find_and_rename_dims( + dom, dim_type.set, + dict(zip(blex_tuple[1::2], all_seq_blex_dim_names[1::2]))) # Add any new params to all_blex_points current_params = all_blex_points.get_var_names(dim_type.param) @@ -403,8 +381,6 @@ def _gather_blex_ordering_info( # }}} - print(prettier_map_string(all_blex_points)) - # TODO may be able to remove some of this stuff now: stmt_inst_to_blex = {} # Map stmt instances to blex space iname_to_blex_dim = {} # Map from inames to corresponding blex space dim @@ -674,6 +650,7 @@ def _gather_blex_ordering_info( # }}} + print("BOTTOM->TOP") print(prettier_map_string(bottom_to_top_map)) # {{{ LAST->POST @@ -728,8 +705,6 @@ def _gather_blex_ordering_info( map_to_subtract = add_eq_isl_constraint_from_names( map_to_subtract, s_blex_var, s_blex_var+BEFORE_MARK) - print("FULL MAP_TO_SUBTRACT FOR LOOP", iname) - print(prettier_map_string(map_to_subtract)) # Bound the blex dims by intersecting with the full blex map, which # contains all the bound constraints map_to_subtract &= blex_order_map From d5c9ea403a6358607c90da27bf102fbb61dc4a69 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 6 Sep 2021 15:00:48 -0500 Subject: [PATCH 187/220] add test for transitivity blex maps with complicated triangular domain --- test/test_linearization_checker.py | 122 ++++++++++++----------------- 1 file changed, 52 insertions(+), 70 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 54f91f33f..11c614cbb 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -47,6 +47,9 @@ ensure_dim_names_match_and_align, prettier_map_string, ) +from loopy.schedule.checker import ( + get_pairwise_statement_orderings, +) logger = logging.getLogger(__name__) @@ -150,73 +153,6 @@ def _process_and_linearize(knl, knl_name="loopy_kernel"): # }}} -# (WIP Testing/debugging; TODO make this into an official test) -from loopy.schedule.checker import ( - get_pairwise_statement_orderings, -) - -assumptions = "ijk_end >= i_start + 1" -knl = lp.make_kernel( - [ - "{[i,j,k]: i_start<=itemp0 = 0 {id=stmt_i0} - ... lbarrier {id=stmt_b0,dep=stmt_i0} - <>temp1 = 1 {id=stmt_i1,dep=stmt_b0} - for j - <>tempj0 = 0 {id=stmt_j0,dep=stmt_i1} - ... lbarrier {id=stmt_jb0,dep=stmt_j0} - ... gbarrier {id=stmt_jbb0,dep=stmt_j0} - <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} - <>tempj2 = 0 {id=stmt_j2,dep=stmt_j1} - for k - <>tempk0 = 0 {id=stmt_k0,dep=stmt_j2} - ... lbarrier {id=stmt_kb0,dep=stmt_k0} - <>tempk1 = 0 {id=stmt_k1,dep=stmt_kb0} - end - end - <>temp2 = 0 {id=stmt_i2,dep=stmt_j0} - end - """, - assumptions=assumptions, - lang_version=(2018, 2) - ) - -# TODO what happens if i+j<=ktemp0 = 0 {id=stmt_i0} + ... lbarrier {id=stmt_b0,dep=stmt_i0} + <>temp1 = 1 {id=stmt_i1,dep=stmt_b0} + for j + <>tempj0 = 0 {id=stmt_j0,dep=stmt_i1} + ... lbarrier {id=stmt_jb0,dep=stmt_j0} + ... gbarrier {id=stmt_jbb0,dep=stmt_j0} + <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} + <>tempj2 = 0 {id=stmt_j2,dep=stmt_j1} + for k + <>tempk0 = 0 {id=stmt_k0,dep=stmt_j2} + ... lbarrier {id=stmt_kb0,dep=stmt_k0} + <>tempk1 = 0 {id=stmt_k1,dep=stmt_kb0} + end + end + <>temp2 = 0 {id=stmt_i2,dep=stmt_j0} + end + """, + assumptions=assumptions, + lang_version=(2018, 2) + ) + + # Get a linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) + + stmt_id_pairs = [ + ("stmt_i0", "stmt_i1"), + ("stmt_i1", "stmt_j0"), + ("stmt_j0", "stmt_j1"), + ("stmt_j1", "stmt_j2"), + ("stmt_j2", "stmt_k0"), + ("stmt_k0", "stmt_k1"), + ("stmt_k1", "stmt_i2"), + ] + # Set perform_closure_checks=True and get the orderings + get_pairwise_statement_orderings( + lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) # }}} From c6f76c4118538a1cc5c84c0000cceba0e45dc922 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 6 Sep 2021 17:28:46 -0500 Subject: [PATCH 188/220] switch stmt var name back to original (pre-debugging) so that doctest passes --- loopy/schedule/checker/schedule.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 613c72b96..977009f2f 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -71,10 +71,9 @@ """ -#LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" +LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" #LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) -LIN_CHECK_IDENTIFIER_PREFIX = "" # TODO change back after debug -LEX_VAR_PREFIX = "%slx" % (LIN_CHECK_IDENTIFIER_PREFIX) # TODO change back +LEX_VAR_PREFIX = "lx" # TODO change back STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) LTAG_VAR_NAMES = [] GTAG_VAR_NAMES = [] From 297946be0fa7e2abe1543401fe82b36acdea8faf Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 8 Sep 2021 19:27:23 -0500 Subject: [PATCH 189/220] (WIP) figure out what does and does not need to change for sio creation to accommodate domain dependencies involving concurrent inames; insert some notes and todos --- loopy/schedule/checker/schedule.py | 22 ++++++++++--- test/test_linearization_checker.py | 51 ++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 977009f2f..c374ded1b 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -259,10 +259,13 @@ def _add_one_blex_tuple( # Get set of inames nested outside (including this iname) seq_within_inames = set(current_inames) + # TODO LEFT OFF HERE, need concurrent inames too because seq iname domain + # may depend on them; move them to params temporarily? + # Get inames domain for current inames # TODO it's possible that we can project out more inames, # how do we figure out which ones to project out? - # TODO what if this iname bound also depends on a concurrent iname? + # TODO what if this iname domain depends on a concurrent iname? dom = knl.get_inames_domain( seq_within_inames).project_out_except( seq_within_inames, [dim_type.set]) @@ -454,6 +457,9 @@ def _gather_blex_ordering_info( # Store 3 tuples that will be used later to create pairs # that will later be subtracted from the blex order map + # TODO some of this storage may be unnecessary now that loop + # bounds are found elsewhere... clean this up + last_iter_blex_pt = pre_end_loop_blex_pt[:] last_iter_blex_pt[-2] = leave_iname blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( @@ -550,6 +556,7 @@ def _gather_blex_ordering_info( # {{{ Subtract unwanted pairs from happens-before blex map # Create mapping (dict) from iname to corresponding blex dim name + # TODO do we need to do something with concurrent inames here? iname_to_blex_var = {} iname_to_iname_prime = {} for iname, dim in iname_to_blex_dim.items(): @@ -603,6 +610,7 @@ def _gather_blex_ordering_info( seq_blex_dim_names_prime+seq_blex_dim_names, pre_tuple_padded+first_tuple_padded)) + # TODO need this to include concurrent inames (as params?) loop_min_bound = loop_bounds[iname][0] # Rename iname dims to blex dims @@ -757,6 +765,7 @@ def _gather_blex_ordering_info( # }}} + pu.db # Add LID/GID dims to blex order map blex_order_map = add_and_name_isl_dims( blex_order_map, dim_type.out, all_par_lex_dim_names) @@ -836,6 +845,7 @@ def get_pairwise_statement_orderings_inner( provided in `stmt_id_pairs` to a :class:`StatementOrdering`, which contains the three SIOs described above. """ + pu.db from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.kernel.data import (LocalInameTag, GroupInameTag) @@ -948,9 +958,9 @@ def get_pairwise_statement_orderings_inner( # (this iname plus any nested outside this iname) inames_involved_in_bound = set(current_inames[:depth+1]) + # TODO LEFT OFF HERE, this needs to include concurrent inames + # Get inames domain - # (It's possible that we can project out more inames, - # but for now, don't.) # TODO what if this iname bound depends on a concurrent iname? dom = knl.get_inames_domain( inames_involved_in_bound).project_out_except( @@ -969,6 +979,9 @@ def get_pairwise_statement_orderings_inner( # }}} + # TODO LEFT OFF HERE, should concurrent inames be moved to + # params before calling lexmin/max? after? + lmin = dom.lexmin() lmax = dom.lexmax() @@ -1073,6 +1086,7 @@ def get_pairwise_statement_orderings_inner( all_par_lex_dim_names = lid_lex_dim_names + gid_lex_dim_names + pu.db # Get the blex schedule blueprint (dict will become a map below) and # blex order map w.r.t. local and global barriers (stmt_inst_to_lblex, @@ -1219,7 +1233,7 @@ def _get_map_for_stmt( lex_order_map = add_and_name_isl_dims( lex_order_map, dim_type.in_, append_mark_to_strings(all_par_lex_dim_names, mark=BEFORE_MARK)) - # Constrain lid/gid vars to be equal + # Constrain lid/gid vars to be equal (this is the intra-thread case) for var_name in all_par_lex_dim_names: lex_order_map = add_eq_isl_constraint_from_names( lex_order_map, var_name, var_name+BEFORE_MARK) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 11c614cbb..9afc112d1 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -153,6 +153,57 @@ def _process_and_linearize(knl, knl_name="loopy_kernel"): # }}} +assumptions = "i_start + 1 <= ijk_end" +knl = lp.make_kernel( + [ + "{[i,j,k]: i_start<=itemp0 = 0 {id=stmt_i0} + ... lbarrier {id=stmt_b0,dep=stmt_i0} + <>temp1 = 1 {id=stmt_i1,dep=stmt_b0} + for j + <>tempj0 = 0 {id=stmt_j0,dep=stmt_i1} + ... lbarrier {id=stmt_jb0,dep=stmt_j0} + ... gbarrier {id=stmt_jbb0,dep=stmt_j0} + <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} + <>tempj2 = 0 {id=stmt_j2,dep=stmt_j1} + for k + <>tempk0 = 0 {id=stmt_k0,dep=stmt_j2} + ... lbarrier {id=stmt_kb0,dep=stmt_k0} + <>tempk1 = 0 {id=stmt_k1,dep=stmt_kb0} + end + end + <>temp2 = 0 {id=stmt_i2,dep=stmt_j0} + end + """, + assumptions=assumptions, + lang_version=(2018, 2) + ) + +knl = lp.tag_inames(knl, "i:g.0") + +# Get a linearization +lin_items, proc_knl, lin_knl = _process_and_linearize(knl) + +stmt_id_pairs = [ + #("stmt_i0", "stmt_i1"), + ("stmt_i1", "stmt_j0"), + ("stmt_j0", "stmt_j1"), + ("stmt_j1", "stmt_j2"), + ("stmt_j2", "stmt_k0"), + ("stmt_k0", "stmt_k1"), + ("stmt_k1", "stmt_i2"), + ] +# Set perform_closure_checks=True and get the orderings +pu.db +get_pairwise_statement_orderings( + lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) + +1/0 + + # {{{ test_intra_thread_pairwise_schedule_creation() def test_intra_thread_pairwise_schedule_creation(): From b9585c3d8ca9b583364436935126ca4117df63cd Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 10 Sep 2021 00:18:09 -0500 Subject: [PATCH 190/220] add move_dims_by_name() --- loopy/schedule/checker/utils.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 9d181de73..09966ef0d 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -86,6 +86,25 @@ def reorder_dims_by_name( return new_set +def move_dims_by_name( + isl_obj, dst_type, dst_pos_start, src_type, dim_names, + ok_if_missing=False): + dst_pos = dst_pos_start + for dim_name in dim_names: + src_idx = isl_obj.find_dim_by_name(src_type, dim_name) + if src_idx == -1: + if ok_if_missing: + continue + else: + raise ValueError( + "move_dims_by_name did not find dimension %s" + % (dim_name)) + isl_obj = isl_obj.move_dims( + dst_type, dst_pos, src_type, src_idx, 1) + dst_pos += 1 + return isl_obj + + def rename_dims( isl_set, rename_map, dts=(dim_type.in_, dim_type.out, dim_type.param)): From 24728f88e2b8473a751f39dd049774fda9d61fa9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 10 Sep 2021 00:20:02 -0500 Subject: [PATCH 191/220] (WIP) accommodate domain dependencies involving concurrent inames when creating SIO by keeping the concurrent inames around as map params when constructing the blex/subtraction map --- loopy/schedule/checker/schedule.py | 213 +++++++++++++++++++++-------- 1 file changed, 154 insertions(+), 59 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index c374ded1b..6eaebc930 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -26,6 +26,7 @@ add_and_name_isl_dims, add_eq_isl_constraint_from_names, append_mark_to_isl_map_var_names, + move_dims_by_name, prettier_map_string, # noqa ) dim_type = isl.dim_type @@ -226,9 +227,17 @@ class StatementOrdering: # {{{ _gather_blex_ordering_info -def _find_and_rename_dims(isl_obj, dt, rename_dict): +def _find_and_rename_dims(isl_obj, dt, rename_dict, ok_if_missing=False): # TODO remove this func once it's merged into isl_helpers for old_name, new_name in rename_dict.items(): + idx = isl_obj.find_dim_by_name(dt, old_name) + if idx == -1: + if ok_if_missing: + continue + else: + raise ValueError( + "_find_and_rename_dims did not find dimension %s" + % (old_name)) isl_obj = isl_obj.set_dim_name( dt, isl_obj.find_dim_by_name(dt, old_name), new_name) return isl_obj @@ -249,7 +258,8 @@ def _assert_exact_closure(mapping): def _add_one_blex_tuple( - all_blex_points, blex_tuple, all_seq_blex_dim_names, knl): + all_blex_points, blex_tuple, all_seq_blex_dim_names, + conc_inames, knl): # blex_tuple contains 1 dim plus 2 dims for each *current* loop, so it may # be shorter than all_seq_blex_dim_names, which contains *all* the blex dim @@ -258,24 +268,27 @@ def _add_one_blex_tuple( # Get set of inames nested outside (including this iname) seq_within_inames = set(current_inames) - - # TODO LEFT OFF HERE, need concurrent inames too because seq iname domain - # may depend on them; move them to params temporarily? + all_within_inames = seq_within_inames | conc_inames # Get inames domain for current inames - # TODO it's possible that we can project out more inames, - # how do we figure out which ones to project out? - # TODO what if this iname domain depends on a concurrent iname? + # (need to account for concurrent inames here rather than adding them on + # to blex map at the end because a sequential iname domain may depend on a + # concurrent iname domain) dom = knl.get_inames_domain( - seq_within_inames).project_out_except( - seq_within_inames, [dim_type.set]) + all_within_inames).project_out_except( + all_within_inames, [dim_type.set]) - # Rename iname dims to blex dims + # Rename sequential iname dims to blex dims dom = _find_and_rename_dims( dom, dim_type.set, dict(zip(blex_tuple[1::2], all_seq_blex_dim_names[1::2]))) - # Add any new params to all_blex_points + # Move concurrent inames to params + dom = move_dims_by_name( + dom, dim_type.param, dom.n_param(), + dim_type.set, conc_inames) + + # Add any new params in dom to all_blex_points current_params = all_blex_points.get_var_names(dim_type.param) needed_params = dom.get_var_names(dim_type.param) missing_params = set(needed_params) - set(current_params) @@ -302,11 +315,14 @@ def _gather_blex_ordering_info( knl, sync_kind, lin_items, loops_with_barriers, - loops_to_ignore, loop_bounds, + loops_to_ignore, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, + conc_iname_lex_var_pairs, perform_closure_checks=False, ): + # TODO some of these params might be redundant + # E.g., is conc_inames always equal to inames in conc_iname_lex_var_pairs? """For the given sync_kind ("local" or "global"), create a mapping from statement instances to blex space (dict), as well as a mapping defining the blex ordering (isl map from blex space -> blex space) @@ -427,7 +443,8 @@ def _gather_blex_ordering_info( # {{{ Create the blex set for this blex point all_blex_points = _add_one_blex_tuple( - all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) + all_blex_points, next_blex_tuple, + seq_blex_dim_names, conc_inames, knl) # }}} @@ -474,7 +491,8 @@ def _gather_blex_ordering_info( # {{{ Create the blex set for this blex point all_blex_points = _add_one_blex_tuple( - all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) + all_blex_points, next_blex_tuple, + seq_blex_dim_names, conc_inames, knl) # }}} @@ -492,7 +510,8 @@ def _gather_blex_ordering_info( # {{{ Create the blex set for this blex point all_blex_points = _add_one_blex_tuple( - all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) + all_blex_points, next_blex_tuple, + seq_blex_dim_names, conc_inames, knl) # }}} @@ -524,7 +543,8 @@ def _gather_blex_ordering_info( # {{{ Create the blex set for this blex point all_blex_points = _add_one_blex_tuple( - all_blex_points, next_blex_tuple, seq_blex_dim_names, knl) + all_blex_points, next_blex_tuple, + seq_blex_dim_names, conc_inames, knl) # }}} else: @@ -546,8 +566,13 @@ def _gather_blex_ordering_info( # {{{ Bound the (pre-subtraction) blex order map + conc_iname_to_iname_prime = { + conc_iname: conc_iname+BEFORE_MARK for conc_iname in conc_inames} all_blex_points_prime = append_mark_to_isl_map_var_names( all_blex_points, dim_type.set, BEFORE_MARK) + all_blex_points_prime = _find_and_rename_dims( + all_blex_points_prime, dim_type.param, conc_iname_to_iname_prime, + ok_if_missing=True) blex_order_map = blex_order_map.intersect_domain( all_blex_points_prime).intersect_range(all_blex_points) @@ -556,7 +581,7 @@ def _gather_blex_ordering_info( # {{{ Subtract unwanted pairs from happens-before blex map # Create mapping (dict) from iname to corresponding blex dim name - # TODO do we need to do something with concurrent inames here? + # TODO rename to "seq_..." iname_to_blex_var = {} iname_to_iname_prime = {} for iname, dim in iname_to_blex_dim.items(): @@ -610,8 +635,8 @@ def _gather_blex_ordering_info( seq_blex_dim_names_prime+seq_blex_dim_names, pre_tuple_padded+first_tuple_padded)) - # TODO need this to include concurrent inames (as params?) loop_min_bound = loop_bounds[iname][0] + # (in loop_bounds sets, concurrent inames are params) # Rename iname dims to blex dims # TODO could there be any other inames involved besides first_tuple[1::2]? @@ -686,16 +711,29 @@ def _gather_blex_ordering_info( loop_max_bound = loop_bounds[iname][1] # Rename iname dims to blex dims - # TODO could there be any other inames involved besides last_tuple[1::2]? loop_max_bound = _find_and_rename_dims( loop_max_bound, dim_type.set, {k: iname_to_blex_var[k] for k in last_tuple[1::2]}) + + # We're going to intersect loop_max_bound with the *domain* + # (in-dimension) of the 'before'->'after' map below. We'll first align + # the space of loop_max_bound with the blex_set_template so that all + # the blex dimensions line up, and then use intersect_domain to apply + # loop_max_bound to the 'before' tuple. Because of this, we don't + # need to append the BEFORE_MARK to the inames in the dim_type.set + # dimensions of the loop_max_bound (even though they do apply to a + # 'before' tuple). However, there may be concurrent inames in the + # dim_type.param dimensions of the loop_max_bound, and we DO need to + # append the BEFORE_MARK to those inames to ensure that they are + # distinguished from the corresponding non-marked 'after' (concurrent) + # inames. + loop_max_bound = _find_and_rename_dims( + loop_max_bound, dim_type.param, conc_iname_to_iname_prime) + # Align with blex space (adds needed dims) loop_last_set = isl.align_spaces(loop_max_bound, blex_set_template) - # These blex vars should all have BEFORE_MARK but that will be added - # when we intersect_domain below - # Make PRE->FIRST pair by intersecting this with the range of our map + # Make LAST->POST pair by intersecting this with the range of our map last_to_post_map = last_to_post_map.intersect_domain(loop_last_set) # }}} @@ -705,10 +743,10 @@ def _gather_blex_ordering_info( map_to_subtract = pre_to_first_map | bottom_to_top_map | last_to_post_map - # Add condition to fix iteration value for *surrounding* loops (j = j') + # Add condition to fix iter value for *surrounding* sequential loops (j = j') # (odd indices in key_lex_tuples[PRE] contain the sounding inames) - for surrounding_iname in key_lex_tuples[slex.PRE][1::2]: - s_blex_var = iname_to_blex_var[surrounding_iname] + for seq_surrounding_iname in key_lex_tuples[slex.PRE][1::2]: + s_blex_var = iname_to_blex_var[seq_surrounding_iname] map_to_subtract = add_eq_isl_constraint_from_names( map_to_subtract, s_blex_var, s_blex_var+BEFORE_MARK) @@ -753,7 +791,7 @@ def _gather_blex_ordering_info( # }}} # Subtract closure from blex order map - blex_order_map = blex_order_map - map_to_subtract_closure + blex_order_map -= map_to_subtract_closure # {{{ Check assumptions about map transitivity @@ -765,16 +803,40 @@ def _gather_blex_ordering_info( # }}} - pu.db - # Add LID/GID dims to blex order map - blex_order_map = add_and_name_isl_dims( - blex_order_map, dim_type.out, all_par_lex_dim_names) - blex_order_map = add_and_name_isl_dims( - blex_order_map, dim_type.in_, - append_mark_to_strings(all_par_lex_dim_names, mark=BEFORE_MARK)) + # Add LID/GID dims to blex order map. + # At this point, all concurrent inames should be params in blex order map. + # Rename them and move them to in_/out dims. + + blex_order_map = _find_and_rename_dims( + blex_order_map, dim_type.param, + {conc_iname+BEFORE_MARK: lex_var+BEFORE_MARK + for conc_iname, lex_var in conc_iname_lex_var_pairs}, # 'before' names + ok_if_missing=True, # TODO actually track these so we know exactly what to expect + ) + blex_order_map = _find_and_rename_dims( + blex_order_map, dim_type.param, + dict(conc_iname_lex_var_pairs), # 'after' names + ok_if_missing=True, + ) + # (this sets the order of the LID/GID dims: ) + blex_order_map = move_dims_by_name( + blex_order_map, dim_type.in_, blex_order_map.dim(dim_type.in_), + dim_type.param, + [lex_var+BEFORE_MARK for _, lex_var in conc_iname_lex_var_pairs], + ok_if_missing=True, + ) + blex_order_map = move_dims_by_name( + blex_order_map, dim_type.out, blex_order_map.dim(dim_type.out), + dim_type.param, [lex_var for _, lex_var in conc_iname_lex_var_pairs], + ok_if_missing=True, + ) + if sync_kind == "local": # For intra-group case, constrain GID 'before' to equal GID 'after' - for var_name in gid_lex_dim_names: + gid_lex_dim_names_found = set( + gid_lex_dim_names) & set(blex_order_map.get_var_names(dim_type.out)) + # TODO actually track these^ so we know exactly what to expect + for var_name in gid_lex_dim_names_found: blex_order_map = add_eq_isl_constraint_from_names( blex_order_map, var_name, var_name+BEFORE_MARK) # (if sync_kind == "global", don't need constraints on LID/GID vars) @@ -845,7 +907,6 @@ def get_pairwise_statement_orderings_inner( provided in `stmt_id_pairs` to a :class:`StatementOrdering`, which contains the three SIOs described above. """ - pu.db from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.kernel.data import (LocalInameTag, GroupInameTag) @@ -859,9 +920,11 @@ def get_pairwise_statement_orderings_inner( sorted_union_of_names_in_isl_sets, create_symbolic_map_from_tuples, insert_and_name_isl_dims, + partition_inames_by_concurrency, ) all_stmt_ids = set().union(*stmt_id_pairs) + conc_inames = partition_inames_by_concurrency(knl)[0] - loops_to_ignore # {{{ Intra-thread lex order creation @@ -955,13 +1018,13 @@ def get_pairwise_statement_orderings_inner( if iname not in loop_bounds: # Get set of inames that might be involved in this bound - # (this iname plus any nested outside this iname) - inames_involved_in_bound = set(current_inames[:depth+1]) - - # TODO LEFT OFF HERE, this needs to include concurrent inames + # (this iname plus any nested outside this iname, including + # concurrent inames) + seq_surrounding_inames = set(current_inames[:depth]) + all_surrounding_inames = seq_surrounding_inames | conc_inames # Get inames domain - # TODO what if this iname bound depends on a concurrent iname? + inames_involved_in_bound = all_surrounding_inames | {iname} dom = knl.get_inames_domain( inames_involved_in_bound).project_out_except( inames_involved_in_bound, [dim_type.set]) @@ -970,32 +1033,53 @@ def get_pairwise_statement_orderings_inner( # (keeping them in order, which might come in handy later...) # Move those inames to params - for outer_iname in current_inames[:depth]: - outer_iname_idx = dom.find_dim_by_name( + # TODO remove: + _dom = dom + for outer_iname in all_surrounding_inames: + outer_iname_idx = _dom.find_dim_by_name( dim_type.set, outer_iname) - dom = dom.move_dims( - dim_type.param, dom.n_param(), dim_type.set, + _dom = _dom.move_dims( + dim_type.param, _dom.n_param(), dim_type.set, outer_iname_idx, 1) - # }}} + dom = move_dims_by_name( + dom, dim_type.param, dom.n_param(), + dim_type.set, all_surrounding_inames) - # TODO LEFT OFF HERE, should concurrent inames be moved to - # params before calling lexmin/max? after? + assert dom == _dom # TODO remove + assert dom.get_var_dict() == _dom.get_var_dict() # TODO remove + + # }}} lmin = dom.lexmin() lmax = dom.lexmax() - # Now move param inames back to set dim - for outer_iname in current_inames[:depth]: - outer_iname_idx = lmin.find_dim_by_name( + # Now move non-concurrent param inames back to set dim + # TODO remove: + _lmin = lmin + _lmax = lmax + for outer_iname in seq_surrounding_inames: + outer_iname_idx = _lmin.find_dim_by_name( dim_type.param, outer_iname) - lmin = lmin.move_dims( + _lmin = _lmin.move_dims( dim_type.set, 0, dim_type.param, outer_iname_idx, 1) - outer_iname_idx = lmax.find_dim_by_name( + outer_iname_idx = _lmax.find_dim_by_name( dim_type.param, outer_iname) - lmax = lmax.move_dims( + _lmax = _lmax.move_dims( dim_type.set, 0, dim_type.param, outer_iname_idx, 1) + lmin = move_dims_by_name( + lmin, dim_type.set, 0, + dim_type.param, seq_surrounding_inames) + lmax = move_dims_by_name( + lmax, dim_type.set, 0, + dim_type.param, seq_surrounding_inames) + + assert lmin == _lmin # TODO remove + assert lmin.get_var_dict() == _lmin.get_var_dict() # TODO remove + assert lmax == _lmax # TODO remove + assert lmax.get_var_dict() == _lmax.get_var_dict() # TODO remove + loop_bounds[iname] = (lmin, lmax) # }}} @@ -1033,9 +1117,11 @@ def get_pairwise_statement_orderings_inner( # At the same time, create the dicts that will be used later to create map # constraints that match each parallel iname to the corresponding lex dim # name in schedules, i.e., i = lid0, j = lid1, etc. + # TODO some of these vars may be redundant: lid_lex_dim_names = set() gid_lex_dim_names = set() par_iname_constraint_dicts = {} + lex_var_to_conc_iname = {} for iname in knl.all_inames(): ltag = knl.iname_tags_of_type(iname, LocalInameTag) if ltag: @@ -1043,7 +1129,7 @@ def get_pairwise_statement_orderings_inner( ltag_var = LTAG_VAR_NAMES[ltag.pop().axis] lid_lex_dim_names.add(ltag_var) par_iname_constraint_dicts[iname] = {1: 0, iname: 1, ltag_var: -1} - + lex_var_to_conc_iname[ltag_var] = iname continue # Shouldn't be any GroupInameTags gtag = knl.iname_tags_of_type(iname, GroupInameTag) @@ -1052,10 +1138,17 @@ def get_pairwise_statement_orderings_inner( gtag_var = GTAG_VAR_NAMES[gtag.pop().axis] gid_lex_dim_names.add(gtag_var) par_iname_constraint_dicts[iname] = {1: 0, iname: 1, gtag_var: -1} + lex_var_to_conc_iname[gtag_var] = iname # Sort for consistent dimension ordering lid_lex_dim_names = sorted(lid_lex_dim_names) gid_lex_dim_names = sorted(gid_lex_dim_names) + # TODO remove redundancy have one definitive list for these + # (just make separate 1-d lists for everything?) + conc_iname_lex_var_pairs = [] + for lex_var in lid_lex_dim_names+gid_lex_dim_names: + conc_iname_lex_var_pairs.append( + (lex_var_to_conc_iname[lex_var], lex_var)) # }}} @@ -1086,7 +1179,6 @@ def get_pairwise_statement_orderings_inner( all_par_lex_dim_names = lid_lex_dim_names + gid_lex_dim_names - pu.db # Get the blex schedule blueprint (dict will become a map below) and # blex order map w.r.t. local and global barriers (stmt_inst_to_lblex, @@ -1095,9 +1187,10 @@ def get_pairwise_statement_orderings_inner( knl, "local", lin_items, loops_with_barriers["local"], - loops_to_ignore, loop_bounds, + loops_to_ignore, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, + conc_iname_lex_var_pairs, perform_closure_checks=perform_closure_checks, ) (stmt_inst_to_gblex, @@ -1106,9 +1199,10 @@ def get_pairwise_statement_orderings_inner( knl, "global", lin_items, loops_with_barriers["global"], - loops_to_ignore, loop_bounds, + loops_to_ignore, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, + conc_iname_lex_var_pairs, perform_closure_checks=perform_closure_checks, ) @@ -1166,7 +1260,7 @@ def _get_map_for_stmt( space=sched_space, ) - # Set inames equal to relevant gid/lid var names + # Set inames equal to relevant GID/LID var names for iname, constraint_dict in par_iname_constraint_dicts.items(): # Even though all parallel thread dims are active throughout the # whole kernel, they may be assigned (tagged) to one iname for some @@ -1270,6 +1364,7 @@ def _get_sched_maps_and_sio( # 'before' to equal GID 'after' earlier in _gather_blex_ordering_info() # Create statement instance ordering + pu.db sio_par = get_statement_ordering_map( *par_sched_maps, # note, func accepts exactly two maps blex_order_map, From efb0095ff34045af2fd72153dddf3cdf5e9fb7f8 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 12 Sep 2021 21:00:24 -0500 Subject: [PATCH 192/220] make sure blex map always has necessary conc inames as params by inserting them at the beginning --- loopy/schedule/checker/schedule.py | 54 +++++++------- test/test_linearization_checker.py | 111 ++++++++++++++++------------- 2 files changed, 84 insertions(+), 81 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 6eaebc930..c309f6535 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -227,17 +227,14 @@ class StatementOrdering: # {{{ _gather_blex_ordering_info -def _find_and_rename_dims(isl_obj, dt, rename_dict, ok_if_missing=False): +def _find_and_rename_dims(isl_obj, dt, rename_dict): # TODO remove this func once it's merged into isl_helpers for old_name, new_name in rename_dict.items(): idx = isl_obj.find_dim_by_name(dt, old_name) if idx == -1: - if ok_if_missing: - continue - else: - raise ValueError( - "_find_and_rename_dims did not find dimension %s" - % (old_name)) + raise ValueError( + "_find_and_rename_dims did not find dimension %s" + % (old_name)) isl_obj = isl_obj.set_dim_name( dt, isl_obj.find_dim_by_name(dt, old_name), new_name) return isl_obj @@ -264,11 +261,9 @@ def _add_one_blex_tuple( # blex_tuple contains 1 dim plus 2 dims for each *current* loop, so it may # be shorter than all_seq_blex_dim_names, which contains *all* the blex dim # names - current_inames = blex_tuple[1::2] # Get set of inames nested outside (including this iname) - seq_within_inames = set(current_inames) - all_within_inames = seq_within_inames | conc_inames + all_within_inames = set(blex_tuple[1::2]) | conc_inames # Get inames domain for current inames # (need to account for concurrent inames here rather than adding them on @@ -396,6 +391,10 @@ def _gather_blex_ordering_info( for var_name in seq_blex_dim_names: all_blex_points = add_eq_isl_constraint_from_names( all_blex_points, var_name, 0) + # Add concurrent inames as params + # (iname domains found in the pass below may depend on concurrent inames) + all_blex_points = add_and_name_isl_dims( + all_blex_points, dim_type.param, conc_inames) # }}} @@ -406,8 +405,6 @@ def _gather_blex_ordering_info( next_blex_tuple = [0] # Next tuple of points in blex order known_blex_dim_ubounds = [0, ] # Place to store bounds for non-iname blex dims - # TODO handle case where one non-iname blex dim is used in multiple - # separate loops? for lin_item in lin_items: if isinstance(lin_item, EnterLoop): @@ -572,7 +569,7 @@ def _gather_blex_ordering_info( all_blex_points, dim_type.set, BEFORE_MARK) all_blex_points_prime = _find_and_rename_dims( all_blex_points_prime, dim_type.param, conc_iname_to_iname_prime, - ok_if_missing=True) + ) blex_order_map = blex_order_map.intersect_domain( all_blex_points_prime).intersect_range(all_blex_points) @@ -811,24 +808,20 @@ def _gather_blex_ordering_info( blex_order_map, dim_type.param, {conc_iname+BEFORE_MARK: lex_var+BEFORE_MARK for conc_iname, lex_var in conc_iname_lex_var_pairs}, # 'before' names - ok_if_missing=True, # TODO actually track these so we know exactly what to expect ) blex_order_map = _find_and_rename_dims( blex_order_map, dim_type.param, dict(conc_iname_lex_var_pairs), # 'after' names - ok_if_missing=True, ) # (this sets the order of the LID/GID dims: ) blex_order_map = move_dims_by_name( blex_order_map, dim_type.in_, blex_order_map.dim(dim_type.in_), dim_type.param, [lex_var+BEFORE_MARK for _, lex_var in conc_iname_lex_var_pairs], - ok_if_missing=True, ) blex_order_map = move_dims_by_name( blex_order_map, dim_type.out, blex_order_map.dim(dim_type.out), dim_type.param, [lex_var for _, lex_var in conc_iname_lex_var_pairs], - ok_if_missing=True, ) if sync_kind == "local": @@ -1008,7 +1001,7 @@ def get_pairwise_statement_orderings_inner( lp_stmt_id = lin_item.originating_insn_id loops_with_barriers[lin_item.synchronization_kind] |= set(current_inames) - # {{{ Store bounds for inames containing barriers + # {{{ Store bounds for loops containing barriers # (only compute the ones we haven't already stored; bounds finding # will only happen once for each barrier-containing loop) @@ -1033,7 +1026,7 @@ def get_pairwise_statement_orderings_inner( # (keeping them in order, which might come in handy later...) # Move those inames to params - # TODO remove: + # TODO remove after testing with downstream branches: _dom = dom for outer_iname in all_surrounding_inames: outer_iname_idx = _dom.find_dim_by_name( @@ -1046,8 +1039,9 @@ def get_pairwise_statement_orderings_inner( dom, dim_type.param, dom.n_param(), dim_type.set, all_surrounding_inames) - assert dom == _dom # TODO remove - assert dom.get_var_dict() == _dom.get_var_dict() # TODO remove + # TODO remove after testing with downstream branches: + assert dom == _dom + assert dom.get_var_dict() == _dom.get_var_dict() # }}} @@ -1055,18 +1049,18 @@ def get_pairwise_statement_orderings_inner( lmax = dom.lexmax() # Now move non-concurrent param inames back to set dim - # TODO remove: + # TODO remove after testing with downstream branches: _lmin = lmin _lmax = lmax - for outer_iname in seq_surrounding_inames: + for new_idx, outer_iname in enumerate(seq_surrounding_inames): outer_iname_idx = _lmin.find_dim_by_name( dim_type.param, outer_iname) _lmin = _lmin.move_dims( - dim_type.set, 0, dim_type.param, outer_iname_idx, 1) + dim_type.set, new_idx, dim_type.param, outer_iname_idx, 1) outer_iname_idx = _lmax.find_dim_by_name( dim_type.param, outer_iname) _lmax = _lmax.move_dims( - dim_type.set, 0, dim_type.param, outer_iname_idx, 1) + dim_type.set, new_idx, dim_type.param, outer_iname_idx, 1) lmin = move_dims_by_name( lmin, dim_type.set, 0, @@ -1075,10 +1069,11 @@ def get_pairwise_statement_orderings_inner( lmax, dim_type.set, 0, dim_type.param, seq_surrounding_inames) - assert lmin == _lmin # TODO remove - assert lmin.get_var_dict() == _lmin.get_var_dict() # TODO remove - assert lmax == _lmax # TODO remove - assert lmax.get_var_dict() == _lmax.get_var_dict() # TODO remove + # TODO remove after testing with downstream branches: + assert lmin == _lmin + assert lmin.get_var_dict() == _lmin.get_var_dict() + assert lmax == _lmax + assert lmax.get_var_dict() == _lmax.get_var_dict() loop_bounds[iname] = (lmin, lmax) @@ -1364,7 +1359,6 @@ def _get_sched_maps_and_sio( # 'before' to equal GID 'after' earlier in _gather_blex_ordering_info() # Create statement instance ordering - pu.db sio_par = get_statement_ordering_map( *par_sched_maps, # note, func accepts exactly two maps blex_order_map, diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 9afc112d1..fc136d035 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -153,57 +153,6 @@ def _process_and_linearize(knl, knl_name="loopy_kernel"): # }}} -assumptions = "i_start + 1 <= ijk_end" -knl = lp.make_kernel( - [ - "{[i,j,k]: i_start<=itemp0 = 0 {id=stmt_i0} - ... lbarrier {id=stmt_b0,dep=stmt_i0} - <>temp1 = 1 {id=stmt_i1,dep=stmt_b0} - for j - <>tempj0 = 0 {id=stmt_j0,dep=stmt_i1} - ... lbarrier {id=stmt_jb0,dep=stmt_j0} - ... gbarrier {id=stmt_jbb0,dep=stmt_j0} - <>tempj1 = 0 {id=stmt_j1,dep=stmt_jb0} - <>tempj2 = 0 {id=stmt_j2,dep=stmt_j1} - for k - <>tempk0 = 0 {id=stmt_k0,dep=stmt_j2} - ... lbarrier {id=stmt_kb0,dep=stmt_k0} - <>tempk1 = 0 {id=stmt_k1,dep=stmt_kb0} - end - end - <>temp2 = 0 {id=stmt_i2,dep=stmt_j0} - end - """, - assumptions=assumptions, - lang_version=(2018, 2) - ) - -knl = lp.tag_inames(knl, "i:g.0") - -# Get a linearization -lin_items, proc_knl, lin_knl = _process_and_linearize(knl) - -stmt_id_pairs = [ - #("stmt_i0", "stmt_i1"), - ("stmt_i1", "stmt_j0"), - ("stmt_j0", "stmt_j1"), - ("stmt_j1", "stmt_j2"), - ("stmt_j2", "stmt_k0"), - ("stmt_k0", "stmt_k1"), - ("stmt_k1", "stmt_i2"), - ] -# Set perform_closure_checks=True and get the orderings -pu.db -get_pairwise_statement_orderings( - lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) - -1/0 - - # {{{ test_intra_thread_pairwise_schedule_creation() def test_intra_thread_pairwise_schedule_creation(): @@ -1685,6 +1634,66 @@ def test_blex_map_transitivity_with_triangular_domain(): lang_version=(2018, 2) ) + ref_knl = knl + + # Get a linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) + + stmt_id_pairs = [ + ("stmt_i0", "stmt_i1"), + ("stmt_i1", "stmt_j0"), + ("stmt_j0", "stmt_j1"), + ("stmt_j1", "stmt_j2"), + ("stmt_j2", "stmt_k0"), + ("stmt_k0", "stmt_k1"), + ("stmt_k1", "stmt_i2"), + ] + # Set perform_closure_checks=True and get the orderings + get_pairwise_statement_orderings( + lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) + + # Now try it with concurrent i loop + knl = lp.tag_inames(knl, "i:g.0") + + # Get a linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) + + stmt_id_pairs = [ + ("stmt_i0", "stmt_i1"), + ("stmt_i1", "stmt_j0"), + ("stmt_j0", "stmt_j1"), + ("stmt_j1", "stmt_j2"), + ("stmt_j2", "stmt_k0"), + ("stmt_k0", "stmt_k1"), + ("stmt_k1", "stmt_i2"), + ] + # Set perform_closure_checks=True and get the orderings + get_pairwise_statement_orderings( + lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) + + # Now try it with concurrent i and j loops + knl = lp.tag_inames(knl, "j:g.1") + + # Get a linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) + + stmt_id_pairs = [ + ("stmt_i0", "stmt_i1"), + ("stmt_i1", "stmt_j0"), + ("stmt_j0", "stmt_j1"), + ("stmt_j1", "stmt_j2"), + ("stmt_j2", "stmt_k0"), + ("stmt_k0", "stmt_k1"), + ("stmt_k1", "stmt_i2"), + ] + # Set perform_closure_checks=True and get the orderings + get_pairwise_statement_orderings( + lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) + + # Now try it with concurrent i and k loops + knl = ref_knl + knl = lp.tag_inames(knl, {"i": "g.0", "k": "g.1"}) + # Get a linearization lin_items, proc_knl, lin_knl = _process_and_linearize(knl) From e778a3cbb8fe4bc5ca5df915ce9660b4100aff16 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Sep 2021 03:11:16 -0500 Subject: [PATCH 193/220] add remove_dims_by_name() --- loopy/schedule/checker/utils.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 09966ef0d..0fc0971da 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -87,24 +87,31 @@ def reorder_dims_by_name( def move_dims_by_name( - isl_obj, dst_type, dst_pos_start, src_type, dim_names, - ok_if_missing=False): + isl_obj, dst_type, dst_pos_start, src_type, dim_names): dst_pos = dst_pos_start for dim_name in dim_names: src_idx = isl_obj.find_dim_by_name(src_type, dim_name) if src_idx == -1: - if ok_if_missing: - continue - else: - raise ValueError( - "move_dims_by_name did not find dimension %s" - % (dim_name)) + raise ValueError( + "move_dims_by_name did not find dimension %s" + % (dim_name)) isl_obj = isl_obj.move_dims( dst_type, dst_pos, src_type, src_idx, 1) dst_pos += 1 return isl_obj +def remove_dims_by_name(isl_obj, dt, dim_names): + for dim_name in dim_names: + idx = isl_obj.find_dim_by_name(dt, dim_name) + if idx == -1: + raise ValueError( + "remove_dims_by_name did not find dimension %s" + % (dim_name)) + isl_obj = isl_obj.remove_dims(dt, idx, 1) + return isl_obj + + def rename_dims( isl_set, rename_map, dts=(dim_type.in_, dim_type.out, dim_type.param)): From 292e5dcff16bdb9b258a1b8068c15db93392ed89 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Sep 2021 03:11:52 -0500 Subject: [PATCH 194/220] in blex map creation, handle case where there are multiple inames tagged with the same parallel iname tag --- loopy/schedule/checker/schedule.py | 114 +++++++++++++++++++---------- 1 file changed, 74 insertions(+), 40 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index c309f6535..e0bfc6e3a 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -27,6 +27,7 @@ add_eq_isl_constraint_from_names, append_mark_to_isl_map_var_names, move_dims_by_name, + remove_dims_by_name, prettier_map_string, # noqa ) dim_type = isl.dim_type @@ -313,11 +314,10 @@ def _gather_blex_ordering_info( loops_to_ignore, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, - conc_iname_lex_var_pairs, + conc_iname_constraint_dicts, conc_iname_constraint_dicts_prime, perform_closure_checks=False, ): # TODO some of these params might be redundant - # E.g., is conc_inames always equal to inames in conc_iname_lex_var_pairs? """For the given sync_kind ("local" or "global"), create a mapping from statement instances to blex space (dict), as well as a mapping defining the blex ordering (isl map from blex space -> blex space) @@ -800,38 +800,58 @@ def _gather_blex_ordering_info( # }}} - # Add LID/GID dims to blex order map. - # At this point, all concurrent inames should be params in blex order map. - # Rename them and move them to in_/out dims. + # Add LID/GID dims to blex order map: - blex_order_map = _find_and_rename_dims( - blex_order_map, dim_type.param, - {conc_iname+BEFORE_MARK: lex_var+BEFORE_MARK - for conc_iname, lex_var in conc_iname_lex_var_pairs}, # 'before' names - ) - blex_order_map = _find_and_rename_dims( + # At this point, all concurrent inames should be params in blex order map. + # Rename them to the corresponding concurrent lex dim name and move them to + # in_/out dims. + + # NOTE: + # Even though all parallel thread dims are active throughout the + # whole kernel, they may be assigned (tagged) to one iname for some + # subset of statements and another iname for a different subset of + # statements (e.g., tiled, parallel matmul). + # There could, e.g., be *multiple* inames that correspond to LID0, and each + # of these inames could be involved in defining the domain set for other + # inames. We don't want to lose any of this information. For this reason, + # we first creat the LID/GID dims, then set each one equal to *all* + # corresponding concurrent inames (which are in param dims), and then + # remove the (param) iname dims. + + # Add conc lex dim names to both in_ and out dims + blex_order_map = add_and_name_isl_dims( + blex_order_map, dim_type.in_, + [v+BEFORE_MARK for v in all_par_lex_dim_names]) + blex_order_map = add_and_name_isl_dims( + blex_order_map, dim_type.out, all_par_lex_dim_names) + + # Set each of the new conc lex dims equal to *all* corresponding inames + for conc_iname, constraint_dict in conc_iname_constraint_dicts_prime.items(): + blex_order_map = blex_order_map.add_constraint( + isl.Constraint.eq_from_names(blex_order_map.space, constraint_dict)) + for conc_iname, constraint_dict in conc_iname_constraint_dicts.items(): + blex_order_map = blex_order_map.add_constraint( + isl.Constraint.eq_from_names(blex_order_map.space, constraint_dict)) + + # Now remove conc inames from params + blex_order_map = remove_dims_by_name( blex_order_map, dim_type.param, - dict(conc_iname_lex_var_pairs), # 'after' names - ) - # (this sets the order of the LID/GID dims: ) - blex_order_map = move_dims_by_name( - blex_order_map, dim_type.in_, blex_order_map.dim(dim_type.in_), - dim_type.param, - [lex_var+BEFORE_MARK for _, lex_var in conc_iname_lex_var_pairs], - ) - blex_order_map = move_dims_by_name( - blex_order_map, dim_type.out, blex_order_map.dim(dim_type.out), - dim_type.param, [lex_var for _, lex_var in conc_iname_lex_var_pairs], - ) + conc_inames | set([v+BEFORE_MARK for v in conc_inames])) if sync_kind == "local": # For intra-group case, constrain GID 'before' to equal GID 'after' + + # TODO remove after testing downstream: + # (they should all be there) gid_lex_dim_names_found = set( gid_lex_dim_names) & set(blex_order_map.get_var_names(dim_type.out)) - # TODO actually track these^ so we know exactly what to expect - for var_name in gid_lex_dim_names_found: + assert gid_lex_dim_names_found == set(gid_lex_dim_names) + #for var_name in gid_lex_dim_names_found: + + for var_name in gid_lex_dim_names: blex_order_map = add_eq_isl_constraint_from_names( blex_order_map, var_name, var_name+BEFORE_MARK) + # (if sync_kind == "global", don't need constraints on LID/GID vars) # }}} @@ -1056,11 +1076,13 @@ def get_pairwise_statement_orderings_inner( outer_iname_idx = _lmin.find_dim_by_name( dim_type.param, outer_iname) _lmin = _lmin.move_dims( - dim_type.set, new_idx, dim_type.param, outer_iname_idx, 1) + dim_type.set, new_idx, + dim_type.param, outer_iname_idx, 1) outer_iname_idx = _lmax.find_dim_by_name( dim_type.param, outer_iname) _lmax = _lmax.move_dims( - dim_type.set, new_idx, dim_type.param, outer_iname_idx, 1) + dim_type.set, new_idx, + dim_type.param, outer_iname_idx, 1) lmin = move_dims_by_name( lmin, dim_type.set, 0, @@ -1115,35 +1137,47 @@ def get_pairwise_statement_orderings_inner( # TODO some of these vars may be redundant: lid_lex_dim_names = set() gid_lex_dim_names = set() - par_iname_constraint_dicts = {} - lex_var_to_conc_iname = {} + + # Dicts that will be used to create constraints i = lid0, j = lid1, etc. + # (for efficiency, create these dicts one time per concurrent iname here, + # rather than recreating the dicts multiple times later) + conc_iname_constraint_dicts = {} + conc_iname_constraint_dicts_prime = {} + + # Even though all parallel thread dims are active throughout the + # whole kernel, they may be assigned (tagged) to one iname for some + # subset of statements and another iname for a different subset of + # statements (e.g., tiled, paralle. matmul). + #lex_var_to_conc_inames = {} for iname in knl.all_inames(): ltag = knl.iname_tags_of_type(iname, LocalInameTag) if ltag: assert len(ltag) == 1 # (should always be true) ltag_var = LTAG_VAR_NAMES[ltag.pop().axis] + ltag_var_prime = ltag_var+BEFORE_MARK + iname_prime = iname+BEFORE_MARK lid_lex_dim_names.add(ltag_var) - par_iname_constraint_dicts[iname] = {1: 0, iname: 1, ltag_var: -1} - lex_var_to_conc_iname[ltag_var] = iname + conc_iname_constraint_dicts[iname] = {1: 0, iname: 1, ltag_var: -1} + conc_iname_constraint_dicts_prime[iname_prime] = { + 1: 0, iname_prime: 1, ltag_var_prime: -1} continue # Shouldn't be any GroupInameTags gtag = knl.iname_tags_of_type(iname, GroupInameTag) if gtag: assert len(gtag) == 1 # (should always be true) gtag_var = GTAG_VAR_NAMES[gtag.pop().axis] + gtag_var_prime = gtag_var+BEFORE_MARK + iname_prime = iname+BEFORE_MARK gid_lex_dim_names.add(gtag_var) - par_iname_constraint_dicts[iname] = {1: 0, iname: 1, gtag_var: -1} - lex_var_to_conc_iname[gtag_var] = iname + conc_iname_constraint_dicts[iname] = {1: 0, iname: 1, gtag_var: -1} + conc_iname_constraint_dicts_prime[iname_prime] = { + 1: 0, iname_prime: 1, gtag_var_prime: -1} # Sort for consistent dimension ordering lid_lex_dim_names = sorted(lid_lex_dim_names) gid_lex_dim_names = sorted(gid_lex_dim_names) # TODO remove redundancy have one definitive list for these # (just make separate 1-d lists for everything?) - conc_iname_lex_var_pairs = [] - for lex_var in lid_lex_dim_names+gid_lex_dim_names: - conc_iname_lex_var_pairs.append( - (lex_var_to_conc_iname[lex_var], lex_var)) # }}} @@ -1185,7 +1219,7 @@ def get_pairwise_statement_orderings_inner( loops_to_ignore, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, - conc_iname_lex_var_pairs, + conc_iname_constraint_dicts, conc_iname_constraint_dicts_prime, perform_closure_checks=perform_closure_checks, ) (stmt_inst_to_gblex, @@ -1197,7 +1231,7 @@ def get_pairwise_statement_orderings_inner( loops_to_ignore, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, - conc_iname_lex_var_pairs, + conc_iname_constraint_dicts, conc_iname_constraint_dicts_prime, perform_closure_checks=perform_closure_checks, ) @@ -1256,7 +1290,7 @@ def _get_map_for_stmt( ) # Set inames equal to relevant GID/LID var names - for iname, constraint_dict in par_iname_constraint_dicts.items(): + for iname, constraint_dict in conc_iname_constraint_dicts.items(): # Even though all parallel thread dims are active throughout the # whole kernel, they may be assigned (tagged) to one iname for some # subset of statements and another iname for a different subset of From a8c7ab833d0e9e36e9213000debe2844ef7d9b42 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Sep 2021 03:12:21 -0500 Subject: [PATCH 195/220] perform transitivity tests on blex maps in case where there are multiple inames tagged with the same parallel iname tag --- test/test_linearization_checker.py | 64 +++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index fc136d035..4622eef7e 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -1603,8 +1603,6 @@ def test_sios_with_matmul(): def test_blex_map_transitivity_with_triangular_domain(): - # TODO make version of this with parallel i and ensure maps are correct? - assumptions = "i_start + 1 <= ijk_end" knl = lp.make_kernel( [ @@ -1710,6 +1708,68 @@ def test_blex_map_transitivity_with_triangular_domain(): get_pairwise_statement_orderings( lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) + # FIXME create some expected sios and compare + +# }}} + + +# {{{ test_blex_map_transitivity_with_duplicate_conc_inames + +def test_blex_map_transitivity_with_duplicate_conc_inames(): + + knl = lp.make_kernel( + [ + "{[i,j,ii,jj]: 0 <= i,j,jj < n and i <= ii < n}", + "{[k, kk]: 0 <= k,kk < n}", + ], + """ + for i + for ii + <> si = 0 {id=si} + ... lbarrier {id=bari, dep=si} + end + end + for j + for jj + <> sj = 0 {id=sj, dep=si} + ... lbarrier {id=barj, dep=sj} + end + end + for k + for kk + <> sk = 0 {id=sk, dep=sj} + ... lbarrier {id=bark, dep=sk} + end + end + """, + assumptions="0 < n", + lang_version=(2018, 2) + ) + + knl = lp.tag_inames(knl, {"i": "l.0", "j": "l.0", "k": "l.0"}) + + # Get a linearization + lin_items, proc_knl, lin_knl = _process_and_linearize(knl) + + stmt_id_pairs = [ + ("si", "si"), + ("si", "sj"), + ("si", "sk"), + ("sj", "sj"), + ("sj", "sk"), + ("sk", "sk"), + ] + + # Set perform_closure_checks=True and get the orderings + get_pairwise_statement_orderings( + lin_knl, lin_items, stmt_id_pairs, perform_closure_checks=True) + + # print(prettier_map_string(pw_sios[("si", "sj")].sio_intra_thread)) + # print(prettier_map_string(pw_sios[("si", "sj")].sio_intra_group)) + # print(prettier_map_string(pw_sios[("si", "sj")].sio_global)) + + # FIXME create some expected sios and compare + # }}} From 6877bd6b07e4388f9951e4fd664c40f7e4aac279 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Sep 2021 15:56:19 -0500 Subject: [PATCH 196/220] pass only values of conc_iname_constraint_dicts to _gather_blex_ordering_info() --- loopy/schedule/checker/schedule.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index e0bfc6e3a..b15a79c2b 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -826,10 +826,10 @@ def _gather_blex_ordering_info( blex_order_map, dim_type.out, all_par_lex_dim_names) # Set each of the new conc lex dims equal to *all* corresponding inames - for conc_iname, constraint_dict in conc_iname_constraint_dicts_prime.items(): + for constraint_dict in conc_iname_constraint_dicts_prime: blex_order_map = blex_order_map.add_constraint( isl.Constraint.eq_from_names(blex_order_map.space, constraint_dict)) - for conc_iname, constraint_dict in conc_iname_constraint_dicts.items(): + for constraint_dict in conc_iname_constraint_dicts: blex_order_map = blex_order_map.add_constraint( isl.Constraint.eq_from_names(blex_order_map.space, constraint_dict)) @@ -1219,7 +1219,8 @@ def get_pairwise_statement_orderings_inner( loops_to_ignore, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, - conc_iname_constraint_dicts, conc_iname_constraint_dicts_prime, + conc_iname_constraint_dicts.values(), + conc_iname_constraint_dicts_prime.values(), perform_closure_checks=perform_closure_checks, ) (stmt_inst_to_gblex, @@ -1231,7 +1232,8 @@ def get_pairwise_statement_orderings_inner( loops_to_ignore, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, - conc_iname_constraint_dicts, conc_iname_constraint_dicts_prime, + conc_iname_constraint_dicts.values(), + conc_iname_constraint_dicts_prime.values(), perform_closure_checks=perform_closure_checks, ) From ad1d7fcf2b2352b956fb3aa048c44d8332b9e6ce Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Sep 2021 13:12:44 -0500 Subject: [PATCH 197/220] remove some sanity checks --- loopy/schedule/checker/schedule.py | 49 +++--------------------------- 1 file changed, 4 insertions(+), 45 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index b15a79c2b..3ebc79204 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -841,13 +841,8 @@ def _gather_blex_ordering_info( if sync_kind == "local": # For intra-group case, constrain GID 'before' to equal GID 'after' - # TODO remove after testing downstream: - # (they should all be there) - gid_lex_dim_names_found = set( - gid_lex_dim_names) & set(blex_order_map.get_var_names(dim_type.out)) - assert gid_lex_dim_names_found == set(gid_lex_dim_names) - #for var_name in gid_lex_dim_names_found: - + # (in the current implementation, all gid_lex_dim_names should be + # present in blex_order_map) for var_name in gid_lex_dim_names: blex_order_map = add_eq_isl_constraint_from_names( blex_order_map, var_name, var_name+BEFORE_MARK) @@ -1023,8 +1018,8 @@ def get_pairwise_statement_orderings_inner( # {{{ Store bounds for loops containing barriers - # (only compute the ones we haven't already stored; bounds finding - # will only happen once for each barrier-containing loop) + # Only compute the bounds we haven't already stored; bounds finding + # will only happen once for each barrier-containing loop for depth, iname in enumerate(current_inames): # If we haven't already stored bounds for this iname, do so @@ -1043,47 +1038,17 @@ def get_pairwise_statement_orderings_inner( inames_involved_in_bound, [dim_type.set]) # {{{ Move domain dims for surrounding inames to parameters - # (keeping them in order, which might come in handy later...) - - # Move those inames to params - # TODO remove after testing with downstream branches: - _dom = dom - for outer_iname in all_surrounding_inames: - outer_iname_idx = _dom.find_dim_by_name( - dim_type.set, outer_iname) - _dom = _dom.move_dims( - dim_type.param, _dom.n_param(), dim_type.set, - outer_iname_idx, 1) dom = move_dims_by_name( dom, dim_type.param, dom.n_param(), dim_type.set, all_surrounding_inames) - # TODO remove after testing with downstream branches: - assert dom == _dom - assert dom.get_var_dict() == _dom.get_var_dict() - # }}} lmin = dom.lexmin() lmax = dom.lexmax() # Now move non-concurrent param inames back to set dim - # TODO remove after testing with downstream branches: - _lmin = lmin - _lmax = lmax - for new_idx, outer_iname in enumerate(seq_surrounding_inames): - outer_iname_idx = _lmin.find_dim_by_name( - dim_type.param, outer_iname) - _lmin = _lmin.move_dims( - dim_type.set, new_idx, - dim_type.param, outer_iname_idx, 1) - outer_iname_idx = _lmax.find_dim_by_name( - dim_type.param, outer_iname) - _lmax = _lmax.move_dims( - dim_type.set, new_idx, - dim_type.param, outer_iname_idx, 1) - lmin = move_dims_by_name( lmin, dim_type.set, 0, dim_type.param, seq_surrounding_inames) @@ -1091,12 +1056,6 @@ def get_pairwise_statement_orderings_inner( lmax, dim_type.set, 0, dim_type.param, seq_surrounding_inames) - # TODO remove after testing with downstream branches: - assert lmin == _lmin - assert lmin.get_var_dict() == _lmin.get_var_dict() - assert lmax == _lmax - assert lmax.get_var_dict() == _lmax.get_var_dict() - loop_bounds[iname] = (lmin, lmax) # }}} From b915810046bd2ee52d9fd1090a128bde6c22ff30 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Sep 2021 13:42:18 -0500 Subject: [PATCH 198/220] change add_and_reanme_dim->add_and_rename_dims and have it take multiple dims to rename in a dict --- loopy/isl_helpers.py | 26 +++++++++++++++----------- loopy/transform/iname.py | 8 ++++---- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/loopy/isl_helpers.py b/loopy/isl_helpers.py index 57183109b..733a00c55 100644 --- a/loopy/isl_helpers.py +++ b/loopy/isl_helpers.py @@ -823,10 +823,10 @@ def add_eq_constraint_from_names(isl_obj, var1, var2): # }}} -# {{{ find_and_rename_dim +# {{{ find_and_rename_dims -def find_and_rename_dim(isl_obj, dt, old_name, new_name): - """Rename a dimension in an ISL object. +def find_and_rename_dims(isl_obj, dt, rename_dict): + """Rename dimensions in an ISL object. :arg isl_obj: An :class:`islpy.Set` or :class:`islpy.Map` containing the dimension to be renamed. @@ -834,18 +834,22 @@ def find_and_rename_dim(isl_obj, dt, old_name, new_name): :arg dt: An :class:`islpy.dim_type` (i.e., :class:`int`) specifying the dimension type containing the dimension to be renamed. - :arg old_name: A :class:`str` specifying the name of the dimension to be - renamed. + :arg rename_dict: A :class:`dict` mapping current :class:`string` dimension + names to replacement names. - :arg new_name: A :class:`str` specifying the new name of the dimension to - be renamed. - - :returns: An object of the same type as *isl_obj* with the dimension - *old_name* renamed to *new_name*. + :returns: An object of the same type as *isl_obj* with the dimension names + changed according to *rename_dict*. """ - return isl_obj.set_dim_name( + for old_name, new_name in rename_dict.items(): + idx = isl_obj.find_dim_by_name(dt, old_name) + if idx == -1: + raise ValueError( + "find_and_rename_dims did not find dimension %s" + % (old_name)) + isl_obj = isl_obj.set_dim_name( dt, isl_obj.find_dim_by_name(dt, old_name), new_name) + return isl_obj # }}} diff --git a/loopy/transform/iname.py b/loopy/transform/iname.py index 548f9ec01..85a548896 100644 --- a/loopy/transform/iname.py +++ b/loopy/transform/iname.py @@ -2158,10 +2158,10 @@ def process_set(s): # Now rename any proxy dims back to their original names - from loopy.isl_helpers import find_and_rename_dim - for real_iname, proxy_iname in proxy_name_pairs: - new_s = find_and_rename_dim( - new_s, dim_type.set, proxy_iname, real_iname) + from loopy.isl_helpers import find_and_rename_dims + new_s = find_and_rename_dims( + new_s, dim_type.set, + dict([pair[::-1] for pair in proxy_name_pairs])) # (reverse pair order) return new_s From 9f8bc7a02a29a999c603fb36457135ab7dffb8a8 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Sep 2021 13:43:23 -0500 Subject: [PATCH 199/220] use find_and_rename_dims from isl_helpers --- loopy/schedule/checker/schedule.py | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 3ebc79204..4cad869d8 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -30,6 +30,9 @@ remove_dims_by_name, prettier_map_string, # noqa ) +from loopy.isl_helpers import ( + find_and_rename_dims, +) dim_type = isl.dim_type @@ -228,19 +231,6 @@ class StatementOrdering: # {{{ _gather_blex_ordering_info -def _find_and_rename_dims(isl_obj, dt, rename_dict): - # TODO remove this func once it's merged into isl_helpers - for old_name, new_name in rename_dict.items(): - idx = isl_obj.find_dim_by_name(dt, old_name) - if idx == -1: - raise ValueError( - "_find_and_rename_dims did not find dimension %s" - % (old_name)) - isl_obj = isl_obj.set_dim_name( - dt, isl_obj.find_dim_by_name(dt, old_name), new_name) - return isl_obj - - def _add_eq_isl_constraints_for_ints_only(isl_obj, assignment_pairs): for dim_name, val in assignment_pairs: if isinstance(val, int): @@ -275,7 +265,7 @@ def _add_one_blex_tuple( all_within_inames, [dim_type.set]) # Rename sequential iname dims to blex dims - dom = _find_and_rename_dims( + dom = find_and_rename_dims( dom, dim_type.set, dict(zip(blex_tuple[1::2], all_seq_blex_dim_names[1::2]))) @@ -567,7 +557,7 @@ def _gather_blex_ordering_info( conc_iname: conc_iname+BEFORE_MARK for conc_iname in conc_inames} all_blex_points_prime = append_mark_to_isl_map_var_names( all_blex_points, dim_type.set, BEFORE_MARK) - all_blex_points_prime = _find_and_rename_dims( + all_blex_points_prime = find_and_rename_dims( all_blex_points_prime, dim_type.param, conc_iname_to_iname_prime, ) blex_order_map = blex_order_map.intersect_domain( @@ -637,7 +627,7 @@ def _gather_blex_ordering_info( # Rename iname dims to blex dims # TODO could there be any other inames involved besides first_tuple[1::2]? - loop_min_bound = _find_and_rename_dims( + loop_min_bound = find_and_rename_dims( loop_min_bound, dim_type.set, {k: iname_to_blex_var[k] for k in first_tuple[1::2]}) # Align with blex space (adds needed dims) @@ -708,7 +698,7 @@ def _gather_blex_ordering_info( loop_max_bound = loop_bounds[iname][1] # Rename iname dims to blex dims - loop_max_bound = _find_and_rename_dims( + loop_max_bound = find_and_rename_dims( loop_max_bound, dim_type.set, {k: iname_to_blex_var[k] for k in last_tuple[1::2]}) @@ -724,7 +714,7 @@ def _gather_blex_ordering_info( # append the BEFORE_MARK to those inames to ensure that they are # distinguished from the corresponding non-marked 'after' (concurrent) # inames. - loop_max_bound = _find_and_rename_dims( + loop_max_bound = find_and_rename_dims( loop_max_bound, dim_type.param, conc_iname_to_iname_prime) # Align with blex space (adds needed dims) From 7bd70745dbbbf63e61c65d1f303232a465380ccd Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Sep 2021 15:24:31 -0500 Subject: [PATCH 200/220] reduce duplicate code in get_pairwise_statement_orderings_inner --- loopy/schedule/checker/schedule.py | 35 ++++++++++++------------------ 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 4cad869d8..6fd9f593c 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -1097,30 +1097,23 @@ def get_pairwise_statement_orderings_inner( # whole kernel, they may be assigned (tagged) to one iname for some # subset of statements and another iname for a different subset of # statements (e.g., tiled, paralle. matmul). - #lex_var_to_conc_inames = {} for iname in knl.all_inames(): - ltag = knl.iname_tags_of_type(iname, LocalInameTag) - if ltag: - assert len(ltag) == 1 # (should always be true) - ltag_var = LTAG_VAR_NAMES[ltag.pop().axis] - ltag_var_prime = ltag_var+BEFORE_MARK + conc_tag = knl.iname_tags_of_type(iname, (LocalInameTag, GroupInameTag)) + if conc_tag: + assert len(conc_tag) == 1 # (should always be true) + conc_tag = conc_tag.pop() + if isinstance(conc_tag, LocalInameTag): + tag_var = LTAG_VAR_NAMES[conc_tag.axis] + lid_lex_dim_names.add(tag_var) + else: # Must be GroupInameTag + tag_var = GTAG_VAR_NAMES[conc_tag.axis] + gid_lex_dim_names.add(tag_var) + + tag_var_prime = tag_var+BEFORE_MARK iname_prime = iname+BEFORE_MARK - lid_lex_dim_names.add(ltag_var) - conc_iname_constraint_dicts[iname] = {1: 0, iname: 1, ltag_var: -1} + conc_iname_constraint_dicts[iname] = {1: 0, iname: 1, tag_var: -1} conc_iname_constraint_dicts_prime[iname_prime] = { - 1: 0, iname_prime: 1, ltag_var_prime: -1} - continue # Shouldn't be any GroupInameTags - - gtag = knl.iname_tags_of_type(iname, GroupInameTag) - if gtag: - assert len(gtag) == 1 # (should always be true) - gtag_var = GTAG_VAR_NAMES[gtag.pop().axis] - gtag_var_prime = gtag_var+BEFORE_MARK - iname_prime = iname+BEFORE_MARK - gid_lex_dim_names.add(gtag_var) - conc_iname_constraint_dicts[iname] = {1: 0, iname: 1, gtag_var: -1} - conc_iname_constraint_dicts_prime[iname_prime] = { - 1: 0, iname_prime: 1, gtag_var_prime: -1} + 1: 0, iname_prime: 1, tag_var_prime: -1} # Sort for consistent dimension ordering lid_lex_dim_names = sorted(lid_lex_dim_names) From 193475930806b3663101b3e8592fedb6632b60e6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 11:16:28 -0500 Subject: [PATCH 201/220] create single list of all conc_iname_constraint_dicts to pass to get_pairwise_statement_orderings_inner --- loopy/schedule/checker/schedule.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 6fd9f593c..e4b5c6a7f 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -304,7 +304,7 @@ def _gather_blex_ordering_info( loops_to_ignore, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, - conc_iname_constraint_dicts, conc_iname_constraint_dicts_prime, + conc_iname_constraint_dicts, perform_closure_checks=False, ): # TODO some of these params might be redundant @@ -816,9 +816,7 @@ def _gather_blex_ordering_info( blex_order_map, dim_type.out, all_par_lex_dim_names) # Set each of the new conc lex dims equal to *all* corresponding inames - for constraint_dict in conc_iname_constraint_dicts_prime: - blex_order_map = blex_order_map.add_constraint( - isl.Constraint.eq_from_names(blex_order_map.space, constraint_dict)) + # (here, conc_iname_constraint_dicts includes primed inames) for constraint_dict in conc_iname_constraint_dicts: blex_order_map = blex_order_map.add_constraint( isl.Constraint.eq_from_names(blex_order_map.space, constraint_dict)) @@ -1149,6 +1147,9 @@ def get_pairwise_statement_orderings_inner( # {{{ Create blex order maps and blex tuples defining statement ordering (x2) all_par_lex_dim_names = lid_lex_dim_names + gid_lex_dim_names + all_conc_iname_constraint_dicts = list( + conc_iname_constraint_dicts.values() + ) + list(conc_iname_constraint_dicts_prime.values()) # Get the blex schedule blueprint (dict will become a map below) and # blex order map w.r.t. local and global barriers @@ -1161,8 +1162,7 @@ def get_pairwise_statement_orderings_inner( loops_to_ignore, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, - conc_iname_constraint_dicts.values(), - conc_iname_constraint_dicts_prime.values(), + all_conc_iname_constraint_dicts, perform_closure_checks=perform_closure_checks, ) (stmt_inst_to_gblex, @@ -1174,8 +1174,7 @@ def get_pairwise_statement_orderings_inner( loops_to_ignore, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, - conc_iname_constraint_dicts.values(), - conc_iname_constraint_dicts_prime.values(), + all_conc_iname_constraint_dicts, perform_closure_checks=perform_closure_checks, ) From 16dde82785acff7e1caa8dbf9175316c8cf90999 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 14:43:13 -0500 Subject: [PATCH 202/220] clean up and document _add_one_blex_tuple() --- loopy/schedule/checker/schedule.py | 47 ++++++++++++++++++------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index e4b5c6a7f..f05938562 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -248,53 +248,64 @@ def _assert_exact_closure(mapping): def _add_one_blex_tuple( all_blex_points, blex_tuple, all_seq_blex_dim_names, conc_inames, knl): + """Create the (bounded) set of blex points represented by *blex_tuple* and + add it to *all_blex_points*. + """ - # blex_tuple contains 1 dim plus 2 dims for each *current* loop, so it may - # be shorter than all_seq_blex_dim_names, which contains *all* the blex dim - # names + # blex_tuple: (int, iname, int, iname, int, ...) + # - Contains 1 initial dim plus 2 dims for each sequential loop surrounding + # the *current* linearization item + # - blex_tuple[1::2] is a subset of all sequential inames - # Get set of inames nested outside (including this iname) - all_within_inames = set(blex_tuple[1::2]) | conc_inames + # {{{ Get inames domain for current inames - # Get inames domain for current inames # (need to account for concurrent inames here rather than adding them on # to blex map at the end because a sequential iname domain may depend on a # concurrent iname domain) + + # Get set of inames nested outside (including this iname) + all_within_inames = set(blex_tuple[1::2]) | conc_inames + dom = knl.get_inames_domain( all_within_inames).project_out_except( all_within_inames, [dim_type.set]) - # Rename sequential iname dims to blex dims + # }}} + + # {{{ Prepare for union between dom and all_blex_points + + # Rename sequential iname dims in dom to corresponding blex dim names dom = find_and_rename_dims( dom, dim_type.set, dict(zip(blex_tuple[1::2], all_seq_blex_dim_names[1::2]))) - # Move concurrent inames to params + # Move concurrent inames in dom to params dom = move_dims_by_name( dom, dim_type.param, dom.n_param(), dim_type.set, conc_inames) - # Add any new params in dom to all_blex_points - current_params = all_blex_points.get_var_names(dim_type.param) - needed_params = dom.get_var_names(dim_type.param) - missing_params = set(needed_params) - set(current_params) + # Add any new params found in dom to all_blex_points prior to aligning dom + # with all_blex_points + missing_params = set( + dom.get_var_names(dim_type.param) # needed params + ) - set(all_blex_points.get_var_names(dim_type.param)) # current params all_blex_points = add_and_name_isl_dims( all_blex_points, dim_type.param, missing_params) - # Add missing blex dims and align + # Add missing blex dims to dom and align it with all_blex_points dom = isl.align_spaces(dom, all_blex_points) - # Set values for non-iname blex dims + # Set values for non-iname (integer) blex dims in dom for blex_dim_name, blex_val in zip(all_seq_blex_dim_names[::2], blex_tuple[::2]): dom = add_eq_isl_constraint_from_names(dom, blex_dim_name, blex_val) - # Set any unused (rightmost, fastest-updating) blex dims to zero + # Set values for any unused (rightmost, fastest-updating) dom blex dims to zero for blex_dim_name in all_seq_blex_dim_names[len(blex_tuple):]: dom = add_eq_isl_constraint_from_names(dom, blex_dim_name, 0) - # Add this blex set to full set of blex points - all_blex_points |= dom + # }}} - return all_blex_points + # Add this blex set to full set of blex points + return all_blex_points | dom def _gather_blex_ordering_info( From 5de7173886ed43f499d2f9d0691b1c46339a3b74 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 15:34:11 -0500 Subject: [PATCH 203/220] clarify distinction between ilp/vec concurrent loops and non-ilp/vec concurrent loops; enable removal of redundant pass over instructions by computing max_depth_of_barrier_loop in first pass --- loopy/schedule/checker/__init__.py | 11 +++++-- loopy/schedule/checker/schedule.py | 50 ++++++++++++++++++------------ 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index eaaf7d52d..6b30e19c0 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -109,17 +109,22 @@ def get_pairwise_statement_orderings( # {{{ Find any EnterLoop inames that are tagged as concurrent # so that get_pairwise_statement_orderings_inner() knows to ignore them # (In the future, this should only include inames tagged with 'vec'.) + + # FIXME Consider just putting this ilp/vec logic inside + # get_pairwise_statement_orderings_inner; passing these in as + # 'loops_to_ignore' made more sense when we were just dealing with the + # intra-thread case. from loopy.schedule.checker.utils import ( partition_inames_by_concurrency, get_EnterLoop_inames, ) conc_inames, _ = partition_inames_by_concurrency(knl) enterloop_inames = get_EnterLoop_inames(lin_items) - conc_loop_inames = conc_inames & enterloop_inames + ilp_and_vec_inames = conc_inames & enterloop_inames # The only concurrent EnterLoop inames should be Vec and ILP from loopy.kernel.data import (VectorizeTag, IlpBaseTag) - for conc_iname in conc_loop_inames: + for conc_iname in ilp_and_vec_inames: # Assert that there exists an ilp or vectorize tag (out of the # potentially multiple other tags on this concurrent iname). assert any( @@ -137,7 +142,7 @@ def get_pairwise_statement_orderings( knl, lin_items, stmt_id_pairs, - loops_to_ignore=conc_loop_inames, + ilp_and_vec_inames=ilp_and_vec_inames, perform_closure_checks=perform_closure_checks, ) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index f05938562..dd4386058 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -312,7 +312,8 @@ def _gather_blex_ordering_info( knl, sync_kind, lin_items, loops_with_barriers, - loops_to_ignore, conc_inames, loop_bounds, + max_seq_loop_depth, + ilp_and_vec_inames, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, conc_iname_constraint_dicts, @@ -348,20 +349,23 @@ def _gather_blex_ordering_info( # {{{ Determine the number of blex dims we will need + # TODO remove after sanity checks on downstream branch(es): max_nested_loops = 0 cur_nested_loops = 0 # TODO for effiency, this pass could be combined with an earlier pass for lin_item in lin_items: if isinstance(lin_item, EnterLoop): - if lin_item.iname in loops_with_barriers - loops_to_ignore: + if lin_item.iname in loops_with_barriers - ilp_and_vec_inames: cur_nested_loops += 1 elif isinstance(lin_item, LeaveLoop): - if lin_item.iname in loops_with_barriers - loops_to_ignore: + if lin_item.iname in loops_with_barriers - ilp_and_vec_inames: max_nested_loops = max(cur_nested_loops, max_nested_loops) cur_nested_loops -= 1 else: pass - n_seq_blex_dims = max_nested_loops*2 + 1 + assert max_nested_loops == max_seq_loop_depth + + n_seq_blex_dims = max_seq_loop_depth*2 + 1 # }}} @@ -410,7 +414,7 @@ def _gather_blex_ordering_info( for lin_item in lin_items: if isinstance(lin_item, EnterLoop): enter_iname = lin_item.iname - if enter_iname in loops_with_barriers - loops_to_ignore: + if enter_iname in loops_with_barriers - ilp_and_vec_inames: pre_loop_blex_pt = next_blex_tuple[:] # Increment next_blex_tuple[-1] for statements in the section @@ -448,7 +452,7 @@ def _gather_blex_ordering_info( elif isinstance(lin_item, LeaveLoop): leave_iname = lin_item.iname - if leave_iname in loops_with_barriers - loops_to_ignore: + if leave_iname in loops_with_barriers - ilp_and_vec_inames: curr_blex_dim_ct = len(next_blex_tuple) @@ -867,7 +871,7 @@ def get_pairwise_statement_orderings_inner( knl, lin_items, stmt_id_pairs, - loops_to_ignore=frozenset(), + ilp_and_vec_inames=frozenset(), perform_closure_checks=False, ): r"""For each statement pair in a subset of all statement pairs found in a @@ -905,7 +909,7 @@ def get_pairwise_statement_orderings_inner( :arg stmt_id_pairs: A list containing pairs of statement identifiers. - :arg loops_to_ignore: A set of inames that will be ignored when + :arg ilp_and_vec_inames: A set of inames that will be ignored when determining the relative ordering of statements. This will typically contain concurrent inames tagged with the ``vec`` or ``ilp`` array access tags. @@ -931,7 +935,7 @@ def get_pairwise_statement_orderings_inner( ) all_stmt_ids = set().union(*stmt_id_pairs) - conc_inames = partition_inames_by_concurrency(knl)[0] - loops_to_ignore + conc_inames = partition_inames_by_concurrency(knl)[0] # {{{ Intra-thread lex order creation @@ -952,7 +956,8 @@ def get_pairwise_statement_orderings_inner( # this information will be used later when creating *intra-group* and # *global* lexicographic orderings loops_with_barriers = {"local": set(), "global": set()} - current_inames = [] + max_depth_of_barrier_loop = {"local": 0, "global": 0} + current_seq_inames = [] # While we're passing through, also determine the values of the active # inames on the first and last iteration of each loop that contains @@ -964,11 +969,12 @@ def get_pairwise_statement_orderings_inner( for lin_item in lin_items: if isinstance(lin_item, EnterLoop): iname = lin_item.iname - current_inames.append(iname) - if iname in loops_to_ignore: + if iname in ilp_and_vec_inames: continue + current_seq_inames.append(iname) + # Increment next_lex_tuple[-1] for statements in the section # of code between this EnterLoop and the matching LeaveLoop. # (not technically necessary if no statement was added in the @@ -983,11 +989,12 @@ def get_pairwise_statement_orderings_inner( elif isinstance(lin_item, LeaveLoop): iname = lin_item.iname - current_inames.pop() - if iname in loops_to_ignore: + if iname in ilp_and_vec_inames: continue + current_seq_inames.pop() + # Upon leaving a loop: # - Pop lex dim for enumerating code sections within this loop # - Pop lex dim for the loop iteration @@ -1013,13 +1020,16 @@ def get_pairwise_statement_orderings_inner( elif isinstance(lin_item, Barrier): lp_stmt_id = lin_item.originating_insn_id - loops_with_barriers[lin_item.synchronization_kind] |= set(current_inames) + sync_kind = lin_item.synchronization_kind + loops_with_barriers[sync_kind] |= set(current_seq_inames) + max_depth_of_barrier_loop[sync_kind] = max( + len(current_seq_inames), max_depth_of_barrier_loop[sync_kind]) # {{{ Store bounds for loops containing barriers # Only compute the bounds we haven't already stored; bounds finding # will only happen once for each barrier-containing loop - for depth, iname in enumerate(current_inames): + for depth, iname in enumerate(current_seq_inames): # If we haven't already stored bounds for this iname, do so if iname not in loop_bounds: @@ -1027,7 +1037,7 @@ def get_pairwise_statement_orderings_inner( # Get set of inames that might be involved in this bound # (this iname plus any nested outside this iname, including # concurrent inames) - seq_surrounding_inames = set(current_inames[:depth]) + seq_surrounding_inames = set(current_seq_inames[:depth]) all_surrounding_inames = seq_surrounding_inames | conc_inames # Get inames domain @@ -1170,7 +1180,8 @@ def get_pairwise_statement_orderings_inner( knl, "local", lin_items, loops_with_barriers["local"], - loops_to_ignore, conc_inames, loop_bounds, + max_depth_of_barrier_loop["local"], + ilp_and_vec_inames, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, all_conc_iname_constraint_dicts, @@ -1182,7 +1193,8 @@ def get_pairwise_statement_orderings_inner( knl, "global", lin_items, loops_with_barriers["global"], - loops_to_ignore, conc_inames, loop_bounds, + max_depth_of_barrier_loop["global"], + ilp_and_vec_inames, conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, all_conc_iname_constraint_dicts, From 5c6b830e219840fb0dbc759908b8c2a12a8cbebe Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 15:37:49 -0500 Subject: [PATCH 204/220] remove now-redundant pass through linearization items to compute max_nested_loops in _gather_blex_ordering_info() --- loopy/schedule/checker/schedule.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index dd4386058..6d0ce4240 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -349,22 +349,6 @@ def _gather_blex_ordering_info( # {{{ Determine the number of blex dims we will need - # TODO remove after sanity checks on downstream branch(es): - max_nested_loops = 0 - cur_nested_loops = 0 - # TODO for effiency, this pass could be combined with an earlier pass - for lin_item in lin_items: - if isinstance(lin_item, EnterLoop): - if lin_item.iname in loops_with_barriers - ilp_and_vec_inames: - cur_nested_loops += 1 - elif isinstance(lin_item, LeaveLoop): - if lin_item.iname in loops_with_barriers - ilp_and_vec_inames: - max_nested_loops = max(cur_nested_loops, max_nested_loops) - cur_nested_loops -= 1 - else: - pass - assert max_nested_loops == max_seq_loop_depth - n_seq_blex_dims = max_seq_loop_depth*2 + 1 # }}} From a7d6509181cba063bb7c2765f422b8d17acc5f7c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 15:43:58 -0500 Subject: [PATCH 205/220] minor formatting changes --- loopy/schedule/checker/schedule.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 6d0ce4240..65f790ca3 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -347,14 +347,11 @@ def _gather_blex_ordering_info( # create sub-maps which will be *excluded* (subtracted) from a standard # lexicographic ordering in order to create the blex ordering - # {{{ Determine the number of blex dims we will need + # {{{ Create the initial (pre-subtraction) blex order map, initially w/o bounds + # Determine the number of blex dims we will need n_seq_blex_dims = max_seq_loop_depth*2 + 1 - # }}} - - # {{{ Create the initial (pre-subtraction) blex order map, initially w/o bounds - # Create names for the blex dimensions for sequential loops seq_blex_dim_names = [ LEX_VAR_PREFIX+str(i) for i in range(n_seq_blex_dims)] @@ -366,8 +363,7 @@ def _gather_blex_ordering_info( # all blex points) blex_order_map = create_lex_order_map( dim_names=seq_blex_dim_names, - in_dim_mark=BEFORE_MARK, - ) + in_dim_mark=BEFORE_MARK) # }}} From 973e319ac37982d458b102c3f5dd575b10e8c1f5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 15:48:40 -0500 Subject: [PATCH 206/220] iliminate redundant arg ilp_and_vec_inames from _gather_blex_ordering_info; rename loops_with_barriers->seq_loops_with_barriers for clarity --- loopy/schedule/checker/schedule.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 65f790ca3..45ed1f4dc 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -311,9 +311,9 @@ def _add_one_blex_tuple( def _gather_blex_ordering_info( knl, sync_kind, - lin_items, loops_with_barriers, + lin_items, seq_loops_with_barriers, max_seq_loop_depth, - ilp_and_vec_inames, conc_inames, loop_bounds, + conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, conc_iname_constraint_dicts, @@ -394,7 +394,7 @@ def _gather_blex_ordering_info( for lin_item in lin_items: if isinstance(lin_item, EnterLoop): enter_iname = lin_item.iname - if enter_iname in loops_with_barriers - ilp_and_vec_inames: + if enter_iname in seq_loops_with_barriers: pre_loop_blex_pt = next_blex_tuple[:] # Increment next_blex_tuple[-1] for statements in the section @@ -432,7 +432,7 @@ def _gather_blex_ordering_info( elif isinstance(lin_item, LeaveLoop): leave_iname = lin_item.iname - if leave_iname in loops_with_barriers - ilp_and_vec_inames: + if leave_iname in seq_loops_with_barriers: curr_blex_dim_ct = len(next_blex_tuple) @@ -935,7 +935,7 @@ def get_pairwise_statement_orderings_inner( # While we're passing through, determine which loops contain barriers, # this information will be used later when creating *intra-group* and # *global* lexicographic orderings - loops_with_barriers = {"local": set(), "global": set()} + seq_loops_with_barriers = {"local": set(), "global": set()} max_depth_of_barrier_loop = {"local": 0, "global": 0} current_seq_inames = [] @@ -1001,7 +1001,7 @@ def get_pairwise_statement_orderings_inner( elif isinstance(lin_item, Barrier): lp_stmt_id = lin_item.originating_insn_id sync_kind = lin_item.synchronization_kind - loops_with_barriers[sync_kind] |= set(current_seq_inames) + seq_loops_with_barriers[sync_kind] |= set(current_seq_inames) max_depth_of_barrier_loop[sync_kind] = max( len(current_seq_inames), max_depth_of_barrier_loop[sync_kind]) @@ -1159,9 +1159,9 @@ def get_pairwise_statement_orderings_inner( seq_lblex_dim_names) = _gather_blex_ordering_info( knl, "local", - lin_items, loops_with_barriers["local"], + lin_items, seq_loops_with_barriers["local"], max_depth_of_barrier_loop["local"], - ilp_and_vec_inames, conc_inames, loop_bounds, + conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, all_conc_iname_constraint_dicts, @@ -1172,9 +1172,9 @@ def get_pairwise_statement_orderings_inner( seq_gblex_dim_names) = _gather_blex_ordering_info( knl, "global", - lin_items, loops_with_barriers["global"], + lin_items, seq_loops_with_barriers["global"], max_depth_of_barrier_loop["global"], - ilp_and_vec_inames, conc_inames, loop_bounds, + conc_inames, loop_bounds, all_stmt_ids, all_par_lex_dim_names, gid_lex_dim_names, all_conc_iname_constraint_dicts, From 77a2c3e78d2ea7036b8eb62f147cf1241f22ea9c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 15:56:54 -0500 Subject: [PATCH 207/220] use 'conc' (concurrent) instead of 'par' for naming consistency --- loopy/schedule/checker/schedule.py | 38 +++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 45ed1f4dc..4adeae750 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -315,7 +315,7 @@ def _gather_blex_ordering_info( max_seq_loop_depth, conc_inames, loop_bounds, all_stmt_ids, - all_par_lex_dim_names, gid_lex_dim_names, + all_conc_lex_dim_names, gid_lex_dim_names, conc_iname_constraint_dicts, perform_closure_checks=False, ): @@ -806,9 +806,9 @@ def _gather_blex_ordering_info( # Add conc lex dim names to both in_ and out dims blex_order_map = add_and_name_isl_dims( blex_order_map, dim_type.in_, - [v+BEFORE_MARK for v in all_par_lex_dim_names]) + [v+BEFORE_MARK for v in all_conc_lex_dim_names]) blex_order_map = add_and_name_isl_dims( - blex_order_map, dim_type.out, all_par_lex_dim_names) + blex_order_map, dim_type.out, all_conc_lex_dim_names) # Set each of the new conc lex dims equal to *all* corresponding inames # (here, conc_iname_constraint_dicts includes primed inames) @@ -1147,7 +1147,7 @@ def get_pairwise_statement_orderings_inner( # {{{ Create blex order maps and blex tuples defining statement ordering (x2) - all_par_lex_dim_names = lid_lex_dim_names + gid_lex_dim_names + all_conc_lex_dim_names = lid_lex_dim_names + gid_lex_dim_names all_conc_iname_constraint_dicts = list( conc_iname_constraint_dicts.values() ) + list(conc_iname_constraint_dicts_prime.values()) @@ -1163,7 +1163,7 @@ def get_pairwise_statement_orderings_inner( max_depth_of_barrier_loop["local"], conc_inames, loop_bounds, all_stmt_ids, - all_par_lex_dim_names, gid_lex_dim_names, + all_conc_lex_dim_names, gid_lex_dim_names, all_conc_iname_constraint_dicts, perform_closure_checks=perform_closure_checks, ) @@ -1176,7 +1176,7 @@ def get_pairwise_statement_orderings_inner( max_depth_of_barrier_loop["global"], conc_inames, loop_bounds, all_stmt_ids, - all_par_lex_dim_names, gid_lex_dim_names, + all_conc_lex_dim_names, gid_lex_dim_names, all_conc_iname_constraint_dicts, perform_closure_checks=perform_closure_checks, ) @@ -1285,7 +1285,7 @@ def _get_map_for_stmt( intra_thread_sched_maps = [ _get_map_for_stmt( stmt_id, lex_tuple, int_sid, - seq_lex_dim_names+all_par_lex_dim_names) + seq_lex_dim_names+all_conc_lex_dim_names) for stmt_id, lex_tuple, int_sid in zip(stmt_ids, lex_tuples_simplified, int_sids) ] @@ -1298,12 +1298,12 @@ def _get_map_for_stmt( # Add lid/gid dims to lex order map lex_order_map = add_and_name_isl_dims( - lex_order_map, dim_type.out, all_par_lex_dim_names) + lex_order_map, dim_type.out, all_conc_lex_dim_names) lex_order_map = add_and_name_isl_dims( lex_order_map, dim_type.in_, - append_mark_to_strings(all_par_lex_dim_names, mark=BEFORE_MARK)) + append_mark_to_strings(all_conc_lex_dim_names, mark=BEFORE_MARK)) # Constrain lid/gid vars to be equal (this is the intra-thread case) - for var_name in all_par_lex_dim_names: + for var_name in all_conc_lex_dim_names: lex_order_map = add_eq_isl_constraint_from_names( lex_order_map, var_name, var_name+BEFORE_MARK) @@ -1319,18 +1319,18 @@ def _get_map_for_stmt( # {{{ Create SIOs for intra-group case (gid0' == gid0, etc) and global case - def _get_sched_maps_and_sio( + def _get_sched_maps_and_sio_for_conc_exec( stmt_inst_to_blex, blex_order_map, seq_blex_dim_names): # (Vars from outside func used here: - # stmt_ids, int_sids, all_par_lex_dim_names) + # stmt_ids, int_sids, all_conc_lex_dim_names) # Use *unsimplified* lex tuples w/ blex map, which are already padded blex_tuples_padded = [stmt_inst_to_blex[stmt_id] for stmt_id in stmt_ids] - par_sched_maps = [ + sched_maps = [ _get_map_for_stmt( stmt_id, blex_tuple, int_sid, - seq_blex_dim_names+all_par_lex_dim_names) # all par names + seq_blex_dim_names+all_conc_lex_dim_names) # all par names for stmt_id, blex_tuple, int_sid in zip(stmt_ids, blex_tuples_padded, int_sids) ] @@ -1339,17 +1339,17 @@ def _get_sched_maps_and_sio( # 'before' to equal GID 'after' earlier in _gather_blex_ordering_info() # Create statement instance ordering - sio_par = get_statement_ordering_map( - *par_sched_maps, # note, func accepts exactly two maps + sio = get_statement_ordering_map( + *sched_maps, # note, func accepts exactly two maps blex_order_map, before_mark=BEFORE_MARK, ) - return par_sched_maps, sio_par + return sched_maps, sio - pwsched_intra_group, sio_intra_group = _get_sched_maps_and_sio( + pwsched_intra_group, sio_intra_group = _get_sched_maps_and_sio_for_conc_exec( stmt_inst_to_lblex, lblex_order_map, seq_lblex_dim_names) - pwsched_global, sio_global = _get_sched_maps_and_sio( + pwsched_global, sio_global = _get_sched_maps_and_sio_for_conc_exec( stmt_inst_to_gblex, gblex_order_map, seq_gblex_dim_names) # }}} From c1a3d3ecbde6596d0fe19cfc42cf7f9ef326cbb4 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 17:52:34 -0500 Subject: [PATCH 208/220] significantly revise/improve comments about subtraction blex map creation --- loopy/schedule/checker/schedule.py | 178 ++++++++++++++++------------- 1 file changed, 98 insertions(+), 80 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 4adeae750..05886877e 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -231,6 +231,8 @@ class StatementOrdering: # {{{ _gather_blex_ordering_info +# {{{ Helper functions + def _add_eq_isl_constraints_for_ints_only(isl_obj, assignment_pairs): for dim_name, val in assignment_pairs: if isinstance(val, int): @@ -255,6 +257,7 @@ def _add_one_blex_tuple( # blex_tuple: (int, iname, int, iname, int, ...) # - Contains 1 initial dim plus 2 dims for each sequential loop surrounding # the *current* linearization item + # - Will need padding with zeros for any trailing blex dims # - blex_tuple[1::2] is a subset of all sequential inames # {{{ Get inames domain for current inames @@ -307,6 +310,8 @@ def _add_one_blex_tuple( # Add this blex set to full set of blex points return all_blex_points | dom +# }}} + def _gather_blex_ordering_info( knl, @@ -341,11 +346,15 @@ def _gather_blex_ordering_info( # {{{ First, create map from stmt instances to blex space. - # At the same time, gather information necessary to create the - # blex ordering map, i.e., for each loop, gather the 6 lex order tuples - # defined above in SpecialLexPointWRTLoop that will be required to - # create sub-maps which will be *excluded* (subtracted) from a standard - # lexicographic ordering in order to create the blex ordering + # At the same time, + # - Gather information necessary to create the blex ordering map, i.e., for + # each loop, gather the 6 lex order tuples defined above in + # SpecialLexPointWRTLoop that will be required to create sub-maps which + # will be *excluded* (subtracted) from a standard lexicographic ordering in + # order to create the blex ordering + # - Create all_blex_points, a set containing *all* blex points, which will + # be used later to impose bounds on the full blex map and any blex maps to + # be subtracted from it # {{{ Create the initial (pre-subtraction) blex order map, initially w/o bounds @@ -383,14 +392,11 @@ def _gather_blex_ordering_info( # }}} - # TODO may be able to remove some of this stuff now: stmt_inst_to_blex = {} # Map stmt instances to blex space iname_to_blex_dim = {} # Map from inames to corresponding blex space dim blex_exclusion_info = {} # Info for creating maps to exclude from blex order next_blex_tuple = [0] # Next tuple of points in blex order - known_blex_dim_ubounds = [0, ] # Place to store bounds for non-iname blex dims - for lin_item in lin_items: if isinstance(lin_item, EnterLoop): enter_iname = lin_item.iname @@ -406,11 +412,10 @@ def _gather_blex_ordering_info( # code within new loop next_blex_tuple.append(enter_iname) next_blex_tuple.append(0) - known_blex_dim_ubounds.append(None) - known_blex_dim_ubounds.append(0) - # Store 3 tuples that will be used later to create pairs - # that will later be subtracted from the blex order map + # Store 3 tuples that will later be used to create mappings + # between blex points that will be subtracted from the full + # blex order map first_iter_blex_pt = next_blex_tuple[:] first_iter_blex_pt[-2] = enter_iname @@ -422,7 +427,7 @@ def _gather_blex_ordering_info( # (copy these three blex points when creating dict because # the lists will continue to be updated) - # {{{ Create the blex set for this blex point + # {{{ Create the blex set for this point, add it to all_blex_points all_blex_points = _add_one_blex_tuple( all_blex_points, next_blex_tuple, @@ -439,10 +444,6 @@ def _gather_blex_ordering_info( # Record the blex dim for this loop iname iname_to_blex_dim[leave_iname] = curr_blex_dim_ct-2 - # Record the max value for the non-iname blex dim - known_blex_dim_ubounds[curr_blex_dim_ct-1] = max( - next_blex_tuple[-1], known_blex_dim_ubounds[curr_blex_dim_ct-1]) - # Update next blex pt pre_end_loop_blex_pt = next_blex_tuple[:] # Upon leaving a loop: @@ -453,8 +454,9 @@ def _gather_blex_ordering_info( next_blex_tuple.pop() next_blex_tuple[-1] += 1 - # Store 3 tuples that will be used later to create pairs - # that will later be subtracted from the blex order map + # Store 3 tuples that will later be used to create mappings + # between blex points that will be subtracted from the full + # blex order map # TODO some of this storage may be unnecessary now that loop # bounds are found elsewhere... clean this up @@ -470,7 +472,7 @@ def _gather_blex_ordering_info( # (copy these three blex points when creating dict because # the lists will continue to be updated) - # {{{ Create the blex set for this blex point + # {{{ Create the blex set for this point, add it to all_blex_points all_blex_points = _add_one_blex_tuple( all_blex_points, next_blex_tuple, @@ -489,7 +491,7 @@ def _gather_blex_ordering_info( if lin_item.synchronization_kind == sync_kind: next_blex_tuple[-1] += 1 - # {{{ Create the blex set for this blex point + # {{{ Create the blex set for this point, add it to all_blex_points all_blex_points = _add_one_blex_tuple( all_blex_points, next_blex_tuple, @@ -522,7 +524,8 @@ def _gather_blex_ordering_info( if lin_item.synchronization_kind == sync_kind: next_blex_tuple[-1] += 1 - # {{{ Create the blex set for this blex point + # {{{ Create the blex set for this point, add it to + # all_blex_points all_blex_points = _add_one_blex_tuple( all_blex_points, next_blex_tuple, @@ -588,74 +591,94 @@ def _gather_blex_ordering_info( # {{{ Create blex map to subtract for one iname - """Create the blex->blex pairs that must be subtracted from the + """Create the maps that must be subtracted from the initial blex order map for this particular loop using the 6 blex tuples in key_lex_tuples: PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST + """ - # {{{ PRE->FIRST + # {{{ Create PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST + # initially without iname domain bounds. - # Values in PRE should be strings (inames) or ints. - # We actually already know which blex dims correspond to the inames - # due to their position, and their bounds will be set later by intersecting - # the subtraction map with the (bounded) full blex map. - # We only need to set the values for blex dims that will be ints, - # i.e., the intra-loop-section blex dims and any trailing zeros. + # We know which blex dims correspond to inames due to their + # position in blex tuples (int, iname, int, iname, int, ...), and their + # iname domain bounds will be set later by intersecting the subtraction + # map with the (bounded) full blex map. - # Values in FIRST will involve one of our lexmin bounds. + # Perform the following: + # - For map domains/ranges corresponding to the PRE, BOTTOM, TOP, and + # POST sets, leave the blex dims corresponding to inames unbounded and + # set the values for blex dims that will be ints, i.e., the + # even-indexed (intra-loop-section) blex dims and any trailing zeros. + # - For map domains/ranges corresponding to the FIRST and LAST sets, + # set the map dimension corresponding to this iname using + # loop_bounds[iname][0] and loop_bounds[iname][1]. + # - For the BOTTOM->TOP map, add constraint iname = iname' + 1 - first_tuple = key_lex_tuples[slex.FIRST] - first_tuple_padded = _pad_tuple_with_zeros(first_tuple, n_seq_blex_dims) + # {{{ Create PRE->FIRST map + + # PRE dim vals should all be inames (bounded later) or ints (assign now). + # FIRST dim values will be inames, ints, or one of our lexmin bounds. + + # Pad PRE tuple pre_tuple_padded = _pad_tuple_with_zeros( key_lex_tuples[slex.PRE], n_seq_blex_dims) - # Assign int dims; all other dims will have any necessary bounds set - # later by intersecting with the (bounded) full blex map + # Pad FIRST tuple + first_tuple = key_lex_tuples[slex.FIRST] + first_tuple_padded = _pad_tuple_with_zeros(first_tuple, n_seq_blex_dims) + + # Create PRE->FIRST map and assign int (non-iname) dim values. pre_to_first_map = _add_eq_isl_constraints_for_ints_only( blex_map_template, zip( seq_blex_dim_names_prime+seq_blex_dim_names, pre_tuple_padded+first_tuple_padded)) + # Get the set representing the value of the iname on the first + # iteration of the loop loop_min_bound = loop_bounds[iname][0] # (in loop_bounds sets, concurrent inames are params) - # Rename iname dims to blex dims - # TODO could there be any other inames involved besides first_tuple[1::2]? + # Prepare the loop_min_bound set for intersection with the range of + # pre_to_first_map by renaming iname dims to blex dims and aligning + # spaces loop_min_bound = find_and_rename_dims( loop_min_bound, dim_type.set, {k: iname_to_blex_var[k] for k in first_tuple[1::2]}) # Align with blex space (adds needed dims) loop_first_set = isl.align_spaces(loop_min_bound, blex_set_template) - # Make PRE->FIRST pair by intersecting this with the range of our map + # Finish making PRE->FIRST pair by intersecting this with the range of + # our pre_to_first_map pre_to_first_map = pre_to_first_map.intersect_range(loop_first_set) + # NOTE: We will add a condition to fix iteration values for + # *surrounding* sequential loops (j = j') after combining the three + # maps (PRE-FIRST, BOTTOM->TOP, LAST->POST) below + # }}} - print("PRE->FIRST") - print(prettier_map_string(pre_to_first_map)) + # {{{ Create BOTTOM->TOP map - # {{{ BOTTOM->TOP - # Wrap loop case: BOTTOM(iname')->TOP(iname'+1) + # BOTTOM/TOP dim vals should all be inames (bounded later) or ints + # (assign now). - # Values in BOTTOM/TOP should be strings (inames) or ints. - # We actually already know which blex dims correspond to the inames - # due to their position, and their bounds will be set later by intersecting - # the subtraction map with the (bounded) full blex map. - # We only need to set the values for blex dims that will be ints, - # i.e., the intra-loop-section blex dims and any trailing zeros. + # Pad BOTTOM tuple bottom_tuple_padded = _pad_tuple_with_zeros( key_lex_tuples[slex.BOTTOM], n_seq_blex_dims) + # Pad TOP tuple top_tuple_padded = _pad_tuple_with_zeros( key_lex_tuples[slex.TOP], n_seq_blex_dims) + + # Create BOTTOM->TOP map and assign int (non-iname) dim values. bottom_to_top_map = _add_eq_isl_constraints_for_ints_only( blex_map_template, zip( seq_blex_dim_names_prime+seq_blex_dim_names, bottom_tuple_padded+top_tuple_padded)) - # Add constraint i = i' + 1 + # Add constraint iname = iname' + 1 blex_var_for_iname = iname_to_blex_var[iname] bottom_to_top_map = bottom_to_top_map.add_constraint( isl.Constraint.eq_from_names( @@ -664,65 +687,60 @@ def _gather_blex_ordering_info( # }}} - print("BOTTOM->TOP") - print(prettier_map_string(bottom_to_top_map)) - # {{{ LAST->POST - # Values in POST should be strings (inames) or ints. - # We actually already know which blex dims correspond to the inames - # due to their position, and their bounds will be set later by intersecting - # the subtraction map with the (bounded) full blex map. - # We only need to set the values for blex dims that will be ints, - # i.e., the intra-loop-section blex dims and any trailing zeros. + # POST dim vals should all be inames (bounded later) or ints (assign now). + # LAST dim values will be inames, ints, or one of our lexmax bounds. - # Values in last will involve one of our lexmax bounds. - - last_tuple = key_lex_tuples[slex.LAST] - last_tuple_padded = _pad_tuple_with_zeros(last_tuple, n_seq_blex_dims) + # Pad POST tuple post_tuple_padded = _pad_tuple_with_zeros( key_lex_tuples[slex.POST], n_seq_blex_dims) - # Assign int dims; all other dims will have any necessary bounds set - # later by intersecting with the (bounded) full blex map + # Pad LAST tuple + last_tuple = key_lex_tuples[slex.LAST] + last_tuple_padded = _pad_tuple_with_zeros(last_tuple, n_seq_blex_dims) + + # Create LAST->POST map and assign int (non-iname) dim values. last_to_post_map = _add_eq_isl_constraints_for_ints_only( blex_map_template, zip( seq_blex_dim_names_prime+seq_blex_dim_names, last_tuple_padded+post_tuple_padded)) + # Get the set representing the value of the iname on the last + # iteration of the loop loop_max_bound = loop_bounds[iname][1] - # Rename iname dims to blex dims + # {{{ Prepare the loop_max_bound set for intersection with the domain of + # last_to_post_map by renaming iname dims to blex dims and aligning + # spaces loop_max_bound = find_and_rename_dims( loop_max_bound, dim_type.set, {k: iname_to_blex_var[k] for k in last_tuple[1::2]}) - # We're going to intersect loop_max_bound with the *domain* - # (in-dimension) of the 'before'->'after' map below. We'll first align - # the space of loop_max_bound with the blex_set_template so that all - # the blex dimensions line up, and then use intersect_domain to apply - # loop_max_bound to the 'before' tuple. Because of this, we don't - # need to append the BEFORE_MARK to the inames in the dim_type.set - # dimensions of the loop_max_bound (even though they do apply to a - # 'before' tuple). However, there may be concurrent inames in the - # dim_type.param dimensions of the loop_max_bound, and we DO need to - # append the BEFORE_MARK to those inames to ensure that they are - # distinguished from the corresponding non-marked 'after' (concurrent) - # inames. + # There may be concurrent inames in the dim_type.param dimensions of + # the loop_max_bound, and we need to append the BEFORE_MARK to those + # inames to ensure that they are distinguished from the corresponding + # non-marked 'after' (concurrent) inames. + # (While the other dims in loop_max_bound also correspond to 'before' + # dimensions of last_to_post_map, which carry the 'before' mark, we do + # not need to append the mark to them in loop_max_bound because calling + # last_to_post_map.intersect_domain(loop_last_set) below will match the + # space.in_ dims by position rather than name) loop_max_bound = find_and_rename_dims( loop_max_bound, dim_type.param, conc_iname_to_iname_prime) # Align with blex space (adds needed dims) loop_last_set = isl.align_spaces(loop_max_bound, blex_set_template) + # }}} + # Make LAST->POST pair by intersecting this with the range of our map + # Finish making LAST->POST pair by intersecting this with the range of + # our last_to_post_map last_to_post_map = last_to_post_map.intersect_domain(loop_last_set) # }}} - print("LAST->POST") - print(prettier_map_string(last_to_post_map)) - map_to_subtract = pre_to_first_map | bottom_to_top_map | last_to_post_map # Add condition to fix iter value for *surrounding* sequential loops (j = j') From d3272733d152f7bd2dc9dcbf3e4c1f04f9bd8920 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 19:35:24 -0500 Subject: [PATCH 209/220] eliminate duplicated code in subtraction map creation by adding function _pad_tuples_and_assign_integer_vals_to_map_template --- loopy/schedule/checker/schedule.py | 110 +++++++++++++---------------- 1 file changed, 51 insertions(+), 59 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 05886877e..7f6b22b7b 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -233,14 +233,6 @@ class StatementOrdering: # {{{ Helper functions -def _add_eq_isl_constraints_for_ints_only(isl_obj, assignment_pairs): - for dim_name, val in assignment_pairs: - if isinstance(val, int): - isl_obj = add_eq_isl_constraint_from_names( - isl_obj, dim_name, val) - return isl_obj - - def _assert_exact_closure(mapping): closure_test, closure_exact = mapping.transitive_closure() assert closure_exact @@ -567,27 +559,55 @@ def _gather_blex_ordering_info( # Create mapping (dict) from iname to corresponding blex dim name # TODO rename to "seq_..." - iname_to_blex_var = {} - iname_to_iname_prime = {} + seq_iname_to_blex_var = {} for iname, dim in iname_to_blex_dim.items(): - iname_to_iname_prime[iname] = iname+BEFORE_MARK - iname_to_blex_var[iname] = seq_blex_dim_names[dim] - iname_to_blex_var[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] + seq_iname_to_blex_var[iname] = seq_blex_dim_names[dim] + seq_iname_to_blex_var[iname+BEFORE_MARK] = seq_blex_dim_names_prime[dim] + + # {{{ Get a template map matching blex_order_map.space that will serve as + # the starting point when creating the maps to subtract from blex_order_map - # Get a map representing blex_order_map space - # (Note that this template cannot be created until *after* the intersection + # This template includes concurrent inames as params, both marked + # ('before') and unmarked ('after'). + # Note that this template cannot be created until *after* the intersection # of blex_order_map with all_blex_points above, otherwise the template will - # be missing necessary parameters) + # be missing necessary parameters. blex_map_template = isl.align_spaces( isl.Map("[ ] -> { [ ] -> [ ] }"), blex_order_map) blex_set_template = blex_map_template.range() + # }}} + + # {{{ _pad_tuples_and_assign_integer_vals_to_map_template() helper + + seq_blex_in_out_dim_names = seq_blex_dim_names_prime + seq_blex_dim_names + + def _pad_tuples_and_assign_integer_vals_to_map_template( + in_tuple, out_tuple): + # External variables read (not written): + # n_seq_blex_dims, seq_blex_in_out_dim_names, blex_map_template + + # Pad the tuples + in_tuple_padded = _pad_tuple_with_zeros(in_tuple, n_seq_blex_dims) + out_tuple_padded = _pad_tuple_with_zeros(out_tuple, n_seq_blex_dims) + + # Assign map values for ints only + map_with_int_vals_assigned = blex_map_template + for dim_name, val in zip( + seq_blex_in_out_dim_names, + in_tuple_padded+out_tuple_padded): + if isinstance(val, int): + map_with_int_vals_assigned = add_eq_isl_constraint_from_names( + map_with_int_vals_assigned, dim_name, val) + + return map_with_int_vals_assigned + + # }}} + # {{{ Create blex map to subtract for each iname in blex_exclusion_info maps_to_subtract = [] for iname, key_lex_tuples in blex_exclusion_info.items(): - print("") - print(iname) # {{{ Create blex map to subtract for one iname @@ -621,19 +641,10 @@ def _gather_blex_ordering_info( # PRE dim vals should all be inames (bounded later) or ints (assign now). # FIRST dim values will be inames, ints, or one of our lexmin bounds. - # Pad PRE tuple - pre_tuple_padded = _pad_tuple_with_zeros( - key_lex_tuples[slex.PRE], n_seq_blex_dims) - # Pad FIRST tuple - first_tuple = key_lex_tuples[slex.FIRST] - first_tuple_padded = _pad_tuple_with_zeros(first_tuple, n_seq_blex_dims) - # Create PRE->FIRST map and assign int (non-iname) dim values. - pre_to_first_map = _add_eq_isl_constraints_for_ints_only( - blex_map_template, - zip( - seq_blex_dim_names_prime+seq_blex_dim_names, - pre_tuple_padded+first_tuple_padded)) + first_tuple = key_lex_tuples[slex.FIRST] + pre_to_first_map = _pad_tuples_and_assign_integer_vals_to_map_template( + key_lex_tuples[slex.PRE], first_tuple) # Get the set representing the value of the iname on the first # iteration of the loop @@ -645,7 +656,7 @@ def _gather_blex_ordering_info( # spaces loop_min_bound = find_and_rename_dims( loop_min_bound, dim_type.set, - {k: iname_to_blex_var[k] for k in first_tuple[1::2]}) + {k: seq_iname_to_blex_var[k] for k in first_tuple[1::2]}) # Align with blex space (adds needed dims) loop_first_set = isl.align_spaces(loop_min_bound, blex_set_template) @@ -664,22 +675,12 @@ def _gather_blex_ordering_info( # BOTTOM/TOP dim vals should all be inames (bounded later) or ints # (assign now). - # Pad BOTTOM tuple - bottom_tuple_padded = _pad_tuple_with_zeros( - key_lex_tuples[slex.BOTTOM], n_seq_blex_dims) - # Pad TOP tuple - top_tuple_padded = _pad_tuple_with_zeros( - key_lex_tuples[slex.TOP], n_seq_blex_dims) - - # Create BOTTOM->TOP map and assign int (non-iname) dim values. - bottom_to_top_map = _add_eq_isl_constraints_for_ints_only( - blex_map_template, - zip( - seq_blex_dim_names_prime+seq_blex_dim_names, - bottom_tuple_padded+top_tuple_padded)) + # Create BOTTOM->TOP map and assign int (non-iname) dim values + bottom_to_top_map = _pad_tuples_and_assign_integer_vals_to_map_template( + key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP]) # Add constraint iname = iname' + 1 - blex_var_for_iname = iname_to_blex_var[iname] + blex_var_for_iname = seq_iname_to_blex_var[iname] bottom_to_top_map = bottom_to_top_map.add_constraint( isl.Constraint.eq_from_names( bottom_to_top_map.space, @@ -692,19 +693,10 @@ def _gather_blex_ordering_info( # POST dim vals should all be inames (bounded later) or ints (assign now). # LAST dim values will be inames, ints, or one of our lexmax bounds. - # Pad POST tuple - post_tuple_padded = _pad_tuple_with_zeros( - key_lex_tuples[slex.POST], n_seq_blex_dims) - # Pad LAST tuple - last_tuple = key_lex_tuples[slex.LAST] - last_tuple_padded = _pad_tuple_with_zeros(last_tuple, n_seq_blex_dims) - # Create LAST->POST map and assign int (non-iname) dim values. - last_to_post_map = _add_eq_isl_constraints_for_ints_only( - blex_map_template, - zip( - seq_blex_dim_names_prime+seq_blex_dim_names, - last_tuple_padded+post_tuple_padded)) + last_tuple = key_lex_tuples[slex.LAST] + last_to_post_map = _pad_tuples_and_assign_integer_vals_to_map_template( + last_tuple, key_lex_tuples[slex.POST]) # Get the set representing the value of the iname on the last # iteration of the loop @@ -715,7 +707,7 @@ def _gather_blex_ordering_info( # spaces loop_max_bound = find_and_rename_dims( loop_max_bound, dim_type.set, - {k: iname_to_blex_var[k] for k in last_tuple[1::2]}) + {k: seq_iname_to_blex_var[k] for k in last_tuple[1::2]}) # There may be concurrent inames in the dim_type.param dimensions of # the loop_max_bound, and we need to append the BEFORE_MARK to those @@ -746,7 +738,7 @@ def _gather_blex_ordering_info( # Add condition to fix iter value for *surrounding* sequential loops (j = j') # (odd indices in key_lex_tuples[PRE] contain the sounding inames) for seq_surrounding_iname in key_lex_tuples[slex.PRE][1::2]: - s_blex_var = iname_to_blex_var[seq_surrounding_iname] + s_blex_var = seq_iname_to_blex_var[seq_surrounding_iname] map_to_subtract = add_eq_isl_constraint_from_names( map_to_subtract, s_blex_var, s_blex_var+BEFORE_MARK) From 6b687304054a9b289ff8ee0cfcbefeaaeacc52dd Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 20:23:11 -0500 Subject: [PATCH 210/220] create slice variables for indexing lex/blex tuples --- loopy/schedule/checker/schedule.py | 41 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 7f6b22b7b..baf080b49 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -28,7 +28,9 @@ append_mark_to_isl_map_var_names, move_dims_by_name, remove_dims_by_name, - prettier_map_string, # noqa +) +from loopy.schedule.checker.utils import ( # noqa + prettier_map_string, ) from loopy.isl_helpers import ( find_and_rename_dims, @@ -239,6 +241,10 @@ def _assert_exact_closure(mapping): assert closure_test == mapping +INAME_DIMS = slice(1, None, 2) # Odd indices of (unpadded) blex tuples track inames +CODE_SEC_DIMS = slice(0, None, 2) # Even indices track code sections + + def _add_one_blex_tuple( all_blex_points, blex_tuple, all_seq_blex_dim_names, conc_inames, knl): @@ -250,7 +256,7 @@ def _add_one_blex_tuple( # - Contains 1 initial dim plus 2 dims for each sequential loop surrounding # the *current* linearization item # - Will need padding with zeros for any trailing blex dims - # - blex_tuple[1::2] is a subset of all sequential inames + # - blex_tuple[INAME_DIMS] is a subset of all sequential inames # {{{ Get inames domain for current inames @@ -259,7 +265,7 @@ def _add_one_blex_tuple( # concurrent iname domain) # Get set of inames nested outside (including this iname) - all_within_inames = set(blex_tuple[1::2]) | conc_inames + all_within_inames = set(blex_tuple[INAME_DIMS]) | conc_inames dom = knl.get_inames_domain( all_within_inames).project_out_except( @@ -272,7 +278,7 @@ def _add_one_blex_tuple( # Rename sequential iname dims in dom to corresponding blex dim names dom = find_and_rename_dims( dom, dim_type.set, - dict(zip(blex_tuple[1::2], all_seq_blex_dim_names[1::2]))) + dict(zip(blex_tuple[INAME_DIMS], all_seq_blex_dim_names[INAME_DIMS]))) # Move concurrent inames in dom to params dom = move_dims_by_name( @@ -290,8 +296,9 @@ def _add_one_blex_tuple( # Add missing blex dims to dom and align it with all_blex_points dom = isl.align_spaces(dom, all_blex_points) - # Set values for non-iname (integer) blex dims in dom - for blex_dim_name, blex_val in zip(all_seq_blex_dim_names[::2], blex_tuple[::2]): + # Set values for non-iname (integer) blex dims in dom (excludes 0-padding at end) + for blex_dim_name, blex_val in zip( + all_seq_blex_dim_names[CODE_SEC_DIMS], blex_tuple[CODE_SEC_DIMS]): dom = add_eq_isl_constraint_from_names(dom, blex_dim_name, blex_val) # Set values for any unused (rightmost, fastest-updating) dom blex dims to zero for blex_dim_name in all_seq_blex_dim_names[len(blex_tuple):]: @@ -541,7 +548,7 @@ def _gather_blex_ordering_info( # {{{ Second, create the blex order map - # {{{ Bound the (pre-subtraction) blex order map + # {{{ Bound the full (pre-subtraction) blex order map conc_iname_to_iname_prime = { conc_iname: conc_iname+BEFORE_MARK for conc_iname in conc_inames} @@ -555,7 +562,7 @@ def _gather_blex_ordering_info( # }}} - # {{{ Subtract unwanted pairs from happens-before blex map + # {{{ Subtract unwanted pairs from full blex order map # Create mapping (dict) from iname to corresponding blex dim name # TODO rename to "seq_..." @@ -615,11 +622,10 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( initial blex order map for this particular loop using the 6 blex tuples in key_lex_tuples: PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST - """ # {{{ Create PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST - # initially without iname domain bounds. + # (initially without iname domain bounds) # We know which blex dims correspond to inames due to their # position in blex tuples (int, iname, int, iname, int, ...), and their @@ -649,14 +655,14 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( # Get the set representing the value of the iname on the first # iteration of the loop loop_min_bound = loop_bounds[iname][0] - # (in loop_bounds sets, concurrent inames are params) + # (concurrent inames included in set params) # Prepare the loop_min_bound set for intersection with the range of # pre_to_first_map by renaming iname dims to blex dims and aligning # spaces loop_min_bound = find_and_rename_dims( loop_min_bound, dim_type.set, - {k: seq_iname_to_blex_var[k] for k in first_tuple[1::2]}) + {k: seq_iname_to_blex_var[k] for k in first_tuple[INAME_DIMS]}) # Align with blex space (adds needed dims) loop_first_set = isl.align_spaces(loop_min_bound, blex_set_template) @@ -701,13 +707,14 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( # Get the set representing the value of the iname on the last # iteration of the loop loop_max_bound = loop_bounds[iname][1] + # (concurrent inames included in set params) # {{{ Prepare the loop_max_bound set for intersection with the domain of # last_to_post_map by renaming iname dims to blex dims and aligning # spaces loop_max_bound = find_and_rename_dims( loop_max_bound, dim_type.set, - {k: seq_iname_to_blex_var[k] for k in last_tuple[1::2]}) + {k: seq_iname_to_blex_var[k] for k in last_tuple[INAME_DIMS]}) # There may be concurrent inames in the dim_type.param dimensions of # the loop_max_bound, and we need to append the BEFORE_MARK to those @@ -733,11 +740,13 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( # }}} + # }}} + map_to_subtract = pre_to_first_map | bottom_to_top_map | last_to_post_map # Add condition to fix iter value for *surrounding* sequential loops (j = j') # (odd indices in key_lex_tuples[PRE] contain the sounding inames) - for seq_surrounding_iname in key_lex_tuples[slex.PRE][1::2]: + for seq_surrounding_iname in key_lex_tuples[slex.PRE][INAME_DIMS]: s_blex_var = seq_iname_to_blex_var[seq_surrounding_iname] map_to_subtract = add_eq_isl_constraint_from_names( map_to_subtract, s_blex_var, s_blex_var+BEFORE_MARK) @@ -745,8 +754,6 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( # Bound the blex dims by intersecting with the full blex map, which # contains all the bound constraints map_to_subtract &= blex_order_map - print("CONSTRAINED MAP_TO_SUBTRACT FOR LOOP", iname) - print(prettier_map_string(map_to_subtract)) # }}} @@ -766,7 +773,7 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( # Get transitive closure of maps map_to_subtract_closure, closure_exact = map_to_subtract.transitive_closure() - assert closure_exact # TODO warn instead? + assert closure_exact # FIXME warn instead? # {{{ Check assumptions about map transitivity From e6f0214b82e6c13bf8d8197db7803b56c7f813a1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 20:39:30 -0500 Subject: [PATCH 211/220] remove some TODOs --- loopy/schedule/checker/schedule.py | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index baf080b49..918fd6642 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -315,15 +315,17 @@ def _add_one_blex_tuple( def _gather_blex_ordering_info( knl, sync_kind, - lin_items, seq_loops_with_barriers, + lin_items, + seq_loops_with_barriers, max_seq_loop_depth, - conc_inames, loop_bounds, + conc_inames, + loop_bounds, all_stmt_ids, - all_conc_lex_dim_names, gid_lex_dim_names, + all_conc_lex_dim_names, + gid_lex_dim_names, conc_iname_constraint_dicts, perform_closure_checks=False, ): - # TODO some of these params might be redundant """For the given sync_kind ("local" or "global"), create a mapping from statement instances to blex space (dict), as well as a mapping defining the blex ordering (isl map from blex space -> blex space) @@ -565,7 +567,6 @@ def _gather_blex_ordering_info( # {{{ Subtract unwanted pairs from full blex order map # Create mapping (dict) from iname to corresponding blex dim name - # TODO rename to "seq_..." seq_iname_to_blex_var = {} for iname, dim in iname_to_blex_dim.items(): seq_iname_to_blex_var[iname] = seq_blex_dim_names[dim] @@ -1176,11 +1177,14 @@ def get_pairwise_statement_orderings_inner( seq_lblex_dim_names) = _gather_blex_ordering_info( knl, "local", - lin_items, seq_loops_with_barriers["local"], + lin_items, + seq_loops_with_barriers["local"], max_depth_of_barrier_loop["local"], - conc_inames, loop_bounds, + conc_inames, + loop_bounds, all_stmt_ids, - all_conc_lex_dim_names, gid_lex_dim_names, + all_conc_lex_dim_names, + gid_lex_dim_names, all_conc_iname_constraint_dicts, perform_closure_checks=perform_closure_checks, ) @@ -1189,11 +1193,14 @@ def get_pairwise_statement_orderings_inner( seq_gblex_dim_names) = _gather_blex_ordering_info( knl, "global", - lin_items, seq_loops_with_barriers["global"], + lin_items, + seq_loops_with_barriers["global"], max_depth_of_barrier_loop["global"], - conc_inames, loop_bounds, + conc_inames, + loop_bounds, all_stmt_ids, - all_conc_lex_dim_names, gid_lex_dim_names, + all_conc_lex_dim_names, + gid_lex_dim_names, all_conc_iname_constraint_dicts, perform_closure_checks=perform_closure_checks, ) From 79fa5d18508d56499296db942f06c7b757c220e6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Sep 2021 21:13:00 -0500 Subject: [PATCH 212/220] eliminate explicit storage of FIRST and LAST blex tuples; these are now computed by starting with TOP/BOTTOM and then applying the appropriate loop bound --- loopy/schedule/checker/schedule.py | 93 +++++++++++++++--------------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 918fd6642..ee3dc9b86 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -172,10 +172,6 @@ class SpecialLexPointWRTLoop: A :class:`str` indicating the last lexicographic point that precedes the loop. - .. attribute:: FIRST - A :class:`str` indicating the first lexicographic point in the - first loop iteration (i.e., with the iname set to its min. val). - .. attribute:: TOP A :class:`str` indicating the first lexicographic point in an arbitrary loop iteration. @@ -184,20 +180,14 @@ class SpecialLexPointWRTLoop: A :class:`str` indicating the last lexicographic point in an arbitrary loop iteration. - .. attribute:: LAST - A :class:`str` indicating the last lexicographic point in the - last loop iteration (i.e., with the iname set to its max val). - .. attribute:: POST A :class:`str` indicating the first lexicographic point that follows the loop. """ PRE = "pre" - FIRST = "first" TOP = "top" BOTTOM = "bottom" - LAST = "last" POST = "post" # }}} @@ -402,6 +392,7 @@ def _gather_blex_ordering_info( if isinstance(lin_item, EnterLoop): enter_iname = lin_item.iname if enter_iname in seq_loops_with_barriers: + # Save the blex point prior to this loop pre_loop_blex_pt = next_blex_tuple[:] # Increment next_blex_tuple[-1] for statements in the section @@ -414,18 +405,14 @@ def _gather_blex_ordering_info( next_blex_tuple.append(enter_iname) next_blex_tuple.append(0) - # Store 3 tuples that will later be used to create mappings + # Store 2 tuples that will later be used to create mappings # between blex points that will be subtracted from the full # blex order map - - first_iter_blex_pt = next_blex_tuple[:] - first_iter_blex_pt[-2] = enter_iname blex_exclusion_info[enter_iname] = { slex.PRE: tuple(pre_loop_blex_pt), slex.TOP: tuple(next_blex_tuple), - slex.FIRST: tuple(first_iter_blex_pt), } - # (copy these three blex points when creating dict because + # (copy these blex points when creating dict because # the lists will continue to be updated) # {{{ Create the blex set for this point, add it to all_blex_points @@ -440,13 +427,12 @@ def _gather_blex_ordering_info( leave_iname = lin_item.iname if leave_iname in seq_loops_with_barriers: - curr_blex_dim_ct = len(next_blex_tuple) - # Record the blex dim for this loop iname - iname_to_blex_dim[leave_iname] = curr_blex_dim_ct-2 + iname_to_blex_dim[leave_iname] = len(next_blex_tuple) - 2 - # Update next blex pt + # Save the blex tuple prior to exiting loop pre_end_loop_blex_pt = next_blex_tuple[:] + # Upon leaving a loop: # - Pop lex dim for enumerating code sections within this loop # - Pop lex dim for the loop iteration @@ -455,22 +441,14 @@ def _gather_blex_ordering_info( next_blex_tuple.pop() next_blex_tuple[-1] += 1 - # Store 3 tuples that will later be used to create mappings + # Store 2 tuples that will later be used to create mappings # between blex points that will be subtracted from the full # blex order map - - # TODO some of this storage may be unnecessary now that loop - # bounds are found elsewhere... clean this up - - last_iter_blex_pt = pre_end_loop_blex_pt[:] - last_iter_blex_pt[-2] = leave_iname blex_exclusion_info[leave_iname][slex.BOTTOM] = tuple( pre_end_loop_blex_pt) - blex_exclusion_info[leave_iname][slex.LAST] = tuple( - last_iter_blex_pt) blex_exclusion_info[leave_iname][slex.POST] = tuple( next_blex_tuple) - # (copy these three blex points when creating dict because + # (copy these blex points when creating dict because # the lists will continue to be updated) # {{{ Create the blex set for this point, add it to all_blex_points @@ -623,10 +601,20 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( initial blex order map for this particular loop using the 6 blex tuples in key_lex_tuples: PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST + + The PRE, TOP, BOTTOM, and POST blex points for a given loop are defined + above in doc for SpecialLexPointWRTLoop. + + FIRST indicates the first lexicographic point in the + first loop iteration (i.e., TOP, with the iname set to its min. val). + + LAST indicates the last lexicographic point in the + last loop iteration (i.e., BOTTOM, with the iname set to its max val). + """ # {{{ Create PRE->FIRST, BOTTOM(iname')->TOP(iname'+1), LAST->POST - # (initially without iname domain bounds) + # maps (initially without iname domain bounds) # We know which blex dims correspond to inames due to their # position in blex tuples (int, iname, int, iname, int, ...), and their @@ -639,19 +627,30 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( # set the values for blex dims that will be ints, i.e., the # even-indexed (intra-loop-section) blex dims and any trailing zeros. # - For map domains/ranges corresponding to the FIRST and LAST sets, - # set the map dimension corresponding to this iname using - # loop_bounds[iname][0] and loop_bounds[iname][1]. + # start with the TOP and BOTTOM sets and then set the map dimension + # corresponding to this iname to loop_bounds[iname][0] and + # loop_bounds[iname][1]. # - For the BOTTOM->TOP map, add constraint iname = iname' + 1 + # We will add a condition to fix iteration values for + # *surrounding* sequential loops (iname = iname') after combining the three + # maps (PRE-FIRST, BOTTOM->TOP, LAST->POST) below + + # BOTTOM/TOP tuples will be used multiple times, so grab them now + top_tuple = key_lex_tuples[slex.TOP] + bottom_tuple = key_lex_tuples[slex.BOTTOM] + # {{{ Create PRE->FIRST map # PRE dim vals should all be inames (bounded later) or ints (assign now). - # FIRST dim values will be inames, ints, or one of our lexmin bounds. + # FIRST dim values will be inames, ints, and the lexmin bound for this iname. - # Create PRE->FIRST map and assign int (non-iname) dim values. - first_tuple = key_lex_tuples[slex.FIRST] + # Create FIRST by starting with TOP blex tuple and then intersecting + # it with a set that imposes the lexmin bound for this loop. + + # Create initial PRE->FIRST map and assign int (non-iname) dim values. pre_to_first_map = _pad_tuples_and_assign_integer_vals_to_map_template( - key_lex_tuples[slex.PRE], first_tuple) + key_lex_tuples[slex.PRE], top_tuple) # Get the set representing the value of the iname on the first # iteration of the loop @@ -663,7 +662,7 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( # spaces loop_min_bound = find_and_rename_dims( loop_min_bound, dim_type.set, - {k: seq_iname_to_blex_var[k] for k in first_tuple[INAME_DIMS]}) + {k: seq_iname_to_blex_var[k] for k in top_tuple[INAME_DIMS]}) # Align with blex space (adds needed dims) loop_first_set = isl.align_spaces(loop_min_bound, blex_set_template) @@ -671,10 +670,6 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( # our pre_to_first_map pre_to_first_map = pre_to_first_map.intersect_range(loop_first_set) - # NOTE: We will add a condition to fix iteration values for - # *surrounding* sequential loops (j = j') after combining the three - # maps (PRE-FIRST, BOTTOM->TOP, LAST->POST) below - # }}} # {{{ Create BOTTOM->TOP map @@ -684,7 +679,7 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( # Create BOTTOM->TOP map and assign int (non-iname) dim values bottom_to_top_map = _pad_tuples_and_assign_integer_vals_to_map_template( - key_lex_tuples[slex.BOTTOM], key_lex_tuples[slex.TOP]) + bottom_tuple, top_tuple) # Add constraint iname = iname' + 1 blex_var_for_iname = seq_iname_to_blex_var[iname] @@ -698,12 +693,14 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( # {{{ LAST->POST # POST dim vals should all be inames (bounded later) or ints (assign now). - # LAST dim values will be inames, ints, or one of our lexmax bounds. + # LAST dim values will be inames, ints, and our lexmax bound for this iname. + + # Create LAST by starting with BOTTOM blex tuple and then intersecting + # it with a set that imposes the lexmax bound for this loop. - # Create LAST->POST map and assign int (non-iname) dim values. - last_tuple = key_lex_tuples[slex.LAST] + # Create initial LAST->POST map and assign int (non-iname) dim values. last_to_post_map = _pad_tuples_and_assign_integer_vals_to_map_template( - last_tuple, key_lex_tuples[slex.POST]) + bottom_tuple, key_lex_tuples[slex.POST]) # Get the set representing the value of the iname on the last # iteration of the loop @@ -715,7 +712,7 @@ def _pad_tuples_and_assign_integer_vals_to_map_template( # spaces loop_max_bound = find_and_rename_dims( loop_max_bound, dim_type.set, - {k: seq_iname_to_blex_var[k] for k in last_tuple[INAME_DIMS]}) + {k: seq_iname_to_blex_var[k] for k in bottom_tuple[INAME_DIMS]}) # There may be concurrent inames in the dim_type.param dimensions of # the loop_max_bound, and we need to append the BEFORE_MARK to those From ee33d5ac6fdb8894f2f208c8cf95c9f782706d8b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 16 Sep 2021 16:47:08 -0500 Subject: [PATCH 213/220] eliminate some final TODOs --- loopy/schedule/checker/schedule.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index ee3dc9b86..5f623a710 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -79,8 +79,7 @@ """ LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" -#LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) -LEX_VAR_PREFIX = "lx" # TODO change back +LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) LTAG_VAR_NAMES = [] GTAG_VAR_NAMES = [] @@ -1097,7 +1096,6 @@ def get_pairwise_statement_orderings_inner( # At the same time, create the dicts that will be used later to create map # constraints that match each parallel iname to the corresponding lex dim # name in schedules, i.e., i = lid0, j = lid1, etc. - # TODO some of these vars may be redundant: lid_lex_dim_names = set() gid_lex_dim_names = set() @@ -1107,7 +1105,7 @@ def get_pairwise_statement_orderings_inner( conc_iname_constraint_dicts = {} conc_iname_constraint_dicts_prime = {} - # Even though all parallel thread dims are active throughout the + # NOTE: Even though all parallel thread dims are active throughout the # whole kernel, they may be assigned (tagged) to one iname for some # subset of statements and another iname for a different subset of # statements (e.g., tiled, paralle. matmul). @@ -1132,8 +1130,6 @@ def get_pairwise_statement_orderings_inner( # Sort for consistent dimension ordering lid_lex_dim_names = sorted(lid_lex_dim_names) gid_lex_dim_names = sorted(gid_lex_dim_names) - # TODO remove redundancy have one definitive list for these - # (just make separate 1-d lists for everything?) # }}} From 178285864192bbe32714296e52bf949cbe37d0af Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 16 Sep 2021 17:38:50 -0500 Subject: [PATCH 214/220] Since global barriers also syncronize threads *within* a work-group, make our mechanisms that account for the effect of *local* barriers on execution order view *global* barriers as also having that effect --- loopy/schedule/checker/schedule.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 5f623a710..0666bb6f7 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -386,6 +386,10 @@ def _gather_blex_ordering_info( iname_to_blex_dim = {} # Map from inames to corresponding blex space dim blex_exclusion_info = {} # Info for creating maps to exclude from blex order next_blex_tuple = [0] # Next tuple of points in blex order + sync_kinds_affecting_ordering = set([sync_kind]) + # Global barriers also syncronize across threads within a group + if sync_kind == "local": + sync_kinds_affecting_ordering.add("global") for lin_item in lin_items: if isinstance(lin_item, EnterLoop): @@ -466,7 +470,7 @@ def _gather_blex_ordering_info( elif isinstance(lin_item, Barrier): # Increment blex dim val if the sync scope matches - if lin_item.synchronization_kind == sync_kind: + if lin_item.synchronization_kind in sync_kinds_affecting_ordering: next_blex_tuple[-1] += 1 # {{{ Create the blex set for this point, add it to all_blex_points @@ -499,7 +503,7 @@ def _gather_blex_ordering_info( # If sync scope matches, give this barrier its *own* point in # lex time by updating blex tuple after barrier. - if lin_item.synchronization_kind == sync_kind: + if lin_item.synchronization_kind in sync_kinds_affecting_ordering: next_blex_tuple[-1] += 1 # {{{ Create the blex set for this point, add it to @@ -1088,6 +1092,15 @@ def get_pairwise_statement_orderings_inner( lin_item, (CallKernel, ReturnFromKernel)) pass + # Since global barriers also syncronize threads *within* a work-group, our + # mechanisms that account for the effect of *local* barriers on execution + # order need to view *global* barriers as also having that effect. + # Include global barriers in seq_loops_with_barriers["local"] and + # max_depth_of_barrier_loop["local"]. + seq_loops_with_barriers["local"] |= seq_loops_with_barriers["global"] + max_depth_of_barrier_loop["local"] = max( + max_depth_of_barrier_loop["local"], max_depth_of_barrier_loop["global"]) + # }}} # {{{ Create lex dim names representing parallel axes From dbb852d797f7477ae287ec1992030ea42a4c56d8 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 16 Sep 2021 17:40:03 -0500 Subject: [PATCH 215/220] Update tests after SIO construction change: (Since global barriers also syncronize threads *within* a work-group, make our mechanisms that account for the effect of *local* barriers on execution order view *global* barriers as also having that effect) --- test/test_linearization_checker.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 4622eef7e..4901b1fd8 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -816,7 +816,6 @@ def test_statement_instance_ordering_of_barriers(): # {{{ Relationship between gbar and stmt_a # intra-thread case - sio_intra_thread_exp = _isl_map_with_marked_dims( "[pi, pj] -> {{ " "[{0}'=0, i', ii'] -> [{0}=1, i, ii, j, jj] : " @@ -829,22 +828,22 @@ def test_statement_instance_ordering_of_barriers(): ) # intra-group case - # TODO figure out what this should be - """ + # (this test also confirms that our SIO construction accounts for the fact + # that global barriers *also* syncronize across threads *within* a group, + # which is why the before->after condition below is *not* + # "and (ii > ii' or (ii = ii' and jj > 0))") sio_intra_group_exp = _isl_map_with_marked_dims( "[pi, pj] -> {{ " "[{0}'=0, i', ii'] -> [{0}=1, i, ii, j, jj] : " "0 <= i,ii,i',ii' < pi and 0 <= j,jj < pj " # domains "and i = i' " # GID inames must be same - "and (ii > ii' or (ii = ii' and jj = 0))" # before->after condtion + "and ii >= ii'" # before->after condtion "}}".format( STATEMENT_VAR_NAME, ) ) - """ # global case - sio_global_exp = _isl_map_with_marked_dims( "[pi, pj] -> {{ " "[{0}'=0, i', ii'] -> [{0}=1, i, ii, j, jj] : " @@ -1062,6 +1061,9 @@ def test_sios_and_schedules_with_barriers(): # {{{ Intra-group + # (this test also confirms that our sched/SIO construction accounts for the + # fact that global barriers *also* syncronize across threads *within* a + # group, which is why dim 2 below is asigned the value 3 instead of 2) sched_stmt_j1_intra_group_exp = isl.Map( "[ij_start, ij_end, lg_end] -> {" "[%s=0, i, j, l0, l1, g0] -> [%s] : " @@ -1069,7 +1071,7 @@ def test_sios_and_schedules_with_barriers(): % ( STATEMENT_VAR_NAME, _lex_point_string( - ["2", "i", "2", "j", "1"], # lex points + ["2", "i", "3", "j", "1"], # lex points lid_inames=["l0", "l1"], gid_inames=["g0"], ), ij_bound_str, From b6ad65a81c2fecc2b75657e85045ec58346a8a2f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 17 Sep 2021 16:06:46 -0500 Subject: [PATCH 216/220] add get_pairwise_statement_orderings to loopy.__init__ --- loopy/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/loopy/__init__.py b/loopy/__init__.py index 177fae61c..ad245c014 100644 --- a/loopy/__init__.py +++ b/loopy/__init__.py @@ -129,6 +129,9 @@ from loopy.schedule import ( generate_loop_schedules, get_one_scheduled_kernel, get_one_linearized_kernel, linearize) +from loopy.schedule.checker import ( + get_pairwise_statement_orderings, +) from loopy.statistics import (ToCountMap, ToCountPolynomialMap, CountGranularity, stringify_stats_mapping, Op, MemAccess, get_op_map, get_mem_access_map, get_synchronization_map, gather_access_footprints, @@ -268,6 +271,7 @@ "generate_loop_schedules", "get_one_scheduled_kernel", "get_one_linearized_kernel", "linearize", + "get_pairwise_statement_orderings", "GeneratedProgram", "CodeGenerationResult", "PreambleInfo", From e564dee4f246dcdf012eb63e3cd373acc6479cb8 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 17 Sep 2021 16:07:59 -0500 Subject: [PATCH 217/220] add new dep checking stuff to documentation --- doc/ref_other.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/ref_other.rst b/doc/ref_other.rst index b13f39869..2fec3d884 100644 --- a/doc/ref_other.rst +++ b/doc/ref_other.rst @@ -26,6 +26,11 @@ Automatic Testing .. autofunction:: auto_test_vs_ref +Checking Dependencies at the Statement-Instance Level +----------------------------------------------------- + +.. autofunction:: get_pairwise_statement_orderings + Troubleshooting --------------- From c99ee105005e950d25e94b37f48141f22b618f03 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 17 Sep 2021 16:57:14 -0500 Subject: [PATCH 218/220] document _gather_blex_ordering_info() --- loopy/schedule/checker/schedule.py | 64 ++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 0666bb6f7..4ea9d19b5 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -60,13 +60,13 @@ The :class:`str` name for the statement-identifying dimension of maps representing schedules and statement instance orderings. -.. data:: LTAG_VAR_NAME +.. data:: LTAG_VAR_NAMES An array of :class:`str` names for map dimensions carrying values for local (intra work-group) thread identifiers in maps representing schedules and statement instance orderings. -.. data:: GTAG_VAR_NAME +.. data:: GTAG_VAR_NAMES An array of :class:`str` names for map dimensions carrying values for group identifiers in maps representing schedules and statement instance orderings. @@ -315,13 +315,71 @@ def _gather_blex_ordering_info( conc_iname_constraint_dicts, perform_closure_checks=False, ): - """For the given sync_kind ("local" or "global"), create a mapping from + r"""For the given sync_kind ("local" or "global"), create a mapping from statement instances to blex space (dict), as well as a mapping defining the blex ordering (isl map from blex space -> blex space) Note that, unlike in the intra-thread case, there will be a single blex ordering map defining the blex ordering for all statement pairs, rather than separate (smaller) lex ordering maps for each pair + + :arg knl: A preprocessed :class:`loopy.kernel.LoopKernel` containing the + linearization items that will be used to create the SIOs. This + kernel will be used to get the domains associated with the inames + used in the statements. + + :sync_kind: A :class:`str` indicating whether we are creating the + intra-group blex ordering ("local") or the global blex ordering + ("global"). + + :arg lin_items: A list of :class:`loopy.schedule.ScheduleItem` + (to be renamed to `loopy.schedule.LinearizationItem`) containing + all linearization items for which SIOs will be + created. To allow usage of this routine during linearization, a + truncated (i.e. partial) linearization may be passed through this + argument + + :arg seq_loops_with_barriers: A set of :class:`str` inames identifying the + non-concurrent loops that contain barriers whose scope affects this + blex ordering. I.e., global barriers affect the global blex ordering, + and both global *and* local barriers affect the intra-group blex + ordering. + + :arg max_seq_loop_depth: A :class:`int` containing the maximum number of + nested non-concurrent loops among those found in + *seq_loops_with_barriers*. + + :arg conc_inames: The set of all :class:`str` inames tagged with a + :class:`loopy.kernel.data.ConcurrentTag`. + + :arg loop_bounds: A :class:`dict` mapping each non-concurrent iname to a + two-tuple containing two :class:`islpy.Set`\ s representing the lower + and upper bounds for the iname. + + :arg all_stmt_ids: A set of all statement identifiers to include in the + mapping from statements to blex time. + + :arg all_conc_lex_dim_names: A list containing the subset of the + :data:`LTAG_VAR_NAMES` and :data:`GTAG_VAR_NAMES` used in this kernel. + + :arg gid_lex_dim_names: A list containing the subset of the + :data:`GTAG_VAR_NAMES` used in this kernel. + + :arg conc_iname_constraint_dicts: A set of :class:`dict`\ s that will be + passed to :func:`islpy.Constratint.eq_from_names` to create constraints + that set each of the concurrent lex dimensions equal to its + corresponding iname. + + :arg perform_closure_checks: A :class:`bool` specifying whether to perform + checks ensuring that the blex map that results after we subtract some + pairs from the full blex map is transitively closed. + + :returns: A :class:`dict` mapping each statement id in :attr:`all_stmt_ids` + to a tuple representing its instances in blex time, an + :class:`islpy.Map` imposing an ordering on the points in blex time, and + a list of the blex dimension names corresponding to sequential + execution (i.e., not the :data:`LTAG_VAR_NAMES` and :data:`GTAG_VAR_NAMES`) + """ from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.schedule.checker.lexicographic_order_map import ( From ce58d7a2c55932d77b45e30b71084f592b9165af Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Fri, 17 Sep 2021 17:15:43 -0500 Subject: [PATCH 219/220] Fix up schedule checker docs --- doc/ref_other.rst | 4 +- loopy/schedule/checker/__init__.py | 10 +++- loopy/schedule/checker/schedule.py | 79 ++++++++++++++++-------------- 3 files changed, 53 insertions(+), 40 deletions(-) diff --git a/doc/ref_other.rst b/doc/ref_other.rst index 2fec3d884..d41109b9d 100644 --- a/doc/ref_other.rst +++ b/doc/ref_other.rst @@ -29,11 +29,13 @@ Automatic Testing Checking Dependencies at the Statement-Instance Level ----------------------------------------------------- -.. autofunction:: get_pairwise_statement_orderings +.. automodule:: loopy.schedule.checker Troubleshooting --------------- +.. currentmodule:: loopy + Printing :class:`LoopKernel` objects ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 6b30e19c0..ac74588fe 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -1,3 +1,10 @@ +""" +.. autofunction:: get_pairwise_statement_orderings + +.. automodule:: loopy.schedule.checker.schedule +""" + + __copyright__ = "Copyright (C) 2019 James Stevens" __license__ = """ @@ -61,7 +68,8 @@ def get_pairwise_statement_orderings( :arg stmt_id_pairs: A sequence containing pairs of statement identifiers. :returns: A dictionary mapping each two-tuple of statement identifiers - provided in `stmt_id_pairs` to a :class:`StatementOrdering`, which + provided in `stmt_id_pairs` to a + :class:`~loopy.schedule.checker.schedule.StatementOrdering`, which contains the three SIOs described above. .. doctest: diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 4ea9d19b5..839718c4f 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -1,3 +1,44 @@ +""" +.. data:: LIN_CHECK_IDENTIFIER_PREFIX + + The :class:`str` prefix for identifiers involved in linearization + checking. + +.. data:: LEX_VAR_PREFIX + + The :class:`str` prefix for the variables representing the + dimensions in the lexicographic ordering used in a pairwise schedule. E.g., + a prefix of ``_lp_linchk_lex`` might yield lexicographic dimension + variables ``_lp_linchk_lex0``, ``_lp_linchk_lex1``, ``_lp_linchk_lex2``. + Cf. :ref:`reserved-identifiers`. + +.. data:: STATEMENT_VAR_NAME + + The :class:`str` name for the statement-identifying dimension of maps + representing schedules and statement instance orderings. + +.. data:: LTAG_VAR_NAMES + + An array of :class:`str` names for map dimensions carrying values for local + (intra work-group) thread identifiers in maps representing schedules and + statement instance orderings. + +.. data:: GTAG_VAR_NAMES + + An array of :class:`str` names for map dimensions carrying values for group + identifiers in maps representing schedules and statement instance orderings. + +.. data:: BEFORE_MARK + + The :class:`str` identifier to be appended to input dimension names in + maps representing schedules and statement instance orderings. + +.. autoclass:: SpecialLexPointWRTLoop +.. autoclass:: StatementOrdering +.. autofunction:: get_pairwise_statement_orderings_inner +""" + + __copyright__ = "Copyright (C) 2019 James Stevens" __license__ = """ @@ -40,44 +81,6 @@ # {{{ Constants -__doc__ = """ - -.. data:: LIN_CHECK_IDENTIFIER_PREFIX - - The :class:`str` prefix for identifiers involved in linearization - checking. - -.. data:: LEX_VAR_PREFIX - - The :class:`str` prefix for the variables representing the - dimensions in the lexicographic ordering used in a pairwise schedule. E.g., - a prefix of ``_lp_linchk_lex`` might yield lexicographic dimension - variables ``_lp_linchk_lex0``, ``_lp_linchk_lex1``, ``_lp_linchk_lex2``. - Cf. :ref:`reserved-identifiers`. - -.. data:: STATEMENT_VAR_NAME - - The :class:`str` name for the statement-identifying dimension of maps - representing schedules and statement instance orderings. - -.. data:: LTAG_VAR_NAMES - - An array of :class:`str` names for map dimensions carrying values for local - (intra work-group) thread identifiers in maps representing schedules and - statement instance orderings. - -.. data:: GTAG_VAR_NAMES - - An array of :class:`str` names for map dimensions carrying values for group - identifiers in maps representing schedules and statement instance orderings. - -.. data:: BEFORE_MARK - - The :class:`str` identifier to be appended to input dimension names in - maps representing schedules and statement instance orderings. - -""" - LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" LEX_VAR_PREFIX = "%slex" % (LIN_CHECK_IDENTIFIER_PREFIX) STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) From 2c2772e6c82ccc5f29587366b326e0a3ebced2fe Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 17 Sep 2021 18:11:39 -0500 Subject: [PATCH 220/220] fix reference in docstrings loopy.kernel.LoopKernel->loopy.LoopKernel --- loopy/schedule/checker/__init__.py | 2 +- loopy/schedule/checker/schedule.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index ac74588fe..b987255d4 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -56,7 +56,7 @@ def get_pairwise_statement_orderings( if the two statement instances in a given before-after pair are executed within different work-groups. - :arg knl: A preprocessed :class:`loopy.kernel.LoopKernel` containing the + :arg knl: A preprocessed :class:`loopy.LoopKernel` containing the linearization items that will be used to create the SIOs. :arg lin_items: A list of :class:`loopy.schedule.ScheduleItem` diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 839718c4f..39b44c2ce 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -326,7 +326,7 @@ def _gather_blex_ordering_info( blex ordering map defining the blex ordering for all statement pairs, rather than separate (smaller) lex ordering maps for each pair - :arg knl: A preprocessed :class:`loopy.kernel.LoopKernel` containing the + :arg knl: A preprocessed :class:`loopy.LoopKernel` containing the linearization items that will be used to create the SIOs. This kernel will be used to get the domains associated with the inames used in the statements. @@ -953,7 +953,7 @@ def get_pairwise_statement_orderings_inner( if the two statement instances in a given before-after pair are executed within different work-groups. - :arg knl: A preprocessed :class:`loopy.kernel.LoopKernel` containing the + :arg knl: A preprocessed :class:`loopy.LoopKernel` containing the linearization items that will be used to create the SIOs. This kernel will be used to get the domains associated with the inames used in the statements, and to determine which inames have been