From ad45361773c7df95760504b8d5a9b375f9564b76 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Apr 2020 22:12:19 -0500 Subject: [PATCH 001/315] improved encapsulation approach for LexSchedule and map creation; improved algorithm for LexSchedule creation so that integer lex dims are not incremented unnecessarily when a block of code didn't contain any statements; fixed minor bugs in LexSchedule/item str methods; extracted only code related to LexSchedule/map creation (removed dependency stuff, for example) to shrink scope of this MR --- .../checker/lexicographic_order_map.py | 159 ++++++ loopy/schedule/checker/schedule.py | 493 ++++++++++++++++++ loopy/schedule/checker/utils.py | 335 ++++++++++++ 3 files changed, 987 insertions(+) create mode 100644 loopy/schedule/checker/lexicographic_order_map.py create mode 100644 loopy/schedule/checker/schedule.py create mode 100644 loopy/schedule/checker/utils.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 diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py new file mode 100644 index 000000000..c395863ef --- /dev/null +++ b/loopy/schedule/checker/schedule.py @@ -0,0 +1,493 @@ +__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 + + +class LexScheduleStatement(object): + """A representation of a :mod:`loopy` statement. + + .. attribute:: insn_id + + A :class:`str` specifying the instruction id. + + .. attribute:: int_id + + A :class:`int` uniquely identifying the instruction. + + .. attribute:: within_inames + + A :class:`list` of :class:`str` inames identifying the loops within + which this statement will be executed. + + """ + + def __init__( + self, + insn_id, # loopy insn id + int_id=None, # sid int (statement id within LexSchedule) + within_inames=None, # [string, ] + ): + self.insn_id = insn_id # string + self.int_id = int_id + self.within_inames = within_inames + + def __eq__(self, other): + return ( + self.insn_id == other.insn_id + and self.int_id == other.int_id + and self.within_inames == other.within_inames + ) + + def __hash__(self): + return hash(repr(self)) + + def update_persistent_hash(self, key_hash, key_builder): + """Custom hash computation function for use with + :class:`pytools.persistent_dict.PersistentDict`. + """ + + key_builder.rec(key_hash, self.insn_id) + key_builder.rec(key_hash, self.int_id) + key_builder.rec(key_hash, self.within_inames) + + def __str__(self): + if self.int_id is not None: + int_id = ":%d" % (self.int_id) + else: + int_id = "" + if self.within_inames: + within_inames = " {%s}" % (",".join(self.within_inames)) + else: + within_inames = "" + return "%s%s%s" % ( + self.insn_id, int_id, within_inames) + + +class LexScheduleStatementInstance(object): + """A representation of a :mod:`loopy` statement instance. + + .. attribute:: stmt + + A :class:`LexScheduleStatement`. + + .. attribute:: lex_pt + + A list of :class:`int` or as :class:`str` :mod:`loopy` inames representing + a point or set of points in a lexicographic ordering. + + """ + + def __init__( + self, + stmt, # a LexScheduleStatement + lex_pt, # [string/int, ] + ): + self.stmt = stmt + self.lex_pt = lex_pt + + def __str__(self): + return "{%s, %s}" % (self.stmt, self.lex_pt) + + +class LexSchedule(object): + """A program ordering represented as a mapping from statement + instances to points in a lexicographic ordering. + + .. attribute:: stmt_instance_before + + A :class:`LexScheduleStatementInstance` describing the dependee + statement's order relative to the depender statment by mapping + a statement to a point or set of points in a lexicographic + ordering. Points in lexicographic ordering are represented as + a list of :class:`int` or as :class:`str` :mod:`loopy` inames. + + .. attribute:: stmt_instance_after + + A :class:`LexScheduleStatementInstance` describing the depender + statement's order relative to the dependee statment by mapping + a statement to a point or set of points in a lexicographic + ordering. Points in lexicographic ordering are represented as + a list of :class:`int` or as :class:`str` :mod:`loopy` inames. + + .. attribute:: statement_var_name + + A :class:`str` specifying the name of the isl variable used + to represent the unique :class:`int` statement id. + + .. attribute:: lex_var_prefix + + A :class:`str` specifying the prefix to be used for the variables + representing the dimensions in the lexicographic ordering. E.g., + a prefix of "lex" might yield variables "lex0", "lex1", "lex2". + + """ + + statement_var_name = "statement" + lex_var_prefix = "l" + + def __init__( + self, + linearization_items_ordered, + before_insn_id, + after_insn_id, + prohibited_var_names=[], + loops_to_ignore=set(), + ): + """ + :arg linearization_items_ordered: A list of :class:`ScheduleItem` whose + order will be described by this :class:`LexSchedule`. + + :arg before_insn_id: A :class:`str` instruction id specifying + the dependee in this pair of instructions. + + :arg after_insn_id: A :class:`str` instruction id specifying + the depender in this pair of instructions. + + :arg prohibited_var_names: A list of :class:`str` variable names + that may not be used as the statement variable name (e.g., + because they are already being used as inames). + + """ + + # LexScheduleStatements + self.stmt_instance_before = None + self.stmt_instance_after = None + + # make sure we don't have an iname name conflict + # TODO use loopy's existing tool for ensuring unique var names + assert not any( + iname == self.statement_var_name for iname in prohibited_var_names) + + from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) + + # go through linearization_items_ordered and generate self.lex_schedule + + # keep track of the next point in our lexicographic ordering + # initially this as a 1-d point with value 0 + next_insn_lex_pt = [0] + stmt_since_last_block_at_tier = [False] + next_sid = 0 + stmt_added_since_last_EnterLoop = False + stmt_added_since_last_LeaveLoop = False + #stmt_added_since_last_new_block = False # blocks start at open/close loop + for linearization_item in linearization_items_ordered: + if isinstance(linearization_item, EnterLoop): + iname = linearization_item.iname + if iname in loops_to_ignore: + continue + + # We could always increment next_insn_lex_pt[-1] here since this new + # section of code comes after the previous section (statements + # since last opened/closed loop), but if we have not added any statements + # within this block yet, we don't have to + # (effectively ignoring that section of code). + if stmt_since_last_block_at_tier[-1]: + next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 + stmt_since_last_block_at_tier[-1] = False + + # upon entering a loop, we enter a new (deeper) tier, + # add one lex dimension for the loop variable, + # add second lex dim to enumerate code blocks within new loop, and + # append a dim to stmt_since_last_block_at_tier to represent new tier + next_insn_lex_pt.append(iname) + next_insn_lex_pt.append(0) + stmt_since_last_block_at_tier.append(False) + elif isinstance(linearization_item, LeaveLoop): + if linearization_item.iname in loops_to_ignore: + continue + # upon leaving a loop, + # pop lex dimension for enumerating code blocks within this loop, and + # pop lex dimension for the loop variable, and + # increment lex dim val enumerating items in current code block + next_insn_lex_pt.pop() + next_insn_lex_pt.pop() + + # We could always increment next_insn_lex_pt[-1] here since this new + # block of code comes after the previous block (all statements + # since last opened/closed loop), but if we have not added any statements + # within this block yet, we don't have to + # (effectively ignoring that section of code). + stmt_since_last_block_at_tier.pop() + if stmt_since_last_block_at_tier[-1]: + next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 + stmt_since_last_block_at_tier[-1] = False + elif isinstance(linearization_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) + if lp_insn_id is None: + # TODO make sure it's okay to ignore barriers without id + # (because they'll never be part of a dependency?) + # matmul example has barrier that fails this assertion... + # assert linearization_item.originating_insn_id is not None + continue + + # only process before/after insns, otherwise ignore + if lp_insn_id == before_insn_id and lp_insn_id == after_insn_id: + # add before sched item + self.stmt_instance_before = LexScheduleStatementInstance( + LexScheduleStatement( + insn_id=lp_insn_id, + int_id=next_sid, # int representing insn + ), + next_insn_lex_pt[:]) + # add after sched item + self.stmt_instance_after = LexScheduleStatementInstance( + LexScheduleStatement( + insn_id=lp_insn_id, + int_id=next_sid, # int representing insn + ), + next_insn_lex_pt[:]) + + # increment lex dim val enumerating items in current code block + next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 + next_sid += 1 + + # all current (nested) blocks now contain a statement + stmt_since_last_block_at_tier = [True]*len(stmt_since_last_block_at_tier) + elif lp_insn_id == before_insn_id: + # add before sched item + self.stmt_instance_before = LexScheduleStatementInstance( + LexScheduleStatement( + insn_id=lp_insn_id, + int_id=next_sid, # int representing insn + ), + next_insn_lex_pt[:]) + + # increment lex dim val enumerating items in current code block + next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 + next_sid += 1 + + # all current (nested) blocks now contain a statement + stmt_since_last_block_at_tier = [True]*len(stmt_since_last_block_at_tier) + elif lp_insn_id == after_insn_id: + # add after sched item + self.stmt_instance_after = LexScheduleStatementInstance( + LexScheduleStatement( + insn_id=lp_insn_id, + int_id=next_sid, # int representing insn + ), + next_insn_lex_pt[:]) + + # increment lex dim val enumerating items in current code block + next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 + next_sid += 1 + + # all current (nested) blocks now contain a statement + stmt_since_last_block_at_tier = [True]*len(stmt_since_last_block_at_tier) + else: + pass + # to save time, stop when we've created both statements + if self.stmt_instance_before and self.stmt_instance_after: + break + + # at this point, lex_schedule may contain lex points missing dimensions, + # the values in these missing dims should be zero, so add them + self.pad_lex_pts_with_zeros() + + def loopy_insn_id_to_lex_sched_id(self): + """Return a dictionary mapping insn_id to int_id, where ``insn_id`` and + ``int_id`` refer to the ``insn_id`` and ``int_id`` attributes of + :class:`LexScheduleStatement`. + """ + return { + self.stmt_instance_before.stmt.insn_id: + self.stmt_instance_before.stmt.int_id, + self.stmt_instance_after.stmt.insn_id: + self.stmt_instance_after.stmt.int_id, + } + + def max_lex_dims(self): + return max([ + len(self.stmt_instance_before.lex_pt), + len(self.stmt_instance_after.lex_pt)]) + + def pad_lex_pts_with_zeros(self): + """Find the maximum number of lexicographic dimensions represented + in the lexicographic ordering, and if any + :class:`LexScheduleStatement` maps to a point in lexicographic + time with fewer dimensions, add a zero for each of the missing + dimensions. + """ + + max_lex_dim = self.max_lex_dims() + self.stmt_instance_before = LexScheduleStatementInstance( + self.stmt_instance_before.stmt, + self.stmt_instance_before.lex_pt[:] + [0]*( + max_lex_dim-len(self.stmt_instance_before.lex_pt)) + ) + self.stmt_instance_after = LexScheduleStatementInstance( + self.stmt_instance_after.stmt, + self.stmt_instance_after.lex_pt[:] + [0]*( + max_lex_dim-len(self.stmt_instance_after.lex_pt)) + ) + + def create_isl_maps( + self, + dom_before, + dom_after, + dom_inames_ordered_before=None, + dom_inames_ordered_after=None, + ): + """Create two isl maps representing lex schedule as two mappings + from statement instances to lexicographic time, one for + the dependee and one for the depender. + + :arg dom_before: A :class:`islpy.BasicSet` representing the + domain for the dependee statement. + + :arg dom_after: A :class:`islpy.BasicSet` representing the + domain for the dependee statement. + + :arg dom_inames_ordered_before: A list of :class:`str` + representing the union of inames used in instances of the + dependee statement. ``statement_var_name`` and + ``dom_inames_ordered_before`` are the names of the dims of + the space of the ISL map domain for the dependee. + + :arg dom_inames_ordered_after: A list of :class:`str` + representing the union of inames used in instances of the + depender statement. ``statement_var_name`` and + ``dom_inames_ordered_after`` are the names of the dims of + the space of the ISL map domain for the depender. + + :returns: A two-tuple containing two :class:`islpy.Map`s + representing the schedule as two mappings + from statement instances to lexicographic time, one for + the dependee and one for the depender. + + """ + + from loopy.schedule.checker.utils import ( + create_symbolic_isl_map_from_tuples, + add_dims_to_isl_set + ) + + from loopy.schedule.checker.utils import ( + list_var_names_in_isl_sets, + ) + if dom_inames_ordered_before is None: + dom_inames_ordered_before = list_var_names_in_isl_sets( + [dom_before]) + if dom_inames_ordered_after is None: + dom_inames_ordered_after = list_var_names_in_isl_sets( + [dom_after]) + + # create an isl space + # {('statement', used in >=1 statement domain>) -> + # (lexicographic ordering dims)} + from loopy.schedule.checker.utils import ( + get_isl_space + ) + params_sched = [] + out_names_sched = self.get_lex_var_names() + + in_names_sched_before = [ + self.statement_var_name] + dom_inames_ordered_before[:] + sched_space_before = get_isl_space( + params_sched, in_names_sched_before, out_names_sched) + in_names_sched_after = [ + self.statement_var_name] + dom_inames_ordered_after[:] + sched_space_after = get_isl_space( + params_sched, in_names_sched_after, out_names_sched) + + # Insert 'statement' dim into domain so that its space allows for + # intersection with sched map later + doms_to_intersect_before = [ + add_dims_to_isl_set( + dom_before, isl.dim_type.set, + [self.statement_var_name], 0), + ] + doms_to_intersect_after = [ + add_dims_to_isl_set( + dom_after, isl.dim_type.set, + [self.statement_var_name], 0), + ] + + # Each isl map representing the schedule maps + # statement instances -> lex time + + # Right now, statement tuples consist of single int. + # Add all inames from domains to map domain tuples. + + # create isl map + return ( + create_symbolic_isl_map_from_tuples( + zip( + [( + (self.stmt_instance_before.stmt.int_id,) + + tuple(dom_inames_ordered_before), + self.stmt_instance_before.lex_pt + )], + doms_to_intersect_before + ), + sched_space_before, self.statement_var_name), + create_symbolic_isl_map_from_tuples( + zip( + [( + (self.stmt_instance_after.stmt.int_id,) + + tuple(dom_inames_ordered_after), + self.stmt_instance_after.lex_pt)], + doms_to_intersect_after + ), + sched_space_after, self.statement_var_name) + ) + + 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 __eq__(self, other): + return ( + self.stmt_instance_before == other.stmt_instance_before + and self.stmt_instance_after == other.stmt_instance_after) + + def __str__(self): + sched_str = "Before: {\n" + domain_elem = "[%s=%s,]" % ( + self.statement_var_name, + self.stmt_instance_before.stmt.int_id) + sched_str += "%s -> %s;\n" % (domain_elem, self.stmt_instance_before.lex_pt) + sched_str += "}\n" + + sched_str += "After: {\n" + domain_elem = "[%s=%s,]" % ( + self.statement_var_name, + self.stmt_instance_after.stmt.int_id) + sched_str += "%s -> %s;\n" % (domain_elem, self.stmt_instance_after.lex_pt) + sched_str += "}" + return sched_str diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py new file mode 100644 index 000000000..8757406b7 --- /dev/null +++ b/loopy/schedule/checker/utils.py @@ -0,0 +1,335 @@ +__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 prettier_map_string(isl_map): + return str(isl_map + ).replace("{ ", "{\n").replace(" }", "\n}").replace("; ", ";\n") + + +def get_islvars_from_space(space): + param_names = space.get_var_names(isl.dim_type.param) + in_names = space.get_var_names(isl.dim_type.in_) + out_names = space.get_var_names(isl.dim_type.out) + return isl.make_zero_and_vars(in_names+out_names, param_names) + + +def add_dims_to_isl_set(isl_set, dim_type, names, new_pose_start): + new_set = isl_set.insert_dims( + dim_type, new_pose_start, len(names) + ).set_dim_name(dim_type, new_pose_start, names[0]) + for i, name in enumerate(names[1:]): + new_set = new_set.set_dim_name(dim_type, new_pose_start+1+i, name) + return new_set + + +def reorder_dims_by_name( + isl_set, dim_type, desired_dims_ordered, + add_missing=False, new_names_are_permutation_only=False): + """Return an isl_set with the dimensions 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`, + specifying the dimension to be reordered. + + :arg desired_dims_ordered: A :class:`list` of :class:`str` elements + representing the desired dimensions order by dimension name. + + :arg add_missing: A :class:`bool` specifying whether to insert + dimensions (by name) found in `desired_dims_ordered` that are not + present in `isl_set`. + + :arg new_names_are_permutation_only: A :class:`bool` indicating that + `desired_dims_ordered` contains the same names as the specified + dimensions in `isl_set`, and does not, e.g., contain additional + dimension names not found in `isl_set`. If set to True, and these + two sets of names do not match, an error is produced. + + :returns: An :class:`islpy.Set` matching `isl_set` with the + dimension order matching `desired_dims_ordered`, optionally + including additional dimensions present in `desred_dims_ordered` + that are not present in `isl_set`. + + """ + + assert set(isl_set.get_var_names(dim_type)).issubset(desired_dims_ordered) + assert dim_type != isl.dim_type.param + + if new_names_are_permutation_only and ( + set(isl_set.get_var_names(dim_type)) + != set(desired_dims_ordered)): + raise ValueError( + "Var name sets must match with new_names_are_permutation_only=True. " + "isl vars: %s, desired dims: %s" + % (isl_set.get_var_names(dim_type), desired_dims_ordered)) + + other_dim_type = isl.dim_type.param + other_dim_len = len(isl_set.get_var_names(other_dim_type)) + + new_set = isl_set.copy() + for desired_pose, name in enumerate(desired_dims_ordered): + # if iname doesn't exist in set, add dim: + if name not in new_set.get_var_names(dim_type): + if add_missing: + # insert missing dim in correct location + new_set = new_set.insert_dims( + dim_type, desired_pose, 1 + ).set_dim_name( + dim_type, desired_pose, name) + else: # iname exists in set + current_pose = new_set.find_dim_by_name(dim_type, name) + if current_pose != desired_pose: + # move_dims(dst_type, dst_pose, src_type, src_pose, n) + + # first move to other dim because isl is stupid + new_set = new_set.move_dims( + other_dim_type, other_dim_len, dim_type, current_pose, 1) + + # now move it where we actually want it + new_set = new_set.move_dims( + dim_type, desired_pose, other_dim_type, other_dim_len, 1) + + return new_set + + +def align_isl_maps_by_var_names(input_map, target_map): + + # align params + aligned_input_map = input_map.align_params(target_map.space) + + # align in_ dims + target_map_in_names = target_map.space.get_var_names(isl.dim_type.in_) + aligned_input_map = reorder_dims_by_name( + aligned_input_map, + isl.dim_type.in_, + target_map_in_names, + add_missing=False, + new_names_are_permutation_only=True, + ) + + # align out dims + target_map_out_names = target_map.space.get_var_names(isl.dim_type.out) + aligned_input_map = reorder_dims_by_name( + aligned_input_map, + isl.dim_type.out, + target_map_out_names, + add_missing=False, + new_names_are_permutation_only=True, + ) + + 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:]: + union = union.union(s) + return union + + +def list_var_names_in_isl_sets( + isl_sets, + set_dim=isl.dim_type.set): + inames = set() + for isl_set in isl_sets: + inames.update(isl_set.get_var_names(set_dim)) + return list(inames) + + +def create_symbolic_isl_map_from_tuples( + tuple_pairs_with_domains, + space, + statement_var_name, + ): + """Return an :class:`islpy.Map` constructed using the provided space, + mapping input->output tuples provided in `tuple_pairs_with_domains`, + with each set of tuple variables constrained by the domains provided. + + :arg tuple_pairs_with_domains: A :class:`list` with each element being + a tuple of the form `((tup_in, tup_out), domain)`. + `tup_in` and `tup_out` are tuples containing elements of type + :class:`int` and :class:`str` representing values for the + input and output dimensions in `space`, and `domain` is a + :class:`islpy.Set` constraining variable bounds. + + :arg space: A :class:`islpy.Space` to be used to create the map. + + :arg statement_var_name: A :class:`str` specifying the name of the + isl variable used to represent the unique :class:`int` statement id. + + :returns: A :class:`islpy.Map` constructed using the provided space + as follows. For each `((tup_in, tup_out), domain)` in + `tuple_pairs_with_domains`, map + `(tup_in)->(tup_out) : domain`, where `tup_in` and `tup_out` are + numeric or symbolic values assigned to the input and output + dimension variables in `space`, and `domain` specifies constraints + on these values. + + """ + # TODO allow None for domains + + dim_type = isl.dim_type + + #param_names = space.get_var_names(isl.dim_type.param) + space_out_names = space.get_var_names(dim_type.out) + space_in_names = space.get_var_names(isl.dim_type.in_) + + islvars = get_islvars_from_space(space) + + # loop through pairs and create a set that will later be converted to a map + + all_maps = [] + for (tup_in, tup_out), dom in tuple_pairs_with_domains: + + # initialize constraint with true + constraint = islvars[0].eq_set(islvars[0]) + + # set values for 'in' dimension using tuple vals + assert len(tup_in) == len(space_in_names) + for dim_name, val_in in zip(space_in_names, tup_in): + if isinstance(val_in, int): + constraint = constraint \ + & islvars[dim_name].eq_set(islvars[0]+val_in) + else: + constraint = constraint \ + & islvars[dim_name].eq_set(islvars[val_in]) + + # set values for 'out' dimension using tuple vals + assert len(tup_out) == len(space_out_names) + for dim_name, val_out in zip(space_out_names, tup_out): + if isinstance(val_out, int): + constraint = constraint \ + & islvars[dim_name].eq_set(islvars[0]+val_out) + else: + constraint = constraint \ + & islvars[dim_name].eq_set(islvars[val_out]) + + # convert set to map by moving dimensions around + map_from_set = isl.Map.from_domain(constraint) + map_from_set = map_from_set.move_dims( + dim_type.out, 0, dim_type.in_, + len(space_in_names), len(space_out_names)) + + assert space_in_names == map_from_set.get_var_names( + isl.dim_type.in_) + + # if there are any dimensions in dom that are missing from + # map_from_set, we have a problem I think? + # (assertion checks this in add_missing... + dom_with_all_inames = reorder_dims_by_name( + dom, isl.dim_type.set, + space_in_names, + add_missing=True, + new_names_are_permutation_only=False, + ) + + # intersect domain with this map + all_maps.append( + map_from_set.intersect_domain(dom_with_all_inames)) + + return _union_of_isl_sets_or_maps(all_maps) + + +def set_all_isl_space_names( + isl_space, param_names=None, in_names=None, out_names=None): + """Return a copy of `isl_space` with the specified dimension names. + If no names are provided, use `p0, p1, ...` for parameters, + `i0, i1, ...`, for in_ dimensions, and `o0, o1, ...` for out + dimensions. + + """ + + new_space = isl_space.copy() + dim_type = isl.dim_type + if param_names: + for i, p in enumerate(param_names): + new_space = new_space.set_dim_name(dim_type.param, i, p) + else: + for i in range(len(isl_space.get_var_names(dim_type.param))): + new_space = new_space.set_dim_name(dim_type.param, i, "p%d" % (i)) + if in_names: + for i, p in enumerate(in_names): + new_space = new_space.set_dim_name(dim_type.in_, i, p) + else: + for i in range(len(isl_space.get_var_names(dim_type.in_))): + new_space = new_space.set_dim_name(dim_type.in_, i, "i%d" % (i)) + if out_names: + for i, p in enumerate(out_names): + new_space = new_space.set_dim_name(dim_type.out, i, p) + else: + for i in range(len(isl_space.get_var_names(dim_type.out))): + new_space = new_space.set_dim_name(dim_type.out, i, "o%d" % (i)) + return new_space + + +def get_isl_space(param_names, in_names, out_names): + """Return an :class:`islpy.Space` with the specified dimension names. + """ + + space = isl.Space.alloc( + isl.DEFAULT_CONTEXT, len(param_names), len(in_names), len(out_names)) + return set_all_isl_space_names( + space, param_names=param_names, in_names=in_names, out_names=out_names) + + +def get_concurrent_inames(knl): + from loopy.kernel.data import ConcurrentTag + conc_inames = set() + non_conc_inames = set() + + all_inames = knl.all_inames() + for iname in all_inames: + if knl.iname_tags_of_type(iname, ConcurrentTag): + conc_inames.add(iname) + else: + non_conc_inames.add(iname) + + return conc_inames, all_inames-conc_inames + + +def _get_insn_id_from_linearization_item(linearization_item): + # TODO could use loopy's sched_item_to_insn_id() + 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, knl): + from loopy.schedule import EnterLoop + loop_inames = set() + for linearization_item in linearization_items: + if isinstance(linearization_item, EnterLoop): + loop_inames.add(linearization_item.iname) + return loop_inames From 1ce81703127df9bddcfe841ee3663373a8369a7c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Apr 2020 22:14:00 -0500 Subject: [PATCH 002/315] adding updated and stripped down checker/__init__ (with aforementioned encapsulation improvements) --- loopy/schedule/checker/__init__.py | 104 +++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 loopy/schedule/checker/__init__.py diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py new file mode 100644 index 000000000..1acee56b9 --- /dev/null +++ b/loopy/schedule/checker/__init__.py @@ -0,0 +1,104 @@ +__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. +""" + + +def get_schedule_for_statement_pair( + knl, + linearization_items, + insn_id_before, + insn_id_after, + prohibited_var_names=set(), + ): + """A set of dependencies between two statements. + + .. arg insn_id_before: An instruction identifier that is unique within + a :class:`loopy.kernel.LoopKernel`. + + .. arg insn_id_after: An instruction identifier that is unique within + a :class:`loopy.kernel.LoopKernel`. + + """ + + # We don't retrieve linearization items from knl because knl may not be + # (fully) linearized yet. This function may be called part way through the + # linearization process and receive the current (unfinished) set of + # linearization items + + # Preprocess if not already preprocessed + from loopy import preprocess_kernel + preproc_knl = preprocess_kernel(knl) + + if not prohibited_var_names: + prohibited_var_names = preproc_knl.all_inames() + + # Get EnterLoop inames tagged as concurrent so LexSchedule can ignore + # (In the future, this shouldn't be necessary because there + # won't be any inames with ConcurrentTags in EnterLoop linearization items. + # Test exercising this: test_linearization_checker_with_stroud_bernstein()) + from loopy.schedule.checker.utils import ( + get_concurrent_inames, + _get_EnterLoop_inames, + ) + conc_inames, _ = get_concurrent_inames(preproc_knl) + enterloop_inames = _get_EnterLoop_inames(linearization_items, preproc_knl) + conc_loop_inames = conc_inames & enterloop_inames + if conc_loop_inames: + from warnings import warn + warn( + "get_schedule_for_statement_pair encountered EnterLoop for inames %s " + "with ConcurrentTag(s) in linearization for kernel %s. " + "Ignoring these loops." % (conc_loop_inames, preproc_knl.name)) + + # Create LexSchedule: mapping of {statement instance: lex point} + # include only instructions involved in this dependency + from loopy.schedule.checker.schedule import LexSchedule + return LexSchedule( + linearization_items, + insn_id_before, + insn_id_after, + prohibited_var_names=prohibited_var_names, + loops_to_ignore=conc_loop_inames, + ) + + +def get_isl_maps_for_LexSchedule( + lex_sched, + knl, + insn_id_before, + insn_id_after, + ): + # Get two isl maps representing the LexSchedule, + # one for the 'before' linearization item and one for 'after'; + # this requires the iname domains + + insn_before_inames = knl.id_to_insn[insn_id_before].within_inames + insn_after_inames = knl.id_to_insn[insn_id_after].within_inames + dom_before = knl.get_inames_domain(insn_before_inames) + dom_after = knl.get_inames_domain(insn_after_inames) + + isl_sched_map_before, isl_sched_map_after = \ + lex_sched.create_isl_maps( + dom_before, + dom_after, + ) + + return isl_sched_map_before, isl_sched_map_after From 387a8f12ef594cdf6d0fc221305bbc0bb9692b4a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Apr 2020 22:25:05 -0500 Subject: [PATCH 003/315] add test for LexSchedule creation and conversion of LexSchedule into isl map --- test/test_linearization_checker.py | 367 +++++++++++++++++++++++++++++ 1 file changed, 367 insertions(+) create mode 100644 test/test_linearization_checker.py diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py new file mode 100644 index 000000000..7e145ce1d --- /dev/null +++ b/test/test_linearization_checker.py @@ -0,0 +1,367 @@ +from __future__ import division, print_function + +__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 six # noqa: F401 +import sys +import numpy as np +import loopy as lp +from pyopencl.tools import ( # noqa + pytest_generate_tests_for_pyopencl + as pytest_generate_tests) +from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_2 # noqa +import logging +from loopy.kernel import KernelState +from loopy import ( + preprocess_kernel, + get_one_linearized_kernel, +) + +logger = logging.getLogger(__name__) + +try: + import faulthandler +except ImportError: + pass +else: + faulthandler.enable() + + +def test_lexschedule_and_islmap_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, + ) + + # example kernel + 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} + end + end + for t + e[t] = f[t] {id=insn_d} + 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 + + # Create LexSchedule: mapping of {statement instance: lex point} + lex_sched_AB = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_a", + "insn_b", + ) + lex_sched_AC = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_a", + "insn_c", + ) + lex_sched_AD = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_a", + "insn_d", + ) + lex_sched_BC = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_b", + "insn_c", + ) + lex_sched_BD = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_b", + "insn_d", + ) + lex_sched_CD = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_c", + "insn_d", + ) + + # Relationship between insn_a and insn_b --------------------------------------- + + assert lex_sched_AB.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] + assert lex_sched_AB.stmt_instance_after.lex_pt == [0, 'i', 1, 'j', 0] + + # Get two isl maps representing the LexSchedule + + isl_sched_map_before, isl_sched_map_after = \ + get_isl_maps_for_LexSchedule(lex_sched_AB, knl, "insn_a", "insn_b") + + # Create expected maps, align, compare + + isl_sched_map_before_expected = isl.Map( + "[pi, pk] -> { " + "[statement = 0, i, k] -> [l0 = 0, l1 = i, l2 = 0, l3 = k, l4 = 0] : " + "0 <= i < pi and 0 <= k < pk }" + ) + isl_sched_map_before_expected = align_isl_maps_by_var_names( + isl_sched_map_before_expected, isl_sched_map_before) + + isl_sched_map_after_expected = isl.Map( + "[pi, pj] -> { " + "[statement = 1, i, j] -> [l0 = 0, l1 = i, l2 = 1, l3 = j, l4 = 0] : " + "0 <= i < pi and 0 <= j < pj }" + ) + isl_sched_map_after_expected = align_isl_maps_by_var_names( + isl_sched_map_after_expected, isl_sched_map_after) + + assert isl_sched_map_before == isl_sched_map_before_expected + assert isl_sched_map_after == isl_sched_map_after_expected + + # ------------------------------------------------------------------------------ + # Relationship between insn_a and insn_c --------------------------------------- + + assert lex_sched_AC.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] + assert lex_sched_AC.stmt_instance_after.lex_pt == [0, 'i', 1, 'j', 0] + + # Get two isl maps representing the LexSchedule + + isl_sched_map_before, isl_sched_map_after = \ + get_isl_maps_for_LexSchedule(lex_sched_AC, knl, "insn_a", "insn_c") + + # Create expected maps, align, compare + + isl_sched_map_before_expected = isl.Map( + "[pi, pk] -> { " + "[statement = 0, i, k] -> [l0 = 0, l1 = i, l2 = 0, l3 = k, l4 = 0] : " + "0 <= i < pi and 0 <= k < pk }" + ) + isl_sched_map_before_expected = align_isl_maps_by_var_names( + isl_sched_map_before_expected, isl_sched_map_before) + + isl_sched_map_after_expected = isl.Map( + "[pi, pj] -> { " + "[statement = 1, i, j] -> [l0 = 0, l1 = i, l2 = 1, l3 = j, l4 = 0] : " + "0 <= i < pi and 0 <= j < pj }" + ) + isl_sched_map_after_expected = align_isl_maps_by_var_names( + isl_sched_map_after_expected, isl_sched_map_after) + + assert isl_sched_map_before == isl_sched_map_before_expected + assert isl_sched_map_after == isl_sched_map_after_expected + + # ------------------------------------------------------------------------------ + # Relationship between insn_a and insn_d --------------------------------------- + + assert lex_sched_AD.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] + assert lex_sched_AD.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] + + # Get two isl maps representing the LexSchedule + + isl_sched_map_before, isl_sched_map_after = \ + get_isl_maps_for_LexSchedule(lex_sched_AD, knl, "insn_a", "insn_d") + + # Create expected maps, align, compare + + isl_sched_map_before_expected = isl.Map( + "[pi, pk] -> { " + "[statement = 0, i, k] -> [l0 = 0, l1 = i, l2 = 0, l3 = k, l4 = 0] : " + "0 <= i < pi and 0 <= k < pk }" + ) + isl_sched_map_before_expected = align_isl_maps_by_var_names( + isl_sched_map_before_expected, isl_sched_map_before) + + isl_sched_map_after_expected = isl.Map( + "[pt] -> { " + "[statement = 1, t] -> [l0 = 1, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " + "0 <= t < pt }" + ) + isl_sched_map_after_expected = align_isl_maps_by_var_names( + isl_sched_map_after_expected, isl_sched_map_after) + + assert isl_sched_map_before == isl_sched_map_before_expected + assert isl_sched_map_after == isl_sched_map_after_expected + + # ------------------------------------------------------------------------------ + # Relationship between insn_b and insn_c --------------------------------------- + + # insn_b and insn_c could have been linearized in either order + if lex_sched_BC.stmt_instance_before.stmt.int_id == 0: + # insn_c comes first + assert lex_sched_BC.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] + assert lex_sched_BC.stmt_instance_after.lex_pt == [0, 'i', 0, 'j', 1] + + # Get two isl maps representing the LexSchedule + + isl_sched_map_before, isl_sched_map_after = \ + get_isl_maps_for_LexSchedule(lex_sched_BC, knl, "insn_b", "insn_c") + + # Create expected maps, align, compare + + isl_sched_map_before_expected = isl.Map( + "[pi, pj] -> { " + "[statement = 0, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 1] : " + "0 <= i < pi and 0 <= j < pj }" + ) + isl_sched_map_before_expected = align_isl_maps_by_var_names( + isl_sched_map_before_expected, isl_sched_map_before) + + isl_sched_map_after_expected = isl.Map( + "[pi, pj] -> { " + "[statement = 1, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 0] : " + "0 <= i < pi and 0 <= j < pj }" + ) + isl_sched_map_after_expected = align_isl_maps_by_var_names( + isl_sched_map_after_expected, isl_sched_map_after) + + assert isl_sched_map_before == isl_sched_map_before_expected + assert isl_sched_map_after == isl_sched_map_after_expected + elif lex_sched_BC.stmt_instance_before.stmt.int_id == 1: + # insn_c comes first + assert lex_sched_BC.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 1] + assert lex_sched_BC.stmt_instance_after.lex_pt == [0, 'i', 0, 'j', 0] + + # Get two isl maps representing the LexSchedule + + isl_sched_map_before, isl_sched_map_after = \ + get_isl_maps_for_LexSchedule(lex_sched_BC, knl, "insn_b", "insn_c") + + # Create expected maps, align, compare + + isl_sched_map_before_expected = isl.Map( + "[pi, pj] -> { " + "[statement = 1, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 1] : " + "0 <= i < pi and 0 <= j < pj }" + ) + isl_sched_map_before_expected = align_isl_maps_by_var_names( + isl_sched_map_before_expected, isl_sched_map_before) + + isl_sched_map_after_expected = isl.Map( + "[pi, pj] -> { " + "[statement = 0, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 0] : " + "0 <= i < pi and 0 <= j < pj }" + ) + isl_sched_map_after_expected = align_isl_maps_by_var_names( + isl_sched_map_after_expected, isl_sched_map_after) + + assert isl_sched_map_before == isl_sched_map_before_expected + assert isl_sched_map_after == isl_sched_map_after_expected + + # ------------------------------------------------------------------------------ + # Relationship between insn_b and insn_d --------------------------------------- + + assert lex_sched_BD.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] + assert lex_sched_BD.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] + + # Get two isl maps representing the LexSchedule + + isl_sched_map_before, isl_sched_map_after = \ + get_isl_maps_for_LexSchedule(lex_sched_BD, knl, "insn_b", "insn_d") + + # Create expected maps, align, compare + + isl_sched_map_before_expected = isl.Map( + "[pi, pj] -> { " + "[statement = 0, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 0] : " + "0 <= i < pi and 0 <= j < pj }" + ) + isl_sched_map_before_expected = align_isl_maps_by_var_names( + isl_sched_map_before_expected, isl_sched_map_before) + + isl_sched_map_after_expected = isl.Map( + "[pt] -> { " + "[statement = 1, t] -> [l0 = 1, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " + "0 <= t < pt }" + ) + isl_sched_map_after_expected = align_isl_maps_by_var_names( + isl_sched_map_after_expected, isl_sched_map_after) + + assert isl_sched_map_before == isl_sched_map_before_expected + assert isl_sched_map_after == isl_sched_map_after_expected + + # ------------------------------------------------------------------------------ + # Relationship between insn_c and insn_d --------------------------------------- + + assert lex_sched_CD.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] + assert lex_sched_CD.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] + + # Get two isl maps representing the LexSchedule + + isl_sched_map_before, isl_sched_map_after = \ + get_isl_maps_for_LexSchedule(lex_sched_CD, knl, "insn_c", "insn_d") + + # Create expected maps, align, compare + + isl_sched_map_before_expected = isl.Map( + "[pi, pj] -> { " + "[statement = 0, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 0] : " + "0 <= i < pi and 0 <= j < pj }" + ) + isl_sched_map_before_expected = align_isl_maps_by_var_names( + isl_sched_map_before_expected, isl_sched_map_before) + + isl_sched_map_after_expected = isl.Map( + "[pt] -> { " + "[statement = 1, t] -> [l0 = 1, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " + "0 <= t < pt }" + ) + isl_sched_map_after_expected = align_isl_maps_by_var_names( + isl_sched_map_after_expected, isl_sched_map_after) + + assert isl_sched_map_before == isl_sched_map_before_expected + assert isl_sched_map_after == isl_sched_map_after_expected + + +if __name__ == "__main__": + if len(sys.argv) > 1: + exec(sys.argv[1]) + else: + from pytest import main + main([__file__]) + +# vim: foldmethod=marker From 17e14b19e0c59c4854e60b0509ba665b870e468e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Apr 2020 23:01:23 -0500 Subject: [PATCH 004/315] add docstrings for get_schedule_for_statement_pair() and get_isl_maps_for_LexSchedule() --- loopy/schedule/checker/__init__.py | 86 ++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 16 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 1acee56b9..99a555e00 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -20,6 +20,7 @@ THE SOFTWARE. """ +# {{{ Create LexSchedule for statement pair def get_schedule_for_statement_pair( knl, @@ -28,32 +29,52 @@ def get_schedule_for_statement_pair( insn_id_after, prohibited_var_names=set(), ): - """A set of dependencies between two statements. - - .. arg insn_id_before: An instruction identifier that is unique within + """Create a :class:`loopy.schedule.checker.schedule.LexSchedule` + representing the order of two statements as a mapping from + :class:`loopy.schedule.checker.LexScheduleStatementInstance` + to lexicographic time. + + :arg knl: A :class:`loopy.kernel.LoopKernel` containing the + linearization items that will be used to create a schedule. + + :arg linearization_items: A list of :class:`loopy.schedule.ScheduleItem` + (to be renamed to `loopy.schedule.LinearizationItem`) containing + the two linearization items for which a schedule will be + created. This list may be a partial linearization for a + kernel since this function may be used during the linearization + process. + + :arg insn_id_before: An instruction identifier that is unique within a :class:`loopy.kernel.LoopKernel`. - .. arg insn_id_after: An instruction identifier that is unique within + :arg insn_id_after: An instruction identifier that is unique within a :class:`loopy.kernel.LoopKernel`. - """ + :arg prohibited_var_names: A set of :class:`str` representing + variable names that should not be used when creating names for + dimensions in a :class:`loopy.schedule.checker.LexSchedule`. - # We don't retrieve linearization items from knl because knl may not be - # (fully) linearized yet. This function may be called part way through the - # linearization process and receive the current (unfinished) set of - # linearization items + :returns: A :class:`loopy.schedule.checker.schedule.LexSchedule` + representing the order of two statements as a mapping from + :class:`loopy.schedule.checker.LexScheduleStatementInstance` + to lexicographic time. + """ - # Preprocess if not already preprocessed + # {{{ Preprocess if not already preprocessed from loopy import preprocess_kernel preproc_knl = preprocess_kernel(knl) + # }}} + # {{{ By default, don't create LexSchedule variables matching existing inames if not prohibited_var_names: prohibited_var_names = preproc_knl.all_inames() + # }}} - # Get EnterLoop inames tagged as concurrent so LexSchedule can ignore + # {{{ Find any EnterLoop inames that are tagged as concurrent + # so that LexSchedule 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 exercising this: test_linearization_checker_with_stroud_bernstein()) + # Test which exercises this: test_linearization_checker_with_stroud_bernstein()) from loopy.schedule.checker.utils import ( get_concurrent_inames, _get_EnterLoop_inames, @@ -67,8 +88,9 @@ def get_schedule_for_statement_pair( "get_schedule_for_statement_pair encountered EnterLoop for inames %s " "with ConcurrentTag(s) in linearization for kernel %s. " "Ignoring these loops." % (conc_loop_inames, preproc_knl.name)) + # }}} - # Create LexSchedule: mapping of {statement instance: lex point} + # {{{ Create LexSchedule: mapping of {statement instance: lex point} # include only instructions involved in this dependency from loopy.schedule.checker.schedule import LexSchedule return LexSchedule( @@ -78,27 +100,59 @@ def get_schedule_for_statement_pair( prohibited_var_names=prohibited_var_names, loops_to_ignore=conc_loop_inames, ) + # }}} + +# }}} +# {{{ Get isl map pair for LexSchedule + def get_isl_maps_for_LexSchedule( lex_sched, knl, insn_id_before, insn_id_after, ): - # Get two isl maps representing the LexSchedule, - # one for the 'before' linearization item and one for 'after'; - # this requires the iname domains + """Create a pair of :class:`islpy.Map`s representing a + :class:`loopy.schedule.checker.LexSchedule` as two mappings + from statement instances to lexicographic time, one for + the dependee statement and one for the depender. + + :arg lex_sched: A :class:`loopy.schedule.checker.schedule.LexSchedule` + representing the order of two statements as a mapping from + :class:`loopy.schedule.checker.LexScheduleStatementInstance` + to lexicographic time. + + :arg knl: A :class:`loopy.kernel.LoopKernel` containing the + linearization items that will be used to create a schedule. + :arg insn_id_before: An instruction identifier that is unique within + a :class:`loopy.kernel.LoopKernel`. + + :arg insn_id_after: An instruction identifier that is unique within + a :class:`loopy.kernel.LoopKernel`. + + :returns: A two-tuple containing two :class:`islpy.Map`s + representing the schedule as two mappings + from statement instances to lexicographic time, one for + the dependee and one for the depender. + """ + + # {{{ Get iname domains insn_before_inames = knl.id_to_insn[insn_id_before].within_inames insn_after_inames = knl.id_to_insn[insn_id_after].within_inames dom_before = knl.get_inames_domain(insn_before_inames) dom_after = knl.get_inames_domain(insn_after_inames) + # }}} + # {{{ Get isl maps isl_sched_map_before, isl_sched_map_after = \ lex_sched.create_isl_maps( dom_before, dom_after, ) + # }}} return isl_sched_map_before, isl_sched_map_after + +# }}} From dc45709e6e9b117940f375c5fba8aeeb53f0d3b6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Apr 2020 23:03:14 -0500 Subject: [PATCH 005/315] remove get_statement_ordering_map() (won't be part of this MR) --- .../checker/lexicographic_order_map.py | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/loopy/schedule/checker/lexicographic_order_map.py b/loopy/schedule/checker/lexicographic_order_map.py index 2e063e7d7..399add0b3 100644 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ b/loopy/schedule/checker/lexicographic_order_map.py @@ -23,44 +23,6 @@ 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 From ee59915fb3d0c163ffddafa82eede6497fb348cf Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Apr 2020 23:07:34 -0500 Subject: [PATCH 006/315] remove lexicographic_order_map (not used in this MR) --- .../checker/lexicographic_order_map.py | 121 ------------------ 1 file changed, 121 deletions(-) delete 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 deleted file mode 100644 index 399add0b3..000000000 --- a/loopy/schedule/checker/lexicographic_order_map.py +++ /dev/null @@ -1,121 +0,0 @@ -__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_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 5401383198da8c7ba6fc840d075a23297379e76a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Apr 2020 23:09:52 -0500 Subject: [PATCH 007/315] remove get_lex_order_map_for_sched_space() (not part of this MR) --- loopy/schedule/checker/schedule.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index c395863ef..199a5deda 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -458,19 +458,6 @@ 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 __eq__(self, other): return ( self.stmt_instance_before == other.stmt_instance_before From 7e94f4beafa84aa525a7eb5c6177c7f12b498d19 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Apr 2020 23:14:12 -0500 Subject: [PATCH 008/315] remove more methods from LexSchedule that are not used in this MR (loopy_insn_id_to_lex_sched_id and __eq__) --- loopy/schedule/checker/schedule.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 199a5deda..ed168ae5b 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -306,18 +306,6 @@ def __init__( # the values in these missing dims should be zero, so add them self.pad_lex_pts_with_zeros() - def loopy_insn_id_to_lex_sched_id(self): - """Return a dictionary mapping insn_id to int_id, where ``insn_id`` and - ``int_id`` refer to the ``insn_id`` and ``int_id`` attributes of - :class:`LexScheduleStatement`. - """ - return { - self.stmt_instance_before.stmt.insn_id: - self.stmt_instance_before.stmt.int_id, - self.stmt_instance_after.stmt.insn_id: - self.stmt_instance_after.stmt.int_id, - } - def max_lex_dims(self): return max([ len(self.stmt_instance_before.lex_pt), @@ -458,11 +446,6 @@ def get_lex_var_names(self): return [self.lex_var_prefix+str(i) for i in range(self.max_lex_dims())] - def __eq__(self, other): - return ( - self.stmt_instance_before == other.stmt_instance_before - and self.stmt_instance_after == other.stmt_instance_after) - def __str__(self): sched_str = "Before: {\n" domain_elem = "[%s=%s,]" % ( From 16afc55bec1d072783e7b2a0e5eae6963e7506fe Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Apr 2020 23:21:08 -0500 Subject: [PATCH 009/315] remove another func from utils that is not used in this MR (append_marker_to_strings) --- loopy/schedule/checker/utils.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 8757406b7..cb933de6f 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -143,13 +143,6 @@ 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 d2f94b7cf6cee1d0f0a24b72209cff6be074852c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Apr 2020 23:41:53 -0500 Subject: [PATCH 010/315] remove LexScheduleStatement methods not needed in this MR --- loopy/schedule/checker/schedule.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index ed168ae5b..542c48f95 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -51,16 +51,6 @@ def __init__( self.int_id = int_id self.within_inames = within_inames - def __eq__(self, other): - return ( - self.insn_id == other.insn_id - and self.int_id == other.int_id - and self.within_inames == other.within_inames - ) - - def __hash__(self): - return hash(repr(self)) - def update_persistent_hash(self, key_hash, key_builder): """Custom hash computation function for use with :class:`pytools.persistent_dict.PersistentDict`. From aa44009f367adb810ee3686047d2fbbec13135e5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Apr 2020 23:47:49 -0500 Subject: [PATCH 011/315] fixing flake8 issues --- loopy/schedule/checker/__init__.py | 1 + loopy/schedule/checker/schedule.py | 20 +++++----- test/test_linearization_checker.py | 59 +++++++++++++++--------------- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 99a555e00..2911351b2 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -20,6 +20,7 @@ THE SOFTWARE. """ + # {{{ Create LexSchedule for statement pair def get_schedule_for_statement_pair( diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 542c48f95..39c8c1161 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -177,9 +177,6 @@ def __init__( next_insn_lex_pt = [0] stmt_since_last_block_at_tier = [False] next_sid = 0 - stmt_added_since_last_EnterLoop = False - stmt_added_since_last_LeaveLoop = False - #stmt_added_since_last_new_block = False # blocks start at open/close loop for linearization_item in linearization_items_ordered: if isinstance(linearization_item, EnterLoop): iname = linearization_item.iname @@ -188,8 +185,8 @@ def __init__( # We could always increment next_insn_lex_pt[-1] here since this new # section of code comes after the previous section (statements - # since last opened/closed loop), but if we have not added any statements - # within this block yet, we don't have to + # since last opened/closed loop), but if we have not added any + # statements within this block yet, we don't have to # (effectively ignoring that section of code). if stmt_since_last_block_at_tier[-1]: next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 @@ -214,8 +211,8 @@ def __init__( # We could always increment next_insn_lex_pt[-1] here since this new # block of code comes after the previous block (all statements - # since last opened/closed loop), but if we have not added any statements - # within this block yet, we don't have to + # since last opened/closed loop), but if we have not added any + # statements within this block yet, we don't have to # (effectively ignoring that section of code). stmt_since_last_block_at_tier.pop() if stmt_since_last_block_at_tier[-1]: @@ -255,7 +252,8 @@ def __init__( next_sid += 1 # all current (nested) blocks now contain a statement - stmt_since_last_block_at_tier = [True]*len(stmt_since_last_block_at_tier) + stmt_since_last_block_at_tier = [True]*len( + stmt_since_last_block_at_tier) elif lp_insn_id == before_insn_id: # add before sched item self.stmt_instance_before = LexScheduleStatementInstance( @@ -270,7 +268,8 @@ def __init__( next_sid += 1 # all current (nested) blocks now contain a statement - stmt_since_last_block_at_tier = [True]*len(stmt_since_last_block_at_tier) + stmt_since_last_block_at_tier = [True]*len( + stmt_since_last_block_at_tier) elif lp_insn_id == after_insn_id: # add after sched item self.stmt_instance_after = LexScheduleStatementInstance( @@ -285,7 +284,8 @@ def __init__( next_sid += 1 # all current (nested) blocks now contain a statement - stmt_since_last_block_at_tier = [True]*len(stmt_since_last_block_at_tier) + stmt_since_last_block_at_tier = [True]*len( + stmt_since_last_block_at_tier) else: pass # to save time, stop when we've created both statements diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 7e145ce1d..68688f0df 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -31,7 +31,6 @@ as pytest_generate_tests) from loopy.version import LOOPY_USE_LANGUAGE_VERSION_2018_2 # noqa import logging -from loopy.kernel import KernelState from loopy import ( preprocess_kernel, get_one_linearized_kernel, @@ -95,37 +94,37 @@ def test_lexschedule_and_islmap_creation(): linearization_items = knl.linearization # Create LexSchedule: mapping of {statement instance: lex point} - lex_sched_AB = get_schedule_for_statement_pair( + lex_sched_ab = get_schedule_for_statement_pair( knl, linearization_items, "insn_a", "insn_b", ) - lex_sched_AC = get_schedule_for_statement_pair( + lex_sched_ac = get_schedule_for_statement_pair( knl, linearization_items, "insn_a", "insn_c", ) - lex_sched_AD = get_schedule_for_statement_pair( + lex_sched_ad = get_schedule_for_statement_pair( knl, linearization_items, "insn_a", "insn_d", ) - lex_sched_BC = get_schedule_for_statement_pair( + lex_sched_bc = get_schedule_for_statement_pair( knl, linearization_items, "insn_b", "insn_c", ) - lex_sched_BD = get_schedule_for_statement_pair( + lex_sched_bd = get_schedule_for_statement_pair( knl, linearization_items, "insn_b", "insn_d", ) - lex_sched_CD = get_schedule_for_statement_pair( + lex_sched_cd = get_schedule_for_statement_pair( knl, linearization_items, "insn_c", @@ -134,13 +133,13 @@ def test_lexschedule_and_islmap_creation(): # Relationship between insn_a and insn_b --------------------------------------- - assert lex_sched_AB.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] - assert lex_sched_AB.stmt_instance_after.lex_pt == [0, 'i', 1, 'j', 0] + assert lex_sched_ab.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] + assert lex_sched_ab.stmt_instance_after.lex_pt == [0, 'i', 1, 'j', 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_AB, knl, "insn_a", "insn_b") + get_isl_maps_for_LexSchedule(lex_sched_ab, knl, "insn_a", "insn_b") # Create expected maps, align, compare @@ -166,13 +165,13 @@ def test_lexschedule_and_islmap_creation(): # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_c --------------------------------------- - assert lex_sched_AC.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] - assert lex_sched_AC.stmt_instance_after.lex_pt == [0, 'i', 1, 'j', 0] + assert lex_sched_ac.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] + assert lex_sched_ac.stmt_instance_after.lex_pt == [0, 'i', 1, 'j', 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_AC, knl, "insn_a", "insn_c") + get_isl_maps_for_LexSchedule(lex_sched_ac, knl, "insn_a", "insn_c") # Create expected maps, align, compare @@ -198,13 +197,13 @@ def test_lexschedule_and_islmap_creation(): # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_d --------------------------------------- - assert lex_sched_AD.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] - assert lex_sched_AD.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] + assert lex_sched_ad.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] + assert lex_sched_ad.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_AD, knl, "insn_a", "insn_d") + get_isl_maps_for_LexSchedule(lex_sched_ad, knl, "insn_a", "insn_d") # Create expected maps, align, compare @@ -231,15 +230,15 @@ def test_lexschedule_and_islmap_creation(): # Relationship between insn_b and insn_c --------------------------------------- # insn_b and insn_c could have been linearized in either order - if lex_sched_BC.stmt_instance_before.stmt.int_id == 0: + if lex_sched_bc.stmt_instance_before.stmt.int_id == 0: # insn_c comes first - assert lex_sched_BC.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] - assert lex_sched_BC.stmt_instance_after.lex_pt == [0, 'i', 0, 'j', 1] + assert lex_sched_bc.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] + assert lex_sched_bc.stmt_instance_after.lex_pt == [0, 'i', 0, 'j', 1] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_BC, knl, "insn_b", "insn_c") + get_isl_maps_for_LexSchedule(lex_sched_bc, knl, "insn_b", "insn_c") # Create expected maps, align, compare @@ -261,15 +260,15 @@ def test_lexschedule_and_islmap_creation(): assert isl_sched_map_before == isl_sched_map_before_expected assert isl_sched_map_after == isl_sched_map_after_expected - elif lex_sched_BC.stmt_instance_before.stmt.int_id == 1: + elif lex_sched_bc.stmt_instance_before.stmt.int_id == 1: # insn_c comes first - assert lex_sched_BC.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 1] - assert lex_sched_BC.stmt_instance_after.lex_pt == [0, 'i', 0, 'j', 0] + assert lex_sched_bc.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 1] + assert lex_sched_bc.stmt_instance_after.lex_pt == [0, 'i', 0, 'j', 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_BC, knl, "insn_b", "insn_c") + get_isl_maps_for_LexSchedule(lex_sched_bc, knl, "insn_b", "insn_c") # Create expected maps, align, compare @@ -295,13 +294,13 @@ def test_lexschedule_and_islmap_creation(): # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_d --------------------------------------- - assert lex_sched_BD.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] - assert lex_sched_BD.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] + assert lex_sched_bd.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] + assert lex_sched_bd.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_BD, knl, "insn_b", "insn_d") + get_isl_maps_for_LexSchedule(lex_sched_bd, knl, "insn_b", "insn_d") # Create expected maps, align, compare @@ -327,13 +326,13 @@ def test_lexschedule_and_islmap_creation(): # ------------------------------------------------------------------------------ # Relationship between insn_c and insn_d --------------------------------------- - assert lex_sched_CD.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] - assert lex_sched_CD.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] + assert lex_sched_cd.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] + assert lex_sched_cd.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_CD, knl, "insn_c", "insn_d") + get_isl_maps_for_LexSchedule(lex_sched_cd, knl, "insn_c", "insn_d") # Create expected maps, align, compare From 08e7342a919856a1f2eee7d1836c65fcdca61655 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Apr 2020 00:29:02 -0500 Subject: [PATCH 012/315] adding LexScheduleStatement.__eq__ back in to see if it fixes caching error --- loopy/schedule/checker/schedule.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 39c8c1161..b5f9b4256 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -51,6 +51,13 @@ def __init__( self.int_id = int_id self.within_inames = within_inames + def __eq__(self, other): + return ( + self.insn_id == other.insn_id + and self.int_id == other.int_id + and self.within_inames == other.within_inames + ) + def update_persistent_hash(self, key_hash, key_builder): """Custom hash computation function for use with :class:`pytools.persistent_dict.PersistentDict`. From 5f53d50fe0b38c288c1fd1a5a681d24a317f6e8d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 17 Apr 2020 03:26:18 -0500 Subject: [PATCH 013/315] eliminate duplicate code in sched.__str__ --- loopy/schedule/checker/schedule.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index b5f9b4256..af35bd68e 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -444,17 +444,13 @@ def get_lex_var_names(self): for i in range(self.max_lex_dims())] def __str__(self): - sched_str = "Before: {\n" - domain_elem = "[%s=%s,]" % ( - self.statement_var_name, - self.stmt_instance_before.stmt.int_id) - sched_str += "%s -> %s;\n" % (domain_elem, self.stmt_instance_before.lex_pt) - sched_str += "}\n" - - sched_str += "After: {\n" - domain_elem = "[%s=%s,]" % ( - self.statement_var_name, - self.stmt_instance_after.stmt.int_id) - sched_str += "%s -> %s;\n" % (domain_elem, self.stmt_instance_after.lex_pt) - sched_str += "}" - return sched_str + + def stringify_sched_stmt_instance(stmt_inst): + return "{\n[%s=%s,] -> %s;\n}" % ( + self.statement_var_name, + stmt_inst.stmt.int_id, + stmt_inst.lex_pt) + + return "Before: %s\nAfter: %s" % ( + stringify_sched_stmt_instance(self.stmt_instance_before), + stringify_sched_stmt_instance(self.stmt_instance_after)) From 5441bfa239a49567c63200ff24f1e0f2e45e4705 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 17 Apr 2020 04:27:41 -0500 Subject: [PATCH 014/315] eliminate duplicate code in sched.create_isl_maps --- loopy/schedule/checker/schedule.py | 110 ++++++++++++----------------- 1 file changed, 46 insertions(+), 64 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index af35bd68e..8ca42e83d 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -365,79 +365,61 @@ def create_isl_maps( """ from loopy.schedule.checker.utils import ( + list_var_names_in_isl_sets, + get_isl_space, create_symbolic_isl_map_from_tuples, - add_dims_to_isl_set + add_dims_to_isl_set, ) - from loopy.schedule.checker.utils import ( - list_var_names_in_isl_sets, - ) - if dom_inames_ordered_before is None: - dom_inames_ordered_before = list_var_names_in_isl_sets( - [dom_before]) - if dom_inames_ordered_after is None: - dom_inames_ordered_after = list_var_names_in_isl_sets( - [dom_after]) - - # create an isl space - # {('statement', used in >=1 statement domain>) -> - # (lexicographic ordering dims)} - from loopy.schedule.checker.utils import ( - get_isl_space - ) params_sched = [] out_names_sched = self.get_lex_var_names() - in_names_sched_before = [ - self.statement_var_name] + dom_inames_ordered_before[:] - sched_space_before = get_isl_space( - params_sched, in_names_sched_before, out_names_sched) - in_names_sched_after = [ - self.statement_var_name] + dom_inames_ordered_after[:] - sched_space_after = get_isl_space( - params_sched, in_names_sched_after, out_names_sched) - - # Insert 'statement' dim into domain so that its space allows for - # intersection with sched map later - doms_to_intersect_before = [ - add_dims_to_isl_set( - dom_before, isl.dim_type.set, - [self.statement_var_name], 0), - ] - doms_to_intersect_after = [ - add_dims_to_isl_set( - dom_after, isl.dim_type.set, - [self.statement_var_name], 0), - ] + def _get_isl_map_for_stmt_inst( + stmt_inst, dom, dom_inames_ordered): - # Each isl map representing the schedule maps - # statement instances -> lex time + # create an isl space + # {('statement', used in statement domain>) -> + # (lexicographic ordering dims)} + if dom_inames_ordered is None: + dom_inames_ordered = list_var_names_in_isl_sets([dom]) - # Right now, statement tuples consist of single int. - # Add all inames from domains to map domain tuples. + in_names_sched = [ + self.statement_var_name] + dom_inames_ordered[:] + sched_space = get_isl_space( + params_sched, in_names_sched, out_names_sched) - # create isl map - return ( - create_symbolic_isl_map_from_tuples( - zip( - [( - (self.stmt_instance_before.stmt.int_id,) - + tuple(dom_inames_ordered_before), - self.stmt_instance_before.lex_pt - )], - doms_to_intersect_before - ), - sched_space_before, self.statement_var_name), - create_symbolic_isl_map_from_tuples( - zip( - [( - (self.stmt_instance_after.stmt.int_id,) - + tuple(dom_inames_ordered_after), - self.stmt_instance_after.lex_pt)], - doms_to_intersect_after - ), - sched_space_after, self.statement_var_name) - ) + # 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, [self.statement_var_name], 0), ] + + # Each isl map representing the schedule will map + # statement instances -> lex time. + # Right now, statement instance tuples consist of single int. + # Add all inames from domains to each map domain tuple. + tuple_pair = [( + (stmt_inst.stmt.int_id, ) + tuple(dom_inames_ordered), + stmt_inst.lex_pt + )] + + # create isl map + return create_symbolic_isl_map_from_tuples( + tuple_pairs_with_domains=zip(tuple_pair, dom_to_intersect), + space=sched_space, + statement_var_name=self.statement_var_name, + ) + + map_before = _get_isl_map_for_stmt_inst( + self.stmt_instance_before, + dom_before, + dom_inames_ordered_before) + map_after = _get_isl_map_for_stmt_inst( + self.stmt_instance_after, + dom_after, + dom_inames_ordered_after) + + return (map_before, map_after) def get_lex_var_names(self): return [self.lex_var_prefix+str(i) From 31c68b724c2c9d6bf1fdadc703b3e6a60c8a6cff Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 17 Apr 2020 04:34:33 -0500 Subject: [PATCH 015/315] eliminate duplicate code in sched.pad_lex_pts_with_zeros --- loopy/schedule/checker/schedule.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 8ca42e83d..4e59fdb7f 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -316,17 +316,18 @@ def pad_lex_pts_with_zeros(self): dimensions. """ + def _pad_lex_pt_with_zeros(stmt_inst, length): + return LexScheduleStatementInstance( + stmt_inst.stmt, + stmt_inst.lex_pt[:] + [0]*(length-len(stmt_inst.lex_pt)), + ) + max_lex_dim = self.max_lex_dims() - self.stmt_instance_before = LexScheduleStatementInstance( - self.stmt_instance_before.stmt, - self.stmt_instance_before.lex_pt[:] + [0]*( - max_lex_dim-len(self.stmt_instance_before.lex_pt)) - ) - self.stmt_instance_after = LexScheduleStatementInstance( - self.stmt_instance_after.stmt, - self.stmt_instance_after.lex_pt[:] + [0]*( - max_lex_dim-len(self.stmt_instance_after.lex_pt)) - ) + + self.stmt_instance_before = _pad_lex_pt_with_zeros( + self.stmt_instance_before, max_lex_dim) + self.stmt_instance_after = _pad_lex_pt_with_zeros( + self.stmt_instance_after, max_lex_dim) def create_isl_maps( self, From da919bfbe6cf9c5128d100caaf581f2b04c76ad0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 17 Apr 2020 04:57:29 -0500 Subject: [PATCH 016/315] eliminate duplicate code in sched.__init__ --- loopy/schedule/checker/schedule.py | 65 ++++++++++-------------------- 1 file changed, 22 insertions(+), 43 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 4e59fdb7f..0aca588c3 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -182,7 +182,7 @@ def __init__( # keep track of the next point in our lexicographic ordering # initially this as a 1-d point with value 0 next_insn_lex_pt = [0] - stmt_since_last_block_at_tier = [False] + stmt_added_since_prev_block_at_tier = [False] next_sid = 0 for linearization_item in linearization_items_ordered: if isinstance(linearization_item, EnterLoop): @@ -193,19 +193,20 @@ def __init__( # We could always increment next_insn_lex_pt[-1] here since this new # section of code comes after the previous section (statements # since last opened/closed loop), but if we have not added any - # statements within this block yet, we don't have to + # statements within the previous section yet, we don't have to # (effectively ignoring that section of code). - if stmt_since_last_block_at_tier[-1]: + if stmt_added_since_prev_block_at_tier[-1]: next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 - stmt_since_last_block_at_tier[-1] = False + stmt_added_since_prev_block_at_tier[-1] = False # upon entering a loop, we enter a new (deeper) tier, # add one lex dimension for the loop variable, # add second lex dim to enumerate code blocks within new loop, and - # append a dim to stmt_since_last_block_at_tier to represent new tier + # append a dim to stmt_added_since_prev_block_at_tier to represent + # new tier next_insn_lex_pt.append(iname) next_insn_lex_pt.append(0) - stmt_since_last_block_at_tier.append(False) + stmt_added_since_prev_block_at_tier.append(False) elif isinstance(linearization_item, LeaveLoop): if linearization_item.iname in loops_to_ignore: continue @@ -219,12 +220,12 @@ def __init__( # We could always increment next_insn_lex_pt[-1] here since this new # block of code comes after the previous block (all statements # since last opened/closed loop), but if we have not added any - # statements within this block yet, we don't have to + # statements within the previous section yet, we don't have to # (effectively ignoring that section of code). - stmt_since_last_block_at_tier.pop() - if stmt_since_last_block_at_tier[-1]: + stmt_added_since_prev_block_at_tier.pop() + if stmt_added_since_prev_block_at_tier[-1]: next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 - stmt_since_last_block_at_tier[-1] = False + stmt_added_since_prev_block_at_tier[-1] = False elif isinstance(linearization_item, (RunInstruction, Barrier)): from loopy.schedule.checker.utils import ( _get_insn_id_from_linearization_item, @@ -238,30 +239,9 @@ def __init__( continue # only process before/after insns, otherwise ignore - if lp_insn_id == before_insn_id and lp_insn_id == after_insn_id: - # add before sched item - self.stmt_instance_before = LexScheduleStatementInstance( - LexScheduleStatement( - insn_id=lp_insn_id, - int_id=next_sid, # int representing insn - ), - next_insn_lex_pt[:]) - # add after sched item - self.stmt_instance_after = LexScheduleStatementInstance( - LexScheduleStatement( - insn_id=lp_insn_id, - int_id=next_sid, # int representing insn - ), - next_insn_lex_pt[:]) - - # increment lex dim val enumerating items in current code block - next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 - next_sid += 1 + stmt_added = False - # all current (nested) blocks now contain a statement - stmt_since_last_block_at_tier = [True]*len( - stmt_since_last_block_at_tier) - elif lp_insn_id == before_insn_id: + if lp_insn_id == before_insn_id: # add before sched item self.stmt_instance_before = LexScheduleStatementInstance( LexScheduleStatement( @@ -269,15 +249,9 @@ def __init__( int_id=next_sid, # int representing insn ), next_insn_lex_pt[:]) + stmt_added = True - # increment lex dim val enumerating items in current code block - next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 - next_sid += 1 - - # all current (nested) blocks now contain a statement - stmt_since_last_block_at_tier = [True]*len( - stmt_since_last_block_at_tier) - elif lp_insn_id == after_insn_id: + if lp_insn_id == after_insn_id: # add after sched item self.stmt_instance_after = LexScheduleStatementInstance( LexScheduleStatement( @@ -285,14 +259,19 @@ def __init__( int_id=next_sid, # int representing insn ), next_insn_lex_pt[:]) + stmt_added = True + + # Note: before/after may refer to same stmt, in which case + # both of the above conditionals execute + if stmt_added: # increment lex dim val enumerating items in current code block next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 next_sid += 1 # all current (nested) blocks now contain a statement - stmt_since_last_block_at_tier = [True]*len( - stmt_since_last_block_at_tier) + stmt_added_since_prev_block_at_tier = [True]*len( + stmt_added_since_prev_block_at_tier) else: pass # to save time, stop when we've created both statements From 7d291b0b49b878cc2c02767c717f6e652eb40cf2 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 19 Apr 2020 21:24:18 -0500 Subject: [PATCH 017/315] allow for all valid linearization orders in LexSchedule/map creation test --- test/test_linearization_checker.py | 187 +++++++++++++++-------------- 1 file changed, 97 insertions(+), 90 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 68688f0df..c112b40ae 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -197,43 +197,53 @@ def test_lexschedule_and_islmap_creation(): # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_d --------------------------------------- - assert lex_sched_ad.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] - assert lex_sched_ad.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] + # insn_a and insn_d could have been linearized in either order + # (i loop could be before or after t loop) + def perform_insn_ad_checks_with(sid_a, sid_d): + assert lex_sched_ad.stmt_instance_before.lex_pt == [sid_a, 'i', 0, 'k', 0] + assert lex_sched_ad.stmt_instance_after.lex_pt == [sid_d, 't', 0, 0, 0] - # Get two isl maps representing the LexSchedule + # Get two isl maps representing the LexSchedule - isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_ad, knl, "insn_a", "insn_d") + isl_sched_map_before, isl_sched_map_after = \ + get_isl_maps_for_LexSchedule(lex_sched_ad, knl, "insn_a", "insn_d") - # Create expected maps, align, compare + # Create expected maps, align, compare - isl_sched_map_before_expected = isl.Map( - "[pi, pk] -> { " - "[statement = 0, i, k] -> [l0 = 0, l1 = i, l2 = 0, l3 = k, l4 = 0] : " - "0 <= i < pi and 0 <= k < pk }" - ) - isl_sched_map_before_expected = align_isl_maps_by_var_names( - isl_sched_map_before_expected, isl_sched_map_before) + isl_sched_map_before_expected = isl.Map( + "[pi, pk] -> { " + "[statement = %d, i, k] -> [l0 = %d, l1 = i, l2 = 0, l3 = k, l4 = 0] : " + "0 <= i < pi and 0 <= k < pk }" + % (sid_a, sid_a) + ) + isl_sched_map_before_expected = align_isl_maps_by_var_names( + isl_sched_map_before_expected, isl_sched_map_before) - isl_sched_map_after_expected = isl.Map( - "[pt] -> { " - "[statement = 1, t] -> [l0 = 1, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " - "0 <= t < pt }" - ) - isl_sched_map_after_expected = align_isl_maps_by_var_names( - isl_sched_map_after_expected, isl_sched_map_after) + isl_sched_map_after_expected = isl.Map( + "[pt] -> { " + "[statement = %d, t] -> [l0 = %d, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " + "0 <= t < pt }" + % (sid_d, sid_d) + ) + isl_sched_map_after_expected = align_isl_maps_by_var_names( + isl_sched_map_after_expected, isl_sched_map_after) - assert isl_sched_map_before == isl_sched_map_before_expected - assert isl_sched_map_after == isl_sched_map_after_expected + assert isl_sched_map_before == isl_sched_map_before_expected + assert isl_sched_map_after == isl_sched_map_after_expected + + if lex_sched_ad.stmt_instance_before.stmt.int_id == 0: + perform_insn_ad_checks_with(0, 1) + else: + perform_insn_ad_checks_with(1, 0) # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_c --------------------------------------- # insn_b and insn_c could have been linearized in either order - if lex_sched_bc.stmt_instance_before.stmt.int_id == 0: - # insn_c comes first - assert lex_sched_bc.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] - assert lex_sched_bc.stmt_instance_after.lex_pt == [0, 'i', 0, 'j', 1] + # (i loop could be before or after t loop) + def perform_insn_bc_checks_with(sid_b, sid_c): + assert lex_sched_bc.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', sid_b] + assert lex_sched_bc.stmt_instance_after.lex_pt == [0, 'i', 0, 'j', sid_c] # Get two isl maps representing the LexSchedule @@ -244,46 +254,60 @@ def test_lexschedule_and_islmap_creation(): isl_sched_map_before_expected = isl.Map( "[pi, pj] -> { " - "[statement = 0, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 1] : " + "[statement = %d, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = %d] : " "0 <= i < pi and 0 <= j < pj }" + % (sid_b, sid_b) ) isl_sched_map_before_expected = align_isl_maps_by_var_names( isl_sched_map_before_expected, isl_sched_map_before) isl_sched_map_after_expected = isl.Map( "[pi, pj] -> { " - "[statement = 1, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 0] : " + "[statement = %d, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = %d] : " "0 <= i < pi and 0 <= j < pj }" + % (sid_c, sid_c) ) isl_sched_map_after_expected = align_isl_maps_by_var_names( isl_sched_map_after_expected, isl_sched_map_after) assert isl_sched_map_before == isl_sched_map_before_expected assert isl_sched_map_after == isl_sched_map_after_expected - elif lex_sched_bc.stmt_instance_before.stmt.int_id == 1: - # insn_c comes first - assert lex_sched_bc.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 1] - assert lex_sched_bc.stmt_instance_after.lex_pt == [0, 'i', 0, 'j', 0] + + if lex_sched_bc.stmt_instance_before.stmt.int_id == 0: + perform_insn_bc_checks_with(0, 1) + else: + perform_insn_bc_checks_with(1, 0) + + # ------------------------------------------------------------------------------ + # Relationship between insn_b and insn_d --------------------------------------- + + # insn_b and insn_d could have been linearized in either order + # (i loop could be before or after t loop) + def perform_insn_bd_checks_with(sid_b, sid_d): + assert lex_sched_bd.stmt_instance_before.lex_pt == [sid_b, 'i', 0, 'j', 0] + assert lex_sched_bd.stmt_instance_after.lex_pt == [sid_d, 't', 0, 0, 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_bc, knl, "insn_b", "insn_c") + get_isl_maps_for_LexSchedule(lex_sched_bd, knl, "insn_b", "insn_d") # Create expected maps, align, compare isl_sched_map_before_expected = isl.Map( "[pi, pj] -> { " - "[statement = 1, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 1] : " + "[statement = %d, i, j] -> [l0 = %d, l1 = i, l2 = 0, l3 = j, l4 = 0] : " "0 <= i < pi and 0 <= j < pj }" + % (sid_b, sid_b) ) isl_sched_map_before_expected = align_isl_maps_by_var_names( isl_sched_map_before_expected, isl_sched_map_before) isl_sched_map_after_expected = isl.Map( - "[pi, pj] -> { " - "[statement = 0, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 0] : " - "0 <= i < pi and 0 <= j < pj }" + "[pt] -> { " + "[statement = %d, t] -> [l0 = %d, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " + "0 <= t < pt }" + % (sid_d, sid_d) ) isl_sched_map_after_expected = align_isl_maps_by_var_names( isl_sched_map_after_expected, isl_sched_map_after) @@ -291,69 +315,52 @@ def test_lexschedule_and_islmap_creation(): assert isl_sched_map_before == isl_sched_map_before_expected assert isl_sched_map_after == isl_sched_map_after_expected - # ------------------------------------------------------------------------------ - # Relationship between insn_b and insn_d --------------------------------------- - - assert lex_sched_bd.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] - assert lex_sched_bd.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] - - # Get two isl maps representing the LexSchedule - - isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_bd, knl, "insn_b", "insn_d") - - # Create expected maps, align, compare - - isl_sched_map_before_expected = isl.Map( - "[pi, pj] -> { " - "[statement = 0, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 0] : " - "0 <= i < pi and 0 <= j < pj }" - ) - isl_sched_map_before_expected = align_isl_maps_by_var_names( - isl_sched_map_before_expected, isl_sched_map_before) - - isl_sched_map_after_expected = isl.Map( - "[pt] -> { " - "[statement = 1, t] -> [l0 = 1, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " - "0 <= t < pt }" - ) - isl_sched_map_after_expected = align_isl_maps_by_var_names( - isl_sched_map_after_expected, isl_sched_map_after) - - assert isl_sched_map_before == isl_sched_map_before_expected - assert isl_sched_map_after == isl_sched_map_after_expected + if lex_sched_bd.stmt_instance_before.stmt.int_id == 0: + perform_insn_bd_checks_with(0, 1) + else: + perform_insn_bd_checks_with(1, 0) # ------------------------------------------------------------------------------ # Relationship between insn_c and insn_d --------------------------------------- - assert lex_sched_cd.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', 0] - assert lex_sched_cd.stmt_instance_after.lex_pt == [1, 't', 0, 0, 0] + # insn_c and insn_d could have been linearized in either order + # (i loop could be before or after t loop) + def perform_insn_cd_checks_with(sid_c, sid_d): + assert lex_sched_cd.stmt_instance_before.lex_pt == [sid_c, 'i', 0, 'j', 0] + assert lex_sched_cd.stmt_instance_after.lex_pt == [sid_d, 't', 0, 0, 0] - # Get two isl maps representing the LexSchedule + # Get two isl maps representing the LexSchedule - isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_cd, knl, "insn_c", "insn_d") + isl_sched_map_before, isl_sched_map_after = \ + get_isl_maps_for_LexSchedule(lex_sched_cd, knl, "insn_c", "insn_d") - # Create expected maps, align, compare + # Create expected maps, align, compare - isl_sched_map_before_expected = isl.Map( - "[pi, pj] -> { " - "[statement = 0, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = 0] : " - "0 <= i < pi and 0 <= j < pj }" - ) - isl_sched_map_before_expected = align_isl_maps_by_var_names( - isl_sched_map_before_expected, isl_sched_map_before) + isl_sched_map_before_expected = isl.Map( + "[pi, pj] -> { " + "[statement = %d, i, j] -> [l0 = %d, l1 = i, l2 = 0, l3 = j, l4 = 0] : " + "0 <= i < pi and 0 <= j < pj }" + % (sid_c, sid_c) + ) + isl_sched_map_before_expected = align_isl_maps_by_var_names( + isl_sched_map_before_expected, isl_sched_map_before) - isl_sched_map_after_expected = isl.Map( - "[pt] -> { " - "[statement = 1, t] -> [l0 = 1, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " - "0 <= t < pt }" - ) - isl_sched_map_after_expected = align_isl_maps_by_var_names( - isl_sched_map_after_expected, isl_sched_map_after) + isl_sched_map_after_expected = isl.Map( + "[pt] -> { " + "[statement = %d, t] -> [l0 = %d, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " + "0 <= t < pt }" + % (sid_d, sid_d) + ) + isl_sched_map_after_expected = align_isl_maps_by_var_names( + isl_sched_map_after_expected, isl_sched_map_after) - assert isl_sched_map_before == isl_sched_map_before_expected - assert isl_sched_map_after == isl_sched_map_after_expected + assert isl_sched_map_before == isl_sched_map_before_expected + assert isl_sched_map_after == isl_sched_map_after_expected + + if lex_sched_cd.stmt_instance_before.stmt.int_id == 0: + perform_insn_cd_checks_with(0, 1) + else: + perform_insn_cd_checks_with(1, 0) if __name__ == "__main__": From 45b29f7a3c97760ccba104e6e189522b1587b552 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Apr 2020 20:34:04 -0500 Subject: [PATCH 018/315] 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 019/315] 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 020/315] 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 021/315] 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 022/315] 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 023/315] 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 de3f00ce791dc98c884d6c705351f4bfd9beb9b8 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 Apr 2020 18:49:49 -0500 Subject: [PATCH 024/315] updated LexSchedule documentation --- 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 0aca588c3..e8e009169 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -107,8 +107,10 @@ def __str__(self): class LexSchedule(object): - """A program ordering represented as a mapping from statement - instances to points in a lexicographic ordering. + """Given a pair of statements in a linearized kernel, LexSchedule + determines the (relative) order in which the instances are executed, + by creating a mapping from statement instances to points in a single + lexicographic ordering. .. attribute:: stmt_instance_before From 948ada80d26df2fec69eefb58d985c979524cdb9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 Apr 2020 18:52:59 -0500 Subject: [PATCH 025/315] simplify+shorten code for getting+returning maps from schedule --- loopy/schedule/checker/__init__.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 2911351b2..260864aff 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -147,13 +147,7 @@ def get_isl_maps_for_LexSchedule( # }}} # {{{ Get isl maps - isl_sched_map_before, isl_sched_map_after = \ - lex_sched.create_isl_maps( - dom_before, - dom_after, - ) + return lex_sched.create_isl_maps(dom_before, dom_after) # }}} - return isl_sched_map_before, isl_sched_map_after - # }}} From 217d480ffc2222e8de0ff01638f4f6f78f51e26b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 Apr 2020 19:01:30 -0500 Subject: [PATCH 026/315] remove underscores from function names if functions are used in separate module --- loopy/schedule/checker/__init__.py | 4 ++-- loopy/schedule/checker/schedule.py | 4 ++-- loopy/schedule/checker/utils.py | 5 ++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 260864aff..79fc2e0e8 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -78,10 +78,10 @@ def get_schedule_for_statement_pair( # Test which exercises this: test_linearization_checker_with_stroud_bernstein()) from loopy.schedule.checker.utils import ( get_concurrent_inames, - _get_EnterLoop_inames, + get_EnterLoop_inames, ) conc_inames, _ = get_concurrent_inames(preproc_knl) - enterloop_inames = _get_EnterLoop_inames(linearization_items, preproc_knl) + enterloop_inames = get_EnterLoop_inames(linearization_items, preproc_knl) conc_loop_inames = conc_inames & enterloop_inames if conc_loop_inames: from warnings import warn diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index e8e009169..e868f5b19 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -230,9 +230,9 @@ def __init__( stmt_added_since_prev_block_at_tier[-1] = False elif isinstance(linearization_item, (RunInstruction, Barrier)): from loopy.schedule.checker.utils import ( - _get_insn_id_from_linearization_item, + 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(linearization_item) if lp_insn_id is None: # TODO make sure it's okay to ignore barriers without id # (because they'll never be part of a dependency?) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index cb933de6f..b6a5487b0 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -310,8 +310,7 @@ def get_concurrent_inames(knl): return conc_inames, all_inames-conc_inames -def _get_insn_id_from_linearization_item(linearization_item): - # TODO could use loopy's sched_item_to_insn_id() +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 @@ -319,7 +318,7 @@ def _get_insn_id_from_linearization_item(linearization_item): return linearization_item.insn_id -def _get_EnterLoop_inames(linearization_items, knl): +def get_EnterLoop_inames(linearization_items, knl): from loopy.schedule import EnterLoop loop_inames = set() for linearization_item in linearization_items: From 70ec6a1bae5fbec9c1ef9b69415c24a079b8b385 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 Apr 2020 19:27:40 -0500 Subject: [PATCH 027/315] don't pass before/after insn_ids to get_isl_maps_for_LexSchedule(), instead get them from LexSchedule --- loopy/schedule/checker/__init__.py | 21 +++++---------------- test/test_linearization_checker.py | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 79fc2e0e8..68ca2e1a0 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -108,12 +108,7 @@ def get_schedule_for_statement_pair( # {{{ Get isl map pair for LexSchedule -def get_isl_maps_for_LexSchedule( - lex_sched, - knl, - insn_id_before, - insn_id_after, - ): +def get_isl_maps_for_LexSchedule(lex_sched, knl): """Create a pair of :class:`islpy.Map`s representing a :class:`loopy.schedule.checker.LexSchedule` as two mappings from statement instances to lexicographic time, one for @@ -127,12 +122,6 @@ def get_isl_maps_for_LexSchedule( :arg knl: A :class:`loopy.kernel.LoopKernel` containing the linearization items that will be used to create a schedule. - :arg insn_id_before: An instruction identifier that is unique within - a :class:`loopy.kernel.LoopKernel`. - - :arg insn_id_after: An instruction identifier that is unique within - a :class:`loopy.kernel.LoopKernel`. - :returns: A two-tuple containing two :class:`islpy.Map`s representing the schedule as two mappings from statement instances to lexicographic time, one for @@ -140,10 +129,10 @@ def get_isl_maps_for_LexSchedule( """ # {{{ Get iname domains - insn_before_inames = knl.id_to_insn[insn_id_before].within_inames - insn_after_inames = knl.id_to_insn[insn_id_after].within_inames - dom_before = knl.get_inames_domain(insn_before_inames) - dom_after = knl.get_inames_domain(insn_after_inames) + dom_before = knl.get_inames_domain( + knl.id_to_insn[lex_sched.stmt_instance_before.stmt.insn_id].within_inames) + dom_after = knl.get_inames_domain( + knl.id_to_insn[lex_sched.stmt_instance_after.stmt.insn_id].within_inames) # }}} # {{{ Get isl maps diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index c112b40ae..ed936a1ff 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -138,8 +138,8 @@ def test_lexschedule_and_islmap_creation(): # Get two isl maps representing the LexSchedule - isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_ab, knl, "insn_a", "insn_b") + isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( + lex_sched_ab, knl) # Create expected maps, align, compare @@ -170,8 +170,8 @@ def test_lexschedule_and_islmap_creation(): # Get two isl maps representing the LexSchedule - isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_ac, knl, "insn_a", "insn_c") + isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( + lex_sched_ac, knl) # Create expected maps, align, compare @@ -205,8 +205,8 @@ def perform_insn_ad_checks_with(sid_a, sid_d): # Get two isl maps representing the LexSchedule - isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_ad, knl, "insn_a", "insn_d") + isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( + lex_sched_ad, knl) # Create expected maps, align, compare @@ -247,8 +247,8 @@ def perform_insn_bc_checks_with(sid_b, sid_c): # Get two isl maps representing the LexSchedule - isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_bc, knl, "insn_b", "insn_c") + isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( + lex_sched_bc, knl) # Create expected maps, align, compare @@ -289,8 +289,8 @@ def perform_insn_bd_checks_with(sid_b, sid_d): # Get two isl maps representing the LexSchedule - isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_bd, knl, "insn_b", "insn_d") + isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( + lex_sched_bd, knl) # Create expected maps, align, compare @@ -331,8 +331,8 @@ def perform_insn_cd_checks_with(sid_c, sid_d): # Get two isl maps representing the LexSchedule - isl_sched_map_before, isl_sched_map_after = \ - get_isl_maps_for_LexSchedule(lex_sched_cd, knl, "insn_c", "insn_d") + isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( + lex_sched_cd, knl) # Create expected maps, align, compare From af72169557b38b5bd26e69e80d657fb0d401aeac Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 27 Apr 2020 18:05:25 -0500 Subject: [PATCH 028/315] add TODO for future consideration of generalizing LexSchedule to allow more than two statements --- loopy/schedule/checker/schedule.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index e868f5b19..5edeecaab 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -171,6 +171,8 @@ def __init__( # LexScheduleStatements self.stmt_instance_before = None self.stmt_instance_after = None + # TODO when/after dependencies are added, consider the possibility + # of removing the two-statements-per-LexSchedule limitation # make sure we don't have an iname name conflict # TODO use loopy's existing tool for ensuring unique var names From 2556e7590f6724b1a49c8370925dc9701aab6097 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 27 Apr 2020 18:16:23 -0500 Subject: [PATCH 029/315] 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 98d744dda96fd835e38ba400d5dbc75f9f076a58 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 4 May 2020 23:25:37 -0500 Subject: [PATCH 030/315] remove no-longer-used arg from create_symbolic_isl_map_from_tuples() --- loopy/schedule/checker/schedule.py | 1 - loopy/schedule/checker/utils.py | 4 ---- 2 files changed, 5 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 5edeecaab..4138336b0 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -391,7 +391,6 @@ def _get_isl_map_for_stmt_inst( return create_symbolic_isl_map_from_tuples( tuple_pairs_with_domains=zip(tuple_pair, dom_to_intersect), space=sched_space, - statement_var_name=self.statement_var_name, ) map_before = _get_isl_map_for_stmt_inst( diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index b6a5487b0..0728e9686 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -162,7 +162,6 @@ def list_var_names_in_isl_sets( def create_symbolic_isl_map_from_tuples( tuple_pairs_with_domains, space, - statement_var_name, ): """Return an :class:`islpy.Map` constructed using the provided space, mapping input->output tuples provided in `tuple_pairs_with_domains`, @@ -177,9 +176,6 @@ def create_symbolic_isl_map_from_tuples( :arg space: A :class:`islpy.Space` to be used to create the map. - :arg statement_var_name: A :class:`str` specifying the name of the - isl variable used to represent the unique :class:`int` statement id. - :returns: A :class:`islpy.Map` constructed using the provided space as follows. For each `((tup_in, tup_out), domain)` in `tuple_pairs_with_domains`, map From ef79ff1deb95192dc2322b3b86aec3a3e1669f5a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 5 May 2020 11:21:20 -0500 Subject: [PATCH 031/315] make var names begin wtih and remove variable/check --- loopy/schedule/checker/__init__.py | 11 --------- loopy/schedule/checker/schedule.py | 14 ++---------- test/test_linearization_checker.py | 36 ++++++++++++++++++++---------- 3 files changed, 26 insertions(+), 35 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 68ca2e1a0..3215201ae 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -28,7 +28,6 @@ def get_schedule_for_statement_pair( linearization_items, insn_id_before, insn_id_after, - prohibited_var_names=set(), ): """Create a :class:`loopy.schedule.checker.schedule.LexSchedule` representing the order of two statements as a mapping from @@ -51,10 +50,6 @@ def get_schedule_for_statement_pair( :arg insn_id_after: An instruction identifier that is unique within a :class:`loopy.kernel.LoopKernel`. - :arg prohibited_var_names: A set of :class:`str` representing - variable names that should not be used when creating names for - dimensions in a :class:`loopy.schedule.checker.LexSchedule`. - :returns: A :class:`loopy.schedule.checker.schedule.LexSchedule` representing the order of two statements as a mapping from :class:`loopy.schedule.checker.LexScheduleStatementInstance` @@ -66,11 +61,6 @@ def get_schedule_for_statement_pair( preproc_knl = preprocess_kernel(knl) # }}} - # {{{ By default, don't create LexSchedule variables matching existing inames - if not prohibited_var_names: - prohibited_var_names = preproc_knl.all_inames() - # }}} - # {{{ Find any EnterLoop inames that are tagged as concurrent # so that LexSchedule knows to ignore them # (In the future, this shouldn't be necessary because there @@ -98,7 +88,6 @@ def get_schedule_for_statement_pair( linearization_items, insn_id_before, insn_id_after, - prohibited_var_names=prohibited_var_names, loops_to_ignore=conc_loop_inames, ) # }}} diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 4138336b0..49c9e0a01 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -141,15 +141,14 @@ class LexSchedule(object): """ - statement_var_name = "statement" - lex_var_prefix = "l" + statement_var_name = "_lp_statement" + lex_var_prefix = "_lp_l" def __init__( self, linearization_items_ordered, before_insn_id, after_insn_id, - prohibited_var_names=[], loops_to_ignore=set(), ): """ @@ -162,10 +161,6 @@ def __init__( :arg after_insn_id: A :class:`str` instruction id specifying the depender in this pair of instructions. - :arg prohibited_var_names: A list of :class:`str` variable names - that may not be used as the statement variable name (e.g., - because they are already being used as inames). - """ # LexScheduleStatements @@ -174,11 +169,6 @@ def __init__( # TODO when/after dependencies are added, consider the possibility # of removing the two-statements-per-LexSchedule limitation - # make sure we don't have an iname name conflict - # TODO use loopy's existing tool for ensuring unique var names - assert not any( - iname == self.statement_var_name for iname in prohibited_var_names) - from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) # go through linearization_items_ordered and generate self.lex_schedule diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index ed936a1ff..39a73718f 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -145,7 +145,8 @@ def test_lexschedule_and_islmap_creation(): isl_sched_map_before_expected = isl.Map( "[pi, pk] -> { " - "[statement = 0, i, k] -> [l0 = 0, l1 = i, l2 = 0, l3 = k, l4 = 0] : " + "[_lp_statement=0, i, k] -> " + "[_lp_l0=0, _lp_l1=i, _lp_l2=0, _lp_l3=k, _lp_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) isl_sched_map_before_expected = align_isl_maps_by_var_names( @@ -153,7 +154,8 @@ def test_lexschedule_and_islmap_creation(): isl_sched_map_after_expected = isl.Map( "[pi, pj] -> { " - "[statement = 1, i, j] -> [l0 = 0, l1 = i, l2 = 1, l3 = j, l4 = 0] : " + "[_lp_statement=1, i, j] -> " + "[_lp_l0=0, _lp_l1=i, _lp_l2=1, _lp_l3=j, _lp_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) isl_sched_map_after_expected = align_isl_maps_by_var_names( @@ -177,7 +179,8 @@ def test_lexschedule_and_islmap_creation(): isl_sched_map_before_expected = isl.Map( "[pi, pk] -> { " - "[statement = 0, i, k] -> [l0 = 0, l1 = i, l2 = 0, l3 = k, l4 = 0] : " + "[_lp_statement=0, i, k] -> " + "[_lp_l0=0, _lp_l1=i, _lp_l2=0, _lp_l3=k, _lp_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) isl_sched_map_before_expected = align_isl_maps_by_var_names( @@ -185,7 +188,8 @@ def test_lexschedule_and_islmap_creation(): isl_sched_map_after_expected = isl.Map( "[pi, pj] -> { " - "[statement = 1, i, j] -> [l0 = 0, l1 = i, l2 = 1, l3 = j, l4 = 0] : " + "[_lp_statement=1, i, j] -> " + "[_lp_l0=0, _lp_l1=i, _lp_l2=1, _lp_l3=j, _lp_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) isl_sched_map_after_expected = align_isl_maps_by_var_names( @@ -212,7 +216,8 @@ def perform_insn_ad_checks_with(sid_a, sid_d): isl_sched_map_before_expected = isl.Map( "[pi, pk] -> { " - "[statement = %d, i, k] -> [l0 = %d, l1 = i, l2 = 0, l3 = k, l4 = 0] : " + "[_lp_statement=%d, i, k] -> " + "[_lp_l0=%d, _lp_l1=i, _lp_l2=0, _lp_l3=k, _lp_l4=0] : " "0 <= i < pi and 0 <= k < pk }" % (sid_a, sid_a) ) @@ -221,7 +226,8 @@ def perform_insn_ad_checks_with(sid_a, sid_d): isl_sched_map_after_expected = isl.Map( "[pt] -> { " - "[statement = %d, t] -> [l0 = %d, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " + "[_lp_statement=%d, t] -> " + "[_lp_l0=%d, _lp_l1=t, _lp_l2=0, _lp_l3=0, _lp_l4=0] : " "0 <= t < pt }" % (sid_d, sid_d) ) @@ -254,7 +260,8 @@ def perform_insn_bc_checks_with(sid_b, sid_c): isl_sched_map_before_expected = isl.Map( "[pi, pj] -> { " - "[statement = %d, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = %d] : " + "[_lp_statement=%d, i, j] -> " + "[_lp_l0=0, _lp_l1=i, _lp_l2=0, _lp_l3=j, _lp_l4=%d] : " "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) @@ -263,7 +270,8 @@ def perform_insn_bc_checks_with(sid_b, sid_c): isl_sched_map_after_expected = isl.Map( "[pi, pj] -> { " - "[statement = %d, i, j] -> [l0 = 0, l1 = i, l2 = 0, l3 = j, l4 = %d] : " + "[_lp_statement=%d, i, j] -> " + "[_lp_l0=0, _lp_l1=i, _lp_l2=0, _lp_l3=j, _lp_l4=%d] : " "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) @@ -296,7 +304,8 @@ def perform_insn_bd_checks_with(sid_b, sid_d): isl_sched_map_before_expected = isl.Map( "[pi, pj] -> { " - "[statement = %d, i, j] -> [l0 = %d, l1 = i, l2 = 0, l3 = j, l4 = 0] : " + "[_lp_statement=%d, i, j] -> " + "[_lp_l0=%d, _lp_l1=i, _lp_l2=0, _lp_l3=j, _lp_l4=0] : " "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) @@ -305,7 +314,8 @@ def perform_insn_bd_checks_with(sid_b, sid_d): isl_sched_map_after_expected = isl.Map( "[pt] -> { " - "[statement = %d, t] -> [l0 = %d, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " + "[_lp_statement=%d, t] -> " + "[_lp_l0=%d, _lp_l1=t, _lp_l2=0, _lp_l3=0, _lp_l4=0] : " "0 <= t < pt }" % (sid_d, sid_d) ) @@ -338,7 +348,8 @@ def perform_insn_cd_checks_with(sid_c, sid_d): isl_sched_map_before_expected = isl.Map( "[pi, pj] -> { " - "[statement = %d, i, j] -> [l0 = %d, l1 = i, l2 = 0, l3 = j, l4 = 0] : " + "[_lp_statement=%d, i, j] -> " + "[_lp_l0=%d, _lp_l1=i, _lp_l2=0, _lp_l3=j, _lp_l4=0] : " "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) @@ -347,7 +358,8 @@ def perform_insn_cd_checks_with(sid_c, sid_d): isl_sched_map_after_expected = isl.Map( "[pt] -> { " - "[statement = %d, t] -> [l0 = %d, l1 = t, l2 = 0, l3 = 0, l4 = 0] : " + "[_lp_statement=%d, t] -> " + "[_lp_l0=%d, _lp_l1=t, _lp_l2=0, _lp_l3=0, _lp_l4=0] : " "0 <= t < pt }" % (sid_d, sid_d) ) From ec11b2f65f4825f2e0526e1418d8a8e7b0ad1355 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 5 May 2020 12:40:02 -0500 Subject: [PATCH 032/315] change _lp previx to _lp_sched (add sub-prefix) --- loopy/schedule/checker/schedule.py | 4 +- test/test_linearization_checker.py | 60 ++++++++++++++++++------------ 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 49c9e0a01..6cabaf1be 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -141,8 +141,8 @@ class LexSchedule(object): """ - statement_var_name = "_lp_statement" - lex_var_prefix = "_lp_l" + statement_var_name = "_lp_sched_statement" + lex_var_prefix = "_lp_sched_l" def __init__( self, diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 39a73718f..0dfb2fc90 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -145,8 +145,9 @@ def test_lexschedule_and_islmap_creation(): isl_sched_map_before_expected = isl.Map( "[pi, pk] -> { " - "[_lp_statement=0, i, k] -> " - "[_lp_l0=0, _lp_l1=i, _lp_l2=0, _lp_l3=k, _lp_l4=0] : " + "[_lp_sched_statement=0, i, k] -> " + "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=k, " + "_lp_sched_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) isl_sched_map_before_expected = align_isl_maps_by_var_names( @@ -154,8 +155,9 @@ def test_lexschedule_and_islmap_creation(): isl_sched_map_after_expected = isl.Map( "[pi, pj] -> { " - "[_lp_statement=1, i, j] -> " - "[_lp_l0=0, _lp_l1=i, _lp_l2=1, _lp_l3=j, _lp_l4=0] : " + "[_lp_sched_statement=1, i, j] -> " + "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=1, _lp_sched_l3=j, " + "_lp_sched_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) isl_sched_map_after_expected = align_isl_maps_by_var_names( @@ -179,8 +181,9 @@ def test_lexschedule_and_islmap_creation(): isl_sched_map_before_expected = isl.Map( "[pi, pk] -> { " - "[_lp_statement=0, i, k] -> " - "[_lp_l0=0, _lp_l1=i, _lp_l2=0, _lp_l3=k, _lp_l4=0] : " + "[_lp_sched_statement=0, i, k] -> " + "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=k, " + "_lp_sched_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) isl_sched_map_before_expected = align_isl_maps_by_var_names( @@ -188,8 +191,9 @@ def test_lexschedule_and_islmap_creation(): isl_sched_map_after_expected = isl.Map( "[pi, pj] -> { " - "[_lp_statement=1, i, j] -> " - "[_lp_l0=0, _lp_l1=i, _lp_l2=1, _lp_l3=j, _lp_l4=0] : " + "[_lp_sched_statement=1, i, j] -> " + "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=1, _lp_sched_l3=j, " + "_lp_sched_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) isl_sched_map_after_expected = align_isl_maps_by_var_names( @@ -216,8 +220,9 @@ def perform_insn_ad_checks_with(sid_a, sid_d): isl_sched_map_before_expected = isl.Map( "[pi, pk] -> { " - "[_lp_statement=%d, i, k] -> " - "[_lp_l0=%d, _lp_l1=i, _lp_l2=0, _lp_l3=k, _lp_l4=0] : " + "[_lp_sched_statement=%d, i, k] -> " + "[_lp_sched_l0=%d, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=k, " + "_lp_sched_l4=0] : " "0 <= i < pi and 0 <= k < pk }" % (sid_a, sid_a) ) @@ -226,8 +231,9 @@ def perform_insn_ad_checks_with(sid_a, sid_d): isl_sched_map_after_expected = isl.Map( "[pt] -> { " - "[_lp_statement=%d, t] -> " - "[_lp_l0=%d, _lp_l1=t, _lp_l2=0, _lp_l3=0, _lp_l4=0] : " + "[_lp_sched_statement=%d, t] -> " + "[_lp_sched_l0=%d, _lp_sched_l1=t, _lp_sched_l2=0, _lp_sched_l3=0, " + "_lp_sched_l4=0] : " "0 <= t < pt }" % (sid_d, sid_d) ) @@ -260,8 +266,9 @@ def perform_insn_bc_checks_with(sid_b, sid_c): isl_sched_map_before_expected = isl.Map( "[pi, pj] -> { " - "[_lp_statement=%d, i, j] -> " - "[_lp_l0=0, _lp_l1=i, _lp_l2=0, _lp_l3=j, _lp_l4=%d] : " + "[_lp_sched_statement=%d, i, j] -> " + "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " + "_lp_sched_l4=%d] : " "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) @@ -270,8 +277,9 @@ def perform_insn_bc_checks_with(sid_b, sid_c): isl_sched_map_after_expected = isl.Map( "[pi, pj] -> { " - "[_lp_statement=%d, i, j] -> " - "[_lp_l0=0, _lp_l1=i, _lp_l2=0, _lp_l3=j, _lp_l4=%d] : " + "[_lp_sched_statement=%d, i, j] -> " + "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " + "_lp_sched_l4=%d] : " "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) @@ -304,8 +312,9 @@ def perform_insn_bd_checks_with(sid_b, sid_d): isl_sched_map_before_expected = isl.Map( "[pi, pj] -> { " - "[_lp_statement=%d, i, j] -> " - "[_lp_l0=%d, _lp_l1=i, _lp_l2=0, _lp_l3=j, _lp_l4=0] : " + "[_lp_sched_statement=%d, i, j] -> " + "[_lp_sched_l0=%d, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " + "_lp_sched_l4=0] : " "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) @@ -314,8 +323,9 @@ def perform_insn_bd_checks_with(sid_b, sid_d): isl_sched_map_after_expected = isl.Map( "[pt] -> { " - "[_lp_statement=%d, t] -> " - "[_lp_l0=%d, _lp_l1=t, _lp_l2=0, _lp_l3=0, _lp_l4=0] : " + "[_lp_sched_statement=%d, t] -> " + "[_lp_sched_l0=%d, _lp_sched_l1=t, _lp_sched_l2=0, _lp_sched_l3=0, " + "_lp_sched_l4=0] : " "0 <= t < pt }" % (sid_d, sid_d) ) @@ -348,8 +358,9 @@ def perform_insn_cd_checks_with(sid_c, sid_d): isl_sched_map_before_expected = isl.Map( "[pi, pj] -> { " - "[_lp_statement=%d, i, j] -> " - "[_lp_l0=%d, _lp_l1=i, _lp_l2=0, _lp_l3=j, _lp_l4=0] : " + "[_lp_sched_statement=%d, i, j] -> " + "[_lp_sched_l0=%d, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " + "_lp_sched_l4=0] : " "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) @@ -358,8 +369,9 @@ def perform_insn_cd_checks_with(sid_c, sid_d): isl_sched_map_after_expected = isl.Map( "[pt] -> { " - "[_lp_statement=%d, t] -> " - "[_lp_l0=%d, _lp_l1=t, _lp_l2=0, _lp_l3=0, _lp_l4=0] : " + "[_lp_sched_statement=%d, t] -> " + "[_lp_sched_l0=%d, _lp_sched_l1=t, _lp_sched_l2=0, _lp_sched_l3=0, " + "_lp_sched_l4=0] : " "0 <= t < pt }" % (sid_d, sid_d) ) From f38f3027c1b575c6cbce1849b80a37292accbb85 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 12 May 2020 00:47:46 -0500 Subject: [PATCH 033/315] 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 034/315] =?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 035/315] 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 036/315] 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 037/315] 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 038/315] 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 039/315] 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 767e821c7cc56331230c61e7d2193dbb6860394f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 25 May 2020 02:22:26 -0500 Subject: [PATCH 040/315] in docstring for LexScheduleStatement, describe usage of int_id --- loopy/schedule/checker/schedule.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 6cabaf1be..bbea293a2 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -28,11 +28,17 @@ class LexScheduleStatement(object): .. attribute:: insn_id - A :class:`str` specifying the instruction id. + A :class:`str` specifying the :mod:`loopy` instruction id + for this statement. .. attribute:: int_id - A :class:`int` uniquely identifying the instruction. + A :class:`int` uniquely identifying the statement within a + :class:`LexSchedule`. A :class:`LexSchedule` describes a mapping + from points in a space of statement instances to points in a + lexicographic ordering. The `statement` dimension of a point + in the statement instance space representing an instance of this + statement is assigned this value (`int_id`). .. attribute:: within_inames From 9d52cc98da397f5ae0987cead564dc427e105459 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 25 May 2020 02:47:29 -0500 Subject: [PATCH 041/315] remove within_inames attribute from LexScheduleStatement() --- loopy/schedule/checker/schedule.py | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index bbea293a2..7f808abd5 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -40,28 +40,20 @@ class LexScheduleStatement(object): in the statement instance space representing an instance of this statement is assigned this value (`int_id`). - .. attribute:: within_inames - - A :class:`list` of :class:`str` inames identifying the loops within - which this statement will be executed. - """ def __init__( self, insn_id, # loopy insn id int_id=None, # sid int (statement id within LexSchedule) - within_inames=None, # [string, ] ): self.insn_id = insn_id # string self.int_id = int_id - self.within_inames = within_inames def __eq__(self, other): return ( self.insn_id == other.insn_id and self.int_id == other.int_id - and self.within_inames == other.within_inames ) def update_persistent_hash(self, key_hash, key_builder): @@ -71,19 +63,13 @@ def update_persistent_hash(self, key_hash, key_builder): key_builder.rec(key_hash, self.insn_id) key_builder.rec(key_hash, self.int_id) - key_builder.rec(key_hash, self.within_inames) def __str__(self): if self.int_id is not None: int_id = ":%d" % (self.int_id) else: int_id = "" - if self.within_inames: - within_inames = " {%s}" % (",".join(self.within_inames)) - else: - within_inames = "" - return "%s%s%s" % ( - self.insn_id, int_id, within_inames) + return "%s%s" % (self.insn_id, int_id) class LexScheduleStatementInstance(object): From a19113153a84148545c08837c2055a774b5f3e75 Mon Sep 17 00:00:00 2001 From: James Stevens Date: Mon, 25 May 2020 10:19:25 +0200 Subject: [PATCH 042/315] Apply suggestion to loopy/schedule/checker/schedule.py --- 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 7f808abd5..ea3181b66 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -73,7 +73,7 @@ def __str__(self): class LexScheduleStatementInstance(object): - """A representation of a :mod:`loopy` statement instance. + """A representation of a statement instance. .. attribute:: stmt From bcef27aa953a07b5fcb49e1c92449bc041d22699 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 25 May 2020 21:12:31 -0500 Subject: [PATCH 043/315] rename {lex_pt->lex_points, pad_lex_pts_with_zeros->pad_lex_tuples_with_zeros, _pad_lex_pt_with_zeros->_pad_lex_tuple_with_zeros, next_insn_lex_pt->next_insn_lex_tuple}; lex_pt actually describes multiple points, not a single point --- loopy/schedule/checker/schedule.py | 70 +++++++++++++++--------------- test/test_linearization_checker.py | 56 ++++++++++++------------ 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index ea3181b66..052a47afe 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -79,7 +79,7 @@ class LexScheduleStatementInstance(object): A :class:`LexScheduleStatement`. - .. attribute:: lex_pt + .. attribute:: lex_points A list of :class:`int` or as :class:`str` :mod:`loopy` inames representing a point or set of points in a lexicographic ordering. @@ -89,13 +89,13 @@ class LexScheduleStatementInstance(object): def __init__( self, stmt, # a LexScheduleStatement - lex_pt, # [string/int, ] + lex_points, # [string/int, ] ): self.stmt = stmt - self.lex_pt = lex_pt + self.lex_points = lex_points def __str__(self): - return "{%s, %s}" % (self.stmt, self.lex_pt) + return "{%s, %s}" % (self.stmt, self.lex_points) class LexSchedule(object): @@ -167,7 +167,7 @@ def __init__( # keep track of the next point in our lexicographic ordering # initially this as a 1-d point with value 0 - next_insn_lex_pt = [0] + next_insn_lex_tuple = [0] stmt_added_since_prev_block_at_tier = [False] next_sid = 0 for linearization_item in linearization_items_ordered: @@ -176,13 +176,13 @@ def __init__( if iname in loops_to_ignore: continue - # We could always increment next_insn_lex_pt[-1] here since this new - # section of code comes after the previous section (statements - # since last opened/closed loop), but if we have not added any - # statements within the previous section yet, we don't have to - # (effectively ignoring that section of code). + # We could always increment next_insn_lex_tuple[-1] here since + # this new section of code comes after the previous section + # (statements since last opened/closed loop), but if we have + # not added any statements within the previous section yet, we + # don't have to (effectively ignoring that section of code). if stmt_added_since_prev_block_at_tier[-1]: - next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 + next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 stmt_added_since_prev_block_at_tier[-1] = False # upon entering a loop, we enter a new (deeper) tier, @@ -190,8 +190,8 @@ def __init__( # add second lex dim to enumerate code blocks within new loop, and # append a dim to stmt_added_since_prev_block_at_tier to represent # new tier - next_insn_lex_pt.append(iname) - next_insn_lex_pt.append(0) + next_insn_lex_tuple.append(iname) + next_insn_lex_tuple.append(0) stmt_added_since_prev_block_at_tier.append(False) elif isinstance(linearization_item, LeaveLoop): if linearization_item.iname in loops_to_ignore: @@ -200,17 +200,17 @@ def __init__( # pop lex dimension for enumerating code blocks within this loop, and # pop lex dimension for the loop variable, and # increment lex dim val enumerating items in current code block - next_insn_lex_pt.pop() - next_insn_lex_pt.pop() - - # We could always increment next_insn_lex_pt[-1] here since this new - # block of code comes after the previous block (all statements - # since last opened/closed loop), but if we have not added any - # statements within the previous section yet, we don't have to - # (effectively ignoring that section of code). + next_insn_lex_tuple.pop() + next_insn_lex_tuple.pop() + + # We could always increment next_insn_lex_tuple[-1] here since + # this new block of code comes after the previous block (all + # statements since last opened/closed loop), but if we have not + # added any statements within the previous section yet, we + # don't have to (effectively ignoring that section of code). stmt_added_since_prev_block_at_tier.pop() if stmt_added_since_prev_block_at_tier[-1]: - next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 + next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 stmt_added_since_prev_block_at_tier[-1] = False elif isinstance(linearization_item, (RunInstruction, Barrier)): from loopy.schedule.checker.utils import ( @@ -234,7 +234,7 @@ def __init__( insn_id=lp_insn_id, int_id=next_sid, # int representing insn ), - next_insn_lex_pt[:]) + next_insn_lex_tuple[:]) stmt_added = True if lp_insn_id == after_insn_id: @@ -244,7 +244,7 @@ def __init__( insn_id=lp_insn_id, int_id=next_sid, # int representing insn ), - next_insn_lex_pt[:]) + next_insn_lex_tuple[:]) stmt_added = True # Note: before/after may refer to same stmt, in which case @@ -252,7 +252,7 @@ def __init__( if stmt_added: # increment lex dim val enumerating items in current code block - next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 + next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1] + 1 next_sid += 1 # all current (nested) blocks now contain a statement @@ -266,14 +266,14 @@ def __init__( # at this point, lex_schedule may contain lex points missing dimensions, # the values in these missing dims should be zero, so add them - self.pad_lex_pts_with_zeros() + self.pad_lex_tuples_with_zeros() def max_lex_dims(self): return max([ - len(self.stmt_instance_before.lex_pt), - len(self.stmt_instance_after.lex_pt)]) + len(self.stmt_instance_before.lex_points), + len(self.stmt_instance_after.lex_points)]) - def pad_lex_pts_with_zeros(self): + def pad_lex_tuples_with_zeros(self): """Find the maximum number of lexicographic dimensions represented in the lexicographic ordering, and if any :class:`LexScheduleStatement` maps to a point in lexicographic @@ -281,17 +281,17 @@ def pad_lex_pts_with_zeros(self): dimensions. """ - def _pad_lex_pt_with_zeros(stmt_inst, length): + def _pad_lex_tuple_with_zeros(stmt_inst, length): return LexScheduleStatementInstance( stmt_inst.stmt, - stmt_inst.lex_pt[:] + [0]*(length-len(stmt_inst.lex_pt)), + stmt_inst.lex_points[:] + [0]*(length-len(stmt_inst.lex_points)), ) max_lex_dim = self.max_lex_dims() - self.stmt_instance_before = _pad_lex_pt_with_zeros( + self.stmt_instance_before = _pad_lex_tuple_with_zeros( self.stmt_instance_before, max_lex_dim) - self.stmt_instance_after = _pad_lex_pt_with_zeros( + self.stmt_instance_after = _pad_lex_tuple_with_zeros( self.stmt_instance_after, max_lex_dim) def create_isl_maps( @@ -366,7 +366,7 @@ def _get_isl_map_for_stmt_inst( # Add all inames from domains to each map domain tuple. tuple_pair = [( (stmt_inst.stmt.int_id, ) + tuple(dom_inames_ordered), - stmt_inst.lex_pt + stmt_inst.lex_points )] # create isl map @@ -396,7 +396,7 @@ def stringify_sched_stmt_instance(stmt_inst): return "{\n[%s=%s,] -> %s;\n}" % ( self.statement_var_name, stmt_inst.stmt.int_id, - stmt_inst.lex_pt) + stmt_inst.lex_points) return "Before: %s\nAfter: %s" % ( stringify_sched_stmt_instance(self.stmt_instance_before), diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 0dfb2fc90..aab9c8507 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -94,37 +94,37 @@ def test_lexschedule_and_islmap_creation(): linearization_items = knl.linearization # Create LexSchedule: mapping of {statement instance: lex point} - lex_sched_ab = get_schedule_for_statement_pair( + sched_ab = get_schedule_for_statement_pair( knl, linearization_items, "insn_a", "insn_b", ) - lex_sched_ac = get_schedule_for_statement_pair( + sched_ac = get_schedule_for_statement_pair( knl, linearization_items, "insn_a", "insn_c", ) - lex_sched_ad = get_schedule_for_statement_pair( + sched_ad = get_schedule_for_statement_pair( knl, linearization_items, "insn_a", "insn_d", ) - lex_sched_bc = get_schedule_for_statement_pair( + sched_bc = get_schedule_for_statement_pair( knl, linearization_items, "insn_b", "insn_c", ) - lex_sched_bd = get_schedule_for_statement_pair( + sched_bd = get_schedule_for_statement_pair( knl, linearization_items, "insn_b", "insn_d", ) - lex_sched_cd = get_schedule_for_statement_pair( + sched_cd = get_schedule_for_statement_pair( knl, linearization_items, "insn_c", @@ -133,13 +133,13 @@ def test_lexschedule_and_islmap_creation(): # Relationship between insn_a and insn_b --------------------------------------- - assert lex_sched_ab.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] - assert lex_sched_ab.stmt_instance_after.lex_pt == [0, 'i', 1, 'j', 0] + assert sched_ab.stmt_instance_before.lex_points == [0, 'i', 0, 'k', 0] + assert sched_ab.stmt_instance_after.lex_points == [0, 'i', 1, 'j', 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - lex_sched_ab, knl) + sched_ab, knl) # Create expected maps, align, compare @@ -169,13 +169,13 @@ def test_lexschedule_and_islmap_creation(): # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_c --------------------------------------- - assert lex_sched_ac.stmt_instance_before.lex_pt == [0, 'i', 0, 'k', 0] - assert lex_sched_ac.stmt_instance_after.lex_pt == [0, 'i', 1, 'j', 0] + assert sched_ac.stmt_instance_before.lex_points == [0, 'i', 0, 'k', 0] + assert sched_ac.stmt_instance_after.lex_points == [0, 'i', 1, 'j', 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - lex_sched_ac, knl) + sched_ac, knl) # Create expected maps, align, compare @@ -208,13 +208,13 @@ def test_lexschedule_and_islmap_creation(): # insn_a and insn_d could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_ad_checks_with(sid_a, sid_d): - assert lex_sched_ad.stmt_instance_before.lex_pt == [sid_a, 'i', 0, 'k', 0] - assert lex_sched_ad.stmt_instance_after.lex_pt == [sid_d, 't', 0, 0, 0] + assert sched_ad.stmt_instance_before.lex_points == [sid_a, 'i', 0, 'k', 0] + assert sched_ad.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - lex_sched_ad, knl) + sched_ad, knl) # Create expected maps, align, compare @@ -243,7 +243,7 @@ def perform_insn_ad_checks_with(sid_a, sid_d): assert isl_sched_map_before == isl_sched_map_before_expected assert isl_sched_map_after == isl_sched_map_after_expected - if lex_sched_ad.stmt_instance_before.stmt.int_id == 0: + if sched_ad.stmt_instance_before.stmt.int_id == 0: perform_insn_ad_checks_with(0, 1) else: perform_insn_ad_checks_with(1, 0) @@ -254,13 +254,13 @@ def perform_insn_ad_checks_with(sid_a, sid_d): # insn_b and insn_c could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_bc_checks_with(sid_b, sid_c): - assert lex_sched_bc.stmt_instance_before.lex_pt == [0, 'i', 0, 'j', sid_b] - assert lex_sched_bc.stmt_instance_after.lex_pt == [0, 'i', 0, 'j', sid_c] + assert sched_bc.stmt_instance_before.lex_points == [0, 'i', 0, 'j', sid_b] + assert sched_bc.stmt_instance_after.lex_points == [0, 'i', 0, 'j', sid_c] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - lex_sched_bc, knl) + sched_bc, knl) # Create expected maps, align, compare @@ -289,7 +289,7 @@ def perform_insn_bc_checks_with(sid_b, sid_c): assert isl_sched_map_before == isl_sched_map_before_expected assert isl_sched_map_after == isl_sched_map_after_expected - if lex_sched_bc.stmt_instance_before.stmt.int_id == 0: + if sched_bc.stmt_instance_before.stmt.int_id == 0: perform_insn_bc_checks_with(0, 1) else: perform_insn_bc_checks_with(1, 0) @@ -300,13 +300,13 @@ def perform_insn_bc_checks_with(sid_b, sid_c): # insn_b and insn_d could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_bd_checks_with(sid_b, sid_d): - assert lex_sched_bd.stmt_instance_before.lex_pt == [sid_b, 'i', 0, 'j', 0] - assert lex_sched_bd.stmt_instance_after.lex_pt == [sid_d, 't', 0, 0, 0] + assert sched_bd.stmt_instance_before.lex_points == [sid_b, 'i', 0, 'j', 0] + assert sched_bd.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - lex_sched_bd, knl) + sched_bd, knl) # Create expected maps, align, compare @@ -335,7 +335,7 @@ def perform_insn_bd_checks_with(sid_b, sid_d): assert isl_sched_map_before == isl_sched_map_before_expected assert isl_sched_map_after == isl_sched_map_after_expected - if lex_sched_bd.stmt_instance_before.stmt.int_id == 0: + if sched_bd.stmt_instance_before.stmt.int_id == 0: perform_insn_bd_checks_with(0, 1) else: perform_insn_bd_checks_with(1, 0) @@ -346,13 +346,13 @@ def perform_insn_bd_checks_with(sid_b, sid_d): # insn_c and insn_d could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_cd_checks_with(sid_c, sid_d): - assert lex_sched_cd.stmt_instance_before.lex_pt == [sid_c, 'i', 0, 'j', 0] - assert lex_sched_cd.stmt_instance_after.lex_pt == [sid_d, 't', 0, 0, 0] + assert sched_cd.stmt_instance_before.lex_points == [sid_c, 'i', 0, 'j', 0] + assert sched_cd.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] # Get two isl maps representing the LexSchedule isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - lex_sched_cd, knl) + sched_cd, knl) # Create expected maps, align, compare @@ -381,7 +381,7 @@ def perform_insn_cd_checks_with(sid_c, sid_d): assert isl_sched_map_before == isl_sched_map_before_expected assert isl_sched_map_after == isl_sched_map_after_expected - if lex_sched_cd.stmt_instance_before.stmt.int_id == 0: + if sched_cd.stmt_instance_before.stmt.int_id == 0: perform_insn_cd_checks_with(0, 1) else: perform_insn_cd_checks_with(1, 0) From 7cc557eaeb4351cf23cf17b76c1648c3a4a0e9e1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 25 May 2020 21:30:20 -0500 Subject: [PATCH 044/315] rename LexScheduleStatementInstance->LexScheduleStatementInstanceSet (will probably rename again) --- loopy/schedule/checker/__init__.py | 6 +++--- loopy/schedule/checker/schedule.py | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 3215201ae..176b1399c 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -31,7 +31,7 @@ def get_schedule_for_statement_pair( ): """Create a :class:`loopy.schedule.checker.schedule.LexSchedule` representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.LexScheduleStatementInstance` + :class:`loopy.schedule.checker.LexScheduleStatementInstanceSet` to lexicographic time. :arg knl: A :class:`loopy.kernel.LoopKernel` containing the @@ -52,7 +52,7 @@ def get_schedule_for_statement_pair( :returns: A :class:`loopy.schedule.checker.schedule.LexSchedule` representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.LexScheduleStatementInstance` + :class:`loopy.schedule.checker.LexScheduleStatementInstanceSet` to lexicographic time. """ @@ -105,7 +105,7 @@ def get_isl_maps_for_LexSchedule(lex_sched, knl): :arg lex_sched: A :class:`loopy.schedule.checker.schedule.LexSchedule` representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.LexScheduleStatementInstance` + :class:`loopy.schedule.checker.LexScheduleStatementInstanceSet` to lexicographic time. :arg knl: A :class:`loopy.kernel.LoopKernel` containing the diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 052a47afe..f839f45aa 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -72,8 +72,9 @@ def __str__(self): return "%s%s" % (self.insn_id, int_id) -class LexScheduleStatementInstance(object): - """A representation of a statement instance. +class LexScheduleStatementInstanceSet(object): + """A representation of a set of instances of a + :class:`LexScheduleStatement`. .. attribute:: stmt @@ -106,7 +107,7 @@ class LexSchedule(object): .. attribute:: stmt_instance_before - A :class:`LexScheduleStatementInstance` describing the dependee + A :class:`LexScheduleStatementInstanceSet` describing the dependee statement's order relative to the depender statment by mapping a statement to a point or set of points in a lexicographic ordering. Points in lexicographic ordering are represented as @@ -114,7 +115,7 @@ class LexSchedule(object): .. attribute:: stmt_instance_after - A :class:`LexScheduleStatementInstance` describing the depender + A :class:`LexScheduleStatementInstanceSet` describing the depender statement's order relative to the dependee statment by mapping a statement to a point or set of points in a lexicographic ordering. Points in lexicographic ordering are represented as @@ -229,7 +230,7 @@ def __init__( if lp_insn_id == before_insn_id: # add before sched item - self.stmt_instance_before = LexScheduleStatementInstance( + self.stmt_instance_before = LexScheduleStatementInstanceSet( LexScheduleStatement( insn_id=lp_insn_id, int_id=next_sid, # int representing insn @@ -239,7 +240,7 @@ def __init__( if lp_insn_id == after_insn_id: # add after sched item - self.stmt_instance_after = LexScheduleStatementInstance( + self.stmt_instance_after = LexScheduleStatementInstanceSet( LexScheduleStatement( insn_id=lp_insn_id, int_id=next_sid, # int representing insn @@ -282,7 +283,7 @@ def pad_lex_tuples_with_zeros(self): """ def _pad_lex_tuple_with_zeros(stmt_inst, length): - return LexScheduleStatementInstance( + return LexScheduleStatementInstanceSet( stmt_inst.stmt, stmt_inst.lex_points[:] + [0]*(length-len(stmt_inst.lex_points)), ) From 2f6942632965b1406bce1b598ab7235dd2759bf7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 25 May 2020 21:43:54 -0500 Subject: [PATCH 045/315] remove comments with redundant documentation --- loopy/schedule/checker/schedule.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index f839f45aa..aac9b5744 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -44,10 +44,10 @@ class LexScheduleStatement(object): def __init__( self, - insn_id, # loopy insn id - int_id=None, # sid int (statement id within LexSchedule) + insn_id, + int_id=None, ): - self.insn_id = insn_id # string + self.insn_id = insn_id self.int_id = int_id def __eq__(self, other): @@ -89,8 +89,8 @@ class LexScheduleStatementInstanceSet(object): def __init__( self, - stmt, # a LexScheduleStatement - lex_points, # [string/int, ] + stmt, + lex_points, ): self.stmt = stmt self.lex_points = lex_points From 2f494a2a02d15339ceb7662fee51ae0bcbb2a18e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 25 May 2020 21:49:33 -0500 Subject: [PATCH 046/315] update more comments to clarify that the lex tuples represent *multiple* points, not a single point --- loopy/schedule/checker/schedule.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index aac9b5744..c40053869 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -166,8 +166,8 @@ def __init__( # go through linearization_items_ordered and generate self.lex_schedule - # keep track of the next point in our lexicographic ordering - # initially this as a 1-d point with value 0 + # 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] stmt_added_since_prev_block_at_tier = [False] next_sid = 0 @@ -265,8 +265,9 @@ def __init__( if self.stmt_instance_before and self.stmt_instance_after: break - # at this point, lex_schedule may contain lex points missing dimensions, - # the values in these missing dims should be zero, so add them + # At this point, lex_schedule may contain lex point tuples + # missing dimensions; the values in these missing dims should + # be zero, so add them. self.pad_lex_tuples_with_zeros() def max_lex_dims(self): @@ -277,9 +278,8 @@ def max_lex_dims(self): def pad_lex_tuples_with_zeros(self): """Find the maximum number of lexicographic dimensions represented in the lexicographic ordering, and if any - :class:`LexScheduleStatement` maps to a point in lexicographic - time with fewer dimensions, add a zero for each of the missing - dimensions. + :class:`LexScheduleStatement` maps to a lex point tuple with + fewer dimensions, add a zero for each of the missing dimensions. """ def _pad_lex_tuple_with_zeros(stmt_inst, length): From c71a0efb3182a50ccfad6d346d62abc93088d3f8 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 25 May 2020 22:13:38 -0500 Subject: [PATCH 047/315] clarify what a LexScheduleStatementInstanceSet is --- loopy/schedule/checker/schedule.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index c40053869..c4b4cfc78 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -73,8 +73,11 @@ def __str__(self): class LexScheduleStatementInstanceSet(object): - """A representation of a set of instances of a - :class:`LexScheduleStatement`. + """A representation of a set of (non-concurrent) instances of a + statement being executed. The ordering of the instances is described + by the `lex_points` attribute, a list representing points in a + lexicographic ordering of statements. Each field in the list + corresponds to a dimension in the lexicographic ordering. .. attribute:: stmt @@ -82,8 +85,9 @@ class LexScheduleStatementInstanceSet(object): .. attribute:: lex_points - A list of :class:`int` or as :class:`str` :mod:`loopy` inames representing - a point or set of points in a lexicographic ordering. + A list containing one value for each dimension in a lexicographic + ordering. These values describe the ordering of the statements, + and may be :class:`str` :mod:`loopy` inames or :class:`int`. """ From 492e1f7d66d837076592caeb20813a8df2fe5373 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 26 May 2020 10:16:32 -0500 Subject: [PATCH 048/315] rename LexScheduleStatement->PairwiseScheduleStatement, get_isl_maps_for_LexSchedule->get_isl_maps_from_PairwiseScheduleBuilder, LexSchedule->PairwiseScheduleBuilder --- loopy/schedule/checker/__init__.py | 32 +++---- loopy/schedule/checker/schedule.py | 42 ++++----- test/test_linearization_checker.py | 132 ++++++++++++++--------------- 3 files changed, 103 insertions(+), 103 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 176b1399c..1da7b1e16 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -21,7 +21,7 @@ """ -# {{{ Create LexSchedule for statement pair +# {{{ Create PairwiseScheduleBuilder for statement pair def get_schedule_for_statement_pair( knl, @@ -29,9 +29,9 @@ def get_schedule_for_statement_pair( insn_id_before, insn_id_after, ): - """Create a :class:`loopy.schedule.checker.schedule.LexSchedule` + """Create a :class:`loopy.schedule.checker.schedule.PairwiseScheduleBuilder` representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.LexScheduleStatementInstanceSet` + :class:`loopy.schedule.checker.PairwiseScheduleStatementInstanceSet` to lexicographic time. :arg knl: A :class:`loopy.kernel.LoopKernel` containing the @@ -50,9 +50,9 @@ def get_schedule_for_statement_pair( :arg insn_id_after: An instruction identifier that is unique within a :class:`loopy.kernel.LoopKernel`. - :returns: A :class:`loopy.schedule.checker.schedule.LexSchedule` + :returns: A :class:`loopy.schedule.checker.schedule.PairwiseScheduleBuilder` representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.LexScheduleStatementInstanceSet` + :class:`loopy.schedule.checker.PairwiseScheduleStatementInstanceSet` to lexicographic time. """ @@ -62,7 +62,7 @@ def get_schedule_for_statement_pair( # }}} # {{{ Find any EnterLoop inames that are tagged as concurrent - # so that LexSchedule knows to ignore them + # so that PairwiseScheduleBuilder 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()) @@ -81,10 +81,10 @@ def get_schedule_for_statement_pair( "Ignoring these loops." % (conc_loop_inames, preproc_knl.name)) # }}} - # {{{ Create LexSchedule: mapping of {statement instance: lex point} + # {{{ Create PairwiseScheduleBuilder: mapping of {statement instance: lex point} # include only instructions involved in this dependency - from loopy.schedule.checker.schedule import LexSchedule - return LexSchedule( + from loopy.schedule.checker.schedule import PairwiseScheduleBuilder + return PairwiseScheduleBuilder( linearization_items, insn_id_before, insn_id_after, @@ -95,17 +95,17 @@ def get_schedule_for_statement_pair( # }}} -# {{{ Get isl map pair for LexSchedule +# {{{ Get isl map pair from PairwiseScheduleBuilder -def get_isl_maps_for_LexSchedule(lex_sched, knl): +def get_isl_maps_from_PairwiseScheduleBuilder(lex_sched, knl): """Create a pair of :class:`islpy.Map`s representing a - :class:`loopy.schedule.checker.LexSchedule` as two mappings - from statement instances to lexicographic time, one for - the dependee statement and one for the depender. + sub-schedule as two mappings from statement instances to lexicographic + time, one for the dependee statement and one for the depender. - :arg lex_sched: A :class:`loopy.schedule.checker.schedule.LexSchedule` + :arg lex_sched: A + :class:`loopy.schedule.checker.schedule.PairwiseScheduleBuilder` representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.LexScheduleStatementInstanceSet` + :class:`loopy.schedule.checker.PairwiseScheduleStatementInstanceSet` to lexicographic time. :arg knl: A :class:`loopy.kernel.LoopKernel` containing the diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index c4b4cfc78..4d80d8945 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -23,7 +23,7 @@ import islpy as isl -class LexScheduleStatement(object): +class PairwiseScheduleStatement(object): """A representation of a :mod:`loopy` statement. .. attribute:: insn_id @@ -34,11 +34,11 @@ class LexScheduleStatement(object): .. attribute:: int_id A :class:`int` uniquely identifying the statement within a - :class:`LexSchedule`. A :class:`LexSchedule` describes a mapping - from points in a space of statement instances to points in a - lexicographic ordering. The `statement` dimension of a point - in the statement instance space representing an instance of this - statement is assigned this value (`int_id`). + :class:`PairwiseScheduleBuilder`. A :class:`PairwiseScheduleBuilder` + builds a mapping from points in a space of statement instances to + points in a lexicographic ordering. The `statement` dimension of a + point in the statement instance space representing an instance of + this statement is assigned this value (`int_id`). """ @@ -72,7 +72,7 @@ def __str__(self): return "%s%s" % (self.insn_id, int_id) -class LexScheduleStatementInstanceSet(object): +class PairwiseScheduleStatementInstanceSet(object): """A representation of a set of (non-concurrent) instances of a statement being executed. The ordering of the instances is described by the `lex_points` attribute, a list representing points in a @@ -81,7 +81,7 @@ class LexScheduleStatementInstanceSet(object): .. attribute:: stmt - A :class:`LexScheduleStatement`. + A :class:`PairwiseScheduleStatement`. .. attribute:: lex_points @@ -103,15 +103,15 @@ def __str__(self): return "{%s, %s}" % (self.stmt, self.lex_points) -class LexSchedule(object): - """Given a pair of statements in a linearized kernel, LexSchedule +class PairwiseScheduleBuilder(object): + """Given a pair of statements in a linearized kernel, PairwiseScheduleBuilder determines the (relative) order in which the instances are executed, by creating a mapping from statement instances to points in a single lexicographic ordering. .. attribute:: stmt_instance_before - A :class:`LexScheduleStatementInstanceSet` describing the dependee + A :class:`PairwiseScheduleStatementInstanceSet` describing the dependee statement's order relative to the depender statment by mapping a statement to a point or set of points in a lexicographic ordering. Points in lexicographic ordering are represented as @@ -119,7 +119,7 @@ class LexSchedule(object): .. attribute:: stmt_instance_after - A :class:`LexScheduleStatementInstanceSet` describing the depender + A :class:`PairwiseScheduleStatementInstanceSet` describing the depender statement's order relative to the dependee statment by mapping a statement to a point or set of points in a lexicographic ordering. Points in lexicographic ordering are represented as @@ -150,7 +150,7 @@ def __init__( ): """ :arg linearization_items_ordered: A list of :class:`ScheduleItem` whose - order will be described by this :class:`LexSchedule`. + order will be described by this :class:`PairwiseScheduleBuilder`. :arg before_insn_id: A :class:`str` instruction id specifying the dependee in this pair of instructions. @@ -160,11 +160,11 @@ def __init__( """ - # LexScheduleStatements + # PairwiseScheduleBuilder statements self.stmt_instance_before = None self.stmt_instance_after = None # TODO when/after dependencies are added, consider the possibility - # of removing the two-statements-per-LexSchedule limitation + # of removing the two-statements-per-PairwiseScheduleBuilder limitation from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) @@ -234,8 +234,8 @@ def __init__( if lp_insn_id == before_insn_id: # add before sched item - self.stmt_instance_before = LexScheduleStatementInstanceSet( - LexScheduleStatement( + self.stmt_instance_before = PairwiseScheduleStatementInstanceSet( + PairwiseScheduleStatement( insn_id=lp_insn_id, int_id=next_sid, # int representing insn ), @@ -244,8 +244,8 @@ def __init__( if lp_insn_id == after_insn_id: # add after sched item - self.stmt_instance_after = LexScheduleStatementInstanceSet( - LexScheduleStatement( + self.stmt_instance_after = PairwiseScheduleStatementInstanceSet( + PairwiseScheduleStatement( insn_id=lp_insn_id, int_id=next_sid, # int representing insn ), @@ -282,12 +282,12 @@ def max_lex_dims(self): def pad_lex_tuples_with_zeros(self): """Find the maximum number of lexicographic dimensions represented in the lexicographic ordering, and if any - :class:`LexScheduleStatement` maps to a lex point tuple with + :class:`PairwiseScheduleStatement` maps to a lex point tuple with fewer dimensions, add a zero for each of the missing dimensions. """ def _pad_lex_tuple_with_zeros(stmt_inst, length): - return LexScheduleStatementInstanceSet( + return PairwiseScheduleStatementInstanceSet( stmt_inst.stmt, stmt_inst.lex_points[:] + [0]*(length-len(stmt_inst.lex_points)), ) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index aab9c8507..a4696c3b2 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -50,7 +50,7 @@ def test_lexschedule_and_islmap_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, @@ -93,7 +93,7 @@ def test_lexschedule_and_islmap_creation(): knl = get_one_linearized_kernel(knl) linearization_items = knl.linearization - # Create LexSchedule: mapping of {statement instance: lex point} + # Create PairwiseScheduleBuilder: mapping of {statement instance: lex point} sched_ab = get_schedule_for_statement_pair( knl, linearization_items, @@ -136,35 +136,35 @@ def test_lexschedule_and_islmap_creation(): assert sched_ab.stmt_instance_before.lex_points == [0, 'i', 0, 'k', 0] assert sched_ab.stmt_instance_after.lex_points == [0, 'i', 1, 'j', 0] - # Get two isl maps representing the LexSchedule + # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( + isl_sched_before, isl_sched_after = get_isl_maps_from_PairwiseScheduleBuilder( sched_ab, knl) # Create expected maps, align, compare - isl_sched_map_before_expected = isl.Map( + isl_sched_before_expected = isl.Map( "[pi, pk] -> { " "[_lp_sched_statement=0, i, k] -> " "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=k, " "_lp_sched_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) - isl_sched_map_before_expected = align_isl_maps_by_var_names( - isl_sched_map_before_expected, isl_sched_map_before) + isl_sched_before_expected = align_isl_maps_by_var_names( + isl_sched_before_expected, isl_sched_before) - isl_sched_map_after_expected = isl.Map( + isl_sched_after_expected = isl.Map( "[pi, pj] -> { " "[_lp_sched_statement=1, i, j] -> " "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=1, _lp_sched_l3=j, " "_lp_sched_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) - isl_sched_map_after_expected = align_isl_maps_by_var_names( - isl_sched_map_after_expected, isl_sched_map_after) + isl_sched_after_expected = align_isl_maps_by_var_names( + isl_sched_after_expected, isl_sched_after) - assert isl_sched_map_before == isl_sched_map_before_expected - assert isl_sched_map_after == isl_sched_map_after_expected + assert isl_sched_before == isl_sched_before_expected + assert isl_sched_after == isl_sched_after_expected # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_c --------------------------------------- @@ -172,35 +172,35 @@ def test_lexschedule_and_islmap_creation(): assert sched_ac.stmt_instance_before.lex_points == [0, 'i', 0, 'k', 0] assert sched_ac.stmt_instance_after.lex_points == [0, 'i', 1, 'j', 0] - # Get two isl maps representing the LexSchedule + # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( + isl_sched_before, isl_sched_after = get_isl_maps_from_PairwiseScheduleBuilder( sched_ac, knl) # Create expected maps, align, compare - isl_sched_map_before_expected = isl.Map( + isl_sched_before_expected = isl.Map( "[pi, pk] -> { " "[_lp_sched_statement=0, i, k] -> " "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=k, " "_lp_sched_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) - isl_sched_map_before_expected = align_isl_maps_by_var_names( - isl_sched_map_before_expected, isl_sched_map_before) + isl_sched_before_expected = align_isl_maps_by_var_names( + isl_sched_before_expected, isl_sched_before) - isl_sched_map_after_expected = isl.Map( + isl_sched_after_expected = isl.Map( "[pi, pj] -> { " "[_lp_sched_statement=1, i, j] -> " "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=1, _lp_sched_l3=j, " "_lp_sched_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) - isl_sched_map_after_expected = align_isl_maps_by_var_names( - isl_sched_map_after_expected, isl_sched_map_after) + isl_sched_after_expected = align_isl_maps_by_var_names( + isl_sched_after_expected, isl_sched_after) - assert isl_sched_map_before == isl_sched_map_before_expected - assert isl_sched_map_after == isl_sched_map_after_expected + assert isl_sched_before == isl_sched_before_expected + assert isl_sched_after == isl_sched_after_expected # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_d --------------------------------------- @@ -211,14 +211,14 @@ def perform_insn_ad_checks_with(sid_a, sid_d): assert sched_ad.stmt_instance_before.lex_points == [sid_a, 'i', 0, 'k', 0] assert sched_ad.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] - # Get two isl maps representing the LexSchedule + # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - sched_ad, knl) + isl_sched_before, isl_sched_after = \ + get_isl_maps_from_PairwiseScheduleBuilder(sched_ad, knl) # Create expected maps, align, compare - isl_sched_map_before_expected = isl.Map( + isl_sched_before_expected = isl.Map( "[pi, pk] -> { " "[_lp_sched_statement=%d, i, k] -> " "[_lp_sched_l0=%d, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=k, " @@ -226,10 +226,10 @@ def perform_insn_ad_checks_with(sid_a, sid_d): "0 <= i < pi and 0 <= k < pk }" % (sid_a, sid_a) ) - isl_sched_map_before_expected = align_isl_maps_by_var_names( - isl_sched_map_before_expected, isl_sched_map_before) + isl_sched_before_expected = align_isl_maps_by_var_names( + isl_sched_before_expected, isl_sched_before) - isl_sched_map_after_expected = isl.Map( + isl_sched_after_expected = isl.Map( "[pt] -> { " "[_lp_sched_statement=%d, t] -> " "[_lp_sched_l0=%d, _lp_sched_l1=t, _lp_sched_l2=0, _lp_sched_l3=0, " @@ -237,11 +237,11 @@ def perform_insn_ad_checks_with(sid_a, sid_d): "0 <= t < pt }" % (sid_d, sid_d) ) - isl_sched_map_after_expected = align_isl_maps_by_var_names( - isl_sched_map_after_expected, isl_sched_map_after) + isl_sched_after_expected = align_isl_maps_by_var_names( + isl_sched_after_expected, isl_sched_after) - assert isl_sched_map_before == isl_sched_map_before_expected - assert isl_sched_map_after == isl_sched_map_after_expected + assert isl_sched_before == isl_sched_before_expected + assert isl_sched_after == isl_sched_after_expected if sched_ad.stmt_instance_before.stmt.int_id == 0: perform_insn_ad_checks_with(0, 1) @@ -257,14 +257,14 @@ def perform_insn_bc_checks_with(sid_b, sid_c): assert sched_bc.stmt_instance_before.lex_points == [0, 'i', 0, 'j', sid_b] assert sched_bc.stmt_instance_after.lex_points == [0, 'i', 0, 'j', sid_c] - # Get two isl maps representing the LexSchedule + # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - sched_bc, knl) + isl_sched_before, isl_sched_after = \ + get_isl_maps_from_PairwiseScheduleBuilder(sched_bc, knl) # Create expected maps, align, compare - isl_sched_map_before_expected = isl.Map( + isl_sched_before_expected = isl.Map( "[pi, pj] -> { " "[_lp_sched_statement=%d, i, j] -> " "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " @@ -272,10 +272,10 @@ def perform_insn_bc_checks_with(sid_b, sid_c): "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) - isl_sched_map_before_expected = align_isl_maps_by_var_names( - isl_sched_map_before_expected, isl_sched_map_before) + isl_sched_before_expected = align_isl_maps_by_var_names( + isl_sched_before_expected, isl_sched_before) - isl_sched_map_after_expected = isl.Map( + isl_sched_after_expected = isl.Map( "[pi, pj] -> { " "[_lp_sched_statement=%d, i, j] -> " "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " @@ -283,11 +283,11 @@ def perform_insn_bc_checks_with(sid_b, sid_c): "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) - isl_sched_map_after_expected = align_isl_maps_by_var_names( - isl_sched_map_after_expected, isl_sched_map_after) + isl_sched_after_expected = align_isl_maps_by_var_names( + isl_sched_after_expected, isl_sched_after) - assert isl_sched_map_before == isl_sched_map_before_expected - assert isl_sched_map_after == isl_sched_map_after_expected + assert isl_sched_before == isl_sched_before_expected + assert isl_sched_after == isl_sched_after_expected if sched_bc.stmt_instance_before.stmt.int_id == 0: perform_insn_bc_checks_with(0, 1) @@ -303,14 +303,14 @@ def perform_insn_bd_checks_with(sid_b, sid_d): assert sched_bd.stmt_instance_before.lex_points == [sid_b, 'i', 0, 'j', 0] assert sched_bd.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] - # Get two isl maps representing the LexSchedule + # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - sched_bd, knl) + isl_sched_before, isl_sched_after = \ + get_isl_maps_from_PairwiseScheduleBuilder(sched_bd, knl) # Create expected maps, align, compare - isl_sched_map_before_expected = isl.Map( + isl_sched_before_expected = isl.Map( "[pi, pj] -> { " "[_lp_sched_statement=%d, i, j] -> " "[_lp_sched_l0=%d, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " @@ -318,10 +318,10 @@ def perform_insn_bd_checks_with(sid_b, sid_d): "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) - isl_sched_map_before_expected = align_isl_maps_by_var_names( - isl_sched_map_before_expected, isl_sched_map_before) + isl_sched_before_expected = align_isl_maps_by_var_names( + isl_sched_before_expected, isl_sched_before) - isl_sched_map_after_expected = isl.Map( + isl_sched_after_expected = isl.Map( "[pt] -> { " "[_lp_sched_statement=%d, t] -> " "[_lp_sched_l0=%d, _lp_sched_l1=t, _lp_sched_l2=0, _lp_sched_l3=0, " @@ -329,11 +329,11 @@ def perform_insn_bd_checks_with(sid_b, sid_d): "0 <= t < pt }" % (sid_d, sid_d) ) - isl_sched_map_after_expected = align_isl_maps_by_var_names( - isl_sched_map_after_expected, isl_sched_map_after) + isl_sched_after_expected = align_isl_maps_by_var_names( + isl_sched_after_expected, isl_sched_after) - assert isl_sched_map_before == isl_sched_map_before_expected - assert isl_sched_map_after == isl_sched_map_after_expected + assert isl_sched_before == isl_sched_before_expected + assert isl_sched_after == isl_sched_after_expected if sched_bd.stmt_instance_before.stmt.int_id == 0: perform_insn_bd_checks_with(0, 1) @@ -349,14 +349,14 @@ def perform_insn_cd_checks_with(sid_c, sid_d): assert sched_cd.stmt_instance_before.lex_points == [sid_c, 'i', 0, 'j', 0] assert sched_cd.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] - # Get two isl maps representing the LexSchedule + # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_map_before, isl_sched_map_after = get_isl_maps_for_LexSchedule( - sched_cd, knl) + isl_sched_before, isl_sched_after = \ + get_isl_maps_from_PairwiseScheduleBuilder(sched_cd, knl) # Create expected maps, align, compare - isl_sched_map_before_expected = isl.Map( + isl_sched_before_expected = isl.Map( "[pi, pj] -> { " "[_lp_sched_statement=%d, i, j] -> " "[_lp_sched_l0=%d, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " @@ -364,10 +364,10 @@ def perform_insn_cd_checks_with(sid_c, sid_d): "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) - isl_sched_map_before_expected = align_isl_maps_by_var_names( - isl_sched_map_before_expected, isl_sched_map_before) + isl_sched_before_expected = align_isl_maps_by_var_names( + isl_sched_before_expected, isl_sched_before) - isl_sched_map_after_expected = isl.Map( + isl_sched_after_expected = isl.Map( "[pt] -> { " "[_lp_sched_statement=%d, t] -> " "[_lp_sched_l0=%d, _lp_sched_l1=t, _lp_sched_l2=0, _lp_sched_l3=0, " @@ -375,11 +375,11 @@ def perform_insn_cd_checks_with(sid_c, sid_d): "0 <= t < pt }" % (sid_d, sid_d) ) - isl_sched_map_after_expected = align_isl_maps_by_var_names( - isl_sched_map_after_expected, isl_sched_map_after) + isl_sched_after_expected = align_isl_maps_by_var_names( + isl_sched_after_expected, isl_sched_after) - assert isl_sched_map_before == isl_sched_map_before_expected - assert isl_sched_map_after == isl_sched_map_after_expected + assert isl_sched_before == isl_sched_before_expected + assert isl_sched_after == isl_sched_after_expected if sched_cd.stmt_instance_before.stmt.int_id == 0: perform_insn_cd_checks_with(0, 1) From e5146b0cf846184562eac98a05f10fb35650d49c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 26 May 2020 10:22:29 -0500 Subject: [PATCH 049/315] change a few variable names to be consistent with name changes for LexSchedule --- loopy/schedule/checker/__init__.py | 12 +++++++----- loopy/schedule/checker/schedule.py | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 1da7b1e16..4ce370b4c 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -97,12 +97,12 @@ def get_schedule_for_statement_pair( # {{{ Get isl map pair from PairwiseScheduleBuilder -def get_isl_maps_from_PairwiseScheduleBuilder(lex_sched, knl): +def get_isl_maps_from_PairwiseScheduleBuilder(sched_builder, knl): """Create a pair of :class:`islpy.Map`s representing a sub-schedule as two mappings from statement instances to lexicographic time, one for the dependee statement and one for the depender. - :arg lex_sched: A + :arg sched_builder: A :class:`loopy.schedule.checker.schedule.PairwiseScheduleBuilder` representing the order of two statements as a mapping from :class:`loopy.schedule.checker.PairwiseScheduleStatementInstanceSet` @@ -119,13 +119,15 @@ def get_isl_maps_from_PairwiseScheduleBuilder(lex_sched, knl): # {{{ Get iname domains dom_before = knl.get_inames_domain( - knl.id_to_insn[lex_sched.stmt_instance_before.stmt.insn_id].within_inames) + knl.id_to_insn[ + sched_builder.stmt_instance_before.stmt.insn_id].within_inames) dom_after = knl.get_inames_domain( - knl.id_to_insn[lex_sched.stmt_instance_after.stmt.insn_id].within_inames) + knl.id_to_insn[ + sched_builder.stmt_instance_after.stmt.insn_id].within_inames) # }}} # {{{ Get isl maps - return lex_sched.create_isl_maps(dom_before, dom_after) + return sched_builder.create_isl_maps(dom_before, dom_after) # }}} # }}} diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 4d80d8945..aaef5de8e 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -168,7 +168,7 @@ def __init__( from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) - # go through linearization_items_ordered and generate self.lex_schedule + # go through linearization_items_ordered and generate pairwise sub-schedule # keep track of the next tuple of points in our lexicographic # ordering, initially this as a 1-d point with value 0 @@ -269,7 +269,7 @@ def __init__( if self.stmt_instance_before and self.stmt_instance_after: break - # At this point, lex_schedule may contain lex point tuples + # At this point, pairwise sub-schedule may contain lex point tuples # missing dimensions; the values in these missing dims should # be zero, so add them. self.pad_lex_tuples_with_zeros() From 3b5d4caa5a5f1e272172370f949bcd19a54d9b0a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 26 May 2020 10:27:36 -0500 Subject: [PATCH 050/315] 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 d06dd8980c6b39588cc63835bb040580f4dc764d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 26 May 2020 10:53:52 -0500 Subject: [PATCH 051/315] remove dependee/depender language for now --- loopy/schedule/checker/schedule.py | 46 ++++++++++++++++-------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index aaef5de8e..27b76c847 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -111,19 +111,21 @@ class PairwiseScheduleBuilder(object): .. attribute:: stmt_instance_before - A :class:`PairwiseScheduleStatementInstanceSet` describing the dependee - statement's order relative to the depender statment by mapping - a statement to a point or set of points in a lexicographic - ordering. Points in lexicographic ordering are represented as - a list of :class:`int` or as :class:`str` :mod:`loopy` inames. + A :class:`PairwiseScheduleStatementInstanceSet` whose ordering relative + to `stmt_instance_after is described by PairwiseScheduleBuilder. This + is achieved by mapping the statement instances in both sets to points + in a single lexicographic ordering. Points in lexicographic ordering + are represented as a list of :class:`int` or as :class:`str` + :mod:`loopy` inames. .. attribute:: stmt_instance_after - A :class:`PairwiseScheduleStatementInstanceSet` describing the depender - statement's order relative to the dependee statment by mapping - a statement to a point or set of points in a lexicographic - ordering. Points in lexicographic ordering are represented as - a list of :class:`int` or as :class:`str` :mod:`loopy` inames. + A :class:`PairwiseScheduleStatementInstanceSet` whose ordering relative + to `stmt_instance_before is described by PairwiseScheduleBuilder. This + is achieved by mapping the statement instances in both sets to points + in a single lexicographic ordering. Points in lexicographic ordering + are represented as a list of :class:`int` or as :class:`str` + :mod:`loopy` inames. .. attribute:: statement_var_name @@ -153,10 +155,10 @@ def __init__( order will be described by this :class:`PairwiseScheduleBuilder`. :arg before_insn_id: A :class:`str` instruction id specifying - the dependee in this pair of instructions. + stmt_instance_before in this pair of instructions. :arg after_insn_id: A :class:`str` instruction id specifying - the depender in this pair of instructions. + stmt_instancce_after in this pair of instructions. """ @@ -308,30 +310,30 @@ def create_isl_maps( ): """Create two isl maps representing lex schedule as two mappings from statement instances to lexicographic time, one for - the dependee and one for the depender. + ``stmt_instance_before`` and one for ``stmt_instance_after``. :arg dom_before: A :class:`islpy.BasicSet` representing the - domain for the dependee statement. + domain for ``stmt_instance_before``. :arg dom_after: A :class:`islpy.BasicSet` representing the - domain for the dependee statement. + domain for ``stmt_instance_after``. :arg dom_inames_ordered_before: A list of :class:`str` - representing the union of inames used in instances of the - dependee statement. ``statement_var_name`` and + representing the union of inames used in + ``stmt_instance_before``. ``statement_var_name`` and ``dom_inames_ordered_before`` are the names of the dims of - the space of the ISL map domain for the dependee. + the space of the ISL map domain. :arg dom_inames_ordered_after: A list of :class:`str` - representing the union of inames used in instances of the - depender statement. ``statement_var_name`` and + representing the union of inames used in + ``stmt_instance_after``. ``statement_var_name`` and ``dom_inames_ordered_after`` are the names of the dims of - the space of the ISL map domain for the depender. + the space of the ISL map domain. :returns: A two-tuple containing two :class:`islpy.Map`s representing the schedule as two mappings from statement instances to lexicographic time, one for - the dependee and one for the depender. + each of the two :class:`PairwiseScheduleStatementInstanceSet`s. """ From 2574becdadd587f37deb26bad7131610bb50188c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 31 May 2020 21:10:07 -0500 Subject: [PATCH 052/315] change identifier prefix for sched checker identifiers from _lp_sched_->lp_linchk_ --- loopy/schedule/checker/schedule.py | 4 +- test/test_linearization_checker.py | 72 +++++++++++++++--------------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 27b76c847..b3f21a6c3 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -140,8 +140,8 @@ class PairwiseScheduleBuilder(object): """ - statement_var_name = "_lp_sched_statement" - lex_var_prefix = "_lp_sched_l" + statement_var_name = "_lp_linchk_statement" + lex_var_prefix = "_lp_linchk_l" def __init__( self, diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index a4696c3b2..7a67ab824 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -145,9 +145,9 @@ def test_lexschedule_and_islmap_creation(): isl_sched_before_expected = isl.Map( "[pi, pk] -> { " - "[_lp_sched_statement=0, i, k] -> " - "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=k, " - "_lp_sched_l4=0] : " + "[_lp_linchk_statement=0, i, k] -> " + "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=k, " + "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) isl_sched_before_expected = align_isl_maps_by_var_names( @@ -155,9 +155,9 @@ def test_lexschedule_and_islmap_creation(): isl_sched_after_expected = isl.Map( "[pi, pj] -> { " - "[_lp_sched_statement=1, i, j] -> " - "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=1, _lp_sched_l3=j, " - "_lp_sched_l4=0] : " + "[_lp_linchk_statement=1, i, j] -> " + "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=1, _lp_linchk_l3=j, " + "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) isl_sched_after_expected = align_isl_maps_by_var_names( @@ -181,9 +181,9 @@ def test_lexschedule_and_islmap_creation(): isl_sched_before_expected = isl.Map( "[pi, pk] -> { " - "[_lp_sched_statement=0, i, k] -> " - "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=k, " - "_lp_sched_l4=0] : " + "[_lp_linchk_statement=0, i, k] -> " + "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=k, " + "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) isl_sched_before_expected = align_isl_maps_by_var_names( @@ -191,9 +191,9 @@ def test_lexschedule_and_islmap_creation(): isl_sched_after_expected = isl.Map( "[pi, pj] -> { " - "[_lp_sched_statement=1, i, j] -> " - "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=1, _lp_sched_l3=j, " - "_lp_sched_l4=0] : " + "[_lp_linchk_statement=1, i, j] -> " + "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=1, _lp_linchk_l3=j, " + "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) isl_sched_after_expected = align_isl_maps_by_var_names( @@ -220,9 +220,9 @@ def perform_insn_ad_checks_with(sid_a, sid_d): isl_sched_before_expected = isl.Map( "[pi, pk] -> { " - "[_lp_sched_statement=%d, i, k] -> " - "[_lp_sched_l0=%d, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=k, " - "_lp_sched_l4=0] : " + "[_lp_linchk_statement=%d, i, k] -> " + "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=k, " + "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= k < pk }" % (sid_a, sid_a) ) @@ -231,9 +231,9 @@ def perform_insn_ad_checks_with(sid_a, sid_d): isl_sched_after_expected = isl.Map( "[pt] -> { " - "[_lp_sched_statement=%d, t] -> " - "[_lp_sched_l0=%d, _lp_sched_l1=t, _lp_sched_l2=0, _lp_sched_l3=0, " - "_lp_sched_l4=0] : " + "[_lp_linchk_statement=%d, t] -> " + "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " + "_lp_linchk_l4=0] : " "0 <= t < pt }" % (sid_d, sid_d) ) @@ -266,9 +266,9 @@ def perform_insn_bc_checks_with(sid_b, sid_c): isl_sched_before_expected = isl.Map( "[pi, pj] -> { " - "[_lp_sched_statement=%d, i, j] -> " - "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " - "_lp_sched_l4=%d] : " + "[_lp_linchk_statement=%d, i, j] -> " + "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " + "_lp_linchk_l4=%d] : " "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) @@ -277,9 +277,9 @@ def perform_insn_bc_checks_with(sid_b, sid_c): isl_sched_after_expected = isl.Map( "[pi, pj] -> { " - "[_lp_sched_statement=%d, i, j] -> " - "[_lp_sched_l0=0, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " - "_lp_sched_l4=%d] : " + "[_lp_linchk_statement=%d, i, j] -> " + "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " + "_lp_linchk_l4=%d] : " "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) @@ -312,9 +312,9 @@ def perform_insn_bd_checks_with(sid_b, sid_d): isl_sched_before_expected = isl.Map( "[pi, pj] -> { " - "[_lp_sched_statement=%d, i, j] -> " - "[_lp_sched_l0=%d, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " - "_lp_sched_l4=0] : " + "[_lp_linchk_statement=%d, i, j] -> " + "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " + "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) @@ -323,9 +323,9 @@ def perform_insn_bd_checks_with(sid_b, sid_d): isl_sched_after_expected = isl.Map( "[pt] -> { " - "[_lp_sched_statement=%d, t] -> " - "[_lp_sched_l0=%d, _lp_sched_l1=t, _lp_sched_l2=0, _lp_sched_l3=0, " - "_lp_sched_l4=0] : " + "[_lp_linchk_statement=%d, t] -> " + "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " + "_lp_linchk_l4=0] : " "0 <= t < pt }" % (sid_d, sid_d) ) @@ -358,9 +358,9 @@ def perform_insn_cd_checks_with(sid_c, sid_d): isl_sched_before_expected = isl.Map( "[pi, pj] -> { " - "[_lp_sched_statement=%d, i, j] -> " - "[_lp_sched_l0=%d, _lp_sched_l1=i, _lp_sched_l2=0, _lp_sched_l3=j, " - "_lp_sched_l4=0] : " + "[_lp_linchk_statement=%d, i, j] -> " + "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " + "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) @@ -369,9 +369,9 @@ def perform_insn_cd_checks_with(sid_c, sid_d): isl_sched_after_expected = isl.Map( "[pt] -> { " - "[_lp_sched_statement=%d, t] -> " - "[_lp_sched_l0=%d, _lp_sched_l1=t, _lp_sched_l2=0, _lp_sched_l3=0, " - "_lp_sched_l4=0] : " + "[_lp_linchk_statement=%d, t] -> " + "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " + "_lp_linchk_l4=0] : " "0 <= t < pt }" % (sid_d, sid_d) ) From 626140b832828432fd5e78b1511b5054d5819214 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 31 May 2020 21:17:29 -0500 Subject: [PATCH 053/315] rename PairwiseScheduleStatementInstanceSet->StatementInstanceSet --- loopy/schedule/checker/__init__.py | 6 +++--- loopy/schedule/checker/schedule.py | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 4ce370b4c..6769b56b7 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -31,7 +31,7 @@ def get_schedule_for_statement_pair( ): """Create a :class:`loopy.schedule.checker.schedule.PairwiseScheduleBuilder` representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.PairwiseScheduleStatementInstanceSet` + :class:`loopy.schedule.checker.StatementInstanceSet` to lexicographic time. :arg knl: A :class:`loopy.kernel.LoopKernel` containing the @@ -52,7 +52,7 @@ def get_schedule_for_statement_pair( :returns: A :class:`loopy.schedule.checker.schedule.PairwiseScheduleBuilder` representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.PairwiseScheduleStatementInstanceSet` + :class:`loopy.schedule.checker.StatementInstanceSet` to lexicographic time. """ @@ -105,7 +105,7 @@ def get_isl_maps_from_PairwiseScheduleBuilder(sched_builder, knl): :arg sched_builder: A :class:`loopy.schedule.checker.schedule.PairwiseScheduleBuilder` representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.PairwiseScheduleStatementInstanceSet` + :class:`loopy.schedule.checker.StatementInstanceSet` to lexicographic time. :arg knl: A :class:`loopy.kernel.LoopKernel` containing the diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index b3f21a6c3..8f55eff39 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -72,7 +72,7 @@ def __str__(self): return "%s%s" % (self.insn_id, int_id) -class PairwiseScheduleStatementInstanceSet(object): +class StatementInstanceSet(object): """A representation of a set of (non-concurrent) instances of a statement being executed. The ordering of the instances is described by the `lex_points` attribute, a list representing points in a @@ -111,7 +111,7 @@ class PairwiseScheduleBuilder(object): .. attribute:: stmt_instance_before - A :class:`PairwiseScheduleStatementInstanceSet` whose ordering relative + A :class:`StatementInstanceSet` whose ordering relative to `stmt_instance_after is described by PairwiseScheduleBuilder. This is achieved by mapping the statement instances in both sets to points in a single lexicographic ordering. Points in lexicographic ordering @@ -120,7 +120,7 @@ class PairwiseScheduleBuilder(object): .. attribute:: stmt_instance_after - A :class:`PairwiseScheduleStatementInstanceSet` whose ordering relative + A :class:`StatementInstanceSet` whose ordering relative to `stmt_instance_before is described by PairwiseScheduleBuilder. This is achieved by mapping the statement instances in both sets to points in a single lexicographic ordering. Points in lexicographic ordering @@ -236,7 +236,7 @@ def __init__( if lp_insn_id == before_insn_id: # add before sched item - self.stmt_instance_before = PairwiseScheduleStatementInstanceSet( + self.stmt_instance_before = StatementInstanceSet( PairwiseScheduleStatement( insn_id=lp_insn_id, int_id=next_sid, # int representing insn @@ -246,7 +246,7 @@ def __init__( if lp_insn_id == after_insn_id: # add after sched item - self.stmt_instance_after = PairwiseScheduleStatementInstanceSet( + self.stmt_instance_after = StatementInstanceSet( PairwiseScheduleStatement( insn_id=lp_insn_id, int_id=next_sid, # int representing insn @@ -289,7 +289,7 @@ def pad_lex_tuples_with_zeros(self): """ def _pad_lex_tuple_with_zeros(stmt_inst, length): - return PairwiseScheduleStatementInstanceSet( + return StatementInstanceSet( stmt_inst.stmt, stmt_inst.lex_points[:] + [0]*(length-len(stmt_inst.lex_points)), ) @@ -333,7 +333,7 @@ def create_isl_maps( :returns: A two-tuple containing two :class:`islpy.Map`s representing the schedule as two mappings from statement instances to lexicographic time, one for - each of the two :class:`PairwiseScheduleStatementInstanceSet`s. + each of the two :class:`StatementInstanceSet`s. """ From 132a1c699a6802714aa18a0c2031c9e469d94c77 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 31 May 2020 21:23:02 -0500 Subject: [PATCH 054/315] rename PairwiseScheduleStatement->StatementRef --- loopy/schedule/checker/schedule.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 8f55eff39..d80b64520 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -23,8 +23,8 @@ import islpy as isl -class PairwiseScheduleStatement(object): - """A representation of a :mod:`loopy` statement. +class StatementRef(object): + """A reference to a :mod:`loopy` statement. .. attribute:: insn_id @@ -81,7 +81,7 @@ class StatementInstanceSet(object): .. attribute:: stmt - A :class:`PairwiseScheduleStatement`. + A :class:`StatementRef`. .. attribute:: lex_points @@ -237,7 +237,7 @@ def __init__( if lp_insn_id == before_insn_id: # add before sched item self.stmt_instance_before = StatementInstanceSet( - PairwiseScheduleStatement( + StatementRef( insn_id=lp_insn_id, int_id=next_sid, # int representing insn ), @@ -247,7 +247,7 @@ def __init__( if lp_insn_id == after_insn_id: # add after sched item self.stmt_instance_after = StatementInstanceSet( - PairwiseScheduleStatement( + StatementRef( insn_id=lp_insn_id, int_id=next_sid, # int representing insn ), @@ -284,7 +284,7 @@ def max_lex_dims(self): def pad_lex_tuples_with_zeros(self): """Find the maximum number of lexicographic dimensions represented in the lexicographic ordering, and if any - :class:`PairwiseScheduleStatement` maps to a lex point tuple with + :class:`StatementRef` maps to a lex point tuple with fewer dimensions, add a zero for each of the missing dimensions. """ From 7a9a5bde0be356d90a012a1fab018c8d31520514 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 31 May 2020 21:28:23 -0500 Subject: [PATCH 055/315] rename StatementInstanceSet.stmt->StatementInstanceSet.stmt_ref --- loopy/schedule/checker/__init__.py | 4 ++-- loopy/schedule/checker/schedule.py | 14 +++++++------- test/test_linearization_checker.py | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 6769b56b7..7729dbbb1 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -120,10 +120,10 @@ def get_isl_maps_from_PairwiseScheduleBuilder(sched_builder, knl): # {{{ Get iname domains dom_before = knl.get_inames_domain( knl.id_to_insn[ - sched_builder.stmt_instance_before.stmt.insn_id].within_inames) + sched_builder.stmt_instance_before.stmt_ref.insn_id].within_inames) dom_after = knl.get_inames_domain( knl.id_to_insn[ - sched_builder.stmt_instance_after.stmt.insn_id].within_inames) + sched_builder.stmt_instance_after.stmt_ref.insn_id].within_inames) # }}} # {{{ Get isl maps diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index d80b64520..8963fb576 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -79,7 +79,7 @@ class StatementInstanceSet(object): lexicographic ordering of statements. Each field in the list corresponds to a dimension in the lexicographic ordering. - .. attribute:: stmt + .. attribute:: stmt_ref A :class:`StatementRef`. @@ -93,14 +93,14 @@ class StatementInstanceSet(object): def __init__( self, - stmt, + stmt_ref, lex_points, ): - self.stmt = stmt + self.stmt_ref = stmt_ref self.lex_points = lex_points def __str__(self): - return "{%s, %s}" % (self.stmt, self.lex_points) + return "{%s, %s}" % (self.stmt_ref, self.lex_points) class PairwiseScheduleBuilder(object): @@ -290,7 +290,7 @@ def pad_lex_tuples_with_zeros(self): def _pad_lex_tuple_with_zeros(stmt_inst, length): return StatementInstanceSet( - stmt_inst.stmt, + stmt_inst.stmt_ref, stmt_inst.lex_points[:] + [0]*(length-len(stmt_inst.lex_points)), ) @@ -372,7 +372,7 @@ def _get_isl_map_for_stmt_inst( # Right now, statement instance tuples consist of single int. # Add all inames from domains to each map domain tuple. tuple_pair = [( - (stmt_inst.stmt.int_id, ) + tuple(dom_inames_ordered), + (stmt_inst.stmt_ref.int_id, ) + tuple(dom_inames_ordered), stmt_inst.lex_points )] @@ -402,7 +402,7 @@ def __str__(self): def stringify_sched_stmt_instance(stmt_inst): return "{\n[%s=%s,] -> %s;\n}" % ( self.statement_var_name, - stmt_inst.stmt.int_id, + stmt_inst.stmt_ref.int_id, stmt_inst.lex_points) return "Before: %s\nAfter: %s" % ( diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 7a67ab824..396fccf4f 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -243,7 +243,7 @@ def perform_insn_ad_checks_with(sid_a, sid_d): assert isl_sched_before == isl_sched_before_expected assert isl_sched_after == isl_sched_after_expected - if sched_ad.stmt_instance_before.stmt.int_id == 0: + if sched_ad.stmt_instance_before.stmt_ref.int_id == 0: perform_insn_ad_checks_with(0, 1) else: perform_insn_ad_checks_with(1, 0) @@ -289,7 +289,7 @@ def perform_insn_bc_checks_with(sid_b, sid_c): assert isl_sched_before == isl_sched_before_expected assert isl_sched_after == isl_sched_after_expected - if sched_bc.stmt_instance_before.stmt.int_id == 0: + if sched_bc.stmt_instance_before.stmt_ref.int_id == 0: perform_insn_bc_checks_with(0, 1) else: perform_insn_bc_checks_with(1, 0) @@ -335,7 +335,7 @@ def perform_insn_bd_checks_with(sid_b, sid_d): assert isl_sched_before == isl_sched_before_expected assert isl_sched_after == isl_sched_after_expected - if sched_bd.stmt_instance_before.stmt.int_id == 0: + if sched_bd.stmt_instance_before.stmt_ref.int_id == 0: perform_insn_bd_checks_with(0, 1) else: perform_insn_bd_checks_with(1, 0) @@ -381,7 +381,7 @@ def perform_insn_cd_checks_with(sid_c, sid_d): assert isl_sched_before == isl_sched_before_expected assert isl_sched_after == isl_sched_after_expected - if sched_cd.stmt_instance_before.stmt.int_id == 0: + if sched_cd.stmt_instance_before.stmt_ref.int_id == 0: perform_insn_cd_checks_with(0, 1) else: perform_insn_cd_checks_with(1, 0) From 30054b19b0751045e4515a95420505cc57f99e3d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 31 May 2020 21:34:58 -0500 Subject: [PATCH 056/315] keep docstring example consistent with identifier naming policy --- loopy/schedule/checker/schedule.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 8963fb576..26ceb49c4 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -136,7 +136,11 @@ class PairwiseScheduleBuilder(object): A :class:`str` specifying the prefix to be used for the variables representing the dimensions in the lexicographic ordering. E.g., - a prefix of "lex" might yield variables "lex0", "lex1", "lex2". + a prefix of "_lp_linchk_lex" might yield variables "_lp_linchk_lex0", + "_lp_linchk_lex1", "_lp_linchk_lex2". Note the identifier prefix + policies described in the documentation under + *Loopy's Model of a Kernel* -> *Identifiers*. + . """ From a9bbc92e840fe9deab63be773141d2be0bbabb17 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 31 May 2020 22:25:13 -0500 Subject: [PATCH 057/315] add example usage to docstring for get_schedule_for_statement_pair() and PairwiseScheduleBuilder() --- loopy/schedule/checker/__init__.py | 39 ++++++++++++++++++++++- loopy/schedule/checker/schedule.py | 50 +++++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 7729dbbb1..c454254f6 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -40,7 +40,7 @@ def get_schedule_for_statement_pair( :arg linearization_items: A list of :class:`loopy.schedule.ScheduleItem` (to be renamed to `loopy.schedule.LinearizationItem`) containing the two linearization items for which a schedule will be - created. This list may be a partial linearization for a + created. This list may be a *partial* linearization for a kernel since this function may be used during the linearization process. @@ -54,6 +54,43 @@ def get_schedule_for_statement_pair( representing the order of two statements as a mapping from :class:`loopy.schedule.checker.StatementInstanceSet` to lexicographic time. + + Example usage:: + + # Make kernel -------------------------------------------------------- + knl = lp.make_kernel( + "{[i,j,k]: 0<=i *Identifiers*. - . + + Example usage:: + + # Make kernel -------------------------------------------------------- + knl = lp.make_kernel( + "{[i,j,k]: 0<=i Date: Sun, 31 May 2020 22:33:59 -0500 Subject: [PATCH 058/315] add example schedule creation output to docstring examples --- loopy/schedule/checker/__init__.py | 16 ++++++++++++++++ loopy/schedule/checker/schedule.py | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index c454254f6..4489ca69b 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -91,6 +91,22 @@ def get_schedule_for_statement_pair( sched_a, sched_b = get_isl_maps_from_PairwiseScheduleBuilder( sched_builder_ab, knl) + print(sched_a) + print(sched_b) + + Example Output:: + + [pi, pj, pk] -> { + [_lp_linchk_statement = 0, i, j, k] -> + [_lp_linchk_l0 = 0, _lp_linchk_l1 = i, _lp_linchk_l2 = 0, + _lp_linchk_l3 = j, _lp_linchk_l4 = 0] : + 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + [pi, pj, pk] -> { + [_lp_linchk_statement = 1, i, j, k] -> + [_lp_linchk_l0 = 0, _lp_linchk_l1 = i, _lp_linchk_l2 = 1, + _lp_linchk_l3 = k, _lp_linchk_l4 = 0] : + 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + """ # {{{ Preprocess if not already preprocessed diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index d7cc7b454..fead079ac 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -190,6 +190,22 @@ class PairwiseScheduleBuilder(object): sched_a, sched_b = get_isl_maps_from_PairwiseScheduleBuilder( sched_builder_ab, knl) + print(sched_a) + print(sched_b) + + Example Output:: + + [pi, pj, pk] -> { + [_lp_linchk_statement = 0, i, j, k] -> + [_lp_linchk_l0 = 0, _lp_linchk_l1 = i, _lp_linchk_l2 = 0, + _lp_linchk_l3 = j, _lp_linchk_l4 = 0] : + 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + [pi, pj, pk] -> { + [_lp_linchk_statement = 1, i, j, k] -> + [_lp_linchk_l0 = 0, _lp_linchk_l1 = i, _lp_linchk_l2 = 1, + _lp_linchk_l3 = k, _lp_linchk_l4 = 0] : + 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + """ statement_var_name = "_lp_linchk_statement" From ba46ade4f5b002e72451d593162cac22cfa10553 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 1 Jun 2020 22:30:23 -0500 Subject: [PATCH 059/315] 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 060/315] 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 061/315] 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 8761fb2734364b27ef52ae28f3760bed18b05ea5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 2 Jun 2020 04:18:13 -0500 Subject: [PATCH 062/315] for consistency between runs, sort var names extracted from isl sets --- 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 0728e9686..eb7707f67 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -156,7 +156,9 @@ def list_var_names_in_isl_sets( inames = set() for isl_set in isl_sets: inames.update(isl_set.get_var_names(set_dim)) - return list(inames) + + # sorting is not necessary, but keeps results consistent between runs + return sorted(list(inames)) def create_symbolic_isl_map_from_tuples( From 055be9744ec3a0377d3c142b0e89cb3f3a237e20 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 2 Jun 2020 12:40:21 -0500 Subject: [PATCH 063/315] fix docstring indentation --- loopy/schedule/checker/schedule.py | 64 +++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index fead079ac..459ab4fcb 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -28,17 +28,17 @@ class StatementRef(object): .. attribute:: insn_id - A :class:`str` specifying the :mod:`loopy` instruction id - for this statement. + A :class:`str` specifying the :mod:`loopy` instruction id + for this statement. .. attribute:: int_id - A :class:`int` uniquely identifying the statement within a - :class:`PairwiseScheduleBuilder`. A :class:`PairwiseScheduleBuilder` - builds a mapping from points in a space of statement instances to - points in a lexicographic ordering. The `statement` dimension of a - point in the statement instance space representing an instance of - this statement is assigned this value (`int_id`). + A :class:`int` uniquely identifying the statement within a + :class:`PairwiseScheduleBuilder`. A :class:`PairwiseScheduleBuilder` + builds a mapping from points in a space of statement instances to + points in a lexicographic ordering. The `statement` dimension of a + point in the statement instance space representing an instance of + this statement is assigned this value (`int_id`). """ @@ -81,13 +81,13 @@ class StatementInstanceSet(object): .. attribute:: stmt_ref - A :class:`StatementRef`. + A :class:`StatementRef`. .. attribute:: lex_points - A list containing one value for each dimension in a lexicographic - ordering. These values describe the ordering of the statements, - and may be :class:`str` :mod:`loopy` inames or :class:`int`. + A list containing one value for each dimension in a lexicographic + ordering. These values describe the ordering of the statements, + and may be :class:`str` :mod:`loopy` inames or :class:`int`. """ @@ -111,35 +111,35 @@ class PairwiseScheduleBuilder(object): .. attribute:: stmt_instance_before - A :class:`StatementInstanceSet` whose ordering relative - to `stmt_instance_after is described by PairwiseScheduleBuilder. This - is achieved by mapping the statement instances in both sets to points - in a single lexicographic ordering. Points in lexicographic ordering - are represented as a list of :class:`int` or as :class:`str` - :mod:`loopy` inames. + A :class:`StatementInstanceSet` whose ordering relative + to `stmt_instance_after is described by PairwiseScheduleBuilder. This + is achieved by mapping the statement instances in both sets to points + in a single lexicographic ordering. Points in lexicographic ordering + are represented as a list of :class:`int` or as :class:`str` + :mod:`loopy` inames. .. attribute:: stmt_instance_after - A :class:`StatementInstanceSet` whose ordering relative - to `stmt_instance_before is described by PairwiseScheduleBuilder. This - is achieved by mapping the statement instances in both sets to points - in a single lexicographic ordering. Points in lexicographic ordering - are represented as a list of :class:`int` or as :class:`str` - :mod:`loopy` inames. + A :class:`StatementInstanceSet` whose ordering relative + to `stmt_instance_before is described by PairwiseScheduleBuilder. This + is achieved by mapping the statement instances in both sets to points + in a single lexicographic ordering. Points in lexicographic ordering + are represented as a list of :class:`int` or as :class:`str` + :mod:`loopy` inames. .. attribute:: statement_var_name - A :class:`str` specifying the name of the isl variable used - to represent the unique :class:`int` statement id. + A :class:`str` specifying the name of the isl variable used + to represent the unique :class:`int` statement id. .. attribute:: lex_var_prefix - A :class:`str` specifying the prefix to be used for the variables - representing the dimensions in the lexicographic ordering. E.g., - a prefix of "_lp_linchk_lex" might yield variables "_lp_linchk_lex0", - "_lp_linchk_lex1", "_lp_linchk_lex2". Note the identifier prefix - policies described in the documentation under - *Loopy's Model of a Kernel* -> *Identifiers*. + A :class:`str` specifying the prefix to be used for the variables + representing the dimensions in the lexicographic ordering. E.g., + a prefix of "_lp_linchk_lex" might yield variables "_lp_linchk_lex0", + "_lp_linchk_lex1", "_lp_linchk_lex2". Note the identifier prefix + policies described in the documentation under + *Loopy's Model of a Kernel* -> *Identifiers*. Example usage:: From 6b0b01bd10aeffc7afbf9f0050b3e04e84710577 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 2 Jun 2020 12:49:20 -0500 Subject: [PATCH 064/315] remove redundant usage example and note that a PairwiseScheduleBuilder should be created using get_schedule_for_statement_pair --- loopy/schedule/checker/__init__.py | 2 +- loopy/schedule/checker/schedule.py | 68 +----------------------------- 2 files changed, 3 insertions(+), 67 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 4489ca69b..8c4b06b0d 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -71,7 +71,7 @@ def get_schedule_for_statement_pair( # Get a linearization knl = lp.get_one_linearized_kernel(lp.preprocess_kernel(knl)) - # Get a pairwise schedule* ------------------------------------------- + # Get a pairwise schedule -------------------------------------------- from loopy.schedule.checker import ( get_schedule_for_statement_pair, diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 459ab4fcb..12547d01c 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -107,7 +107,8 @@ class PairwiseScheduleBuilder(object): """Given a pair of statements in a linearized kernel, PairwiseScheduleBuilder determines the (relative) order in which the instances are executed, by creating a mapping from statement instances to points in a single - lexicographic ordering. + lexicographic ordering. To create a PairwiseScheduleBuilder, use + :func:`loopy.schedule.checker.get_schedule_for_statement_pair`. .. attribute:: stmt_instance_before @@ -141,71 +142,6 @@ class PairwiseScheduleBuilder(object): policies described in the documentation under *Loopy's Model of a Kernel* -> *Identifiers*. - Example usage:: - - # Make kernel -------------------------------------------------------- - knl = lp.make_kernel( - "{[i,j,k]: 0<=i { - [_lp_linchk_statement = 0, i, j, k] -> - [_lp_linchk_l0 = 0, _lp_linchk_l1 = i, _lp_linchk_l2 = 0, - _lp_linchk_l3 = j, _lp_linchk_l4 = 0] : - 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } - [pi, pj, pk] -> { - [_lp_linchk_statement = 1, i, j, k] -> - [_lp_linchk_l0 = 0, _lp_linchk_l1 = i, _lp_linchk_l2 = 1, - _lp_linchk_l3 = k, _lp_linchk_l4 = 0] : - 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } - """ statement_var_name = "_lp_linchk_statement" From bdef0a639f8a4dd9a6ceb9d58c74650437861831 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 2 Jun 2020 12:55:56 -0500 Subject: [PATCH 065/315] rephrase doc comment about using get_schedule_for_statement_pair to create a PairwiseScheduleBuilder --- 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 12547d01c..756b85628 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -107,8 +107,9 @@ class PairwiseScheduleBuilder(object): """Given a pair of statements in a linearized kernel, PairwiseScheduleBuilder determines the (relative) order in which the instances are executed, by creating a mapping from statement instances to points in a single - lexicographic ordering. To create a PairwiseScheduleBuilder, use - :func:`loopy.schedule.checker.get_schedule_for_statement_pair`. + lexicographic ordering. The function + :func:`loopy.schedule.checker.get_schedule_for_statement_pair` is the + preferred method of creating a PairwiseScheduleBuilder. .. attribute:: stmt_instance_before From 66283621373e8706b17795cb40e949dc2457c6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kl=C3=B6ckner?= Date: Wed, 3 Jun 2020 01:03:55 +0200 Subject: [PATCH 066/315] Some styling fixes for pairwise schedule representation --- doc/ref_kernel.rst | 2 ++ loopy/schedule/checker/__init__.py | 28 +++++++++++++++++----------- loopy/schedule/checker/schedule.py | 10 +++------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/doc/ref_kernel.rst b/doc/ref_kernel.rst index af35221ad..1c4d8971d 100644 --- a/doc/ref_kernel.rst +++ b/doc/ref_kernel.rst @@ -154,6 +154,8 @@ Tag Meaning Identifiers ----------- +.. _reserved-identifiers: + Reserved Identifiers ^^^^^^^^^^^^^^^^^^^^ diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 8c4b06b0d..64d3d7c66 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -21,7 +21,7 @@ """ -# {{{ Create PairwiseScheduleBuilder for statement pair +# {{{ create PairwiseScheduleBuilder for statement pair def get_schedule_for_statement_pair( knl, @@ -30,9 +30,9 @@ def get_schedule_for_statement_pair( insn_id_after, ): """Create a :class:`loopy.schedule.checker.schedule.PairwiseScheduleBuilder` - representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.StatementInstanceSet` - to lexicographic time. + representing the order of two statements as a mapping from + :class:`loopy.schedule.checker.StatementInstanceSet` + to lexicographic time. :arg knl: A :class:`loopy.kernel.LoopKernel` containing the linearization items that will be used to create a schedule. @@ -109,12 +109,15 @@ def get_schedule_for_statement_pair( """ - # {{{ Preprocess if not already preprocessed + # {{{ preprocess if not already preprocessed + from loopy import preprocess_kernel preproc_knl = preprocess_kernel(knl) + # }}} - # {{{ Find any EnterLoop inames that are tagged as concurrent + # {{{ find any EnterLoop inames that are tagged as concurrent + # so that PairwiseScheduleBuilder 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. @@ -132,9 +135,11 @@ def get_schedule_for_statement_pair( "get_schedule_for_statement_pair encountered EnterLoop for inames %s " "with ConcurrentTag(s) in linearization for kernel %s. " "Ignoring these loops." % (conc_loop_inames, preproc_knl.name)) + # }}} # {{{ Create PairwiseScheduleBuilder: mapping of {statement instance: lex point} + # include only instructions involved in this dependency from loopy.schedule.checker.schedule import PairwiseScheduleBuilder return PairwiseScheduleBuilder( @@ -143,17 +148,18 @@ def get_schedule_for_statement_pair( insn_id_after, loops_to_ignore=conc_loop_inames, ) + # }}} # }}} -# {{{ Get isl map pair from PairwiseScheduleBuilder +# {{{ get_isl_maps_from_PairwiseScheduleBuilder def get_isl_maps_from_PairwiseScheduleBuilder(sched_builder, knl): - """Create a pair of :class:`islpy.Map`s representing a - sub-schedule as two mappings from statement instances to lexicographic - time, one for the dependee statement and one for the depender. + """Create a pair of :class:`islpy.Map`\ s representing a + sub-schedule as two mappings from statement instances to lexicographic + time, one for the dependee statement and one for the depender. :arg sched_builder: A :class:`loopy.schedule.checker.schedule.PairwiseScheduleBuilder` @@ -164,7 +170,7 @@ def get_isl_maps_from_PairwiseScheduleBuilder(sched_builder, knl): :arg knl: A :class:`loopy.kernel.LoopKernel` containing the linearization items that will be used to create a schedule. - :returns: A two-tuple containing two :class:`islpy.Map`s + :returns: A two-tuple containing two :class:`islpy.Map`\ s representing the schedule as two mappings from statement instances to lexicographic time, one for the dependee and one for the depender. diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 756b85628..6dc091f9e 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -38,7 +38,7 @@ class StatementRef(object): builds a mapping from points in a space of statement instances to points in a lexicographic ordering. The `statement` dimension of a point in the statement instance space representing an instance of - this statement is assigned this value (`int_id`). + this statement is assigned this value. """ @@ -88,7 +88,6 @@ class StatementInstanceSet(object): A list containing one value for each dimension in a lexicographic ordering. These values describe the ordering of the statements, and may be :class:`str` :mod:`loopy` inames or :class:`int`. - """ def __init__( @@ -131,7 +130,7 @@ class PairwiseScheduleBuilder(object): .. attribute:: statement_var_name - A :class:`str` specifying the name of the isl variable used + A :class:`str` specifying the name of the variable used to represent the unique :class:`int` statement id. .. attribute:: lex_var_prefix @@ -139,10 +138,7 @@ class PairwiseScheduleBuilder(object): A :class:`str` specifying the prefix to be used for the variables representing the dimensions in the lexicographic ordering. E.g., a prefix of "_lp_linchk_lex" might yield variables "_lp_linchk_lex0", - "_lp_linchk_lex1", "_lp_linchk_lex2". Note the identifier prefix - policies described in the documentation under - *Loopy's Model of a Kernel* -> *Identifiers*. - + "_lp_linchk_lex1", "_lp_linchk_lex2". Cf. :ref:`reserved-identifiers`. """ statement_var_name = "_lp_linchk_statement" From 0bb444450e327a11aae08ce9e26c441e0d706057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kl=C3=B6ckner?= Date: Wed, 3 Jun 2020 01:32:19 +0200 Subject: [PATCH 067/315] Placate flake8 --- 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 64d3d7c66..790088d5c 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -117,7 +117,7 @@ def get_schedule_for_statement_pair( # }}} # {{{ find any EnterLoop inames that are tagged as concurrent - + # so that PairwiseScheduleBuilder 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. @@ -157,7 +157,7 @@ def get_schedule_for_statement_pair( # {{{ get_isl_maps_from_PairwiseScheduleBuilder def get_isl_maps_from_PairwiseScheduleBuilder(sched_builder, knl): - """Create a pair of :class:`islpy.Map`\ s representing a + r"""Create a pair of :class:`islpy.Map`\ s representing a sub-schedule as two mappings from statement instances to lexicographic time, one for the dependee statement and one for the depender. From 5dafc30ab3e7f189f80980d21064b6bc6dff2c5a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 5 Jun 2020 06:27:08 -0500 Subject: [PATCH 068/315] remove get_isl_maps_from_PairwiseScheduleBuilder(); instead get j inames domains inside PairwiseScheduleBuilder.create_isl_maps() and just call PairwiseScheduleBuilder.create_isl_maps directly --- loopy/schedule/checker/__init__.py | 50 +++--------------------------- loopy/schedule/checker/schedule.py | 29 +++++++++-------- test/test_linearization_checker.py | 19 ++++-------- 3 files changed, 24 insertions(+), 74 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 8c4b06b0d..b287ca4b7 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -57,7 +57,7 @@ def get_schedule_for_statement_pair( Example usage:: - # Make kernel -------------------------------------------------------- + # Make kernel ------------------------------------------------------------ knl = lp.make_kernel( "{[i,j,k]: 0<=i used in statement domain>) -> @@ -389,11 +390,9 @@ def _get_isl_map_for_stmt_inst( map_before = _get_isl_map_for_stmt_inst( self.stmt_instance_before, - dom_before, dom_inames_ordered_before) map_after = _get_isl_map_for_stmt_inst( self.stmt_instance_after, - dom_after, dom_inames_ordered_after) return (map_before, map_after) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 396fccf4f..02ac08592 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -50,7 +50,6 @@ def test_lexschedule_and_islmap_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, @@ -138,8 +137,7 @@ def test_lexschedule_and_islmap_creation(): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = get_isl_maps_from_PairwiseScheduleBuilder( - sched_ab, knl) + isl_sched_before, isl_sched_after = sched_ab.create_isl_maps(knl) # Create expected maps, align, compare @@ -174,8 +172,7 @@ def test_lexschedule_and_islmap_creation(): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = get_isl_maps_from_PairwiseScheduleBuilder( - sched_ac, knl) + isl_sched_before, isl_sched_after = sched_ac.create_isl_maps(knl) # Create expected maps, align, compare @@ -213,8 +210,7 @@ def perform_insn_ad_checks_with(sid_a, sid_d): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = \ - get_isl_maps_from_PairwiseScheduleBuilder(sched_ad, knl) + isl_sched_before, isl_sched_after = sched_ad.create_isl_maps(knl) # Create expected maps, align, compare @@ -259,8 +255,7 @@ def perform_insn_bc_checks_with(sid_b, sid_c): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = \ - get_isl_maps_from_PairwiseScheduleBuilder(sched_bc, knl) + isl_sched_before, isl_sched_after = sched_bc.create_isl_maps(knl) # Create expected maps, align, compare @@ -305,8 +300,7 @@ def perform_insn_bd_checks_with(sid_b, sid_d): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = \ - get_isl_maps_from_PairwiseScheduleBuilder(sched_bd, knl) + isl_sched_before, isl_sched_after = sched_bd.create_isl_maps(knl) # Create expected maps, align, compare @@ -351,8 +345,7 @@ def perform_insn_cd_checks_with(sid_c, sid_d): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = \ - get_isl_maps_from_PairwiseScheduleBuilder(sched_cd, knl) + isl_sched_before, isl_sched_after = sched_cd.create_isl_maps(knl) # Create expected maps, align, compare From bb2ebcf84438be2678be35a3fb3cea2e543783ad Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 5 Jun 2020 09:09:09 -0500 Subject: [PATCH 069/315] print name of class in PairwiseScheduleBuilder.__str__() --- loopy/schedule/checker/schedule.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 37e5a5f4c..882bcc73f 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -405,6 +405,7 @@ def stringify_sched_stmt_instance(stmt_inst): stmt_inst.stmt_ref.int_id, stmt_inst.lex_points) - return "Before: %s\nAfter: %s" % ( + return "%s(\nBefore: %s\nAfter: %s\n)" % ( + self.__class__.__name__, stringify_sched_stmt_instance(self.stmt_instance_before), stringify_sched_stmt_instance(self.stmt_instance_after)) From a87f101a6b6339319eb9129a040304792d821389 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 5 Jun 2020 09:11:15 -0500 Subject: [PATCH 070/315] rename pose->idx --- loopy/schedule/checker/utils.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index eb7707f67..af9e4aaef 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -35,12 +35,12 @@ def get_islvars_from_space(space): return isl.make_zero_and_vars(in_names+out_names, param_names) -def add_dims_to_isl_set(isl_set, dim_type, names, new_pose_start): +def add_dims_to_isl_set(isl_set, dim_type, names, new_idx_start): new_set = isl_set.insert_dims( - dim_type, new_pose_start, len(names) - ).set_dim_name(dim_type, new_pose_start, names[0]) + 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_pose_start+1+i, name) + new_set = new_set.set_dim_name(dim_type, new_idx_start+1+i, name) return new_set @@ -90,27 +90,27 @@ def reorder_dims_by_name( other_dim_len = len(isl_set.get_var_names(other_dim_type)) new_set = isl_set.copy() - for desired_pose, name in enumerate(desired_dims_ordered): + for desired_idx, name in enumerate(desired_dims_ordered): # if iname doesn't exist in set, add dim: if name not in new_set.get_var_names(dim_type): if add_missing: # insert missing dim in correct location new_set = new_set.insert_dims( - dim_type, desired_pose, 1 + dim_type, desired_idx, 1 ).set_dim_name( - dim_type, desired_pose, name) + dim_type, desired_idx, name) else: # iname exists in set - current_pose = new_set.find_dim_by_name(dim_type, name) - if current_pose != desired_pose: - # move_dims(dst_type, dst_pose, src_type, src_pose, n) + current_idx = new_set.find_dim_by_name(dim_type, name) + if current_idx != desired_idx: + # move_dims(dst_type, dst_idx, src_type, src_idx, n) # first move to other dim because isl is stupid new_set = new_set.move_dims( - other_dim_type, other_dim_len, dim_type, current_pose, 1) + other_dim_type, other_dim_len, dim_type, current_idx, 1) # now move it where we actually want it new_set = new_set.move_dims( - dim_type, desired_pose, other_dim_type, other_dim_len, 1) + dim_type, desired_idx, other_dim_type, other_dim_len, 1) return new_set From 57669bc184019b3d8ee86f0600f2242aeb657504 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 5 Jun 2020 09:55:41 -0500 Subject: [PATCH 071/315] change __str__ to __repr__ in StatementInstanceSet() and include class name in string --- 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 882bcc73f..dbb2a7455 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -98,8 +98,9 @@ def __init__( self.stmt_ref = stmt_ref self.lex_points = lex_points - def __str__(self): - return "{%s, %s}" % (self.stmt_ref, self.lex_points) + def __repr__(self): + return "%s(%s, %s)" % ( + self.__class__.__name__, self.stmt_ref, self.lex_points) class PairwiseScheduleBuilder(object): From e3a4db902e49ee92b228219ac9cdce62a324137c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 7 Jun 2020 15:24:42 -0500 Subject: [PATCH 072/315] rename _get_isl_map_for_stmt_inst()->_get_map_for_stmt_inst() --- loopy/schedule/checker/schedule.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index dbb2a7455..dc55a3bcd 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -347,7 +347,7 @@ def create_isl_maps( params_sched = [] out_names_sched = self.get_lex_var_names() - def _get_isl_map_for_stmt_inst(stmt_inst, dom_inames_ordered): + def _get_map_for_stmt_inst(stmt_inst, dom_inames_ordered): # Get inames domain for statement instance (a BasicSet) dom = knl.get_inames_domain( @@ -385,10 +385,10 @@ def _get_isl_map_for_stmt_inst(stmt_inst, dom_inames_ordered): space=sched_space, ) - map_before = _get_isl_map_for_stmt_inst( + map_before = _get_map_for_stmt_inst( self.stmt_instance_before, dom_inames_ordered_before) - map_after = _get_isl_map_for_stmt_inst( + map_after = _get_map_for_stmt_inst( self.stmt_instance_after, dom_inames_ordered_after) From 0e317270aeebd9e154c4e307d27cdb7b4375a07d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 7 Jun 2020 15:30:34 -0500 Subject: [PATCH 073/315] rename create_isl_maps()->build_maps() --- loopy/schedule/checker/__init__.py | 2 +- loopy/schedule/checker/schedule.py | 2 +- test/test_linearization_checker.py | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 9698b95fc..6fd280a45 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -85,7 +85,7 @@ def get_schedule_for_statement_pair( # Get two isl maps from the PairwiseScheduleBuilder ---------------------- - sched_a, sched_b = sched_builder_ab.create_isl_maps(knl) + sched_a, sched_b = sched_builder_ab.build_maps(knl) print(sched_a) print(sched_b) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index dc55a3bcd..c9cc5981e 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -303,7 +303,7 @@ def _pad_lex_tuple_with_zeros(stmt_inst, length): self.stmt_instance_after = _pad_lex_tuple_with_zeros( self.stmt_instance_after, max_lex_dim) - def create_isl_maps( + def build_maps( self, knl, dom_inames_ordered_before=None, diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 02ac08592..16c56274d 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -137,7 +137,7 @@ def test_lexschedule_and_islmap_creation(): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_ab.create_isl_maps(knl) + isl_sched_before, isl_sched_after = sched_ab.build_maps(knl) # Create expected maps, align, compare @@ -172,7 +172,7 @@ def test_lexschedule_and_islmap_creation(): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_ac.create_isl_maps(knl) + isl_sched_before, isl_sched_after = sched_ac.build_maps(knl) # Create expected maps, align, compare @@ -210,7 +210,7 @@ def perform_insn_ad_checks_with(sid_a, sid_d): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_ad.create_isl_maps(knl) + isl_sched_before, isl_sched_after = sched_ad.build_maps(knl) # Create expected maps, align, compare @@ -255,7 +255,7 @@ def perform_insn_bc_checks_with(sid_b, sid_c): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_bc.create_isl_maps(knl) + isl_sched_before, isl_sched_after = sched_bc.build_maps(knl) # Create expected maps, align, compare @@ -300,7 +300,7 @@ def perform_insn_bd_checks_with(sid_b, sid_d): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_bd.create_isl_maps(knl) + isl_sched_before, isl_sched_after = sched_bd.build_maps(knl) # Create expected maps, align, compare @@ -345,7 +345,7 @@ def perform_insn_cd_checks_with(sid_c, sid_d): # Get two isl maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_cd.create_isl_maps(knl) + isl_sched_before, isl_sched_after = sched_cd.build_maps(knl) # Create expected maps, align, compare From 3e93b622192980ecd6c1a2b46391a25497e60127 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 7 Jun 2020 15:45:21 -0500 Subject: [PATCH 074/315] rename isl_map->map_obj --- loopy/schedule/checker/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index af9e4aaef..5c8ae05f2 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -23,8 +23,8 @@ import islpy as isl -def prettier_map_string(isl_map): - return str(isl_map +def prettier_map_string(map_obj): + return str(map_obj ).replace("{ ", "{\n").replace(" }", "\n}").replace("; ", ";\n") From d345c21fc0b6cc4c6c4de3b403c1565f4f35ec17 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 7 Jun 2020 16:00:32 -0500 Subject: [PATCH 075/315] 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 ee4d98fbef071df03daaa6c99f36e3b10aae1881 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 8 Jun 2020 14:13:15 -0500 Subject: [PATCH 076/315] renamed create_symbolic_isl_map_from_tuples()->create_symbolic_map_from_tuples() --- loopy/schedule/checker/schedule.py | 4 ++-- loopy/schedule/checker/utils.py | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index c9cc5981e..d63bb9c41 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -340,7 +340,7 @@ def build_maps( from loopy.schedule.checker.utils import ( list_var_names_in_isl_sets, get_isl_space, - create_symbolic_isl_map_from_tuples, + create_symbolic_map_from_tuples, add_dims_to_isl_set, ) @@ -380,7 +380,7 @@ def _get_map_for_stmt_inst(stmt_inst, dom_inames_ordered): )] # create isl map - return create_symbolic_isl_map_from_tuples( + return create_symbolic_map_from_tuples( tuple_pairs_with_domains=zip(tuple_pair, dom_to_intersect), space=sched_space, ) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 5c8ae05f2..8e65d9905 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -161,7 +161,7 @@ def list_var_names_in_isl_sets( return sorted(list(inames)) -def create_symbolic_isl_map_from_tuples( +def create_symbolic_map_from_tuples( tuple_pairs_with_domains, space, ): @@ -191,7 +191,6 @@ def create_symbolic_isl_map_from_tuples( dim_type = isl.dim_type - #param_names = space.get_var_names(isl.dim_type.param) space_out_names = space.get_var_names(dim_type.out) space_in_names = space.get_var_names(isl.dim_type.in_) From 6e2becf4da7f0567ab801bb012ee4dd9a48055bc Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 8 Jun 2020 14:29:40 -0500 Subject: [PATCH 077/315] remove 'isl' from more locally used var names --- loopy/schedule/checker/__init__.py | 2 +- loopy/schedule/checker/schedule.py | 6 +- test/test_linearization_checker.py | 122 ++++++++++++++--------------- 3 files changed, 65 insertions(+), 65 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 6fd280a45..716a0cb58 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -83,7 +83,7 @@ def get_schedule_for_statement_pair( "insn_b", ) - # Get two isl maps from the PairwiseScheduleBuilder ---------------------- + # Get two maps from the PairwiseScheduleBuilder -------------------------- sched_a, sched_b = sched_builder_ab.build_maps(knl) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index d63bb9c41..8c503b191 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -353,7 +353,7 @@ def _get_map_for_stmt_inst(stmt_inst, dom_inames_ordered): dom = knl.get_inames_domain( knl.id_to_insn[stmt_inst.stmt_ref.insn_id].within_inames) - # create an isl space + # create space (an isl space in current implementation) # {('statement', used in statement domain>) -> # (lexicographic ordering dims)} if dom_inames_ordered is None: @@ -370,7 +370,7 @@ def _get_map_for_stmt_inst(stmt_inst, dom_inames_ordered): add_dims_to_isl_set( dom, isl.dim_type.set, [self.statement_var_name], 0), ] - # Each isl map representing the schedule will map + # Each map representing the schedule will map # statement instances -> lex time. # Right now, statement instance tuples consist of single int. # Add all inames from domains to each map domain tuple. @@ -379,7 +379,7 @@ def _get_map_for_stmt_inst(stmt_inst, dom_inames_ordered): stmt_inst.lex_points )] - # create isl map + # create map return create_symbolic_map_from_tuples( 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 16c56274d..559a5c24e 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -46,7 +46,7 @@ faulthandler.enable() -def test_lexschedule_and_islmap_creation(): +def test_lexschedule_and_map_creation(): import islpy as isl from loopy.schedule.checker import ( get_schedule_for_statement_pair, @@ -135,34 +135,34 @@ def test_lexschedule_and_islmap_creation(): assert sched_ab.stmt_instance_before.lex_points == [0, 'i', 0, 'k', 0] assert sched_ab.stmt_instance_after.lex_points == [0, 'i', 1, 'j', 0] - # Get two isl maps from the PairwiseScheduleBuilder + # Get two maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_ab.build_maps(knl) + sched_map_before, sched_map_after = sched_ab.build_maps(knl) # Create expected maps, align, compare - isl_sched_before_expected = isl.Map( + sched_map_before_expected = isl.Map( "[pi, pk] -> { " "[_lp_linchk_statement=0, i, k] -> " "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=k, " "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) - isl_sched_before_expected = align_isl_maps_by_var_names( - isl_sched_before_expected, isl_sched_before) + sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected, sched_map_before) - isl_sched_after_expected = isl.Map( + sched_map_after_expected = isl.Map( "[pi, pj] -> { " "[_lp_linchk_statement=1, i, j] -> " "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=1, _lp_linchk_l3=j, " "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) - isl_sched_after_expected = align_isl_maps_by_var_names( - isl_sched_after_expected, isl_sched_after) + sched_map_after_expected = align_isl_maps_by_var_names( + sched_map_after_expected, sched_map_after) - assert isl_sched_before == isl_sched_before_expected - assert isl_sched_after == isl_sched_after_expected + assert sched_map_before == sched_map_before_expected + assert sched_map_after == sched_map_after_expected # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_c --------------------------------------- @@ -170,34 +170,34 @@ def test_lexschedule_and_islmap_creation(): assert sched_ac.stmt_instance_before.lex_points == [0, 'i', 0, 'k', 0] assert sched_ac.stmt_instance_after.lex_points == [0, 'i', 1, 'j', 0] - # Get two isl maps from the PairwiseScheduleBuilder + # Get two maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_ac.build_maps(knl) + sched_map_before, sched_map_after = sched_ac.build_maps(knl) # Create expected maps, align, compare - isl_sched_before_expected = isl.Map( + sched_map_before_expected = isl.Map( "[pi, pk] -> { " "[_lp_linchk_statement=0, i, k] -> " "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=k, " "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) - isl_sched_before_expected = align_isl_maps_by_var_names( - isl_sched_before_expected, isl_sched_before) + sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected, sched_map_before) - isl_sched_after_expected = isl.Map( + sched_map_after_expected = isl.Map( "[pi, pj] -> { " "[_lp_linchk_statement=1, i, j] -> " "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=1, _lp_linchk_l3=j, " "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) - isl_sched_after_expected = align_isl_maps_by_var_names( - isl_sched_after_expected, isl_sched_after) + sched_map_after_expected = align_isl_maps_by_var_names( + sched_map_after_expected, sched_map_after) - assert isl_sched_before == isl_sched_before_expected - assert isl_sched_after == isl_sched_after_expected + assert sched_map_before == sched_map_before_expected + assert sched_map_after == sched_map_after_expected # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_d --------------------------------------- @@ -208,13 +208,13 @@ def perform_insn_ad_checks_with(sid_a, sid_d): assert sched_ad.stmt_instance_before.lex_points == [sid_a, 'i', 0, 'k', 0] assert sched_ad.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] - # Get two isl maps from the PairwiseScheduleBuilder + # Get two maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_ad.build_maps(knl) + sched_map_before, sched_map_after = sched_ad.build_maps(knl) # Create expected maps, align, compare - isl_sched_before_expected = isl.Map( + sched_map_before_expected = isl.Map( "[pi, pk] -> { " "[_lp_linchk_statement=%d, i, k] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=k, " @@ -222,10 +222,10 @@ def perform_insn_ad_checks_with(sid_a, sid_d): "0 <= i < pi and 0 <= k < pk }" % (sid_a, sid_a) ) - isl_sched_before_expected = align_isl_maps_by_var_names( - isl_sched_before_expected, isl_sched_before) + sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected, sched_map_before) - isl_sched_after_expected = isl.Map( + sched_map_after_expected = isl.Map( "[pt] -> { " "[_lp_linchk_statement=%d, t] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " @@ -233,11 +233,11 @@ def perform_insn_ad_checks_with(sid_a, sid_d): "0 <= t < pt }" % (sid_d, sid_d) ) - isl_sched_after_expected = align_isl_maps_by_var_names( - isl_sched_after_expected, isl_sched_after) + sched_map_after_expected = align_isl_maps_by_var_names( + sched_map_after_expected, sched_map_after) - assert isl_sched_before == isl_sched_before_expected - assert isl_sched_after == isl_sched_after_expected + assert sched_map_before == sched_map_before_expected + assert sched_map_after == sched_map_after_expected if sched_ad.stmt_instance_before.stmt_ref.int_id == 0: perform_insn_ad_checks_with(0, 1) @@ -253,13 +253,13 @@ def perform_insn_bc_checks_with(sid_b, sid_c): assert sched_bc.stmt_instance_before.lex_points == [0, 'i', 0, 'j', sid_b] assert sched_bc.stmt_instance_after.lex_points == [0, 'i', 0, 'j', sid_c] - # Get two isl maps from the PairwiseScheduleBuilder + # Get two maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_bc.build_maps(knl) + sched_map_before, sched_map_after = sched_bc.build_maps(knl) # Create expected maps, align, compare - isl_sched_before_expected = isl.Map( + sched_map_before_expected = isl.Map( "[pi, pj] -> { " "[_lp_linchk_statement=%d, i, j] -> " "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " @@ -267,10 +267,10 @@ def perform_insn_bc_checks_with(sid_b, sid_c): "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) - isl_sched_before_expected = align_isl_maps_by_var_names( - isl_sched_before_expected, isl_sched_before) + sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected, sched_map_before) - isl_sched_after_expected = isl.Map( + sched_map_after_expected = isl.Map( "[pi, pj] -> { " "[_lp_linchk_statement=%d, i, j] -> " "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " @@ -278,11 +278,11 @@ def perform_insn_bc_checks_with(sid_b, sid_c): "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) - isl_sched_after_expected = align_isl_maps_by_var_names( - isl_sched_after_expected, isl_sched_after) + sched_map_after_expected = align_isl_maps_by_var_names( + sched_map_after_expected, sched_map_after) - assert isl_sched_before == isl_sched_before_expected - assert isl_sched_after == isl_sched_after_expected + assert sched_map_before == sched_map_before_expected + assert sched_map_after == sched_map_after_expected if sched_bc.stmt_instance_before.stmt_ref.int_id == 0: perform_insn_bc_checks_with(0, 1) @@ -298,13 +298,13 @@ def perform_insn_bd_checks_with(sid_b, sid_d): assert sched_bd.stmt_instance_before.lex_points == [sid_b, 'i', 0, 'j', 0] assert sched_bd.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] - # Get two isl maps from the PairwiseScheduleBuilder + # Get two maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_bd.build_maps(knl) + sched_map_before, sched_map_after = sched_bd.build_maps(knl) # Create expected maps, align, compare - isl_sched_before_expected = isl.Map( + sched_map_before_expected = isl.Map( "[pi, pj] -> { " "[_lp_linchk_statement=%d, i, j] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " @@ -312,10 +312,10 @@ def perform_insn_bd_checks_with(sid_b, sid_d): "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) - isl_sched_before_expected = align_isl_maps_by_var_names( - isl_sched_before_expected, isl_sched_before) + sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected, sched_map_before) - isl_sched_after_expected = isl.Map( + sched_map_after_expected = isl.Map( "[pt] -> { " "[_lp_linchk_statement=%d, t] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " @@ -323,11 +323,11 @@ def perform_insn_bd_checks_with(sid_b, sid_d): "0 <= t < pt }" % (sid_d, sid_d) ) - isl_sched_after_expected = align_isl_maps_by_var_names( - isl_sched_after_expected, isl_sched_after) + sched_map_after_expected = align_isl_maps_by_var_names( + sched_map_after_expected, sched_map_after) - assert isl_sched_before == isl_sched_before_expected - assert isl_sched_after == isl_sched_after_expected + assert sched_map_before == sched_map_before_expected + assert sched_map_after == sched_map_after_expected if sched_bd.stmt_instance_before.stmt_ref.int_id == 0: perform_insn_bd_checks_with(0, 1) @@ -343,13 +343,13 @@ def perform_insn_cd_checks_with(sid_c, sid_d): assert sched_cd.stmt_instance_before.lex_points == [sid_c, 'i', 0, 'j', 0] assert sched_cd.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] - # Get two isl maps from the PairwiseScheduleBuilder + # Get two maps from the PairwiseScheduleBuilder - isl_sched_before, isl_sched_after = sched_cd.build_maps(knl) + sched_map_before, sched_map_after = sched_cd.build_maps(knl) # Create expected maps, align, compare - isl_sched_before_expected = isl.Map( + sched_map_before_expected = isl.Map( "[pi, pj] -> { " "[_lp_linchk_statement=%d, i, j] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " @@ -357,10 +357,10 @@ def perform_insn_cd_checks_with(sid_c, sid_d): "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) - isl_sched_before_expected = align_isl_maps_by_var_names( - isl_sched_before_expected, isl_sched_before) + sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected, sched_map_before) - isl_sched_after_expected = isl.Map( + sched_map_after_expected = isl.Map( "[pt] -> { " "[_lp_linchk_statement=%d, t] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " @@ -368,11 +368,11 @@ def perform_insn_cd_checks_with(sid_c, sid_d): "0 <= t < pt }" % (sid_d, sid_d) ) - isl_sched_after_expected = align_isl_maps_by_var_names( - isl_sched_after_expected, isl_sched_after) + sched_map_after_expected = align_isl_maps_by_var_names( + sched_map_after_expected, sched_map_after) - assert isl_sched_before == isl_sched_before_expected - assert isl_sched_after == isl_sched_after_expected + assert sched_map_before == sched_map_before_expected + assert sched_map_after == sched_map_after_expected if sched_cd.stmt_instance_before.stmt_ref.int_id == 0: perform_insn_cd_checks_with(0, 1) From f528b58622953390e5930c4ba1543ae2c17abae9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 8 Jun 2020 14:32:42 -0500 Subject: [PATCH 078/315] rename _union_of_isl_sets_or_maps()->_get_union() --- loopy/schedule/checker/utils.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 8e65d9905..4b51a16d1 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -143,9 +143,9 @@ def align_isl_maps_by_var_names(input_map, target_map): return aligned_input_map -def _union_of_isl_sets_or_maps(set_list): - union = set_list[0] - for s in set_list[1:]: +def _get_union(list_items): + union = list_items[0] + for s in list_items[1:]: union = union.union(s) return union @@ -247,7 +247,7 @@ def create_symbolic_map_from_tuples( all_maps.append( map_from_set.intersect_domain(dom_with_all_inames)) - return _union_of_isl_sets_or_maps(all_maps) + return _get_union(all_maps) def set_all_isl_space_names( From 7c2309ab23db59413b5fb3dbdf3cb58325087941 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 8 Jun 2020 14:42:59 -0500 Subject: [PATCH 079/315] 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 070ca3a534ea135607cbfd0717b2caef9b1d5a49 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 8 Jun 2020 16:31:06 -0500 Subject: [PATCH 080/315] create map_names_match_check() function for checking conditions on isl set/map name matching; use it to verify conditions before calling islpy.align_space() (which doesn't perform all necessary checks); TODO after making sure this works: remove now unused calls to reorder_dims_by_name() --- loopy/schedule/checker/utils.py | 54 +++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 4b51a16d1..852b24735 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -44,6 +44,27 @@ def add_dims_to_isl_set(isl_set, dim_type, names, new_idx_start): return new_set +def map_names_match_check( + obj_map, + desired_names, + dim_type, + assert_subset=True, + assert_permutation=True, + ): + + obj_map_names = obj_map.space.get_var_names(dim_type) + if assert_permutation: + if not set(obj_map_names) == set(desired_names): + raise ValueError( + "Set of map names %s for dim %s does not match target set %s" + % (obj_map_names, dim_type, desired_names)) + elif assert_subset: + if not set(obj_map_names).issubset(desired_names): + raise ValueError( + "Map names %s for dim %s are not a subset of target names %s" + % (obj_map_names, dim_type, desired_names)) + + def reorder_dims_by_name( isl_set, dim_type, desired_dims_ordered, add_missing=False, new_names_are_permutation_only=False): @@ -75,7 +96,10 @@ def reorder_dims_by_name( """ - assert set(isl_set.get_var_names(dim_type)).issubset(desired_dims_ordered) + map_names_match_check( + isl_set, desired_dims_ordered, dim_type, + assert_subset=True, assert_permutation=False) + assert dim_type != isl.dim_type.param if new_names_are_permutation_only and ( @@ -117,13 +141,23 @@ def reorder_dims_by_name( def align_isl_maps_by_var_names(input_map, target_map): + # first make sure names match + for dt in [isl.dim_type.in_, isl.dim_type.out, isl.dim_type.param]: + map_names_match_check( + input_map, target_map.get_var_names(dt), dt, + assert_permutation=True) + + aligned_input_map = isl.align_spaces(input_map, target_map) + + # TODO remove once satisfied that above can replace below: + # align params - aligned_input_map = input_map.align_params(target_map.space) + _aligned_input_map = input_map.align_params(target_map.space) # align in_ dims target_map_in_names = target_map.space.get_var_names(isl.dim_type.in_) - aligned_input_map = reorder_dims_by_name( - aligned_input_map, + _aligned_input_map = reorder_dims_by_name( + _aligned_input_map, isl.dim_type.in_, target_map_in_names, add_missing=False, @@ -132,14 +166,22 @@ def align_isl_maps_by_var_names(input_map, target_map): # align out dims target_map_out_names = target_map.space.get_var_names(isl.dim_type.out) - aligned_input_map = reorder_dims_by_name( - aligned_input_map, + _aligned_input_map = reorder_dims_by_name( + _aligned_input_map, isl.dim_type.out, target_map_out_names, add_missing=False, new_names_are_permutation_only=True, ) + assert aligned_input_map == _aligned_input_map + assert aligned_input_map.get_var_names( + isl.dim_type.param) == _aligned_input_map.get_var_names(isl.dim_type.param) + assert aligned_input_map.get_var_names( + isl.dim_type.in_) == _aligned_input_map.get_var_names(isl.dim_type.in_) + assert aligned_input_map.get_var_names( + isl.dim_type.out) == _aligned_input_map.get_var_names(isl.dim_type.out) + return aligned_input_map From 2f980346c719722ef61fb36055ec31705f17c534 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 8 Jun 2020 16:48:33 -0500 Subject: [PATCH 081/315] rename align_isl_maps_by_var_names()->ensure_dim_names_match_and_align() --- loopy/schedule/checker/utils.py | 43 ++++-------------------------- test/test_linearization_checker.py | 26 +++++++++--------- 2 files changed, 18 insertions(+), 51 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 852b24735..2a42a098f 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -139,50 +139,17 @@ def reorder_dims_by_name( return new_set -def align_isl_maps_by_var_names(input_map, target_map): +def ensure_dim_names_match_and_align(obj_map, tgt_map): # first make sure names match for dt in [isl.dim_type.in_, isl.dim_type.out, isl.dim_type.param]: map_names_match_check( - input_map, target_map.get_var_names(dt), dt, + obj_map, tgt_map.get_var_names(dt), dt, assert_permutation=True) - aligned_input_map = isl.align_spaces(input_map, target_map) - - # TODO remove once satisfied that above can replace below: - - # align params - _aligned_input_map = input_map.align_params(target_map.space) - - # align in_ dims - target_map_in_names = target_map.space.get_var_names(isl.dim_type.in_) - _aligned_input_map = reorder_dims_by_name( - _aligned_input_map, - isl.dim_type.in_, - target_map_in_names, - add_missing=False, - new_names_are_permutation_only=True, - ) - - # align out dims - target_map_out_names = target_map.space.get_var_names(isl.dim_type.out) - _aligned_input_map = reorder_dims_by_name( - _aligned_input_map, - isl.dim_type.out, - target_map_out_names, - add_missing=False, - new_names_are_permutation_only=True, - ) - - assert aligned_input_map == _aligned_input_map - assert aligned_input_map.get_var_names( - isl.dim_type.param) == _aligned_input_map.get_var_names(isl.dim_type.param) - assert aligned_input_map.get_var_names( - isl.dim_type.in_) == _aligned_input_map.get_var_names(isl.dim_type.in_) - assert aligned_input_map.get_var_names( - isl.dim_type.out) == _aligned_input_map.get_var_names(isl.dim_type.out) - - return aligned_input_map + aligned_obj_map = isl.align_spaces(obj_map, tgt_map) + + return aligned_obj_map def _get_union(list_items): diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 559a5c24e..41ac16feb 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -52,7 +52,7 @@ def test_lexschedule_and_map_creation(): get_schedule_for_statement_pair, ) from loopy.schedule.checker.utils import ( - align_isl_maps_by_var_names, + ensure_dim_names_match_and_align, ) # example kernel @@ -148,7 +148,7 @@ def test_lexschedule_and_map_creation(): "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) - sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected = ensure_dim_names_match_and_align( sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( @@ -158,7 +158,7 @@ def test_lexschedule_and_map_creation(): "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) - sched_map_after_expected = align_isl_maps_by_var_names( + 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 @@ -183,7 +183,7 @@ def test_lexschedule_and_map_creation(): "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= k < pk }" ) - sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected = ensure_dim_names_match_and_align( sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( @@ -193,7 +193,7 @@ def test_lexschedule_and_map_creation(): "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= j < pj }" ) - sched_map_after_expected = align_isl_maps_by_var_names( + 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 @@ -222,7 +222,7 @@ def perform_insn_ad_checks_with(sid_a, sid_d): "0 <= i < pi and 0 <= k < pk }" % (sid_a, sid_a) ) - sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected = ensure_dim_names_match_and_align( sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( @@ -233,7 +233,7 @@ def perform_insn_ad_checks_with(sid_a, sid_d): "0 <= t < pt }" % (sid_d, sid_d) ) - sched_map_after_expected = align_isl_maps_by_var_names( + 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 @@ -267,7 +267,7 @@ def perform_insn_bc_checks_with(sid_b, sid_c): "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) - sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected = ensure_dim_names_match_and_align( sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( @@ -278,7 +278,7 @@ def perform_insn_bc_checks_with(sid_b, sid_c): "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) - sched_map_after_expected = align_isl_maps_by_var_names( + 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 @@ -312,7 +312,7 @@ def perform_insn_bd_checks_with(sid_b, sid_d): "0 <= i < pi and 0 <= j < pj }" % (sid_b, sid_b) ) - sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected = ensure_dim_names_match_and_align( sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( @@ -323,7 +323,7 @@ def perform_insn_bd_checks_with(sid_b, sid_d): "0 <= t < pt }" % (sid_d, sid_d) ) - sched_map_after_expected = align_isl_maps_by_var_names( + 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 @@ -357,7 +357,7 @@ def perform_insn_cd_checks_with(sid_c, sid_d): "0 <= i < pi and 0 <= j < pj }" % (sid_c, sid_c) ) - sched_map_before_expected = align_isl_maps_by_var_names( + sched_map_before_expected = ensure_dim_names_match_and_align( sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( @@ -368,7 +368,7 @@ def perform_insn_cd_checks_with(sid_c, sid_d): "0 <= t < pt }" % (sid_d, sid_d) ) - sched_map_after_expected = align_isl_maps_by_var_names( + 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 From 0f4269b86ae1d7b1863184b731d007bb8463324f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 8 Jun 2020 16:50:25 -0500 Subject: [PATCH 082/315] 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 c7ce50da737d3a6df80a26184fd6d5d7c3762d45 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 8 Jun 2020 17:00:06 -0500 Subject: [PATCH 083/315] use map_names_match_check() to perform name set match check inside reorder_dims_by_name() --- loopy/schedule/checker/utils.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 2a42a098f..b9de94921 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -98,18 +98,10 @@ def reorder_dims_by_name( map_names_match_check( isl_set, desired_dims_ordered, dim_type, - assert_subset=True, assert_permutation=False) + assert_subset=True, assert_permutation=new_names_are_permutation_only) assert dim_type != isl.dim_type.param - if new_names_are_permutation_only and ( - set(isl_set.get_var_names(dim_type)) - != set(desired_dims_ordered)): - raise ValueError( - "Var name sets must match with new_names_are_permutation_only=True. " - "isl vars: %s, desired dims: %s" - % (isl_set.get_var_names(dim_type), desired_dims_ordered)) - other_dim_type = isl.dim_type.param other_dim_len = len(isl_set.get_var_names(other_dim_type)) From d1a73971fd24902a0068f6c3cff3306c031b22e0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 8 Jun 2020 17:21:48 -0500 Subject: [PATCH 084/315] rename reorder_dims_by_name()->insert_missing_dims_and_reorder_by_name(); remove params add_missing (now always true) and new_names_are_permutation_only (now always false) --- loopy/schedule/checker/utils.py | 38 +++++++++++---------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index b9de94921..e862d166e 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -65,32 +65,21 @@ def map_names_match_check( % (obj_map_names, dim_type, desired_names)) -def reorder_dims_by_name( - isl_set, dim_type, desired_dims_ordered, - add_missing=False, new_names_are_permutation_only=False): +def insert_missing_dims_and_reorder_by_name( + isl_set, dim_type, desired_dims_ordered): """Return an isl_set with the dimensions in the specified order. :arg isl_set: A :class:`islpy.Set` whose dimensions are - to be reordered. + to be reordered and, if necessary, augmented with missing dimensions. :arg dim_type: 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 - representing the desired dimensions order by dimension name. - - :arg add_missing: A :class:`bool` specifying whether to insert - dimensions (by name) found in `desired_dims_ordered` that are not - present in `isl_set`. - - :arg new_names_are_permutation_only: A :class:`bool` indicating that - `desired_dims_ordered` contains the same names as the specified - dimensions in `isl_set`, and does not, e.g., contain additional - dimension names not found in `isl_set`. If set to True, and these - two sets of names do not match, an error is produced. + representing the desired dimensions in order by dimension name. :returns: An :class:`islpy.Set` matching `isl_set` with the - dimension order matching `desired_dims_ordered`, optionally + dimension order matching `desired_dims_ordered`, including additional dimensions present in `desred_dims_ordered` that are not present in `isl_set`. @@ -98,7 +87,7 @@ def reorder_dims_by_name( map_names_match_check( isl_set, desired_dims_ordered, dim_type, - assert_subset=True, assert_permutation=new_names_are_permutation_only) + assert_subset=True, assert_permutation=False) assert dim_type != isl.dim_type.param @@ -109,12 +98,11 @@ def reorder_dims_by_name( for desired_idx, name in enumerate(desired_dims_ordered): # if iname doesn't exist in set, add dim: if name not in new_set.get_var_names(dim_type): - if add_missing: - # insert missing dim in correct location - new_set = new_set.insert_dims( - dim_type, desired_idx, 1 - ).set_dim_name( - dim_type, desired_idx, name) + # insert missing dim in correct location + new_set = new_set.insert_dims( + dim_type, desired_idx, 1 + ).set_dim_name( + dim_type, desired_idx, name) else: # iname exists in set current_idx = new_set.find_dim_by_name(dim_type, name) if current_idx != desired_idx: @@ -237,11 +225,9 @@ def create_symbolic_map_from_tuples( # if there are any dimensions in dom that are missing from # map_from_set, we have a problem I think? # (assertion checks this in add_missing... - dom_with_all_inames = reorder_dims_by_name( + dom_with_all_inames = insert_missing_dims_and_reorder_by_name( dom, isl.dim_type.set, space_in_names, - add_missing=True, - new_names_are_permutation_only=False, ) # intersect domain with this map From 14105e5de024ebb657b25e2c29d95cd030291aab Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 11 Jun 2020 20:17:15 -0500 Subject: [PATCH 085/315] add class name to __str__ for StatementRef() --- 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 8c503b191..18337481c 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -69,7 +69,7 @@ def __str__(self): int_id = ":%d" % (self.int_id) else: int_id = "" - return "%s%s" % (self.insn_id, int_id) + return "%s(%s%s)" % (self.__class__.__name__, self.insn_id, int_id) class StatementInstanceSet(object): From 6058001645158d0ca04c59b8e40cc082b89319c8 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 30 Jun 2020 06:59:10 -0500 Subject: [PATCH 086/315] make the integer ids that are used to represent before/after statements in domain of PairwiseSchedule deterministic so that the 'before' statement is always 0 and 'after' statement is always 1 (unless they're the same statement) --- loopy/schedule/checker/schedule.py | 13 +++-- test/test_linearization_checker.py | 85 +++++++++++++++++++----------- 2 files changed, 62 insertions(+), 36 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 18337481c..e4a9a5864 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -167,6 +167,13 @@ def __init__( # PairwiseScheduleBuilder statements self.stmt_instance_before = None self.stmt_instance_after = None + + # 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_sid_before = 0 + int_sid_after = 0 if before_insn_id == after_insn_id else 1 + # TODO when/after dependencies are added, consider the possibility # of removing the two-statements-per-PairwiseScheduleBuilder limitation @@ -178,7 +185,6 @@ def __init__( # ordering, initially this as a 1-d point with value 0 next_insn_lex_tuple = [0] stmt_added_since_prev_block_at_tier = [False] - next_sid = 0 for linearization_item in linearization_items_ordered: if isinstance(linearization_item, EnterLoop): iname = linearization_item.iname @@ -241,7 +247,7 @@ def __init__( self.stmt_instance_before = StatementInstanceSet( StatementRef( insn_id=lp_insn_id, - int_id=next_sid, # int representing insn + int_id=int_sid_before, # int representing insn ), next_insn_lex_tuple[:]) stmt_added = True @@ -251,7 +257,7 @@ def __init__( self.stmt_instance_after = StatementInstanceSet( StatementRef( insn_id=lp_insn_id, - int_id=next_sid, # int representing insn + int_id=int_sid_after, # int representing insn ), next_insn_lex_tuple[:]) stmt_added = True @@ -262,7 +268,6 @@ def __init__( if stmt_added: # increment lex dim val enumerating items in current code block next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1] + 1 - next_sid += 1 # all current (nested) blocks now contain a statement stmt_added_since_prev_block_at_tier = [True]*len( diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 41ac16feb..520efba9b 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -130,6 +130,15 @@ def test_lexschedule_and_map_creation(): "insn_d", ) + # There are multiple potential linearization orders for this kernel, so when + # performing our comparisons for schedule correctness, we need to know which + # order loopy chose. + from loopy.schedule import RunInstruction + linearized_insn_ord = [] + for item in linearization_items: + if isinstance(item, RunInstruction): + linearized_insn_ord.append(item.insn_id) + # Relationship between insn_a and insn_b --------------------------------------- assert sched_ab.stmt_instance_before.lex_points == [0, 'i', 0, 'k', 0] @@ -204,9 +213,10 @@ def test_lexschedule_and_map_creation(): # insn_a and insn_d could have been linearized in either order # (i loop could be before or after t loop) - def perform_insn_ad_checks_with(sid_a, sid_d): - assert sched_ad.stmt_instance_before.lex_points == [sid_a, 'i', 0, 'k', 0] - assert sched_ad.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] + def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): + assert sched_ad.stmt_instance_before.lex_points == [ + a_lex_idx, 'i', 0, 'k', 0] + assert sched_ad.stmt_instance_after.lex_points == [d_lex_idx, 't', 0, 0, 0] # Get two maps from the PairwiseScheduleBuilder @@ -216,22 +226,22 @@ def perform_insn_ad_checks_with(sid_a, sid_d): sched_map_before_expected = isl.Map( "[pi, pk] -> { " - "[_lp_linchk_statement=%d, i, k] -> " + "[_lp_linchk_statement=0, i, k] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=k, " "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= k < pk }" - % (sid_a, sid_a) + % (a_lex_idx) ) sched_map_before_expected = ensure_dim_names_match_and_align( sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( "[pt] -> { " - "[_lp_linchk_statement=%d, t] -> " + "[_lp_linchk_statement=1, t] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " "_lp_linchk_l4=0] : " "0 <= t < pt }" - % (sid_d, sid_d) + % (d_lex_idx) ) sched_map_after_expected = ensure_dim_names_match_and_align( sched_map_after_expected, sched_map_after) @@ -239,9 +249,11 @@ def perform_insn_ad_checks_with(sid_a, sid_d): assert sched_map_before == sched_map_before_expected assert sched_map_after == sched_map_after_expected - if sched_ad.stmt_instance_before.stmt_ref.int_id == 0: + if linearized_insn_ord.index("insn_a") < linearized_insn_ord.index("insn_d"): + # insn_a was linearized first, check schedule accordingly perform_insn_ad_checks_with(0, 1) else: + # insn_d was linearized first, check schedule accordingly perform_insn_ad_checks_with(1, 0) # ------------------------------------------------------------------------------ @@ -249,9 +261,10 @@ def perform_insn_ad_checks_with(sid_a, sid_d): # insn_b and insn_c could have been linearized in either order # (i loop could be before or after t loop) - def perform_insn_bc_checks_with(sid_b, sid_c): - assert sched_bc.stmt_instance_before.lex_points == [0, 'i', 0, 'j', sid_b] - assert sched_bc.stmt_instance_after.lex_points == [0, 'i', 0, 'j', sid_c] + def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): + assert sched_bc.stmt_instance_before.lex_points == [ + 0, 'i', 0, 'j', b_lex_idx] + assert sched_bc.stmt_instance_after.lex_points == [0, 'i', 0, 'j', c_lex_idx] # Get two maps from the PairwiseScheduleBuilder @@ -261,22 +274,22 @@ def perform_insn_bc_checks_with(sid_b, sid_c): sched_map_before_expected = isl.Map( "[pi, pj] -> { " - "[_lp_linchk_statement=%d, i, j] -> " + "[_lp_linchk_statement=0, i, j] -> " "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " "_lp_linchk_l4=%d] : " "0 <= i < pi and 0 <= j < pj }" - % (sid_b, sid_b) + % (b_lex_idx) ) 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] -> { " - "[_lp_linchk_statement=%d, i, j] -> " + "[_lp_linchk_statement=1, i, j] -> " "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " "_lp_linchk_l4=%d] : " "0 <= i < pi and 0 <= j < pj }" - % (sid_c, sid_c) + % (c_lex_idx) ) sched_map_after_expected = ensure_dim_names_match_and_align( sched_map_after_expected, sched_map_after) @@ -284,9 +297,11 @@ def perform_insn_bc_checks_with(sid_b, sid_c): assert sched_map_before == sched_map_before_expected assert sched_map_after == sched_map_after_expected - if sched_bc.stmt_instance_before.stmt_ref.int_id == 0: + if linearized_insn_ord.index("insn_b") < linearized_insn_ord.index("insn_c"): + # insn_b was linearized first, check schedule accordingly perform_insn_bc_checks_with(0, 1) else: + # insn_c was linearized first, check schedule accordingly perform_insn_bc_checks_with(1, 0) # ------------------------------------------------------------------------------ @@ -294,9 +309,10 @@ def perform_insn_bc_checks_with(sid_b, sid_c): # insn_b and insn_d could have been linearized in either order # (i loop could be before or after t loop) - def perform_insn_bd_checks_with(sid_b, sid_d): - assert sched_bd.stmt_instance_before.lex_points == [sid_b, 'i', 0, 'j', 0] - assert sched_bd.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] + def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): + assert sched_bd.stmt_instance_before.lex_points == [ + b_lex_idx, 'i', 0, 'j', 0] + assert sched_bd.stmt_instance_after.lex_points == [d_lex_idx, 't', 0, 0, 0] # Get two maps from the PairwiseScheduleBuilder @@ -306,22 +322,22 @@ def perform_insn_bd_checks_with(sid_b, sid_d): sched_map_before_expected = isl.Map( "[pi, pj] -> { " - "[_lp_linchk_statement=%d, i, j] -> " + "[_lp_linchk_statement=0, i, j] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= j < pj }" - % (sid_b, sid_b) + % (b_lex_idx) ) sched_map_before_expected = ensure_dim_names_match_and_align( sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( "[pt] -> { " - "[_lp_linchk_statement=%d, t] -> " + "[_lp_linchk_statement=1, t] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " "_lp_linchk_l4=0] : " "0 <= t < pt }" - % (sid_d, sid_d) + % (d_lex_idx) ) sched_map_after_expected = ensure_dim_names_match_and_align( sched_map_after_expected, sched_map_after) @@ -329,9 +345,11 @@ def perform_insn_bd_checks_with(sid_b, sid_d): assert sched_map_before == sched_map_before_expected assert sched_map_after == sched_map_after_expected - if sched_bd.stmt_instance_before.stmt_ref.int_id == 0: + if linearized_insn_ord.index("insn_b") < linearized_insn_ord.index("insn_d"): + # insn_b was linearized first, check schedule accordingly perform_insn_bd_checks_with(0, 1) else: + # insn_d was linearized first, check schedule accordingly perform_insn_bd_checks_with(1, 0) # ------------------------------------------------------------------------------ @@ -339,9 +357,10 @@ def perform_insn_bd_checks_with(sid_b, sid_d): # insn_c and insn_d could have been linearized in either order # (i loop could be before or after t loop) - def perform_insn_cd_checks_with(sid_c, sid_d): - assert sched_cd.stmt_instance_before.lex_points == [sid_c, 'i', 0, 'j', 0] - assert sched_cd.stmt_instance_after.lex_points == [sid_d, 't', 0, 0, 0] + def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): + assert sched_cd.stmt_instance_before.lex_points == [ + c_lex_idx, 'i', 0, 'j', 0] + assert sched_cd.stmt_instance_after.lex_points == [d_lex_idx, 't', 0, 0, 0] # Get two maps from the PairwiseScheduleBuilder @@ -351,22 +370,22 @@ def perform_insn_cd_checks_with(sid_c, sid_d): sched_map_before_expected = isl.Map( "[pi, pj] -> { " - "[_lp_linchk_statement=%d, i, j] -> " + "[_lp_linchk_statement=0, i, j] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " "_lp_linchk_l4=0] : " "0 <= i < pi and 0 <= j < pj }" - % (sid_c, sid_c) + % (c_lex_idx) ) sched_map_before_expected = ensure_dim_names_match_and_align( sched_map_before_expected, sched_map_before) sched_map_after_expected = isl.Map( "[pt] -> { " - "[_lp_linchk_statement=%d, t] -> " + "[_lp_linchk_statement=1, t] -> " "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " "_lp_linchk_l4=0] : " "0 <= t < pt }" - % (sid_d, sid_d) + % (d_lex_idx) ) sched_map_after_expected = ensure_dim_names_match_and_align( sched_map_after_expected, sched_map_after) @@ -374,9 +393,11 @@ def perform_insn_cd_checks_with(sid_c, sid_d): assert sched_map_before == sched_map_before_expected assert sched_map_after == sched_map_after_expected - if sched_cd.stmt_instance_before.stmt_ref.int_id == 0: + if linearized_insn_ord.index("insn_c") < linearized_insn_ord.index("insn_d"): + # insn_c was linearized first, check schedule accordingly perform_insn_cd_checks_with(0, 1) else: + # insn_d was linearized first, check schedule accordingly perform_insn_cd_checks_with(1, 0) From ffdca113b9c9fef44fdf3ff0fa70c77f399d0f2a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 7 Jul 2020 00:08:06 -0500 Subject: [PATCH 087/315] eliminate 'dom_inames_ordered' args in build_maps() --- loopy/schedule/checker/schedule.py | 27 ++++----------------------- 1 file changed, 4 insertions(+), 23 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index e4a9a5864..bcdbb6346 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -311,8 +311,6 @@ def _pad_lex_tuple_with_zeros(stmt_inst, length): def build_maps( self, knl, - dom_inames_ordered_before=None, - dom_inames_ordered_after=None, ): r"""Create a pair of :class:`islpy.Map`\ s representing a pairwise schedule as two mappings from statement instances to lexicographic time, @@ -323,18 +321,6 @@ def build_maps( kernel will be used to get the domains associated with the inames used in the statements. - :arg dom_inames_ordered_before: A list of :class:`str` - representing the union of inames used in - ``stmt_instance_before``. ``statement_var_name`` and - ``dom_inames_ordered_before`` are the names of the dims of - the space of the ISL map domain. - - :arg dom_inames_ordered_after: A list of :class:`str` - representing the union of inames used in - ``stmt_instance_after``. ``statement_var_name`` and - ``dom_inames_ordered_after`` are the names of the dims of - the space of the ISL map domain. - :returns: A two-tuple containing two :class:`islpy.Map`s representing the a pairwise schedule as two mappings from statement instances to lexicographic time, one for @@ -352,7 +338,7 @@ def build_maps( params_sched = [] out_names_sched = self.get_lex_var_names() - def _get_map_for_stmt_inst(stmt_inst, dom_inames_ordered): + def _get_map_for_stmt_inst(stmt_inst): # Get inames domain for statement instance (a BasicSet) dom = knl.get_inames_domain( @@ -361,8 +347,7 @@ def _get_map_for_stmt_inst(stmt_inst, dom_inames_ordered): # create space (an isl space in current implementation) # {('statement', used in statement domain>) -> # (lexicographic ordering dims)} - if dom_inames_ordered is None: - dom_inames_ordered = list_var_names_in_isl_sets([dom]) + dom_inames_ordered = list_var_names_in_isl_sets([dom]) in_names_sched = [ self.statement_var_name] + dom_inames_ordered[:] @@ -390,12 +375,8 @@ def _get_map_for_stmt_inst(stmt_inst, dom_inames_ordered): space=sched_space, ) - map_before = _get_map_for_stmt_inst( - self.stmt_instance_before, - dom_inames_ordered_before) - map_after = _get_map_for_stmt_inst( - self.stmt_instance_after, - dom_inames_ordered_after) + map_before = _get_map_for_stmt_inst(self.stmt_instance_before) + map_after = _get_map_for_stmt_inst(self.stmt_instance_after) return (map_before, map_after) From 72a91ab7b3c8b3b482eb800b8a65518257ba75e7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 7 Jul 2020 00:58:35 -0500 Subject: [PATCH 088/315] remove class variables statement_var_name and lex_var_prefix from schedule class; make them module-level variables that can be imported; (reducing state that is maintained in schedule objects) --- loopy/schedule/checker/schedule.py | 53 ++++++++++++++++++------------ 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index bcdbb6346..6e1faf0a4 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -23,6 +23,34 @@ import islpy as isl +STATEMENT_VAR_NAME = "_lp_linchk_statement" + + +def set_statement_var_name(name): + """Set the :class:`str` specifying the name of the variable used + to represent the unique :class:`int` statement id in a + pairwise schedule. + """ + global STATEMENT_VAR_NAME + STATEMENT_VAR_NAME = name + + +LEX_VAR_PREFIX = "_lp_linchk_l" + + +def set_lex_var_prefix(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. + + 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`. + """ + global LEX_VAR_PREFIX + LEX_VAR_PREFIX = name + + class StatementRef(object): """A reference to a :mod:`loopy` statement. @@ -128,23 +156,8 @@ class PairwiseScheduleBuilder(object): in a single lexicographic ordering. Points in lexicographic ordering are represented as a list of :class:`int` or as :class:`str` :mod:`loopy` inames. - - .. attribute:: statement_var_name - - A :class:`str` specifying the name of the variable used - to represent the unique :class:`int` statement id. - - .. attribute:: lex_var_prefix - - A :class:`str` specifying the prefix to be used for the variables - representing the dimensions in the lexicographic ordering. E.g., - a prefix of "_lp_linchk_lex" might yield variables "_lp_linchk_lex0", - "_lp_linchk_lex1", "_lp_linchk_lex2". Cf. :ref:`reserved-identifiers`. """ - statement_var_name = "_lp_linchk_statement" - lex_var_prefix = "_lp_linchk_l" - def __init__( self, linearization_items_ordered, @@ -349,8 +362,7 @@ def _get_map_for_stmt_inst(stmt_inst): # (lexicographic ordering dims)} dom_inames_ordered = list_var_names_in_isl_sets([dom]) - in_names_sched = [ - self.statement_var_name] + dom_inames_ordered[:] + in_names_sched = [STATEMENT_VAR_NAME] + dom_inames_ordered[:] sched_space = get_isl_space( params_sched, in_names_sched, out_names_sched) @@ -358,7 +370,7 @@ def _get_map_for_stmt_inst(stmt_inst): # for intersection with sched map later dom_to_intersect = [ add_dims_to_isl_set( - dom, isl.dim_type.set, [self.statement_var_name], 0), ] + dom, isl.dim_type.set, [STATEMENT_VAR_NAME], 0), ] # Each map representing the schedule will map # statement instances -> lex time. @@ -381,14 +393,13 @@ def _get_map_for_stmt_inst(stmt_inst): return (map_before, map_after) def get_lex_var_names(self): - return [self.lex_var_prefix+str(i) - for i in range(self.max_lex_dims())] + return [LEX_VAR_PREFIX+str(i) for i in range(self.max_lex_dims())] def __str__(self): def stringify_sched_stmt_instance(stmt_inst): return "{\n[%s=%s,] -> %s;\n}" % ( - self.statement_var_name, + STATEMENT_VAR_NAME, stmt_inst.stmt_ref.int_id, stmt_inst.lex_points) From 67bbe8b3ac14b7a05be3c14b1f0ab3000ae8987a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 10 Jul 2020 06:40:29 -0500 Subject: [PATCH 089/315] remove setters for sched checking constants; make __doc__ string; add LIN_CHECK_IDENTIFIER_PREFIX --- loopy/schedule/checker/schedule.py | 32 +++++++++++++----------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 6e1faf0a4..00a9ead51 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -22,33 +22,29 @@ import islpy as isl +__doc__ = """ -STATEMENT_VAR_NAME = "_lp_linchk_statement" +.. data:: LIN_CHECK_IDENTIFIER_PREFIX + The prefix for identifiers involved in linearization checking. -def set_statement_var_name(name): - """Set the :class:`str` specifying the name of the variable used - to represent the unique :class:`int` statement id in a - pairwise schedule. - """ - global STATEMENT_VAR_NAME - STATEMENT_VAR_NAME = name - +.. data:: LEX_VAR_PREFIX -LEX_VAR_PREFIX = "_lp_linchk_l" + 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 -def set_lex_var_prefix(name): - """Set the :class:`str` specifying the prefix to be used for the variables + 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. - 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`. - """ - global LEX_VAR_PREFIX - LEX_VAR_PREFIX = name +""" + +LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" +LEX_VAR_PREFIX = "%sl" % (LIN_CHECK_IDENTIFIER_PREFIX) +STATEMENT_VAR_NAME = "%sstatement" % (LIN_CHECK_IDENTIFIER_PREFIX) class StatementRef(object): From b54ed6f839c88618582085dc6d1393c5c3656a1a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 10 Jul 2020 07:21:19 -0500 Subject: [PATCH 090/315] use STATEMENT_VAR_NAME and LEX_VAR_PREFIX constants when building test maps; use function to make test map creation easier --- test/test_linearization_checker.py | 139 +++++++++++++++-------------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 520efba9b..d3042b36c 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -35,6 +35,10 @@ preprocess_kernel, get_one_linearized_kernel, ) +from loopy.schedule.checker.schedule import ( + LEX_VAR_PREFIX, + STATEMENT_VAR_NAME, +) logger = logging.getLogger(__name__) @@ -139,6 +143,13 @@ def test_lexschedule_and_map_creation(): if isinstance(item, RunInstruction): linearized_insn_ord.append(item.insn_id) + 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)]) + # Relationship between insn_a and insn_b --------------------------------------- assert sched_ab.stmt_instance_before.lex_points == [0, 'i', 0, 'k', 0] @@ -151,21 +162,21 @@ def test_lexschedule_and_map_creation(): # Create expected maps, align, compare sched_map_before_expected = isl.Map( - "[pi, pk] -> { " - "[_lp_linchk_statement=0, i, k] -> " - "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=k, " - "_lp_linchk_l4=0] : " - "0 <= i < pi and 0 <= k < pk }" + "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string(["0", "i", "0", "k", "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] -> { " - "[_lp_linchk_statement=1, i, j] -> " - "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=1, _lp_linchk_l3=j, " - "_lp_linchk_l4=0] : " - "0 <= i < pi and 0 <= j < pj }" + "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string(["0", "i", "1", "j", "0"]), + ) ) sched_map_after_expected = ensure_dim_names_match_and_align( sched_map_after_expected, sched_map_after) @@ -186,21 +197,21 @@ def test_lexschedule_and_map_creation(): # Create expected maps, align, compare sched_map_before_expected = isl.Map( - "[pi, pk] -> { " - "[_lp_linchk_statement=0, i, k] -> " - "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=k, " - "_lp_linchk_l4=0] : " - "0 <= i < pi and 0 <= k < pk }" + "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string(["0", "i", "0", "k", "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] -> { " - "[_lp_linchk_statement=1, i, j] -> " - "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=1, _lp_linchk_l3=j, " - "_lp_linchk_l4=0] : " - "0 <= i < pi and 0 <= j < pj }" + "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string(["0", "i", "1", "j", "0"]), + ) ) sched_map_after_expected = ensure_dim_names_match_and_align( sched_map_after_expected, sched_map_after) @@ -225,23 +236,21 @@ def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): # Create expected maps, align, compare sched_map_before_expected = isl.Map( - "[pi, pk] -> { " - "[_lp_linchk_statement=0, i, k] -> " - "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=k, " - "_lp_linchk_l4=0] : " - "0 <= i < pi and 0 <= k < pk }" - % (a_lex_idx) + "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string([a_lex_idx, "i", "0", "k", "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] -> { " - "[_lp_linchk_statement=1, t] -> " - "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " - "_lp_linchk_l4=0] : " - "0 <= t < pt }" - % (d_lex_idx) + "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string([d_lex_idx, "t", "0", "0", "0"]), + ) ) sched_map_after_expected = ensure_dim_names_match_and_align( sched_map_after_expected, sched_map_after) @@ -273,23 +282,21 @@ def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): # Create expected maps, align, compare sched_map_before_expected = isl.Map( - "[pi, pj] -> { " - "[_lp_linchk_statement=0, i, j] -> " - "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " - "_lp_linchk_l4=%d] : " - "0 <= i < pi and 0 <= j < pj }" - % (b_lex_idx) + "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string(["0", "i", "0", "j", b_lex_idx]), + ) ) 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] -> { " - "[_lp_linchk_statement=1, i, j] -> " - "[_lp_linchk_l0=0, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " - "_lp_linchk_l4=%d] : " - "0 <= i < pi and 0 <= j < pj }" - % (c_lex_idx) + "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string(["0", "i", "0", "j", c_lex_idx]), + ) ) sched_map_after_expected = ensure_dim_names_match_and_align( sched_map_after_expected, sched_map_after) @@ -321,23 +328,21 @@ def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): # Create expected maps, align, compare sched_map_before_expected = isl.Map( - "[pi, pj] -> { " - "[_lp_linchk_statement=0, i, j] -> " - "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " - "_lp_linchk_l4=0] : " - "0 <= i < pi and 0 <= j < pj }" - % (b_lex_idx) + "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string([b_lex_idx, "i", "0", "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( - "[pt] -> { " - "[_lp_linchk_statement=1, t] -> " - "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " - "_lp_linchk_l4=0] : " - "0 <= t < pt }" - % (d_lex_idx) + "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string([d_lex_idx, "t", "0", "0", "0"]), + ) ) sched_map_after_expected = ensure_dim_names_match_and_align( sched_map_after_expected, sched_map_after) @@ -369,23 +374,21 @@ def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): # Create expected maps, align, compare sched_map_before_expected = isl.Map( - "[pi, pj] -> { " - "[_lp_linchk_statement=0, i, j] -> " - "[_lp_linchk_l0=%d, _lp_linchk_l1=i, _lp_linchk_l2=0, _lp_linchk_l3=j, " - "_lp_linchk_l4=0] : " - "0 <= i < pi and 0 <= j < pj }" - % (c_lex_idx) + "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string([c_lex_idx, "i", "0", "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( - "[pt] -> { " - "[_lp_linchk_statement=1, t] -> " - "[_lp_linchk_l0=%d, _lp_linchk_l1=t, _lp_linchk_l2=0, _lp_linchk_l3=0, " - "_lp_linchk_l4=0] : " - "0 <= t < pt }" - % (d_lex_idx) + "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" + % ( + STATEMENT_VAR_NAME, + _lex_space_string([d_lex_idx, "t", "0", "0", "0"]), + ) ) sched_map_after_expected = ensure_dim_names_match_and_align( sched_map_after_expected, sched_map_after) From c549f652e739af191d0297e5b2621bdbe33d44a2 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 10 Jul 2020 07:33:43 -0500 Subject: [PATCH 091/315] 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 b2c589713f7cc152650b5b3dec50bdfa9fb59b9d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 10 Jul 2020 08:28:25 -0500 Subject: [PATCH 092/315] remove StatementRef and change StatementInstanceSet.stmt_ref to just StatementInstanceSet.insn_id --- loopy/schedule/checker/schedule.py | 116 +++++++++-------------------- 1 file changed, 37 insertions(+), 79 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 00a9ead51..db35ec124 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -47,55 +47,6 @@ STATEMENT_VAR_NAME = "%sstatement" % (LIN_CHECK_IDENTIFIER_PREFIX) -class StatementRef(object): - """A reference to a :mod:`loopy` statement. - - .. attribute:: insn_id - - A :class:`str` specifying the :mod:`loopy` instruction id - for this statement. - - .. attribute:: int_id - - A :class:`int` uniquely identifying the statement within a - :class:`PairwiseScheduleBuilder`. A :class:`PairwiseScheduleBuilder` - builds a mapping from points in a space of statement instances to - points in a lexicographic ordering. The `statement` dimension of a - point in the statement instance space representing an instance of - this statement is assigned this value. - - """ - - def __init__( - self, - insn_id, - int_id=None, - ): - self.insn_id = insn_id - self.int_id = int_id - - def __eq__(self, other): - return ( - self.insn_id == other.insn_id - and self.int_id == other.int_id - ) - - def update_persistent_hash(self, key_hash, key_builder): - """Custom hash computation function for use with - :class:`pytools.persistent_dict.PersistentDict`. - """ - - key_builder.rec(key_hash, self.insn_id) - key_builder.rec(key_hash, self.int_id) - - def __str__(self): - if self.int_id is not None: - int_id = ":%d" % (self.int_id) - else: - int_id = "" - return "%s(%s%s)" % (self.__class__.__name__, self.insn_id, int_id) - - class StatementInstanceSet(object): """A representation of a set of (non-concurrent) instances of a statement being executed. The ordering of the instances is described @@ -103,9 +54,10 @@ class StatementInstanceSet(object): lexicographic ordering of statements. Each field in the list corresponds to a dimension in the lexicographic ordering. - .. attribute:: stmt_ref + .. attribute:: insn_id - A :class:`StatementRef`. + A :class:`str` instruction identifier that is unique within + a :class:`loopy.kernel.LoopKernel`. .. attribute:: lex_points @@ -116,15 +68,15 @@ class StatementInstanceSet(object): def __init__( self, - stmt_ref, + insn_id, lex_points, ): - self.stmt_ref = stmt_ref + self.insn_id = insn_id self.lex_points = lex_points def __repr__(self): return "%s(%s, %s)" % ( - self.__class__.__name__, self.stmt_ref, self.lex_points) + self.__class__.__name__, self.insn_id, self.lex_points) class PairwiseScheduleBuilder(object): @@ -177,12 +129,6 @@ def __init__( self.stmt_instance_before = None self.stmt_instance_after = None - # 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_sid_before = 0 - int_sid_after = 0 if before_insn_id == after_insn_id else 1 - # TODO when/after dependencies are added, consider the possibility # of removing the two-statements-per-PairwiseScheduleBuilder limitation @@ -254,20 +200,14 @@ def __init__( if lp_insn_id == before_insn_id: # add before sched item self.stmt_instance_before = StatementInstanceSet( - StatementRef( - insn_id=lp_insn_id, - int_id=int_sid_before, # int representing insn - ), + lp_insn_id, next_insn_lex_tuple[:]) stmt_added = True if lp_insn_id == after_insn_id: # add after sched item self.stmt_instance_after = StatementInstanceSet( - StatementRef( - insn_id=lp_insn_id, - int_id=int_sid_after, # int representing insn - ), + lp_insn_id, next_insn_lex_tuple[:]) stmt_added = True @@ -300,13 +240,13 @@ def max_lex_dims(self): def pad_lex_tuples_with_zeros(self): """Find the maximum number of lexicographic dimensions represented in the lexicographic ordering, and if any - :class:`StatementRef` maps to a lex point tuple with + :class:`StatementInstanceSet` maps to a lex point tuple with fewer dimensions, add a zero for each of the missing dimensions. """ def _pad_lex_tuple_with_zeros(stmt_inst, length): return StatementInstanceSet( - stmt_inst.stmt_ref, + stmt_inst.insn_id, stmt_inst.lex_points[:] + [0]*(length-len(stmt_inst.lex_points)), ) @@ -347,11 +287,11 @@ def build_maps( params_sched = [] out_names_sched = self.get_lex_var_names() - def _get_map_for_stmt_inst(stmt_inst): + def _get_map_for_stmt_inst(stmt_inst, int_sid): # Get inames domain for statement instance (a BasicSet) dom = knl.get_inames_domain( - knl.id_to_insn[stmt_inst.stmt_ref.insn_id].within_inames) + knl.id_to_insn[stmt_inst.insn_id].within_inames) # create space (an isl space in current implementation) # {('statement', used in statement domain>) -> @@ -373,7 +313,7 @@ def _get_map_for_stmt_inst(stmt_inst): # Right now, statement instance tuples consist of single int. # Add all inames from domains to each map domain tuple. tuple_pair = [( - (stmt_inst.stmt_ref.int_id, ) + tuple(dom_inames_ordered), + (int_sid, ) + tuple(dom_inames_ordered), stmt_inst.lex_points )] @@ -383,8 +323,18 @@ def _get_map_for_stmt_inst(stmt_inst): space=sched_space, ) - map_before = _get_map_for_stmt_inst(self.stmt_instance_before) - map_after = _get_map_for_stmt_inst(self.stmt_instance_after) + # 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_sid_before = 0 + int_sid_after = 0 if ( + self.stmt_instance_before.insn_id == self.stmt_instance_after.insn_id + ) else 1 + + map_before = _get_map_for_stmt_inst( + self.stmt_instance_before, int_sid_before) + map_after = _get_map_for_stmt_inst( + self.stmt_instance_after, int_sid_after) return (map_before, map_after) @@ -393,13 +343,21 @@ def get_lex_var_names(self): def __str__(self): - def stringify_sched_stmt_instance(stmt_inst): + def stringify_sched_stmt_instance(stmt_inst, int_sid): return "{\n[%s=%s,] -> %s;\n}" % ( STATEMENT_VAR_NAME, - stmt_inst.stmt_ref.int_id, + int_sid, stmt_inst.lex_points) + # TODO once we change class -> funcs, this repetition of logic will disappear + int_sid_before = 0 + int_sid_after = 0 if ( + self.stmt_instance_before.insn_id == self.stmt_instance_after.insn_id + ) else 1 + return "%s(\nBefore: %s\nAfter: %s\n)" % ( self.__class__.__name__, - stringify_sched_stmt_instance(self.stmt_instance_before), - stringify_sched_stmt_instance(self.stmt_instance_after)) + stringify_sched_stmt_instance( + self.stmt_instance_before, int_sid_before), + stringify_sched_stmt_instance( + self.stmt_instance_after, int_sid_after)) From b4e25dde21b214f5d5fa22c54fe8be1b0ad1664f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 10 Jul 2020 08:30:22 -0500 Subject: [PATCH 093/315] rename PairwiseScheduleBuilder.statement_instance_before/after to PairwiseScheduleBuilder.statement_instance_set_before/after (since they're not just a single instance) --- loopy/schedule/checker/schedule.py | 49 ++++++++++++++++-------------- test/test_linearization_checker.py | 28 +++++++++-------- 2 files changed, 42 insertions(+), 35 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index db35ec124..04d1315e1 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -87,19 +87,19 @@ class PairwiseScheduleBuilder(object): :func:`loopy.schedule.checker.get_schedule_for_statement_pair` is the preferred method of creating a PairwiseScheduleBuilder. - .. attribute:: stmt_instance_before + .. attribute:: stmt_instance_set_before A :class:`StatementInstanceSet` whose ordering relative - to `stmt_instance_after is described by PairwiseScheduleBuilder. This + to `stmt_instance_set_after is described by PairwiseScheduleBuilder. This is achieved by mapping the statement instances in both sets to points in a single lexicographic ordering. Points in lexicographic ordering are represented as a list of :class:`int` or as :class:`str` :mod:`loopy` inames. - .. attribute:: stmt_instance_after + .. attribute:: stmt_instance_set_after A :class:`StatementInstanceSet` whose ordering relative - to `stmt_instance_before is described by PairwiseScheduleBuilder. This + to `stmt_instance_set_before is described by PairwiseScheduleBuilder. This is achieved by mapping the statement instances in both sets to points in a single lexicographic ordering. Points in lexicographic ordering are represented as a list of :class:`int` or as :class:`str` @@ -118,7 +118,7 @@ def __init__( order will be described by this :class:`PairwiseScheduleBuilder`. :arg before_insn_id: A :class:`str` instruction id specifying - stmt_instance_before in this pair of instructions. + stmt_instance_set_before in this pair of instructions. :arg after_insn_id: A :class:`str` instruction id specifying stmt_instancce_after in this pair of instructions. @@ -126,8 +126,8 @@ def __init__( """ # PairwiseScheduleBuilder statements - self.stmt_instance_before = None - self.stmt_instance_after = None + self.stmt_instance_set_before = None + self.stmt_instance_set_after = None # TODO when/after dependencies are added, consider the possibility # of removing the two-statements-per-PairwiseScheduleBuilder limitation @@ -199,14 +199,14 @@ def __init__( if lp_insn_id == before_insn_id: # add before sched item - self.stmt_instance_before = StatementInstanceSet( + self.stmt_instance_set_before = StatementInstanceSet( lp_insn_id, next_insn_lex_tuple[:]) stmt_added = True if lp_insn_id == after_insn_id: # add after sched item - self.stmt_instance_after = StatementInstanceSet( + self.stmt_instance_set_after = StatementInstanceSet( lp_insn_id, next_insn_lex_tuple[:]) stmt_added = True @@ -224,7 +224,7 @@ def __init__( else: pass # to save time, stop when we've created both statements - if self.stmt_instance_before and self.stmt_instance_after: + if self.stmt_instance_set_before and self.stmt_instance_set_after: break # At this point, pairwise sub-schedule may contain lex point tuples @@ -234,8 +234,8 @@ def __init__( def max_lex_dims(self): return max([ - len(self.stmt_instance_before.lex_points), - len(self.stmt_instance_after.lex_points)]) + len(self.stmt_instance_set_before.lex_points), + len(self.stmt_instance_set_after.lex_points)]) def pad_lex_tuples_with_zeros(self): """Find the maximum number of lexicographic dimensions represented @@ -252,10 +252,10 @@ def _pad_lex_tuple_with_zeros(stmt_inst, length): max_lex_dim = self.max_lex_dims() - self.stmt_instance_before = _pad_lex_tuple_with_zeros( - self.stmt_instance_before, max_lex_dim) - self.stmt_instance_after = _pad_lex_tuple_with_zeros( - self.stmt_instance_after, max_lex_dim) + self.stmt_instance_set_before = _pad_lex_tuple_with_zeros( + self.stmt_instance_set_before, max_lex_dim) + self.stmt_instance_set_after = _pad_lex_tuple_with_zeros( + self.stmt_instance_set_after, max_lex_dim) def build_maps( self, @@ -263,7 +263,8 @@ def build_maps( ): r"""Create a pair of :class:`islpy.Map`\ s representing a pairwise schedule as two mappings from statement instances to lexicographic time, - one for ``stmt_instance_before`` and one for ``stmt_instance_after``. + one for ``stmt_instance_set_before`` and one for + ``stmt_instance_set_after``. :arg knl: A :class:`loopy.kernel.LoopKernel` containing the linearization items that are described by the schedule. This @@ -328,13 +329,14 @@ def _get_map_for_stmt_inst(stmt_inst, int_sid): # before and after refer to same stmt, in which case sid_before=sid_after=0) int_sid_before = 0 int_sid_after = 0 if ( - self.stmt_instance_before.insn_id == self.stmt_instance_after.insn_id + self.stmt_instance_set_before.insn_id == + self.stmt_instance_set_after.insn_id ) else 1 map_before = _get_map_for_stmt_inst( - self.stmt_instance_before, int_sid_before) + self.stmt_instance_set_before, int_sid_before) map_after = _get_map_for_stmt_inst( - self.stmt_instance_after, int_sid_after) + self.stmt_instance_set_after, int_sid_after) return (map_before, map_after) @@ -352,12 +354,13 @@ def stringify_sched_stmt_instance(stmt_inst, int_sid): # TODO once we change class -> funcs, this repetition of logic will disappear int_sid_before = 0 int_sid_after = 0 if ( - self.stmt_instance_before.insn_id == self.stmt_instance_after.insn_id + self.stmt_instance_set_before.insn_id == + self.stmt_instance_set_after.insn_id ) else 1 return "%s(\nBefore: %s\nAfter: %s\n)" % ( self.__class__.__name__, stringify_sched_stmt_instance( - self.stmt_instance_before, int_sid_before), + self.stmt_instance_set_before, int_sid_before), stringify_sched_stmt_instance( - self.stmt_instance_after, int_sid_after)) + self.stmt_instance_set_after, int_sid_after)) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index d3042b36c..c87bb149b 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -152,8 +152,8 @@ def _lex_space_string(dim_vals): # Relationship between insn_a and insn_b --------------------------------------- - assert sched_ab.stmt_instance_before.lex_points == [0, 'i', 0, 'k', 0] - assert sched_ab.stmt_instance_after.lex_points == [0, 'i', 1, 'j', 0] + assert sched_ab.stmt_instance_set_before.lex_points == [0, 'i', 0, 'k', 0] + assert sched_ab.stmt_instance_set_after.lex_points == [0, 'i', 1, 'j', 0] # Get two maps from the PairwiseScheduleBuilder @@ -187,8 +187,8 @@ def _lex_space_string(dim_vals): # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_c --------------------------------------- - assert sched_ac.stmt_instance_before.lex_points == [0, 'i', 0, 'k', 0] - assert sched_ac.stmt_instance_after.lex_points == [0, 'i', 1, 'j', 0] + assert sched_ac.stmt_instance_set_before.lex_points == [0, 'i', 0, 'k', 0] + assert sched_ac.stmt_instance_set_after.lex_points == [0, 'i', 1, 'j', 0] # Get two maps from the PairwiseScheduleBuilder @@ -225,9 +225,10 @@ def _lex_space_string(dim_vals): # insn_a and insn_d could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): - assert sched_ad.stmt_instance_before.lex_points == [ + assert sched_ad.stmt_instance_set_before.lex_points == [ a_lex_idx, 'i', 0, 'k', 0] - assert sched_ad.stmt_instance_after.lex_points == [d_lex_idx, 't', 0, 0, 0] + assert sched_ad.stmt_instance_set_after.lex_points == [ + d_lex_idx, 't', 0, 0, 0] # Get two maps from the PairwiseScheduleBuilder @@ -271,9 +272,10 @@ def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): # insn_b and insn_c could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): - assert sched_bc.stmt_instance_before.lex_points == [ + assert sched_bc.stmt_instance_set_before.lex_points == [ 0, 'i', 0, 'j', b_lex_idx] - assert sched_bc.stmt_instance_after.lex_points == [0, 'i', 0, 'j', c_lex_idx] + assert sched_bc.stmt_instance_set_after.lex_points == [ + 0, 'i', 0, 'j', c_lex_idx] # Get two maps from the PairwiseScheduleBuilder @@ -317,9 +319,10 @@ def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): # insn_b and insn_d could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): - assert sched_bd.stmt_instance_before.lex_points == [ + assert sched_bd.stmt_instance_set_before.lex_points == [ b_lex_idx, 'i', 0, 'j', 0] - assert sched_bd.stmt_instance_after.lex_points == [d_lex_idx, 't', 0, 0, 0] + assert sched_bd.stmt_instance_set_after.lex_points == [ + d_lex_idx, 't', 0, 0, 0] # Get two maps from the PairwiseScheduleBuilder @@ -363,9 +366,10 @@ def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): # insn_c and insn_d could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): - assert sched_cd.stmt_instance_before.lex_points == [ + assert sched_cd.stmt_instance_set_before.lex_points == [ c_lex_idx, 'i', 0, 'j', 0] - assert sched_cd.stmt_instance_after.lex_points == [d_lex_idx, 't', 0, 0, 0] + assert sched_cd.stmt_instance_set_after.lex_points == [ + d_lex_idx, 't', 0, 0, 0] # Get two maps from the PairwiseScheduleBuilder From bb18e5823f422ce1b034389c52119fd3a4efd5f7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Jul 2020 02:47:33 -0500 Subject: [PATCH 094/315] remove pad_lex_tuples_with_zeros() method since it's only ever called once (in-line its functionality) --- loopy/schedule/checker/schedule.py | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 04d1315e1..818d8355c 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -230,19 +230,6 @@ def __init__( # At this point, pairwise sub-schedule may contain lex point tuples # missing dimensions; the values in these missing dims should # be zero, so add them. - self.pad_lex_tuples_with_zeros() - - def max_lex_dims(self): - return max([ - len(self.stmt_instance_set_before.lex_points), - len(self.stmt_instance_set_after.lex_points)]) - - def pad_lex_tuples_with_zeros(self): - """Find the maximum number of lexicographic dimensions represented - in the lexicographic ordering, and if any - :class:`StatementInstanceSet` maps to a lex point tuple with - fewer dimensions, add a zero for each of the missing dimensions. - """ def _pad_lex_tuple_with_zeros(stmt_inst, length): return StatementInstanceSet( @@ -257,6 +244,11 @@ def _pad_lex_tuple_with_zeros(stmt_inst, length): self.stmt_instance_set_after = _pad_lex_tuple_with_zeros( self.stmt_instance_set_after, max_lex_dim) + def max_lex_dims(self): + return max([ + len(self.stmt_instance_set_before.lex_points), + len(self.stmt_instance_set_after.lex_points)]) + def build_maps( self, knl, From 2f0c95cec3659c3e154e5fee60b664a21ef7f77e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Jul 2020 03:25:15 -0500 Subject: [PATCH 095/315] remove get_isl_space() and set_all_isl_space_names(), instead use isl.Space.create_from_names() --- loopy/schedule/checker/schedule.py | 6 ++--- loopy/schedule/checker/utils.py | 42 ------------------------------ 2 files changed, 3 insertions(+), 45 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 818d8355c..f085547c6 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -272,7 +272,6 @@ def build_maps( from loopy.schedule.checker.utils import ( list_var_names_in_isl_sets, - get_isl_space, create_symbolic_map_from_tuples, add_dims_to_isl_set, ) @@ -292,8 +291,9 @@ def _get_map_for_stmt_inst(stmt_inst, int_sid): dom_inames_ordered = list_var_names_in_isl_sets([dom]) in_names_sched = [STATEMENT_VAR_NAME] + dom_inames_ordered[:] - sched_space = get_isl_space( - params_sched, in_names_sched, out_names_sched) + sched_space = isl.Space.create_from_names( + isl.DEFAULT_CONTEXT, + in_=in_names_sched, out=out_names_sched, params=params_sched) # Insert 'statement' dim into domain so that its space allows # for intersection with sched map later diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index e862d166e..f336d21f7 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -237,48 +237,6 @@ def create_symbolic_map_from_tuples( return _get_union(all_maps) -def set_all_isl_space_names( - isl_space, param_names=None, in_names=None, out_names=None): - """Return a copy of `isl_space` with the specified dimension names. - If no names are provided, use `p0, p1, ...` for parameters, - `i0, i1, ...`, for in_ dimensions, and `o0, o1, ...` for out - dimensions. - - """ - - new_space = isl_space.copy() - dim_type = isl.dim_type - if param_names: - for i, p in enumerate(param_names): - new_space = new_space.set_dim_name(dim_type.param, i, p) - else: - for i in range(len(isl_space.get_var_names(dim_type.param))): - new_space = new_space.set_dim_name(dim_type.param, i, "p%d" % (i)) - if in_names: - for i, p in enumerate(in_names): - new_space = new_space.set_dim_name(dim_type.in_, i, p) - else: - for i in range(len(isl_space.get_var_names(dim_type.in_))): - new_space = new_space.set_dim_name(dim_type.in_, i, "i%d" % (i)) - if out_names: - for i, p in enumerate(out_names): - new_space = new_space.set_dim_name(dim_type.out, i, p) - else: - for i in range(len(isl_space.get_var_names(dim_type.out))): - new_space = new_space.set_dim_name(dim_type.out, i, "o%d" % (i)) - return new_space - - -def get_isl_space(param_names, in_names, out_names): - """Return an :class:`islpy.Space` with the specified dimension names. - """ - - space = isl.Space.alloc( - isl.DEFAULT_CONTEXT, len(param_names), len(in_names), len(out_names)) - return set_all_isl_space_names( - space, param_names=param_names, in_names=in_names, out_names=out_names) - - def get_concurrent_inames(knl): from loopy.kernel.data import ConcurrentTag conc_inames = set() From d8587b0f824e45b1640c2747a332100dd9ab469b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Jul 2020 04:12:49 -0500 Subject: [PATCH 096/315] perform union of maps upon creation in create_symbolic_map_from_tuples() rather than afterward; temporarily leave old version in place to test for equality --- loopy/schedule/checker/utils.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index f336d21f7..3a7688e4d 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -187,7 +187,14 @@ def create_symbolic_map_from_tuples( # loop through pairs and create a set that will later be converted to a map + # TODO remove after testing: all_maps = [] + + # initialize union to empty + 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)) for (tup_in, tup_out), dom in tuple_pairs_with_domains: # initialize constraint with true @@ -231,10 +238,17 @@ def create_symbolic_map_from_tuples( ) # intersect domain with this map + union_of_maps = union_of_maps.union( + map_from_set.intersect_domain(dom_with_all_inames)) + + # TODO remove after testing: all_maps.append( map_from_set.intersect_domain(dom_with_all_inames)) - return _get_union(all_maps) + # TODO remove after testing: + assert union_of_maps == _get_union(all_maps) + + return union_of_maps def get_concurrent_inames(knl): From c465bdb4cecfe1f700bede85680b06d51734b634 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Jul 2020 04:15:58 -0500 Subject: [PATCH 097/315] remove utils._get_union() --- loopy/schedule/checker/utils.py | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 3a7688e4d..cef985ee6 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -132,13 +132,6 @@ def ensure_dim_names_match_and_align(obj_map, tgt_map): return aligned_obj_map -def _get_union(list_items): - union = list_items[0] - for s in list_items[1:]: - union = union.union(s) - return union - - def list_var_names_in_isl_sets( isl_sets, set_dim=isl.dim_type.set): @@ -187,9 +180,6 @@ def create_symbolic_map_from_tuples( # loop through pairs and create a set that will later be converted to a map - # TODO remove after testing: - all_maps = [] - # initialize union to empty union_of_maps = isl.Map.from_domain( islvars[0].eq_set(islvars[0]+1) # 0 == 1 (false) @@ -241,13 +231,6 @@ def create_symbolic_map_from_tuples( union_of_maps = union_of_maps.union( map_from_set.intersect_domain(dom_with_all_inames)) - # TODO remove after testing: - all_maps.append( - map_from_set.intersect_domain(dom_with_all_inames)) - - # TODO remove after testing: - assert union_of_maps == _get_union(all_maps) - return union_of_maps From 138702bda0750e4693b946ccf31b6e0fa06b23fa Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Jul 2020 11:45:25 -0500 Subject: [PATCH 098/315] (commented out code that compares result from isl.affs_from_space() to result from isl.make_zero_and_vars()) --- loopy/schedule/checker/utils.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index cef985ee6..0bfdf0a54 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -29,10 +29,15 @@ def prettier_map_string(map_obj): def get_islvars_from_space(space): + #pu.db param_names = space.get_var_names(isl.dim_type.param) in_names = space.get_var_names(isl.dim_type.in_) out_names = space.get_var_names(isl.dim_type.out) return isl.make_zero_and_vars(in_names+out_names, param_names) + #old = isl.make_zero_and_vars(in_names+out_names, param_names) + #new = isl.affs_from_space(space) + #assert old == new + #return new def add_dims_to_isl_set(isl_set, dim_type, names, new_idx_start): From 6f7e2a3168f05d6def4925fa1bac13c9032d51bf Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Jul 2020 08:28:42 -0500 Subject: [PATCH 099/315] removed PairwiseScheduleBuilder class; removed PSB methods max_lex_dims() and build_maps() (and __str__() but no one cares); combined removed functions/class into single generate_pairwise_schedule() func that returns a pair of maps (one for each statement) so that intermediate state (what used to be PSB) is no longer kept around --- loopy/schedule/checker/__init__.py | 43 +-- loopy/schedule/checker/schedule.py | 508 +++++++++++++---------------- test/test_linearization_checker.py | 124 +++---- 3 files changed, 299 insertions(+), 376 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 716a0cb58..a2963f689 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -21,7 +21,7 @@ """ -# {{{ create PairwiseScheduleBuilder for statement pair +# {{{ create a pairwise schedule for statement pair def get_schedule_for_statement_pair( knl, @@ -29,9 +29,11 @@ def get_schedule_for_statement_pair( insn_id_before, insn_id_after, ): - """Create a :class:`loopy.schedule.checker.schedule.PairwiseScheduleBuilder` - representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.StatementInstanceSet` + r"""Given a pair of statements in a linearized kernel, determine + the (relative) order in which the instances are executed, + by creating a mapping from statement instances to points in a single + lexicographic ordering. Create a pair of :class:`islpy.Map`\ s + representing a pairwise schedule as two mappings from statement instances to lexicographic time. :arg knl: A :class:`loopy.kernel.LoopKernel` containing the @@ -50,10 +52,10 @@ def get_schedule_for_statement_pair( :arg insn_id_after: An instruction identifier that is unique within a :class:`loopy.kernel.LoopKernel`. - :returns: A :class:`loopy.schedule.checker.schedule.PairwiseScheduleBuilder` - representing the order of two statements as a mapping from - :class:`loopy.schedule.checker.StatementInstanceSet` - to lexicographic time. + :returns: A two-tuple containing two :class:`islpy.Map`s + representing the a pairwise schedule as two mappings + from statement instances to lexicographic time, one for + each of the two statements. Example usage:: @@ -76,17 +78,16 @@ def get_schedule_for_statement_pair( from loopy.schedule.checker import ( get_schedule_for_statement_pair, ) - sched_builder_ab = get_schedule_for_statement_pair( + + # Get two maps ----------------------------------------------------------- + + sched_a, sched_b = get_schedule_for_statement_pair( knl, knl.linearization, "insn_a", "insn_b", ) - # Get two maps from the PairwiseScheduleBuilder -------------------------- - - sched_a, sched_b = sched_builder_ab.build_maps(knl) - print(sched_a) print(sched_b) @@ -112,12 +113,11 @@ def get_schedule_for_statement_pair( # }}} - # {{{ find any EnterLoop inames that are tagged as concurrent - - # so that PairwiseScheduleBuilder knows to ignore them + # {{{ Find any EnterLoop inames that are tagged as concurrent + # so that generate_pairwise_schedule() 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()) + # won't be any inames with ConcurrentTags in EnterLoop linearization items. + # Test which exercises this: test_linearization_checker_with_stroud_bernstein()) from loopy.schedule.checker.utils import ( get_concurrent_inames, get_EnterLoop_inames, @@ -134,11 +134,12 @@ def get_schedule_for_statement_pair( # }}} - # {{{ Create PairwiseScheduleBuilder: mapping of {statement instance: lex point} + # {{{ Create two mappings from {statement instance: lex point} # include only instructions involved in this dependency - from loopy.schedule.checker.schedule import PairwiseScheduleBuilder - return PairwiseScheduleBuilder( + from loopy.schedule.checker.schedule import generate_pairwise_schedule + return generate_pairwise_schedule( + preproc_knl, linearization_items, insn_id_before, insn_id_after, diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index f085547c6..9e693a9a1 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -79,280 +79,242 @@ def __repr__(self): self.__class__.__name__, self.insn_id, self.lex_points) -class PairwiseScheduleBuilder(object): - """Given a pair of statements in a linearized kernel, PairwiseScheduleBuilder - determines the (relative) order in which the instances are executed, +def generate_pairwise_schedule( + knl, + linearization_items_ordered, + before_insn_id, + after_insn_id, + loops_to_ignore=set(), + ): + r"""Given a pair of statements in a linearized kernel, determine + the (relative) order in which the instances are executed, by creating a mapping from statement instances to points in a single - lexicographic ordering. The function - :func:`loopy.schedule.checker.get_schedule_for_statement_pair` is the - preferred method of creating a PairwiseScheduleBuilder. - - .. attribute:: stmt_instance_set_before - - A :class:`StatementInstanceSet` whose ordering relative - to `stmt_instance_set_after is described by PairwiseScheduleBuilder. This - is achieved by mapping the statement instances in both sets to points - in a single lexicographic ordering. Points in lexicographic ordering - are represented as a list of :class:`int` or as :class:`str` - :mod:`loopy` inames. - - .. attribute:: stmt_instance_set_after - - A :class:`StatementInstanceSet` whose ordering relative - to `stmt_instance_set_before is described by PairwiseScheduleBuilder. This - is achieved by mapping the statement instances in both sets to points - in a single lexicographic ordering. Points in lexicographic ordering - are represented as a list of :class:`int` or as :class:`str` - :mod:`loopy` inames. + lexicographic ordering. Create a pair of :class:`islpy.Map`\ s + representing a pairwise schedule as two mappings from statement instances + to lexicographic time. + + :arg knl: A :class:`loopy.kernel.LoopKernel` containing the + linearization items that will be described by the schedule. This + kernel will be used to get the domains associated with the inames + used in the statements. + + :arg linearization_items_ordered: A list of :class:`loopy.schedule.ScheduleItem` + (to be renamed to `loopy.schedule.LinearizationItem`) containing the + two linearization items whose relative order will be described by the + schedule. This list may be a *partial* linearization for a kernel since + this function may be used during the linearization process. + + :arg before_insn_id: A :class:`str` instruction id specifying + stmt_instance_set_before in this pair of instructions. + + :arg after_insn_id: A :class:`str` instruction id specifying + stmt_instance_set_after in this pair of instructions. + + :returns: A two-tuple containing two :class:`islpy.Map`s + representing the a pairwise schedule as two mappings + from statement instances to lexicographic time, one for + each of the two statements. """ - def __init__( - self, - linearization_items_ordered, - before_insn_id, - after_insn_id, - loops_to_ignore=set(), - ): - """ - :arg linearization_items_ordered: A list of :class:`ScheduleItem` whose - order will be described by this :class:`PairwiseScheduleBuilder`. - - :arg before_insn_id: A :class:`str` instruction id specifying - stmt_instance_set_before in this pair of instructions. - - :arg after_insn_id: A :class:`str` instruction id specifying - stmt_instancce_after in this pair of instructions. - - """ - - # PairwiseScheduleBuilder statements - self.stmt_instance_set_before = None - self.stmt_instance_set_after = None - - # TODO when/after dependencies are added, consider the possibility - # of removing the two-statements-per-PairwiseScheduleBuilder limitation - - from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) - - # go through linearization_items_ordered and generate pairwise sub-schedule - - # 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] - stmt_added_since_prev_block_at_tier = [False] - for linearization_item in linearization_items_ordered: - if isinstance(linearization_item, EnterLoop): - iname = linearization_item.iname - if iname in loops_to_ignore: - continue - - # We could always increment next_insn_lex_tuple[-1] here since - # this new section of code comes after the previous section - # (statements since last opened/closed loop), but if we have - # not added any statements within the previous section yet, we - # don't have to (effectively ignoring that section of code). - if stmt_added_since_prev_block_at_tier[-1]: - next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 - stmt_added_since_prev_block_at_tier[-1] = False - - # upon entering a loop, we enter a new (deeper) tier, - # add one lex dimension for the loop variable, - # add second lex dim to enumerate code blocks within new loop, and - # append a dim to stmt_added_since_prev_block_at_tier to represent - # new tier - next_insn_lex_tuple.append(iname) - next_insn_lex_tuple.append(0) - stmt_added_since_prev_block_at_tier.append(False) - elif isinstance(linearization_item, LeaveLoop): - if linearization_item.iname in loops_to_ignore: - continue - # upon leaving a loop, - # pop lex dimension for enumerating code blocks within this loop, and - # pop lex dimension for the loop variable, and + # Two StatementInstanceSets, one for each statement: + + """ + stmt_instance_set_before + + A :class:`StatementInstanceSet` whose ordering relative + to `stmt_instance_set_after is described by the schedule blueprint. This + is achieved by mapping the statement instances in both sets to points + in a single lexicographic ordering. Points in lexicographic ordering + are represented as a list of :class:`int` or as :class:`str` + :mod:`loopy` inames. + """ + stmt_instance_set_before = None + + """ + stmt_instance_set_after + + A :class:`StatementInstanceSet` whose ordering relative + to `stmt_instance_set_before is described by the schedule blueprint. This + is achieved by mapping the statement instances in both sets to points + in a single lexicographic ordering. Points in lexicographic ordering + are represented as a list of :class:`int` or as :class:`str` + :mod:`loopy` inames. + """ + stmt_instance_set_after = None + + from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) + + # go through linearization_items_ordered and generate pairwise sub-schedule + + # 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] + stmt_added_since_prev_block_at_tier = [False] + max_lex_dim = 0 + for linearization_item in linearization_items_ordered: + if isinstance(linearization_item, EnterLoop): + iname = linearization_item.iname + if iname in loops_to_ignore: + continue + + # We could always increment next_insn_lex_tuple[-1] here since + # this new section of code comes after the previous section + # (statements since last opened/closed loop), but if we have + # not added any statements within the previous section yet, we + # don't have to (effectively ignoring that section of code). + if stmt_added_since_prev_block_at_tier[-1]: + next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 + stmt_added_since_prev_block_at_tier[-1] = False + + # upon entering a loop, we enter a new (deeper) tier, + # add one lex dimension for the loop variable, + # add second lex dim to enumerate code blocks within new loop, and + # append a dim to stmt_added_since_prev_block_at_tier to represent + # new tier + next_insn_lex_tuple.append(iname) + next_insn_lex_tuple.append(0) + stmt_added_since_prev_block_at_tier.append(False) + elif isinstance(linearization_item, LeaveLoop): + if linearization_item.iname in loops_to_ignore: + continue + # upon leaving a loop, + # pop lex dimension for enumerating code blocks within this loop, and + # pop lex dimension for the loop variable, and + # increment lex dim val enumerating items in current code block + next_insn_lex_tuple.pop() + next_insn_lex_tuple.pop() + + # We could always increment next_insn_lex_tuple[-1] here since + # this new block of code comes after the previous block (all + # statements since last opened/closed loop), but if we have not + # added any statements within the previous section yet, we + # don't have to (effectively ignoring that section of code). + stmt_added_since_prev_block_at_tier.pop() + if stmt_added_since_prev_block_at_tier[-1]: + next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 + stmt_added_since_prev_block_at_tier[-1] = False + elif isinstance(linearization_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) + if lp_insn_id is None: + # TODO make sure it's okay to ignore barriers without id + # (because they'll never be part of a dependency?) + # matmul example has barrier that fails this assertion... + # assert linearization_item.originating_insn_id is not None + continue + + # only process before/after insns, otherwise ignore + stmt_added = False + + if lp_insn_id == before_insn_id: + # add before sched item + stmt_instance_set_before = StatementInstanceSet( + lp_insn_id, + next_insn_lex_tuple[:]) + stmt_added = True + + if lp_insn_id == after_insn_id: + # add after sched item + stmt_instance_set_after = StatementInstanceSet( + lp_insn_id, + next_insn_lex_tuple[:]) + stmt_added = True + + # Note: before/after may refer to same stmt, in which case + # both of the above conditionals execute + + if stmt_added: + + # track the max number of lex dims used + if len(next_insn_lex_tuple) > max_lex_dim: + max_lex_dim = len(next_insn_lex_tuple) + # increment lex dim val enumerating items in current code block - next_insn_lex_tuple.pop() - next_insn_lex_tuple.pop() - - # We could always increment next_insn_lex_tuple[-1] here since - # this new block of code comes after the previous block (all - # statements since last opened/closed loop), but if we have not - # added any statements within the previous section yet, we - # don't have to (effectively ignoring that section of code). - stmt_added_since_prev_block_at_tier.pop() - if stmt_added_since_prev_block_at_tier[-1]: - next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 - stmt_added_since_prev_block_at_tier[-1] = False - elif isinstance(linearization_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) - if lp_insn_id is None: - # TODO make sure it's okay to ignore barriers without id - # (because they'll never be part of a dependency?) - # matmul example has barrier that fails this assertion... - # assert linearization_item.originating_insn_id is not None - continue - - # only process before/after insns, otherwise ignore - stmt_added = False - - if lp_insn_id == before_insn_id: - # add before sched item - self.stmt_instance_set_before = StatementInstanceSet( - lp_insn_id, - next_insn_lex_tuple[:]) - stmt_added = True - - if lp_insn_id == after_insn_id: - # add after sched item - self.stmt_instance_set_after = StatementInstanceSet( - lp_insn_id, - next_insn_lex_tuple[:]) - stmt_added = True - - # Note: before/after may refer to same stmt, in which case - # both of the above conditionals execute - - if stmt_added: - # increment lex dim val enumerating items in current code block - next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1] + 1 - - # all current (nested) blocks now contain a statement - stmt_added_since_prev_block_at_tier = [True]*len( - stmt_added_since_prev_block_at_tier) - else: - pass - # to save time, stop when we've created both statements - if self.stmt_instance_set_before and self.stmt_instance_set_after: - break - - # At this point, pairwise sub-schedule may contain lex point tuples - # missing dimensions; the values in these missing dims should - # be zero, so add them. - - def _pad_lex_tuple_with_zeros(stmt_inst, length): - return StatementInstanceSet( - stmt_inst.insn_id, - stmt_inst.lex_points[:] + [0]*(length-len(stmt_inst.lex_points)), - ) - - max_lex_dim = self.max_lex_dims() - - self.stmt_instance_set_before = _pad_lex_tuple_with_zeros( - self.stmt_instance_set_before, max_lex_dim) - self.stmt_instance_set_after = _pad_lex_tuple_with_zeros( - self.stmt_instance_set_after, max_lex_dim) - - def max_lex_dims(self): - return max([ - len(self.stmt_instance_set_before.lex_points), - len(self.stmt_instance_set_after.lex_points)]) - - def build_maps( - self, - knl, - ): - r"""Create a pair of :class:`islpy.Map`\ s representing a pairwise schedule - as two mappings from statement instances to lexicographic time, - one for ``stmt_instance_set_before`` and one for - ``stmt_instance_set_after``. - - :arg knl: A :class:`loopy.kernel.LoopKernel` containing the - linearization items that are described by the schedule. This - kernel will be used to get the domains associated with the inames - used in the statements. - - :returns: A two-tuple containing two :class:`islpy.Map`s - representing the a pairwise schedule as two mappings - from statement instances to lexicographic time, one for - each of the two :class:`StatementInstanceSet`s. - - """ - - from loopy.schedule.checker.utils import ( - list_var_names_in_isl_sets, - create_symbolic_map_from_tuples, - add_dims_to_isl_set, - ) - - params_sched = [] - out_names_sched = self.get_lex_var_names() - - def _get_map_for_stmt_inst(stmt_inst, int_sid): - - # Get inames domain for statement instance (a BasicSet) - dom = knl.get_inames_domain( - knl.id_to_insn[stmt_inst.insn_id].within_inames) - - # create space (an isl space in current implementation) - # {('statement', used in statement domain>) -> - # (lexicographic ordering dims)} - dom_inames_ordered = list_var_names_in_isl_sets([dom]) - - 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=params_sched) - - # 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), ] - - # Each map representing the schedule will map - # statement instances -> lex time. - # Right now, 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), - stmt_inst.lex_points - )] - - # create map - return create_symbolic_map_from_tuples( - tuple_pairs_with_domains=zip(tuple_pair, dom_to_intersect), - space=sched_space, - ) - - # 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_sid_before = 0 - int_sid_after = 0 if ( - self.stmt_instance_set_before.insn_id == - self.stmt_instance_set_after.insn_id - ) else 1 - - map_before = _get_map_for_stmt_inst( - self.stmt_instance_set_before, int_sid_before) - map_after = _get_map_for_stmt_inst( - self.stmt_instance_set_after, int_sid_after) - - return (map_before, map_after) - - def get_lex_var_names(self): - return [LEX_VAR_PREFIX+str(i) for i in range(self.max_lex_dims())] - - def __str__(self): - - def stringify_sched_stmt_instance(stmt_inst, int_sid): - return "{\n[%s=%s,] -> %s;\n}" % ( - STATEMENT_VAR_NAME, - int_sid, - stmt_inst.lex_points) - - # TODO once we change class -> funcs, this repetition of logic will disappear - int_sid_before = 0 - int_sid_after = 0 if ( - self.stmt_instance_set_before.insn_id == - self.stmt_instance_set_after.insn_id - ) else 1 - - return "%s(\nBefore: %s\nAfter: %s\n)" % ( - self.__class__.__name__, - stringify_sched_stmt_instance( - self.stmt_instance_set_before, int_sid_before), - stringify_sched_stmt_instance( - self.stmt_instance_set_after, int_sid_after)) + next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1] + 1 + + # all current (nested) blocks now contain a statement + stmt_added_since_prev_block_at_tier = [True]*len( + stmt_added_since_prev_block_at_tier) + else: + pass + # to save time, stop when we've created both statements + if stmt_instance_set_before and stmt_instance_set_after: + break + + # At this point, pairwise sub-schedule may contain lex point tuples + # missing dimensions; the values in these missing dims should + # be zero, so add them. + + def _pad_lex_tuple_with_zeros(stmt_inst, length): + return StatementInstanceSet( + stmt_inst.insn_id, + stmt_inst.lex_points[:] + [0]*(length-len(stmt_inst.lex_points)), + ) + + stmt_instance_set_before = _pad_lex_tuple_with_zeros( + stmt_instance_set_before, max_lex_dim) + stmt_instance_set_after = _pad_lex_tuple_with_zeros( + stmt_instance_set_after, max_lex_dim) + + # Now generate maps from the blueprint --------------------------------------- + + from loopy.schedule.checker.utils import ( + list_var_names_in_isl_sets, + create_symbolic_map_from_tuples, + add_dims_to_isl_set, + ) + + params_sched = [] + out_names_sched = [LEX_VAR_PREFIX+str(i) for i in range(max_lex_dim)] + + def _get_map_for_stmt_inst(stmt_inst, int_sid): + + # Get inames domain for statement instance (a BasicSet) + dom = knl.get_inames_domain( + knl.id_to_insn[stmt_inst.insn_id].within_inames) + + # create space (an isl space in current implementation) + # {('statement', used in statement domain>) -> + # (lexicographic ordering dims)} + dom_inames_ordered = list_var_names_in_isl_sets([dom]) + + 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=params_sched) + + # 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), ] + + # Each map representing the schedule will map + # statement instances -> lex time. + # Right now, 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), + stmt_inst.lex_points + )] + + # create map + return create_symbolic_map_from_tuples( + tuple_pairs_with_domains=zip(tuple_pair, dom_to_intersect), + space=sched_space, + ) + + # 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_sid_before = 0 + int_sid_after = 0 if ( + stmt_instance_set_before.insn_id == stmt_instance_set_after.insn_id + ) else 1 + + map_before = _get_map_for_stmt_inst(stmt_instance_set_before, int_sid_before) + map_after = _get_map_for_stmt_inst(stmt_instance_set_after, int_sid_after) + + return (map_before, map_after) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index c87bb149b..3834f280a 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -96,44 +96,6 @@ def test_lexschedule_and_map_creation(): knl = get_one_linearized_kernel(knl) linearization_items = knl.linearization - # Create PairwiseScheduleBuilder: mapping of {statement instance: lex point} - sched_ab = get_schedule_for_statement_pair( - knl, - linearization_items, - "insn_a", - "insn_b", - ) - sched_ac = get_schedule_for_statement_pair( - knl, - linearization_items, - "insn_a", - "insn_c", - ) - sched_ad = get_schedule_for_statement_pair( - knl, - linearization_items, - "insn_a", - "insn_d", - ) - sched_bc = get_schedule_for_statement_pair( - knl, - linearization_items, - "insn_b", - "insn_c", - ) - sched_bd = get_schedule_for_statement_pair( - knl, - linearization_items, - "insn_b", - "insn_d", - ) - sched_cd = get_schedule_for_statement_pair( - knl, - linearization_items, - "insn_c", - "insn_d", - ) - # There are multiple potential linearization orders for this kernel, so when # performing our comparisons for schedule correctness, we need to know which # order loopy chose. @@ -152,12 +114,13 @@ def _lex_space_string(dim_vals): # Relationship between insn_a and insn_b --------------------------------------- - assert sched_ab.stmt_instance_set_before.lex_points == [0, 'i', 0, 'k', 0] - assert sched_ab.stmt_instance_set_after.lex_points == [0, 'i', 1, 'j', 0] - - # Get two maps from the PairwiseScheduleBuilder - - sched_map_before, sched_map_after = sched_ab.build_maps(knl) + # Get two maps + sched_map_before, sched_map_after = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_a", + "insn_b", + ) # Create expected maps, align, compare @@ -187,12 +150,13 @@ def _lex_space_string(dim_vals): # ------------------------------------------------------------------------------ # Relationship between insn_a and insn_c --------------------------------------- - assert sched_ac.stmt_instance_set_before.lex_points == [0, 'i', 0, 'k', 0] - assert sched_ac.stmt_instance_set_after.lex_points == [0, 'i', 1, 'j', 0] - - # Get two maps from the PairwiseScheduleBuilder - - sched_map_before, sched_map_after = sched_ac.build_maps(knl) + # Get two maps + sched_map_before, sched_map_after = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_a", + "insn_c", + ) # Create expected maps, align, compare @@ -225,14 +189,13 @@ def _lex_space_string(dim_vals): # insn_a and insn_d could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): - assert sched_ad.stmt_instance_set_before.lex_points == [ - a_lex_idx, 'i', 0, 'k', 0] - assert sched_ad.stmt_instance_set_after.lex_points == [ - d_lex_idx, 't', 0, 0, 0] - - # Get two maps from the PairwiseScheduleBuilder - - sched_map_before, sched_map_after = sched_ad.build_maps(knl) + # Get two maps + sched_map_before, sched_map_after = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_a", + "insn_d", + ) # Create expected maps, align, compare @@ -272,14 +235,13 @@ def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): # insn_b and insn_c could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): - assert sched_bc.stmt_instance_set_before.lex_points == [ - 0, 'i', 0, 'j', b_lex_idx] - assert sched_bc.stmt_instance_set_after.lex_points == [ - 0, 'i', 0, 'j', c_lex_idx] - - # Get two maps from the PairwiseScheduleBuilder - - sched_map_before, sched_map_after = sched_bc.build_maps(knl) + # Get two maps + sched_map_before, sched_map_after = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_b", + "insn_c", + ) # Create expected maps, align, compare @@ -319,14 +281,13 @@ def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): # insn_b and insn_d could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): - assert sched_bd.stmt_instance_set_before.lex_points == [ - b_lex_idx, 'i', 0, 'j', 0] - assert sched_bd.stmt_instance_set_after.lex_points == [ - d_lex_idx, 't', 0, 0, 0] - - # Get two maps from the PairwiseScheduleBuilder - - sched_map_before, sched_map_after = sched_bd.build_maps(knl) + # Get two maps + sched_map_before, sched_map_after = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_b", + "insn_d", + ) # Create expected maps, align, compare @@ -366,14 +327,13 @@ def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): # insn_c and insn_d could have been linearized in either order # (i loop could be before or after t loop) def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): - assert sched_cd.stmt_instance_set_before.lex_points == [ - c_lex_idx, 'i', 0, 'j', 0] - assert sched_cd.stmt_instance_set_after.lex_points == [ - d_lex_idx, 't', 0, 0, 0] - - # Get two maps from the PairwiseScheduleBuilder - - sched_map_before, sched_map_after = sched_cd.build_maps(knl) + # Get two maps + sched_map_before, sched_map_after = get_schedule_for_statement_pair( + knl, + linearization_items, + "insn_c", + "insn_d", + ) # Create expected maps, align, compare From 200eed41de56f90bec1a8c3f85d6a3ef9ddc05bc Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Jul 2020 09:07:08 -0500 Subject: [PATCH 100/315] 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 101/315] 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 87ac1b9e8c99f52e4a64f3db701159e907bc3764 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Jul 2020 09:13:00 -0500 Subject: [PATCH 102/315] rename test_lexschedule_and_map_creation()->test_lexschedule_creation() --- 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 3834f280a..60abfade0 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -50,7 +50,7 @@ faulthandler.enable() -def test_lexschedule_and_map_creation(): +def test_lexschedule_creation(): import islpy as isl from loopy.schedule.checker import ( get_schedule_for_statement_pair, From 2251fa20eefb7f978c1a16131cefdeeb36c2586a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Jul 2020 10:30:02 -0500 Subject: [PATCH 103/315] remove StatementInstanceSet class, use an ImmutableRecord instead --- loopy/schedule/checker/schedule.py | 78 ++++++------------------------ 1 file changed, 14 insertions(+), 64 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 9e693a9a1..fc4938c98 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -47,38 +47,6 @@ STATEMENT_VAR_NAME = "%sstatement" % (LIN_CHECK_IDENTIFIER_PREFIX) -class StatementInstanceSet(object): - """A representation of a set of (non-concurrent) instances of a - statement being executed. The ordering of the instances is described - by the `lex_points` attribute, a list representing points in a - lexicographic ordering of statements. Each field in the list - corresponds to a dimension in the lexicographic ordering. - - .. attribute:: insn_id - - A :class:`str` instruction identifier that is unique within - a :class:`loopy.kernel.LoopKernel`. - - .. attribute:: lex_points - - A list containing one value for each dimension in a lexicographic - ordering. These values describe the ordering of the statements, - and may be :class:`str` :mod:`loopy` inames or :class:`int`. - """ - - def __init__( - self, - insn_id, - lex_points, - ): - self.insn_id = insn_id - self.lex_points = lex_points - - def __repr__(self): - return "%s(%s, %s)" % ( - self.__class__.__name__, self.insn_id, self.lex_points) - - def generate_pairwise_schedule( knl, linearization_items_ordered, @@ -116,33 +84,15 @@ def generate_pairwise_schedule( each of the two statements. """ - # Two StatementInstanceSets, one for each statement: - - """ - stmt_instance_set_before - - A :class:`StatementInstanceSet` whose ordering relative - to `stmt_instance_set_after is described by the schedule blueprint. This - is achieved by mapping the statement instances in both sets to points - in a single lexicographic ordering. Points in lexicographic ordering - are represented as a list of :class:`int` or as :class:`str` - :mod:`loopy` inames. - """ + # For each statement, create a :class:`ImmutableRecord` describing the set of + # statement instances. Contains the insn_id and a list representing points + # in the lexicographic ordering containing items of :class:`int` or + # :class:`str` :mod:`loopy` inames. stmt_instance_set_before = None - - """ - stmt_instance_set_after - - A :class:`StatementInstanceSet` whose ordering relative - to `stmt_instance_set_before is described by the schedule blueprint. This - is achieved by mapping the statement instances in both sets to points - in a single lexicographic ordering. Points in lexicographic ordering - are represented as a list of :class:`int` or as :class:`str` - :mod:`loopy` inames. - """ stmt_instance_set_after = None from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) + from pytools import ImmutableRecord # go through linearization_items_ordered and generate pairwise sub-schedule @@ -210,16 +160,16 @@ def generate_pairwise_schedule( if lp_insn_id == before_insn_id: # add before sched item - stmt_instance_set_before = StatementInstanceSet( - lp_insn_id, - next_insn_lex_tuple[:]) + stmt_instance_set_before = ImmutableRecord( + insn_id=lp_insn_id, + lex_points=next_insn_lex_tuple[:]) stmt_added = True if lp_insn_id == after_insn_id: # add after sched item - stmt_instance_set_after = StatementInstanceSet( - lp_insn_id, - next_insn_lex_tuple[:]) + stmt_instance_set_after = ImmutableRecord( + insn_id=lp_insn_id, + lex_points=next_insn_lex_tuple[:]) stmt_added = True # Note: before/after may refer to same stmt, in which case @@ -248,9 +198,9 @@ def generate_pairwise_schedule( # be zero, so add them. def _pad_lex_tuple_with_zeros(stmt_inst, length): - return StatementInstanceSet( - stmt_inst.insn_id, - stmt_inst.lex_points[:] + [0]*(length-len(stmt_inst.lex_points)), + return ImmutableRecord( + insn_id=stmt_inst.insn_id, + lex_points=stmt_inst.lex_points[:] + [0]*(length-len(stmt_inst.lex_points)) ) stmt_instance_set_before = _pad_lex_tuple_with_zeros( From 87933ce1f4a8b90c578b250a8d7c666af9479505 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 14 Jul 2020 11:09:43 -0500 Subject: [PATCH 104/315] fix flake8 error --- loopy/schedule/checker/schedule.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index fc4938c98..6b047ed26 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -200,7 +200,8 @@ def generate_pairwise_schedule( def _pad_lex_tuple_with_zeros(stmt_inst, length): return ImmutableRecord( insn_id=stmt_inst.insn_id, - lex_points=stmt_inst.lex_points[:] + [0]*(length-len(stmt_inst.lex_points)) + lex_points=stmt_inst.lex_points[:] + [0]*( + length-len(stmt_inst.lex_points)) ) stmt_instance_set_before = _pad_lex_tuple_with_zeros( From e07b1476c6e04e094901412cc4ecce09562bc23f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 19 Jul 2020 14:26:38 -0500 Subject: [PATCH 105/315] assert knl is preprocessed (rather than performing the preprocessing) in get_schedule_for_statement_pair() --- loopy/schedule/checker/__init__.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index a2963f689..ca1684ec4 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -36,7 +36,7 @@ def get_schedule_for_statement_pair( representing a pairwise schedule as two mappings from statement instances to lexicographic time. - :arg knl: A :class:`loopy.kernel.LoopKernel` containing the + :arg knl: A preprocessed :class:`loopy.kernel.LoopKernel` containing the linearization items that will be used to create a schedule. :arg linearization_items: A list of :class:`loopy.schedule.ScheduleItem` @@ -106,10 +106,12 @@ def get_schedule_for_statement_pair( """ - # {{{ preprocess if not already preprocessed + # {{{ make sure kernel has been preprocessed - from loopy import preprocess_kernel - preproc_knl = preprocess_kernel(knl) + from loopy.kernel import KernelState + assert knl.state in [ + KernelState.PREPROCESSED, + KernelState.LINEARIZED] # }}} @@ -122,15 +124,15 @@ def get_schedule_for_statement_pair( get_concurrent_inames, get_EnterLoop_inames, ) - conc_inames, _ = get_concurrent_inames(preproc_knl) - enterloop_inames = get_EnterLoop_inames(linearization_items, preproc_knl) + conc_inames, _ = get_concurrent_inames(knl) + enterloop_inames = get_EnterLoop_inames(linearization_items, knl) conc_loop_inames = conc_inames & enterloop_inames if conc_loop_inames: from warnings import warn warn( "get_schedule_for_statement_pair encountered EnterLoop for inames %s " "with ConcurrentTag(s) in linearization for kernel %s. " - "Ignoring these loops." % (conc_loop_inames, preproc_knl.name)) + "Ignoring these loops." % (conc_loop_inames, knl.name)) # }}} @@ -139,7 +141,7 @@ def get_schedule_for_statement_pair( # include only instructions involved in this dependency from loopy.schedule.checker.schedule import generate_pairwise_schedule return generate_pairwise_schedule( - preproc_knl, + knl, linearization_items, insn_id_before, insn_id_after, From 17ed282c9955e399b3363993abd675ca571742d5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 19 Jul 2020 14:34:34 -0500 Subject: [PATCH 106/315] make lex_points a tuple instead of a list --- 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 6b047ed26..8ee2e5106 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -162,14 +162,14 @@ def generate_pairwise_schedule( # add before sched item stmt_instance_set_before = ImmutableRecord( insn_id=lp_insn_id, - lex_points=next_insn_lex_tuple[:]) + lex_points=tuple(next_insn_lex_tuple[:])) stmt_added = True if lp_insn_id == after_insn_id: # add after sched item stmt_instance_set_after = ImmutableRecord( insn_id=lp_insn_id, - lex_points=next_insn_lex_tuple[:]) + lex_points=tuple(next_insn_lex_tuple[:])) stmt_added = True # Note: before/after may refer to same stmt, in which case @@ -200,8 +200,8 @@ def generate_pairwise_schedule( def _pad_lex_tuple_with_zeros(stmt_inst, length): return ImmutableRecord( insn_id=stmt_inst.insn_id, - lex_points=stmt_inst.lex_points[:] + [0]*( - length-len(stmt_inst.lex_points)) + lex_points=stmt_inst.lex_points[:] + tuple( + [0]*(length-len(stmt_inst.lex_points))) ) stmt_instance_set_before = _pad_lex_tuple_with_zeros( From 41e8acbbcbf265e3b28d18fdd6a5228d71f569e5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 19 Jul 2020 14:37:52 -0500 Subject: [PATCH 107/315] renamed linearization_items_ordered->linearization_items in generate_pairwise_schedule() --- loopy/schedule/checker/schedule.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 8ee2e5106..838c5f74b 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -49,7 +49,7 @@ def generate_pairwise_schedule( knl, - linearization_items_ordered, + linearization_items, before_insn_id, after_insn_id, loops_to_ignore=set(), @@ -66,8 +66,8 @@ def generate_pairwise_schedule( kernel will be used to get the domains associated with the inames used in the statements. - :arg linearization_items_ordered: A list of :class:`loopy.schedule.ScheduleItem` - (to be renamed to `loopy.schedule.LinearizationItem`) containing the + :arg linearization_items: A list of :class:`loopy.schedule.ScheduleItem` + (to be renamed to `loopy.schedule.LinearizationItem`) including the two linearization items whose relative order will be described by the schedule. This list may be a *partial* linearization for a kernel since this function may be used during the linearization process. @@ -94,14 +94,14 @@ def generate_pairwise_schedule( from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from pytools import ImmutableRecord - # go through linearization_items_ordered and generate pairwise sub-schedule + # go through linearization_items and generate pairwise sub-schedule # 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] stmt_added_since_prev_block_at_tier = [False] max_lex_dim = 0 - for linearization_item in linearization_items_ordered: + for linearization_item in linearization_items: if isinstance(linearization_item, EnterLoop): iname = linearization_item.iname if iname in loops_to_ignore: From bb5128d61f15cfa8fdee667e5f93c02d6bf88c00 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 19 Jul 2020 14:49:39 -0500 Subject: [PATCH 108/315] when creating schedule, if lp_insn_id is None, assert that the linearization item is a barrier; update comment explaining this scenario; add fixme about potential future work --- loopy/schedule/checker/schedule.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 838c5f74b..c71381761 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -148,11 +148,17 @@ def generate_pairwise_schedule( get_insn_id_from_linearization_item, ) lp_insn_id = get_insn_id_from_linearization_item(linearization_item) + if lp_insn_id is None: - # TODO make sure it's okay to ignore barriers without id - # (because they'll never be part of a dependency?) - # matmul example has barrier that fails this assertion... - # assert linearization_item.originating_insn_id is not None + assert isinstance(linearization_item, Barrier) + + # Barriers without insn 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 + # (e.g. what dependency produced them) and verify that they're + # adequately protecting all statement instance pairs. + continue # only process before/after insns, otherwise ignore From 3550e6d35dcfe5baf9c759024170fcf887b73e60 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 19 Jul 2020 16:49:00 -0500 Subject: [PATCH 109/315] fix indentation on function docstring --- loopy/schedule/checker/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 0bfdf0a54..abd06685a 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -153,8 +153,8 @@ def create_symbolic_map_from_tuples( space, ): """Return an :class:`islpy.Map` constructed using the provided space, - mapping input->output tuples provided in `tuple_pairs_with_domains`, - with each set of tuple variables constrained by the domains provided. + mapping input->output tuples provided in `tuple_pairs_with_domains`, + with each set of tuple variables constrained by the domains provided. :arg tuple_pairs_with_domains: A :class:`list` with each element being a tuple of the form `((tup_in, tup_out), domain)`. From 38d584a9409cbb3486f0e05cf94258a2455c7ad2 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 19 Jul 2020 16:55:45 -0500 Subject: [PATCH 110/315] fix pluralizing class in docstring --- 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 c71381761..5cbe4c463 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -78,7 +78,7 @@ def generate_pairwise_schedule( :arg after_insn_id: A :class:`str` instruction id specifying stmt_instance_set_after in this pair of instructions. - :returns: A two-tuple containing two :class:`islpy.Map`s + :returns: A two-tuple containing two :class:`islpy.Map`\ s representing the a pairwise schedule as two mappings from statement instances to lexicographic time, one for each of the two statements. From 18e468134f3b6e8fc36838d178207933deb53115 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Jul 2020 14:21:59 -0500 Subject: [PATCH 111/315] assert that ignored linearization items are of specific type --- loopy/schedule/checker/schedule.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 5cbe4c463..6d4382c11 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -194,6 +194,10 @@ def generate_pairwise_schedule( stmt_added_since_prev_block_at_tier = [True]*len( stmt_added_since_prev_block_at_tier) else: + from loopy.schedule import (CallKernel, ReturnFromKernel) + # no action needed for these types of linearization item + assert isinstance( + linearization_item, (CallKernel, ReturnFromKernel)) pass # to save time, stop when we've created both statements if stmt_instance_set_before and stmt_instance_set_after: From 1f4edf2e678e257f30ec32d8ffc65b9b1a7e0fed Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Jul 2020 14:46:16 -0500 Subject: [PATCH 112/315] use set().union(*[list comprehension]) instead of loop in list_var_names_in_isl_sets() --- loopy/schedule/checker/utils.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index abd06685a..6c6cf160d 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -140,12 +140,11 @@ def ensure_dim_names_match_and_align(obj_map, tgt_map): def list_var_names_in_isl_sets( isl_sets, set_dim=isl.dim_type.set): - inames = set() - for isl_set in isl_sets: - inames.update(isl_set.get_var_names(set_dim)) + + inames = set().union(*[isl_set.get_var_names(set_dim) for isl_set in isl_sets]) # sorting is not necessary, but keeps results consistent between runs - return sorted(list(inames)) + return sorted(inames) def create_symbolic_map_from_tuples( From 7635f47bfafadcd9936a7be8b728b71ed31e75d0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Jul 2020 14:55:19 -0500 Subject: [PATCH 113/315] renamed list_var_names_in_isl_sets()->sorted_union_of_names_in_isl_sets() --- loopy/schedule/checker/schedule.py | 4 ++-- loopy/schedule/checker/utils.py | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 6d4382c11..b56040adf 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -222,7 +222,7 @@ def _pad_lex_tuple_with_zeros(stmt_inst, length): # Now generate maps from the blueprint --------------------------------------- from loopy.schedule.checker.utils import ( - list_var_names_in_isl_sets, + sorted_union_of_names_in_isl_sets, create_symbolic_map_from_tuples, add_dims_to_isl_set, ) @@ -239,7 +239,7 @@ def _get_map_for_stmt_inst(stmt_inst, int_sid): # create space (an isl space in current implementation) # {('statement', used in statement domain>) -> # (lexicographic ordering dims)} - dom_inames_ordered = list_var_names_in_isl_sets([dom]) + dom_inames_ordered = sorted_union_of_names_in_isl_sets([dom]) in_names_sched = [STATEMENT_VAR_NAME] + dom_inames_ordered[:] sched_space = isl.Space.create_from_names( diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 6c6cf160d..b845edacc 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -137,9 +137,12 @@ def ensure_dim_names_match_and_align(obj_map, tgt_map): return aligned_obj_map -def list_var_names_in_isl_sets( +def sorted_union_of_names_in_isl_sets( isl_sets, set_dim=isl.dim_type.set): + """Return a sorted list of the union of all variable names found in + the provided :class:`islpy.Set`\ s. + """ inames = set().union(*[isl_set.get_var_names(set_dim) for isl_set in isl_sets]) From 227762f5a6e345843584495310c138fac3c684a4 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Jul 2020 15:04:54 -0500 Subject: [PATCH 114/315] rename constraint->condition in create_symbolic_map_from_tuples() --- 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 b845edacc..92219b875 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -172,7 +172,7 @@ def create_symbolic_map_from_tuples( `tuple_pairs_with_domains`, map `(tup_in)->(tup_out) : domain`, where `tup_in` and `tup_out` are numeric or symbolic values assigned to the input and output - dimension variables in `space`, and `domain` specifies constraints + dimension variables in `space`, and `domain` specifies conditions on these values. """ @@ -194,31 +194,31 @@ def create_symbolic_map_from_tuples( dim_type.out, 0, dim_type.in_, len(space_in_names), len(space_out_names)) for (tup_in, tup_out), dom in tuple_pairs_with_domains: - # initialize constraint with true - constraint = islvars[0].eq_set(islvars[0]) + # initialize condition with true + condition = islvars[0].eq_set(islvars[0]) # set values for 'in' dimension using tuple vals assert len(tup_in) == len(space_in_names) for dim_name, val_in in zip(space_in_names, tup_in): if isinstance(val_in, int): - constraint = constraint \ + condition = condition \ & islvars[dim_name].eq_set(islvars[0]+val_in) else: - constraint = constraint \ + condition = condition \ & islvars[dim_name].eq_set(islvars[val_in]) # set values for 'out' dimension using tuple vals assert len(tup_out) == len(space_out_names) for dim_name, val_out in zip(space_out_names, tup_out): if isinstance(val_out, int): - constraint = constraint \ + condition = condition \ & islvars[dim_name].eq_set(islvars[0]+val_out) else: - constraint = constraint \ + condition = condition \ & islvars[dim_name].eq_set(islvars[val_out]) # convert set to map by moving dimensions around - map_from_set = isl.Map.from_domain(constraint) + map_from_set = isl.Map.from_domain(condition) map_from_set = map_from_set.move_dims( dim_type.out, 0, dim_type.in_, len(space_in_names), len(space_out_names)) From 6d336bae34cc43ed628d9fa67f56161a4d7dbb20 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Jul 2020 15:48:56 -0500 Subject: [PATCH 115/315] make function for duplicated code: _conjunction_of_dim_eq_conditions() --- loopy/schedule/checker/utils.py | 34 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 92219b875..2cf8e90fb 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -187,6 +187,17 @@ def create_symbolic_map_from_tuples( # loop through pairs and create a set that will later be converted to a map + 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 to empty union_of_maps = isl.Map.from_domain( islvars[0].eq_set(islvars[0]+1) # 0 == 1 (false) @@ -194,28 +205,13 @@ def create_symbolic_map_from_tuples( dim_type.out, 0, dim_type.in_, len(space_in_names), len(space_out_names)) for (tup_in, tup_out), dom in tuple_pairs_with_domains: - # initialize condition with true - condition = islvars[0].eq_set(islvars[0]) - # set values for 'in' dimension using tuple vals - assert len(tup_in) == len(space_in_names) - for dim_name, val_in in zip(space_in_names, tup_in): - if isinstance(val_in, int): - condition = condition \ - & islvars[dim_name].eq_set(islvars[0]+val_in) - else: - condition = condition \ - & islvars[dim_name].eq_set(islvars[val_in]) + condition = _conjunction_of_dim_eq_conditions( + space_in_names, tup_in, islvars) # set values for 'out' dimension using tuple vals - assert len(tup_out) == len(space_out_names) - for dim_name, val_out in zip(space_out_names, tup_out): - if isinstance(val_out, int): - condition = condition \ - & islvars[dim_name].eq_set(islvars[0]+val_out) - else: - condition = condition \ - & islvars[dim_name].eq_set(islvars[val_out]) + condition = condition & _conjunction_of_dim_eq_conditions( + space_out_names, tup_out, islvars) # convert set to map by moving dimensions around map_from_set = isl.Map.from_domain(condition) From a81bd480459cbddb9b9c025e60407ca5cbaf3192 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 Jul 2020 15:56:36 -0500 Subject: [PATCH 116/315] rename get_concurrent_inames(knl)->partition_inames_by_concurrency(knl) --- loopy/schedule/checker/__init__.py | 4 ++-- loopy/schedule/checker/utils.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index ca1684ec4..466837534 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -121,10 +121,10 @@ def get_schedule_for_statement_pair( # won't be any inames with ConcurrentTags in EnterLoop linearization items. # Test which exercises this: test_linearization_checker_with_stroud_bernstein()) from loopy.schedule.checker.utils import ( - get_concurrent_inames, + partition_inames_by_concurrency, get_EnterLoop_inames, ) - conc_inames, _ = get_concurrent_inames(knl) + conc_inames, _ = partition_inames_by_concurrency(knl) enterloop_inames = get_EnterLoop_inames(linearization_items, knl) conc_loop_inames = conc_inames & enterloop_inames if conc_loop_inames: diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 2cf8e90fb..bad083558 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -237,7 +237,7 @@ def _conjunction_of_dim_eq_conditions(dim_names, values, islvars): return union_of_maps -def get_concurrent_inames(knl): +def partition_inames_by_concurrency(knl): from loopy.kernel.data import ConcurrentTag conc_inames = set() non_conc_inames = set() From be1cf81556b359c5c63fe21d6f2909198b83732d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 21 Jul 2020 11:14:32 -0500 Subject: [PATCH 117/315] to prevent quadratic complexity in schedule creation, create lex points for all relevant insn_ids simultaneously; then afterward process pairs individually; (also eliminate more unnecessary lex dims) --- loopy/schedule/checker/__init__.py | 14 ++- loopy/schedule/checker/schedule.py | 138 +++++++++++++++-------------- test/test_linearization_checker.py | 68 +++++++------- 3 files changed, 107 insertions(+), 113 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 466837534..fa9700b47 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -21,13 +21,12 @@ """ -# {{{ create a pairwise schedule for statement pair +# {{{ create a pairwise schedules for statement pairs -def get_schedule_for_statement_pair( +def get_schedules_for_statement_pairs( knl, linearization_items, - insn_id_before, - insn_id_after, + insn_id_pairs, ): r"""Given a pair of statements in a linearized kernel, determine the (relative) order in which the instances are executed, @@ -139,12 +138,11 @@ def get_schedule_for_statement_pair( # {{{ Create two mappings from {statement instance: lex point} # include only instructions involved in this dependency - from loopy.schedule.checker.schedule import generate_pairwise_schedule - return generate_pairwise_schedule( + from loopy.schedule.checker.schedule import generate_pairwise_schedules + return generate_pairwise_schedules( knl, linearization_items, - insn_id_before, - insn_id_after, + insn_id_pairs, loops_to_ignore=conc_loop_inames, ) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index b56040adf..6b9905613 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -47,11 +47,10 @@ STATEMENT_VAR_NAME = "%sstatement" % (LIN_CHECK_IDENTIFIER_PREFIX) -def generate_pairwise_schedule( +def generate_pairwise_schedules( knl, linearization_items, - before_insn_id, - after_insn_id, + insn_id_pairs, loops_to_ignore=set(), ): r"""Given a pair of statements in a linearized kernel, determine @@ -79,17 +78,21 @@ def generate_pairwise_schedule( stmt_instance_set_after in this pair of instructions. :returns: A two-tuple containing two :class:`islpy.Map`\ s - representing the a pairwise schedule as two mappings + representing a pairwise schedule as two mappings from statement instances to lexicographic time, one for each of the two statements. """ + # TODO + # update documentation + + all_insn_ids = set().union(*insn_id_pairs) + # For each statement, create a :class:`ImmutableRecord` describing the set of # statement instances. Contains the insn_id and a list representing points # in the lexicographic ordering containing items of :class:`int` or # :class:`str` :mod:`loopy` inames. - stmt_instance_set_before = None - stmt_instance_set_after = None + stmt_instances = {} from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from pytools import ImmutableRecord @@ -161,31 +164,10 @@ def generate_pairwise_schedule( continue - # only process before/after insns, otherwise ignore - stmt_added = False - - if lp_insn_id == before_insn_id: - # add before sched item - stmt_instance_set_before = ImmutableRecord( - insn_id=lp_insn_id, - lex_points=tuple(next_insn_lex_tuple[:])) - stmt_added = True - - if lp_insn_id == after_insn_id: - # add after sched item - stmt_instance_set_after = ImmutableRecord( - insn_id=lp_insn_id, - lex_points=tuple(next_insn_lex_tuple[:])) - stmt_added = True - - # Note: before/after may refer to same stmt, in which case - # both of the above conditionals execute - - if stmt_added: - - # track the max number of lex dims used - if len(next_insn_lex_tuple) > max_lex_dim: - max_lex_dim = len(next_insn_lex_tuple) + # only process listed insns, otherwise ignore + if lp_insn_id in all_insn_ids: + # add item + stmt_instances[lp_insn_id] = tuple(next_insn_lex_tuple[:]) # increment lex dim val enumerating items in current code block next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1] + 1 @@ -199,27 +181,10 @@ def generate_pairwise_schedule( assert isinstance( linearization_item, (CallKernel, ReturnFromKernel)) pass - # to save time, stop when we've created both statements - if stmt_instance_set_before and stmt_instance_set_after: - break - - # At this point, pairwise sub-schedule may contain lex point tuples - # missing dimensions; the values in these missing dims should - # be zero, so add them. - - def _pad_lex_tuple_with_zeros(stmt_inst, length): - return ImmutableRecord( - insn_id=stmt_inst.insn_id, - lex_points=stmt_inst.lex_points[:] + tuple( - [0]*(length-len(stmt_inst.lex_points))) - ) - stmt_instance_set_before = _pad_lex_tuple_with_zeros( - stmt_instance_set_before, max_lex_dim) - stmt_instance_set_after = _pad_lex_tuple_with_zeros( - stmt_instance_set_after, max_lex_dim) - - # Now generate maps from the blueprint --------------------------------------- + # to save time, stop when we've created all statements + if len(stmt_instances.keys()) == all_insn_ids: + break from loopy.schedule.checker.utils import ( sorted_union_of_names_in_isl_sets, @@ -227,14 +192,28 @@ def _pad_lex_tuple_with_zeros(stmt_inst, length): add_dims_to_isl_set, ) - params_sched = [] - out_names_sched = [LEX_VAR_PREFIX+str(i) for i in range(max_lex_dim)] - - def _get_map_for_stmt_inst(stmt_inst, int_sid): + def _pad_tuple_with_zeros(tup, length): + return tup[:] + tuple([0]*(length-len(tup))) + + def _remove_matching_integer_dims(tup0, tup1): + new_tup0 = [] + new_tup1 = [] + for d0, d1 in zip(tup0, tup1): + if not ( + isinstance(d0, int) and + isinstance(d1, int) and + d0 == d1): + # keep this dim + new_tup0.append(d0) + new_tup1.append(d1) + # TODO? also change all ints to 0 or 1 + return tuple(new_tup0), tuple(new_tup1) + + def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): # Get inames domain for statement instance (a BasicSet) dom = knl.get_inames_domain( - knl.id_to_insn[stmt_inst.insn_id].within_inames) + knl.id_to_insn[insn_id].within_inames) # create space (an isl space in current implementation) # {('statement', used in statement domain>) -> @@ -244,7 +223,7 @@ def _get_map_for_stmt_inst(stmt_inst, int_sid): 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=params_sched) + in_=in_names_sched, out=out_names_sched, params=[]) # Insert 'statement' dim into domain so that its space allows # for intersection with sched map later @@ -258,7 +237,7 @@ def _get_map_for_stmt_inst(stmt_inst, int_sid): # Add all inames from domains to each map domain tuple. tuple_pair = [( (int_sid, ) + tuple(dom_inames_ordered), - stmt_inst.lex_points + lex_points )] # create map @@ -267,15 +246,38 @@ def _get_map_for_stmt_inst(stmt_inst, int_sid): space=sched_space, ) - # 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_sid_before = 0 - int_sid_after = 0 if ( - stmt_instance_set_before.insn_id == stmt_instance_set_after.insn_id - ) else 1 + pairwise_schedules = [] + for insn_id_before, insn_id_after in insn_id_pairs: + lex_tup_before = stmt_instances[insn_id_before] + lex_tup_after = stmt_instances[insn_id_after] + + # simplify tuples to the extent possible ------------------------------------- + + # At this point, pairwise sub-schedule may contain lex point tuples + # missing dimensions; the values in these missing dims should + # be zero, so add them. + max_lex_dims = max(len(lex_tup_before), len(lex_tup_after)) + lex_tup_before = _pad_tuple_with_zeros(lex_tup_before, max_lex_dims) + lex_tup_after = _pad_tuple_with_zeros(lex_tup_after, max_lex_dims) + + lex_tup_before, lex_tup_after = _remove_matching_integer_dims( + lex_tup_before, lex_tup_after) + + # Now generate maps from the blueprint --------------------------------------- + + out_names_sched = [LEX_VAR_PREFIX+str(i) for i in range(len(lex_tup_before))] + + # 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_sid_before = 0 + int_sid_after = 0 if insn_id_before == insn_id_after else 1 + + map_before = _get_map_for_stmt_inst( + insn_id_before, lex_tup_before, int_sid_before, out_names_sched) + map_after = _get_map_for_stmt_inst( + insn_id_after, lex_tup_after, int_sid_after, out_names_sched) - map_before = _get_map_for_stmt_inst(stmt_instance_set_before, int_sid_before) - map_after = _get_map_for_stmt_inst(stmt_instance_set_after, int_sid_after) + pairwise_schedules.append((map_before, map_after)) - return (map_before, map_after) + return pairwise_schedules diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 60abfade0..716737bdd 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -53,7 +53,7 @@ def test_lexschedule_creation(): import islpy as isl from loopy.schedule.checker import ( - get_schedule_for_statement_pair, + get_schedules_for_statement_pairs, ) from loopy.schedule.checker.utils import ( ensure_dim_names_match_and_align, @@ -115,12 +115,11 @@ def _lex_space_string(dim_vals): # Relationship between insn_a and insn_b --------------------------------------- # Get two maps - sched_map_before, sched_map_after = get_schedule_for_statement_pair( + sched_map_before, sched_map_after = get_schedules_for_statement_pairs( knl, linearization_items, - "insn_a", - "insn_b", - ) + [("insn_a", "insn_b")], + )[0] # Create expected maps, align, compare @@ -128,7 +127,7 @@ def _lex_space_string(dim_vals): "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["0", "i", "0", "k", "0"]), + _lex_space_string(["i", "0", "k"]), ) ) sched_map_before_expected = ensure_dim_names_match_and_align( @@ -138,7 +137,7 @@ def _lex_space_string(dim_vals): "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["0", "i", "1", "j", "0"]), + _lex_space_string(["i", "1", "j"]), ) ) sched_map_after_expected = ensure_dim_names_match_and_align( @@ -151,12 +150,11 @@ def _lex_space_string(dim_vals): # Relationship between insn_a and insn_c --------------------------------------- # Get two maps - sched_map_before, sched_map_after = get_schedule_for_statement_pair( + sched_map_before, sched_map_after = get_schedules_for_statement_pairs( knl, linearization_items, - "insn_a", - "insn_c", - ) + [("insn_a", "insn_c")], + )[0] # Create expected maps, align, compare @@ -164,7 +162,7 @@ def _lex_space_string(dim_vals): "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["0", "i", "0", "k", "0"]), + _lex_space_string(["i", "0", "k"]), ) ) sched_map_before_expected = ensure_dim_names_match_and_align( @@ -174,7 +172,7 @@ def _lex_space_string(dim_vals): "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["0", "i", "1", "j", "0"]), + _lex_space_string(["i", "1", "j"]), ) ) sched_map_after_expected = ensure_dim_names_match_and_align( @@ -190,12 +188,11 @@ def _lex_space_string(dim_vals): # (i loop could be before or after t loop) def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): # Get two maps - sched_map_before, sched_map_after = get_schedule_for_statement_pair( + sched_map_before, sched_map_after = get_schedules_for_statement_pairs( knl, linearization_items, - "insn_a", - "insn_d", - ) + [("insn_a", "insn_d")], + )[0] # Create expected maps, align, compare @@ -203,7 +200,7 @@ def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, - _lex_space_string([a_lex_idx, "i", "0", "k", "0"]), + _lex_space_string([a_lex_idx, "i", "k"]), ) ) sched_map_before_expected = ensure_dim_names_match_and_align( @@ -213,7 +210,7 @@ def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, - _lex_space_string([d_lex_idx, "t", "0", "0", "0"]), + _lex_space_string([d_lex_idx, "t", "0"]), ) ) sched_map_after_expected = ensure_dim_names_match_and_align( @@ -236,12 +233,11 @@ def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): # (i loop could be before or after t loop) def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): # Get two maps - sched_map_before, sched_map_after = get_schedule_for_statement_pair( + sched_map_before, sched_map_after = get_schedules_for_statement_pairs( knl, linearization_items, - "insn_b", - "insn_c", - ) + [("insn_b", "insn_c")], + )[0] # Create expected maps, align, compare @@ -249,7 +245,7 @@ def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["0", "i", "0", "j", b_lex_idx]), + _lex_space_string(["i", "j", b_lex_idx]), ) ) sched_map_before_expected = ensure_dim_names_match_and_align( @@ -259,7 +255,7 @@ def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["0", "i", "0", "j", c_lex_idx]), + _lex_space_string(["i", "j", c_lex_idx]), ) ) sched_map_after_expected = ensure_dim_names_match_and_align( @@ -282,12 +278,11 @@ def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): # (i loop could be before or after t loop) def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): # Get two maps - sched_map_before, sched_map_after = get_schedule_for_statement_pair( + sched_map_before, sched_map_after = get_schedules_for_statement_pairs( knl, linearization_items, - "insn_b", - "insn_d", - ) + [("insn_b", "insn_d")], + )[0] # Create expected maps, align, compare @@ -295,7 +290,7 @@ def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string([b_lex_idx, "i", "0", "j", "0"]), + _lex_space_string([b_lex_idx, "i", "j"]), ) ) sched_map_before_expected = ensure_dim_names_match_and_align( @@ -305,7 +300,7 @@ def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, - _lex_space_string([d_lex_idx, "t", "0", "0", "0"]), + _lex_space_string([d_lex_idx, "t", "0"]), ) ) sched_map_after_expected = ensure_dim_names_match_and_align( @@ -328,12 +323,11 @@ def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): # (i loop could be before or after t loop) def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): # Get two maps - sched_map_before, sched_map_after = get_schedule_for_statement_pair( + sched_map_before, sched_map_after = get_schedules_for_statement_pairs( knl, linearization_items, - "insn_c", - "insn_d", - ) + [("insn_c", "insn_d")], + )[0] # Create expected maps, align, compare @@ -341,7 +335,7 @@ def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string([c_lex_idx, "i", "0", "j", "0"]), + _lex_space_string([c_lex_idx, "i", "j"]), ) ) sched_map_before_expected = ensure_dim_names_match_and_align( @@ -351,7 +345,7 @@ def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, - _lex_space_string([d_lex_idx, "t", "0", "0", "0"]), + _lex_space_string([d_lex_idx, "t", "0"]), ) ) sched_map_after_expected = ensure_dim_names_match_and_align( From 4211f6e3c519072970830c796d46cef7a975ea17 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 24 Jul 2020 13:14:32 -0500 Subject: [PATCH 118/315] add todo --- loopy/schedule/checker/schedule.py | 1 + 1 file changed, 1 insertion(+) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 6b9905613..6ebf7848d 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -142,6 +142,7 @@ def generate_pairwise_schedules( # statements since last opened/closed loop), but if we have not # added any statements within the previous section yet, we # don't have to (effectively ignoring that section of code). + # TODO since we're getting rid of unnecessary dims later, maybe don't need this? stmt_added_since_prev_block_at_tier.pop() if stmt_added_since_prev_block_at_tier[-1]: next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 From a4e790f28563f62479a6f66b93d5c41a38045f17 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 Jul 2020 18:33:30 -0500 Subject: [PATCH 119/315] while removing unnecessary dims in maps, also replace int-valued dims that are not in {0,1} with {0,1} (we're only describing relative order, so higher int values are unnecessary and confusing) --- loopy/schedule/checker/schedule.py | 47 +++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 6ebf7848d..dff0162d6 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -88,14 +88,12 @@ def generate_pairwise_schedules( all_insn_ids = set().union(*insn_id_pairs) - # For each statement, create a :class:`ImmutableRecord` describing the set of - # statement instances. Contains the insn_id and a list representing points + # 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 = {} from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) - from pytools import ImmutableRecord # go through linearization_items and generate pairwise sub-schedule @@ -103,7 +101,6 @@ def generate_pairwise_schedules( # ordering, initially this as a 1-d point with value 0 next_insn_lex_tuple = [0] stmt_added_since_prev_block_at_tier = [False] - max_lex_dim = 0 for linearization_item in linearization_items: if isinstance(linearization_item, EnterLoop): iname = linearization_item.iname @@ -196,18 +193,41 @@ def generate_pairwise_schedules( def _pad_tuple_with_zeros(tup, length): return tup[:] + tuple([0]*(length-len(tup))) - def _remove_matching_integer_dims(tup0, tup1): + def _simplify_dims(tup0, tup1): new_tup0 = [] new_tup1 = [] + # loop over dims for d0, d1 in zip(tup0, tup1): - if not ( - isinstance(d0, int) and - isinstance(d1, int) and - d0 == d1): + if isinstance(d0, int) and isinstance(d1, int): + # Both vals are ints for this dim + + # If the ints match, this dim doesn't provide info about the + # relative ordering of these two statements, + # so skip (remove) this dim. + + # Otherwise, the ints inform us about the relative ordering of + # two statements. While their values may be larger than 1 in + # the lexicographic ordering describing a larger set of + # statements, in a pairwise schedule, only ints 0 and 1 are + # necessary to specify relative order. To keep the pairwise + # schedules as simple and comprehensible as possible, use only + # integers 0 and 1 to specify relative orderings in integer lex + # dims. + # (doesn't take much extra time since we are already going + # through these to remove unnecessary map dims) + + if d0 == d1: + continue + elif d0 > d1: + new_tup0.append(1) + new_tup1.append(0) + else: # d1 > d0 + new_tup0.append(0) + new_tup1.append(1) + else: # keep this dim new_tup0.append(d0) new_tup1.append(d1) - # TODO? also change all ints to 0 or 1 return tuple(new_tup0), tuple(new_tup1) def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): @@ -252,7 +272,7 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): lex_tup_before = stmt_instances[insn_id_before] lex_tup_after = stmt_instances[insn_id_after] - # simplify tuples to the extent possible ------------------------------------- + # simplify tuples to the extent possible ------------------------------------ # At this point, pairwise sub-schedule may contain lex point tuples # missing dimensions; the values in these missing dims should @@ -261,10 +281,9 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): lex_tup_before = _pad_tuple_with_zeros(lex_tup_before, max_lex_dims) lex_tup_after = _pad_tuple_with_zeros(lex_tup_after, max_lex_dims) - lex_tup_before, lex_tup_after = _remove_matching_integer_dims( - lex_tup_before, lex_tup_after) + lex_tup_before, lex_tup_after = _simplify_dims(lex_tup_before, lex_tup_after) - # Now generate maps from the blueprint --------------------------------------- + # Now generate maps from the blueprint -------------------------------------- out_names_sched = [LEX_VAR_PREFIX+str(i) for i in range(len(lex_tup_before))] From 80a89ea3a1e06ffe5c91158d6789f154cd93076b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 Jul 2020 20:19:28 -0500 Subject: [PATCH 120/315] Remove logic avoiding gratuitous incrementing of integer lex dim values in schedule outline creation since these are replaced with {0, 1} in the map simplification step. Further reduce number of lex dims in pairwise maps with the following strategy: once a lex tuple dimension is found where both tuples have non-matching integer values, remove any faster-updating lex dimensions where both tuples have integer values, even if the integers don't match. --- loopy/schedule/checker/schedule.py | 86 +++++++++++++++--------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index dff0162d6..cd9443e67 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -100,33 +100,29 @@ def generate_pairwise_schedules( # 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] - stmt_added_since_prev_block_at_tier = [False] for linearization_item in linearization_items: if isinstance(linearization_item, EnterLoop): iname = linearization_item.iname if iname in loops_to_ignore: continue - # We could always increment next_insn_lex_tuple[-1] here since - # this new section of code comes after the previous section - # (statements since last opened/closed loop), but if we have - # not added any statements within the previous section yet, we - # don't have to (effectively ignoring that section of code). - if stmt_added_since_prev_block_at_tier[-1]: - next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 - stmt_added_since_prev_block_at_tier[-1] = False + # Increment next_insn_lex_tuple[-1] for statements in the section + # of code after this EnterLoop. + # (not technically necessary if no statement was added in the + # previous section; gratuitious incrementing is counteracted + # in the simplification step below) + next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 # upon entering a loop, we enter a new (deeper) tier, # add one lex dimension for the loop variable, - # add second lex dim to enumerate code blocks within new loop, and - # append a dim to stmt_added_since_prev_block_at_tier to represent - # new tier + # add second lex dim to enumerate code blocks within new loop next_insn_lex_tuple.append(iname) next_insn_lex_tuple.append(0) - stmt_added_since_prev_block_at_tier.append(False) + elif isinstance(linearization_item, LeaveLoop): if linearization_item.iname in loops_to_ignore: continue + # upon leaving a loop, # pop lex dimension for enumerating code blocks within this loop, and # pop lex dimension for the loop variable, and @@ -134,16 +130,13 @@ def generate_pairwise_schedules( next_insn_lex_tuple.pop() next_insn_lex_tuple.pop() - # We could always increment next_insn_lex_tuple[-1] here since - # this new block of code comes after the previous block (all - # statements since last opened/closed loop), but if we have not - # added any statements within the previous section yet, we - # don't have to (effectively ignoring that section of code). - # TODO since we're getting rid of unnecessary dims later, maybe don't need this? - stmt_added_since_prev_block_at_tier.pop() - if stmt_added_since_prev_block_at_tier[-1]: - next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 - stmt_added_since_prev_block_at_tier[-1] = False + # 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; gratuitious incrementing is counteracted + # in the simplification step below) + next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 + elif isinstance(linearization_item, (RunInstruction, Barrier)): from loopy.schedule.checker.utils import ( get_insn_id_from_linearization_item, @@ -170,9 +163,6 @@ def generate_pairwise_schedules( # increment lex dim val enumerating items in current code block next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1] + 1 - # all current (nested) blocks now contain a statement - stmt_added_since_prev_block_at_tier = [True]*len( - stmt_added_since_prev_block_at_tier) else: from loopy.schedule import (CallKernel, ReturnFromKernel) # no action needed for these types of linearization item @@ -193,37 +183,44 @@ def generate_pairwise_schedules( def _pad_tuple_with_zeros(tup, length): return tup[:] + tuple([0]*(length-len(tup))) - def _simplify_dims(tup0, tup1): + def _simplify_lex_dims(tup0, tup1): + """Simplify pair of lex tuples in order to reduce the complexity of + resulting maps. Remove lex tuple dimensions with matching integer values + since these do not provide information on relative ordering. For the same + reason, once a dimension is found where both tuples have non-matching integer + values, remove any faster-updating lex dimensions where both tuples have + integer values, even if the integers don't match. + """ + # TODO actually, once we find non-matching integer dims, we don't + # need *any* more lex dims to specify relative ordering. + new_tup0 = [] new_tup1 = [] + non_matching_int_dims_found = False # loop over dims for d0, d1 in zip(tup0, tup1): if isinstance(d0, int) and isinstance(d1, int): # Both vals are ints for this dim - # If the ints match, this dim doesn't provide info about the - # relative ordering of these two statements, - # so skip (remove) this dim. - - # Otherwise, the ints inform us about the relative ordering of - # two statements. While their values may be larger than 1 in - # the lexicographic ordering describing a larger set of - # statements, in a pairwise schedule, only ints 0 and 1 are - # necessary to specify relative order. To keep the pairwise - # schedules as simple and comprehensible as possible, use only - # integers 0 and 1 to specify relative orderings in integer lex - # dims. - # (doesn't take much extra time since we are already going - # through these to remove unnecessary map dims) - - if d0 == d1: + if non_matching_int_dims_found or d0 == d1: continue elif d0 > d1: + # These ints inform us about the relative ordering of + # two statements. While their values may be larger than 1 in + # the lexicographic ordering describing a larger set of + # statements, in a pairwise schedule, only ints 0 and 1 are + # necessary to specify relative order. To keep the pairwise + # schedules as simple and comprehensible as possible, use only + # integers 0 and 1 to specify this relative ordering. + # (doesn't take much extra time since we are already going + # through these to remove unnecessary lex tuple dims) new_tup0.append(1) new_tup1.append(0) + non_matching_int_dims_found = True else: # d1 > d0 new_tup0.append(0) new_tup1.append(1) + non_matching_int_dims_found = True else: # keep this dim new_tup0.append(d0) @@ -281,7 +278,8 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): lex_tup_before = _pad_tuple_with_zeros(lex_tup_before, max_lex_dims) lex_tup_after = _pad_tuple_with_zeros(lex_tup_after, max_lex_dims) - lex_tup_before, lex_tup_after = _simplify_dims(lex_tup_before, lex_tup_after) + lex_tup_before, lex_tup_after = _simplify_lex_dims( + lex_tup_before, lex_tup_after) # Now generate maps from the blueprint -------------------------------------- From 3dd9327d0ad604ba8e6ace69d9ddda0478695ed7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 Jul 2020 20:33:19 -0500 Subject: [PATCH 121/315] make generate_pairwise_schedules() return a dictionary mapping (insn_id_before, insn_id_after) tuples to (schedule_before, schedule_after) tuples --- loopy/schedule/checker/__init__.py | 2 ++ loopy/schedule/checker/schedule.py | 4 +-- test/test_linearization_checker.py | 51 ++++++++++++------------------ 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index fa9700b47..000265486 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -105,6 +105,8 @@ def get_schedules_for_statement_pairs( """ + # TODO update documentation + # {{{ make sure kernel has been preprocessed from loopy.kernel import KernelState diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index cd9443e67..7b98c621a 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -264,7 +264,7 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): space=sched_space, ) - pairwise_schedules = [] + pairwise_schedules = {} for insn_id_before, insn_id_after in insn_id_pairs: lex_tup_before = stmt_instances[insn_id_before] lex_tup_after = stmt_instances[insn_id_after] @@ -296,6 +296,6 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): map_after = _get_map_for_stmt_inst( insn_id_after, lex_tup_after, int_sid_after, out_names_sched) - pairwise_schedules.append((map_before, map_after)) + pairwise_schedules[(insn_id_before, insn_id_after)] = (map_before, map_after) return pairwise_schedules diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 716737bdd..a4657ba1f 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -112,14 +112,24 @@ def _lex_space_string(dim_vals): ["%s%d=%s" % (LEX_VAR_PREFIX, idx, str(val)) for idx, val in enumerate(dim_vals)]) + 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, + ) + # Relationship between insn_a and insn_b --------------------------------------- # Get two maps - sched_map_before, sched_map_after = get_schedules_for_statement_pairs( - knl, - linearization_items, - [("insn_a", "insn_b")], - )[0] + sched_map_before, sched_map_after = sched_maps[("insn_a", "insn_b")] # Create expected maps, align, compare @@ -150,11 +160,7 @@ def _lex_space_string(dim_vals): # Relationship between insn_a and insn_c --------------------------------------- # Get two maps - sched_map_before, sched_map_after = get_schedules_for_statement_pairs( - knl, - linearization_items, - [("insn_a", "insn_c")], - )[0] + sched_map_before, sched_map_after = sched_maps[("insn_a", "insn_c")] # Create expected maps, align, compare @@ -188,11 +194,7 @@ def _lex_space_string(dim_vals): # (i loop could be before or after t loop) def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): # Get two maps - sched_map_before, sched_map_after = get_schedules_for_statement_pairs( - knl, - linearization_items, - [("insn_a", "insn_d")], - )[0] + sched_map_before, sched_map_after = sched_maps[("insn_a", "insn_d")] # Create expected maps, align, compare @@ -230,14 +232,9 @@ def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): # Relationship between insn_b and insn_c --------------------------------------- # insn_b and insn_c could have been linearized in either order - # (i loop could be before or after t loop) def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): # Get two maps - sched_map_before, sched_map_after = get_schedules_for_statement_pairs( - knl, - linearization_items, - [("insn_b", "insn_c")], - )[0] + sched_map_before, sched_map_after = sched_maps[("insn_b", "insn_c")] # Create expected maps, align, compare @@ -278,11 +275,7 @@ def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): # (i loop could be before or after t loop) def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): # Get two maps - sched_map_before, sched_map_after = get_schedules_for_statement_pairs( - knl, - linearization_items, - [("insn_b", "insn_d")], - )[0] + sched_map_before, sched_map_after = sched_maps[("insn_b", "insn_d")] # Create expected maps, align, compare @@ -323,11 +316,7 @@ def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): # (i loop could be before or after t loop) def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): # Get two maps - sched_map_before, sched_map_after = get_schedules_for_statement_pairs( - knl, - linearization_items, - [("insn_c", "insn_d")], - )[0] + sched_map_before, sched_map_after = sched_maps[("insn_c", "insn_d")] # Create expected maps, align, compare From 67887d36ed9eb1b1a229833b4590cac030f7d2b1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 Jul 2020 21:02:18 -0500 Subject: [PATCH 122/315] 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 123/315] 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 a4ff29d4f828f0b00983b57bd0ec90206f4478f5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 27 Jul 2020 18:06:02 -0500 Subject: [PATCH 124/315] minor comment change --- loopy/schedule/checker/schedule.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 7b98c621a..65905862e 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -113,8 +113,7 @@ def generate_pairwise_schedules( # in the simplification step below) next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 - # upon entering a loop, we enter a new (deeper) tier, - # add one lex dimension for the loop variable, + # Upon entering a loop, add one lex dimension for the loop variable, # add second lex dim to enumerate code blocks within new loop next_insn_lex_tuple.append(iname) next_insn_lex_tuple.append(0) From 86c3ff938be14495e4567d62dd9d86761e650009 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 2 Aug 2020 20:58:50 -0500 Subject: [PATCH 125/315] When simplifying pairs of lex tuples before map creation, once a dimension is found where both tuples have non-matching integer values, remove all faster-updating lex dimensions. --- loopy/schedule/checker/schedule.py | 30 +++++++++++++++++------------- test/test_linearization_checker.py | 20 ++++++++++---------- 2 files changed, 27 insertions(+), 23 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 65905862e..6044f7c7d 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -183,25 +183,24 @@ def _pad_tuple_with_zeros(tup, length): return tup[:] + tuple([0]*(length-len(tup))) def _simplify_lex_dims(tup0, tup1): - """Simplify pair of lex tuples in order to reduce the complexity of + """Simplify a pair of lex tuples in order to reduce the complexity of resulting maps. Remove lex tuple dimensions with matching integer values - since these do not provide information on relative ordering. For the same - reason, once a dimension is found where both tuples have non-matching integer - values, remove any faster-updating lex dimensions where both tuples have - integer values, even if the integers don't match. + since these do not provide information on relative ordering. Once a + dimension is found where both tuples have non-matching integer values, + remove any faster-updating lex dimensions since they are not necessary + to speficy relative ordering. """ - # TODO actually, once we find non-matching integer dims, we don't - # need *any* more lex dims to specify relative ordering. new_tup0 = [] new_tup1 = [] - non_matching_int_dims_found = False + # loop over dims for d0, d1 in zip(tup0, tup1): if isinstance(d0, int) and isinstance(d1, int): - # Both vals are ints for this dim - if non_matching_int_dims_found or d0 == d1: + # Both vals are ints for this dim + if d0 == d1: + # Do not keep this dim continue elif d0 > d1: # These ints inform us about the relative ordering of @@ -215,15 +214,20 @@ def _simplify_lex_dims(tup0, tup1): # through these to remove unnecessary lex tuple dims) new_tup0.append(1) new_tup1.append(0) - non_matching_int_dims_found = True + + # No further dims needed to fully specify ordering + break else: # d1 > d0 new_tup0.append(0) new_tup1.append(1) - non_matching_int_dims_found = True + + # No further dims needed to fully specify ordering + break else: - # keep this dim + # Keep this dim without modifying new_tup0.append(d0) new_tup1.append(d1) + return tuple(new_tup0), tuple(new_tup1) def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index a4657ba1f..6d0fd3abf 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -137,7 +137,7 @@ def _lex_space_string(dim_vals): "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "0", "k"]), + _lex_space_string(["i", "0"]), ) ) sched_map_before_expected = ensure_dim_names_match_and_align( @@ -147,7 +147,7 @@ def _lex_space_string(dim_vals): "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "1", "j"]), + _lex_space_string(["i", "1"]), ) ) sched_map_after_expected = ensure_dim_names_match_and_align( @@ -168,7 +168,7 @@ def _lex_space_string(dim_vals): "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "0", "k"]), + _lex_space_string(["i", "0"]), ) ) sched_map_before_expected = ensure_dim_names_match_and_align( @@ -178,7 +178,7 @@ def _lex_space_string(dim_vals): "[pi, pj] -> { [%s=1, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string(["i", "1", "j"]), + _lex_space_string(["i", "1"]), ) ) sched_map_after_expected = ensure_dim_names_match_and_align( @@ -202,7 +202,7 @@ def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): "[pi, pk] -> { [%s=0, i, k] -> [%s] : 0 <= i < pi and 0 <= k < pk }" % ( STATEMENT_VAR_NAME, - _lex_space_string([a_lex_idx, "i", "k"]), + _lex_space_string([a_lex_idx, ]), ) ) sched_map_before_expected = ensure_dim_names_match_and_align( @@ -212,7 +212,7 @@ def perform_insn_ad_checks_with(a_lex_idx, d_lex_idx): "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, - _lex_space_string([d_lex_idx, "t", "0"]), + _lex_space_string([d_lex_idx, ]), ) ) sched_map_after_expected = ensure_dim_names_match_and_align( @@ -283,7 +283,7 @@ def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string([b_lex_idx, "i", "j"]), + _lex_space_string([b_lex_idx, ]), ) ) sched_map_before_expected = ensure_dim_names_match_and_align( @@ -293,7 +293,7 @@ def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, - _lex_space_string([d_lex_idx, "t", "0"]), + _lex_space_string([d_lex_idx, ]), ) ) sched_map_after_expected = ensure_dim_names_match_and_align( @@ -324,7 +324,7 @@ def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): "[pi, pj] -> { [%s=0, i, j] -> [%s] : 0 <= i < pi and 0 <= j < pj }" % ( STATEMENT_VAR_NAME, - _lex_space_string([c_lex_idx, "i", "j"]), + _lex_space_string([c_lex_idx, ]), ) ) sched_map_before_expected = ensure_dim_names_match_and_align( @@ -334,7 +334,7 @@ def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): "[pt] -> { [%s=1, t] -> [%s] : 0 <= t < pt }" % ( STATEMENT_VAR_NAME, - _lex_space_string([d_lex_idx, "t", "0"]), + _lex_space_string([d_lex_idx, ]), ) ) sched_map_after_expected = ensure_dim_names_match_and_align( From 39ec3c4ebfca2b02e36a8c94d2953d5a62aa2ea7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 2 Aug 2020 21:26:25 -0500 Subject: [PATCH 126/315] instead of operating on Xbefore and Xafter pairs in pairs of statements, keep all pairs in lists (of length 2) and operate on the lists with loops --- loopy/schedule/checker/schedule.py | 32 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 6044f7c7d..769a690f2 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -268,37 +268,37 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): ) pairwise_schedules = {} - for insn_id_before, insn_id_after in insn_id_pairs: - lex_tup_before = stmt_instances[insn_id_before] - lex_tup_after = stmt_instances[insn_id_after] + for insn_ids in insn_id_pairs: + lex_tuples = [stmt_instances[insn_id] for insn_id in insn_ids] # simplify tuples to the extent possible ------------------------------------ # At this point, pairwise sub-schedule may contain lex point tuples # missing dimensions; the values in these missing dims should # be zero, so add them. - max_lex_dims = max(len(lex_tup_before), len(lex_tup_after)) - lex_tup_before = _pad_tuple_with_zeros(lex_tup_before, max_lex_dims) - lex_tup_after = _pad_tuple_with_zeros(lex_tup_after, max_lex_dims) + 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) + for lex_tuple in lex_tuples] - lex_tup_before, lex_tup_after = _simplify_lex_dims( - lex_tup_before, lex_tup_after) + lex_tuples_simplified = _simplify_lex_dims(*lex_tuples_padded) # Now generate maps from the blueprint -------------------------------------- - out_names_sched = [LEX_VAR_PREFIX+str(i) for i in range(len(lex_tup_before))] + out_names_sched = [ + 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_sid_before = 0 - int_sid_after = 0 if insn_id_before == insn_id_after else 1 + int_sids = [0, 0] if insn_ids[0] == insn_ids[1] else [0, 1] - map_before = _get_map_for_stmt_inst( - insn_id_before, lex_tup_before, int_sid_before, out_names_sched) - map_after = _get_map_for_stmt_inst( - insn_id_after, lex_tup_after, int_sid_after, out_names_sched) + sched_maps = [ + _get_map_for_stmt_inst(insn_id, lex_tuple, int_sid, out_names_sched) + for insn_id, lex_tuple, int_sid + in zip(insn_ids, lex_tuples_simplified, int_sids) + ] - pairwise_schedules[(insn_id_before, insn_id_after)] = (map_before, map_after) + pairwise_schedules[tuple(insn_ids)] = tuple(sched_maps) return pairwise_schedules From 5f060a84d96cf960c50a528b0b37b18ec355c170 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 2 Aug 2020 21:32:55 -0500 Subject: [PATCH 127/315] 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 6bb69899730e940ce5e462500cc40827ec23261f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 2 Aug 2020 21:34:24 -0500 Subject: [PATCH 128/315] fix flake8 issue --- 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 bad083558..3bde5247b 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -140,7 +140,7 @@ def ensure_dim_names_match_and_align(obj_map, tgt_map): def sorted_union_of_names_in_isl_sets( isl_sets, set_dim=isl.dim_type.set): - """Return a sorted list of the union of all variable names found in + r"""Return a sorted list of the union of all variable names found in the provided :class:`islpy.Set`\ s. """ From 41654850aac4b18394883c6f3607076b74b10021 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 2 Aug 2020 22:25:56 -0500 Subject: [PATCH 129/315] remove get_islvars_from_space(); instead use isl.affs_from_space() --- loopy/schedule/checker/utils.py | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 3bde5247b..019117231 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -28,18 +28,6 @@ def prettier_map_string(map_obj): ).replace("{ ", "{\n").replace(" }", "\n}").replace("; ", ";\n") -def get_islvars_from_space(space): - #pu.db - param_names = space.get_var_names(isl.dim_type.param) - in_names = space.get_var_names(isl.dim_type.in_) - out_names = space.get_var_names(isl.dim_type.out) - return isl.make_zero_and_vars(in_names+out_names, param_names) - #old = isl.make_zero_and_vars(in_names+out_names, param_names) - #new = isl.affs_from_space(space) - #assert old == new - #return new - - 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) @@ -183,7 +171,14 @@ def create_symbolic_map_from_tuples( space_out_names = space.get_var_names(dim_type.out) space_in_names = space.get_var_names(isl.dim_type.in_) - islvars = get_islvars_from_space(space) + # get islvars from space + islvars = isl.affs_from_space( + space.move_dims( + isl.dim_type.out, 0, + isl.dim_type.in_, 0, + len(space_in_names), + ).range() + ) # loop through pairs and create a set that will later be converted to a map From 3f4b3b8fbf0d057e317d48eb4164eaedc86f3c94 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 01:41:09 -0500 Subject: [PATCH 130/315] make example usage of get_schedules_for_statement_pairs() into a doctest; probably the wrong way to do this... (but it's not time to add this to tutorial yet) --- loopy/schedule/checker/__init__.py | 73 +++++++++++------------------- 1 file changed, 27 insertions(+), 46 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 000265486..d28c2f676 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -56,52 +56,33 @@ def get_schedules_for_statement_pairs( from statement instances to lexicographic time, one for each of the two statements. - Example usage:: - - # Make kernel ------------------------------------------------------------ - knl = lp.make_kernel( - "{[i,j,k]: 0<=i { - [_lp_linchk_statement = 0, i, j, k] -> - [_lp_linchk_l0 = 0, _lp_linchk_l1 = i, _lp_linchk_l2 = 0, - _lp_linchk_l3 = j, _lp_linchk_l4 = 0] : - 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } - [pi, pj, pk] -> { - [_lp_linchk_statement = 1, i, j, k] -> - [_lp_linchk_l0 = 0, _lp_linchk_l1 = i, _lp_linchk_l2 = 1, - _lp_linchk_l3 = k, _lp_linchk_l4 = 0] : - 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + .. doctest: + + >>> import loopy as lp + >>> 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( + ... knl, + ... knl.linearization, + ... [("insn_a", "insn_b")], + ... ) + >>> print(*schedules[("insn_a", "insn_b")], sep="\n") + [pi, pj, pk] -> { [_lp_linchk_statement = 0, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 0] : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + [pi, pj, pk] -> { [_lp_linchk_statement = 1, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 1] : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } """ From de5ab4480058c797d09830102e70a9a402053f9b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 02:37:14 -0500 Subject: [PATCH 131/315] update all docstrings/comments after recent changes --- loopy/schedule/checker/__init__.py | 31 ++++---- loopy/schedule/checker/schedule.py | 115 +++++++++++++++-------------- loopy/schedule/checker/utils.py | 41 +++++----- 3 files changed, 94 insertions(+), 93 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index d28c2f676..269e7ba05 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -28,32 +28,31 @@ def get_schedules_for_statement_pairs( linearization_items, insn_id_pairs, ): - r"""Given a pair of statements in a linearized kernel, determine - the (relative) order in which the instances are executed, - by creating a mapping from statement instances to points in a single - lexicographic ordering. Create a pair of :class:`islpy.Map`\ s - representing a pairwise schedule as two mappings from statement instances - to lexicographic time. + 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. :arg knl: A preprocessed :class:`loopy.kernel.LoopKernel` containing the linearization items that will be used to create a schedule. :arg linearization_items: A list of :class:`loopy.schedule.ScheduleItem` (to be renamed to `loopy.schedule.LinearizationItem`) containing - the two linearization items for which a schedule will be + all linearization items for which pairwise schedules will be created. This list may be a *partial* linearization for a kernel since this function may be used during the linearization process. - :arg insn_id_before: An instruction identifier that is unique within - a :class:`loopy.kernel.LoopKernel`. + :arg insn_id_pairs: A list of two-tuples containing pairs of instruction + identifiers, each of which is unique within a + :class:`loopy.kernel.LoopKernel`. - :arg insn_id_after: An instruction identifier that is unique within - a :class:`loopy.kernel.LoopKernel`. - - :returns: A two-tuple containing two :class:`islpy.Map`s - representing the a pairwise schedule as two mappings - from statement instances to lexicographic time, one for + :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. .. doctest: @@ -86,8 +85,6 @@ def get_schedules_for_statement_pairs( """ - # TODO update documentation - # {{{ make sure kernel has been preprocessed from loopy.kernel import KernelState diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 769a690f2..724053e59 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -53,53 +53,56 @@ def generate_pairwise_schedules( insn_id_pairs, loops_to_ignore=set(), ): - r"""Given a pair of statements in a linearized kernel, determine - the (relative) order in which the instances are executed, - by creating a mapping from statement instances to points in a single - lexicographic ordering. Create a pair of :class:`islpy.Map`\ s - representing a pairwise schedule as two mappings from statement instances - to lexicographic time. - - :arg knl: A :class:`loopy.kernel.LoopKernel` containing the - linearization items that will be described by the schedule. This + 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''). + + :arg knl: A preprocessed :class:`loopy.kernel.LoopKernel` containing the + linearization items that will be used to create a schedule. This 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` - (to be renamed to `loopy.schedule.LinearizationItem`) including the - two linearization items whose relative order will be described by the - schedule. This list may be a *partial* linearization for a kernel since - this function may be used during the linearization process. - - :arg before_insn_id: A :class:`str` instruction id specifying - stmt_instance_set_before in this pair of instructions. - - :arg after_insn_id: A :class:`str` instruction id specifying - stmt_instance_set_after in this pair of instructions. - - :returns: A two-tuple containing two :class:`islpy.Map`\ s - representing a pairwise schedule as two mappings - from statement instances to lexicographic time, one for + (to be renamed to `loopy.schedule.LinearizationItem`) containing + all linearization items for which pairwise schedules will be + created. This list may be a *partial* linearization for a + kernel since this function may be used during the linearization + process. + + :arg insn_id_pairs: A list of two-tuples containing pairs of instruction + identifiers, each of which is unique within a + :class:`loopy.kernel.LoopKernel`. + + :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. + + :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. """ - # TODO - # update documentation + from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) all_insn_ids = set().union(*insn_id_pairs) + # First, use one pass through linearization_items to generate a 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. stmt_instances = {} - from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) - - # go through linearization_items and generate pairwise sub-schedule - - # keep track of the next tuple of points in our lexicographic + # 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] + for linearization_item in linearization_items: if isinstance(linearization_item, EnterLoop): iname = linearization_item.iname @@ -109,12 +112,12 @@ def generate_pairwise_schedules( # Increment next_insn_lex_tuple[-1] for statements in the section # of code after this EnterLoop. # (not technically necessary if no statement was added in the - # previous section; gratuitious incrementing is counteracted + # previous section; gratuitous incrementing is counteracted # in the simplification step below) next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 # Upon entering a loop, add one lex dimension for the loop variable, - # add second lex dim to enumerate code blocks within new loop + # add second lex dim to enumerate sections of code within new loop next_insn_lex_tuple.append(iname) next_insn_lex_tuple.append(0) @@ -122,17 +125,17 @@ def generate_pairwise_schedules( if linearization_item.iname in loops_to_ignore: continue - # upon leaving a loop, - # pop lex dimension for enumerating code blocks within this loop, and + # 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 code block + # increment lex dim val enumerating items in current section of code next_insn_lex_tuple.pop() next_insn_lex_tuple.pop() # 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; gratuitious incrementing is counteracted + # previous section; gratuitous incrementing is counteracted # in the simplification step below) next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1]+1 @@ -154,23 +157,23 @@ def generate_pairwise_schedules( continue - # only process listed insns, otherwise ignore + # Only process listed insns, otherwise ignore if lp_insn_id in all_insn_ids: - # add item + # Add item to stmt_instances stmt_instances[lp_insn_id] = tuple(next_insn_lex_tuple[:]) - # increment lex dim val enumerating items in current code block + # Increment lex dim val enumerating items in current section of code next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1] + 1 else: from loopy.schedule import (CallKernel, ReturnFromKernel) - # no action needed for these types of linearization item + # No action needed for these types of linearization item assert isinstance( linearization_item, (CallKernel, ReturnFromKernel)) pass - # to save time, stop when we've created all statements - if len(stmt_instances.keys()) == all_insn_ids: + # To save time, stop when we've found all statements + if len(stmt_instances.keys()) == len(all_insn_ids): break from loopy.schedule.checker.utils import ( @@ -179,8 +182,8 @@ def generate_pairwise_schedules( add_dims_to_isl_set, ) - def _pad_tuple_with_zeros(tup, length): - return tup[:] + tuple([0]*(length-len(tup))) + def _pad_tuple_with_zeros(tup, desired_length): + return tup[:] + tuple([0]*(desired_length-len(tup))) def _simplify_lex_dims(tup0, tup1): """Simplify a pair of lex tuples in order to reduce the complexity of @@ -188,13 +191,13 @@ def _simplify_lex_dims(tup0, tup1): since these do not provide information on relative ordering. Once a dimension is found where both tuples have non-matching integer values, remove any faster-updating lex dimensions since they are not necessary - to speficy relative ordering. + to specify a relative ordering. """ new_tup0 = [] new_tup1 = [] - # loop over dims + # Loop over dims from slowest updating to fastest for d0, d1 in zip(tup0, tup1): if isinstance(d0, int) and isinstance(d1, int): @@ -236,8 +239,8 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): dom = knl.get_inames_domain( knl.id_to_insn[insn_id].within_inames) - # create space (an isl space in current implementation) - # {('statement', used in statement domain>) -> + # Create map space (an isl space in current implementation) + # {('statement', ) -> # (lexicographic ordering dims)} dom_inames_ordered = sorted_union_of_names_in_isl_sets([dom]) @@ -252,8 +255,7 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): add_dims_to_isl_set( dom, isl.dim_type.set, [STATEMENT_VAR_NAME], 0), ] - # Each map representing the schedule will map - # statement instances -> lex time. + # Each map will map statement instances -> lex time. # Right now, statement instance tuples consist of single int. # Add all inames from domains to each map domain tuple. tuple_pair = [( @@ -261,21 +263,23 @@ def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): lex_points )] - # create map + # Create map return create_symbolic_map_from_tuples( tuple_pairs_with_domains=zip(tuple_pair, dom_to_intersect), space=sched_space, ) + # Second, create pairwise schedules for each individual pair of insns + pairwise_schedules = {} for insn_ids in insn_id_pairs: lex_tuples = [stmt_instances[insn_id] for insn_id in insn_ids] - # simplify tuples to the extent possible ------------------------------------ + # Simplify tuples to the extent possible ------------------------------------ - # At this point, pairwise sub-schedule may contain lex point tuples - # missing dimensions; the values in these missing dims should - # be zero, so 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) @@ -285,6 +289,7 @@ 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 = [ LEX_VAR_PREFIX+str(i) for i in range(len(lex_tuples_simplified[0]))] diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 019117231..10ccc7191 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -44,6 +44,9 @@ def map_names_match_check( assert_subset=True, assert_permutation=True, ): + """Raise an error if names of the specified map dimension do not match + the desired names + """ obj_map_names = obj_map.space.get_var_names(dim_type) if assert_permutation: @@ -89,23 +92,19 @@ def insert_missing_dims_and_reorder_by_name( new_set = isl_set.copy() for desired_idx, name in enumerate(desired_dims_ordered): - # if iname doesn't exist in set, add dim: + # If iname doesn't exist in set, add dim if name not in new_set.get_var_names(dim_type): - # insert missing dim in correct location + # Insert missing dim in correct location new_set = new_set.insert_dims( dim_type, desired_idx, 1 - ).set_dim_name( - dim_type, desired_idx, name) - else: # iname exists in set + ).set_dim_name(dim_type, desired_idx, name) + else: # Iname exists in set current_idx = new_set.find_dim_by_name(dim_type, name) if current_idx != desired_idx: - # move_dims(dst_type, dst_idx, src_type, src_idx, n) - - # first move to other dim because isl is stupid + # 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) - - # now move it where we actually want it + # 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) @@ -134,7 +133,7 @@ def sorted_union_of_names_in_isl_sets( inames = set().union(*[isl_set.get_var_names(set_dim) for isl_set in isl_sets]) - # sorting is not necessary, but keeps results consistent between runs + # Sorting is not necessary, but keeps results consistent between runs return sorted(inames) @@ -171,7 +170,7 @@ def create_symbolic_map_from_tuples( space_out_names = space.get_var_names(dim_type.out) space_in_names = space.get_var_names(isl.dim_type.in_) - # get islvars from space + # Get islvars from space islvars = isl.affs_from_space( space.move_dims( isl.dim_type.out, 0, @@ -180,8 +179,6 @@ def create_symbolic_map_from_tuples( ).range() ) - # loop through pairs and create a set that will later be converted to a map - 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): @@ -193,22 +190,24 @@ def _conjunction_of_dim_eq_conditions(dim_names, values, islvars): & islvars[dim_name].eq_set(islvars[val]) return condition - # initialize union to empty + # Initialize union of maps to empty 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)) + + # Loop through tuple pairs for (tup_in, tup_out), dom in tuple_pairs_with_domains: - # set values for 'in' dimension using tuple vals + # Set values for 'in' dimension using tuple vals condition = _conjunction_of_dim_eq_conditions( space_in_names, tup_in, islvars) - # set values for 'out' dimension using tuple vals + # Set values for 'out' dimension using tuple vals condition = condition & _conjunction_of_dim_eq_conditions( space_out_names, tup_out, islvars) - # convert set to map by moving dimensions around + # 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_, @@ -217,15 +216,15 @@ def _conjunction_of_dim_eq_conditions(dim_names, values, islvars): assert space_in_names == map_from_set.get_var_names( isl.dim_type.in_) - # if there are any dimensions in dom that are missing from + # If there are any dimensions in dom that are missing from # map_from_set, we have a problem I think? - # (assertion checks this in add_missing... + # (assertion checks this in add_missing...) dom_with_all_inames = insert_missing_dims_and_reorder_by_name( dom, isl.dim_type.set, space_in_names, ) - # intersect domain with this map + # Intersect domain with this map union_of_maps = union_of_maps.union( map_from_set.intersect_domain(dom_with_all_inames)) From 5551fd9ba664e99042205bf6564d540c8b6781c6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 02:38:41 -0500 Subject: [PATCH 132/315] remove unused arg (knl) from get_EnterLoop_inames() --- loopy/schedule/checker/__init__.py | 2 +- loopy/schedule/checker/utils.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 269e7ba05..09ffd6bde 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -104,7 +104,7 @@ def get_schedules_for_statement_pairs( get_EnterLoop_inames, ) conc_inames, _ = partition_inames_by_concurrency(knl) - enterloop_inames = get_EnterLoop_inames(linearization_items, knl) + enterloop_inames = get_EnterLoop_inames(linearization_items) conc_loop_inames = conc_inames & enterloop_inames if conc_loop_inames: from warnings import warn diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 10ccc7191..23880bbfa 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -254,7 +254,7 @@ def get_insn_id_from_linearization_item(linearization_item): return linearization_item.insn_id -def get_EnterLoop_inames(linearization_items, knl): +def get_EnterLoop_inames(linearization_items): from loopy.schedule import EnterLoop loop_inames = set() for linearization_item in linearization_items: From 222b0c729b07936d13b72763859d41b23857f8b7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 02:56:05 -0500 Subject: [PATCH 133/315] use list comprehension instead of loop in get_EnterLoop_inames() --- loopy/schedule/checker/utils.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 23880bbfa..b09c9fb16 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -256,8 +256,9 @@ def get_insn_id_from_linearization_item(linearization_item): def get_EnterLoop_inames(linearization_items): from loopy.schedule import EnterLoop - loop_inames = set() - for linearization_item in linearization_items: - if isinstance(linearization_item, EnterLoop): - loop_inames.add(linearization_item.iname) - return loop_inames + + # Note: each iname must live in len-1 list to avoid char separation + return set().union(*[ + [item.iname, ] for item in linearization_items + if isinstance(item, EnterLoop) + ]) From f1e31d52ffe97d10583469fd4fe870f5a6ae2429 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 03:11:10 -0500 Subject: [PATCH 134/315] temporarily add an assert-false to check for unnecessary functionality --- loopy/schedule/checker/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index b09c9fb16..babb2b24a 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -94,6 +94,7 @@ def insert_missing_dims_and_reorder_by_name( for desired_idx, name in enumerate(desired_dims_ordered): # If iname doesn't exist in set, add dim if name not in new_set.get_var_names(dim_type): + assert False # Insert missing dim in correct location new_set = new_set.insert_dims( dim_type, desired_idx, 1 From 8001bd61ad9c3a77c5c9a781bb856c5cf331e66c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 03:35:12 -0500 Subject: [PATCH 135/315] handle special case where simplified lex tuples are empty (means statements map to the exact same point(s) in the lex ordering, which is okay, but to represent this, our lex tuple cannot be empty, so map to (0)) --- loopy/schedule/checker/schedule.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 724053e59..1e6e30fb7 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -231,7 +231,12 @@ def _simplify_lex_dims(tup0, tup1): new_tup0.append(d0) new_tup1.append(d1) - return tuple(new_tup0), tuple(new_tup1) + if len(new_tup0) == 0: + # Statements map to the exact same point(s) in the lex ordering, + # which is okay, but to represent this, our lex tuple cannot be empty. + return (0, ), (0, ) + else: + return tuple(new_tup0), tuple(new_tup1) def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): From 567c40545d5c77731d8cc3a097ee72cc3d8e12f9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 04:53:05 -0500 Subject: [PATCH 136/315] don't add missing dims when aligning domain for intersection in create_symbolic_map_from_tuples(), all dims will always be present by construction; rename insert_missing_dims_and_reorder_by_name()->reorder_dims_by_name() --- loopy/schedule/checker/utils.py | 46 ++++++++++++--------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index babb2b24a..3a2c7c682 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -61,12 +61,12 @@ def map_names_match_check( % (obj_map_names, dim_type, desired_names)) -def insert_missing_dims_and_reorder_by_name( +def reorder_dims_by_name( isl_set, dim_type, desired_dims_ordered): """Return an isl_set with the dimensions in the specified order. :arg isl_set: A :class:`islpy.Set` whose dimensions are - to be reordered and, if necessary, augmented with missing dimensions. + to be reordered. :arg dim_type: A :class:`islpy.dim_type`, i.e., an :class:`int`, specifying the dimension to be reordered. @@ -75,9 +75,7 @@ def insert_missing_dims_and_reorder_by_name( representing the desired dimensions in order by dimension name. :returns: An :class:`islpy.Set` matching `isl_set` with the - dimension order matching `desired_dims_ordered`, - including additional dimensions present in `desred_dims_ordered` - that are not present in `isl_set`. + dimension order matching `desired_dims_ordered`. """ @@ -92,22 +90,16 @@ def insert_missing_dims_and_reorder_by_name( new_set = isl_set.copy() for desired_idx, name in enumerate(desired_dims_ordered): - # If iname doesn't exist in set, add dim - if name not in new_set.get_var_names(dim_type): - assert False - # Insert missing dim in correct location - new_set = new_set.insert_dims( - dim_type, desired_idx, 1 - ).set_dim_name(dim_type, desired_idx, name) - else: # Iname exists in set - current_idx = new_set.find_dim_by_name(dim_type, 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) - # 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) + assert name in new_set.get_var_names(dim_type) + + current_idx = new_set.find_dim_by_name(dim_type, 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) + # 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) return new_set @@ -214,20 +206,16 @@ def _conjunction_of_dim_eq_conditions(dim_names, values, islvars): dim_type.out, 0, dim_type.in_, len(space_in_names), len(space_out_names)) - assert space_in_names == map_from_set.get_var_names( - isl.dim_type.in_) - - # If there are any dimensions in dom that are missing from - # map_from_set, we have a problem I think? - # (assertion checks this in add_missing...) - dom_with_all_inames = insert_missing_dims_and_reorder_by_name( + # 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, space_in_names, ) # Intersect domain with this map union_of_maps = union_of_maps.union( - map_from_set.intersect_domain(dom_with_all_inames)) + map_from_set.intersect_domain(dom_with_set_dim_aligned)) return union_of_maps From 3d321ae5d83592162fb5012b743ab32ac5506b18 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 05:04:02 -0500 Subject: [PATCH 137/315] more precise docstring for reorder_dims_by_name() --- loopy/schedule/checker/utils.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 3a2c7c682..b3143a2ff 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -63,7 +63,8 @@ def map_names_match_check( def reorder_dims_by_name( isl_set, dim_type, desired_dims_ordered): - """Return an isl_set with the dimensions in the specified order. + """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. From 0f1857921263d0e568ee59496a5f2480ed37e975 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 12:35:26 -0500 Subject: [PATCH 138/315] make doctest output invalid to see if it fails ci test --- 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 09ffd6bde..446aeb377 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -80,7 +80,7 @@ def get_schedules_for_statement_pairs( ... [("insn_a", "insn_b")], ... ) >>> print(*schedules[("insn_a", "insn_b")], sep="\n") - [pi, pj, pk] -> { [_lp_linchk_statement = 0, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 0] : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + [pi, pj, pk] -> { [_lp_linchk_statement = 777, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 0] : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } [pi, pj, pk] -> { [_lp_linchk_statement = 1, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 1] : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } """ From 503247dde928408b87244e150dfb13629d088268 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 13:39:37 -0500 Subject: [PATCH 139/315] undo intentionally incorrect doctest output, also add line break to placate flake8 --- loopy/schedule/checker/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 446aeb377..55d2876da 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -80,8 +80,12 @@ def get_schedules_for_statement_pairs( ... [("insn_a", "insn_b")], ... ) >>> print(*schedules[("insn_a", "insn_b")], sep="\n") - [pi, pj, pk] -> { [_lp_linchk_statement = 777, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 0] : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } - [pi, pj, pk] -> { [_lp_linchk_statement = 1, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 1] : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + [pi, pj, pk] -> { [_lp_linchk_statement = 0, i, j, k] -> \ + [_lp_linchk_l0 = i, _lp_linchk_l1 = 0] : \ + 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + [pi, pj, pk] -> { [_lp_linchk_statement = 1, i, j, k] -> \ + [_lp_linchk_l0 = i, _lp_linchk_l1 = 1] : \ + 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } """ From 2504e3a5c0bd25b060448a6afde20202bc52e3b4 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 13:58:54 -0500 Subject: [PATCH 140/315] try another approach to handling broken lines in expected doctest results --- loopy/schedule/checker/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 55d2876da..89395b198 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -81,11 +81,11 @@ def get_schedules_for_statement_pairs( ... ) >>> print(*schedules[("insn_a", "insn_b")], sep="\n") [pi, pj, pk] -> { [_lp_linchk_statement = 0, i, j, k] -> \ - [_lp_linchk_l0 = i, _lp_linchk_l1 = 0] : \ - 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } +[_lp_linchk_l0 = i, _lp_linchk_l1 = 0] : \ +0 <= i < pi and 0 <= j < pj and 0 <= k < pk } [pi, pj, pk] -> { [_lp_linchk_statement = 1, i, j, k] -> \ - [_lp_linchk_l0 = i, _lp_linchk_l1 = 1] : \ - 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } +[_lp_linchk_l0 = i, _lp_linchk_l1 = 1] : \ +0 <= i < pi and 0 <= j < pj and 0 <= k < pk } """ From 0d7742396f83c25946852a3b8c25990bd9c0e66a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 4 Aug 2020 14:19:01 -0500 Subject: [PATCH 141/315] workaround for dumb doctest that can't handle expected output split up across lines: add line breaks to print statement --- loopy/schedule/checker/__init__.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 89395b198..bb96ebbaa 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -79,13 +79,17 @@ def get_schedules_for_statement_pairs( ... knl.linearization, ... [("insn_a", "insn_b")], ... ) - >>> print(*schedules[("insn_a", "insn_b")], sep="\n") - [pi, pj, pk] -> { [_lp_linchk_statement = 0, i, j, k] -> \ -[_lp_linchk_l0 = i, _lp_linchk_l1 = 0] : \ -0 <= i < pi and 0 <= j < pj and 0 <= k < pk } - [pi, pj, pk] -> { [_lp_linchk_statement = 1, i, j, k] -> \ -[_lp_linchk_l0 = i, _lp_linchk_l1 = 1] : \ -0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + >>> # Print maps + >>> print("\n".join( + ... str(m).replace("{ ", "{\n").replace(" :", "\n:") + ... for m in schedules[("insn_a", "insn_b")] + ... )) + [pi, pj, pk] -> { + [_lp_linchk_statement = 0, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 0] + : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } + [pi, pj, pk] -> { + [_lp_linchk_statement = 1, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 1] + : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } """ From 049d17b4ecc7c1aa39011aaeaa55956d9ccc1e4c Mon Sep 17 00:00:00 2001 From: James Stevens Date: Fri, 28 Aug 2020 04:19:45 +0200 Subject: [PATCH 142/315] Apply 1 suggestion(s) to 1 file(s) --- 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 1e6e30fb7..b088c40f1 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -114,7 +114,7 @@ def generate_pairwise_schedules( # (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] = next_insn_lex_tuple[-1]+1 + next_insn_lex_tuple[-1] += 1 # Upon entering a loop, add one lex dimension for the loop variable, # add second lex dim to enumerate sections of code within new loop From 15f085598653d904e62d4758818b21aff010299d Mon Sep 17 00:00:00 2001 From: James Stevens Date: Fri, 28 Aug 2020 04:20:20 +0200 Subject: [PATCH 143/315] Apply 1 suggestion(s) to 1 file(s) --- 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 b088c40f1..bc249952a 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -44,7 +44,7 @@ LIN_CHECK_IDENTIFIER_PREFIX = "_lp_linchk_" LEX_VAR_PREFIX = "%sl" % (LIN_CHECK_IDENTIFIER_PREFIX) -STATEMENT_VAR_NAME = "%sstatement" % (LIN_CHECK_IDENTIFIER_PREFIX) +STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) def generate_pairwise_schedules( From 2f583e5468b99d6b643cb7aa9d84fe09a187e03a Mon Sep 17 00:00:00 2001 From: James Stevens Date: Fri, 28 Aug 2020 04:21:01 +0200 Subject: [PATCH 144/315] Apply 1 suggestion(s) to 1 file(s) --- 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 bc249952a..0380bd4f0 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -30,8 +30,8 @@ .. 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. + 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 From 05d57062a681bb6f0c85a91d4f88120567953005 Mon Sep 17 00:00:00 2001 From: James Stevens Date: Fri, 28 Aug 2020 04:21:22 +0200 Subject: [PATCH 145/315] Apply 1 suggestion(s) to 1 file(s) --- loopy/schedule/checker/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index bb96ebbaa..99525a983 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -46,8 +46,7 @@ def get_schedules_for_statement_pairs( process. :arg insn_id_pairs: A list of two-tuples containing pairs of instruction - identifiers, each of which is unique within a - :class:`loopy.kernel.LoopKernel`. + identifiers. :returns: A dictionary mapping each two-tuple of instruction identifiers provided in `insn_id_pairs` to a corresponding two-tuple containing two From 8a882e008a68bd89779053458c2b543d5fb21fb2 Mon Sep 17 00:00:00 2001 From: James Stevens Date: Fri, 28 Aug 2020 04:21:37 +0200 Subject: [PATCH 146/315] Apply 1 suggestion(s) to 1 file(s) --- 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 99525a983..e41215897 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -45,7 +45,7 @@ def get_schedules_for_statement_pairs( kernel since this function may be used during the linearization process. - :arg insn_id_pairs: A list of two-tuples containing pairs of instruction + :arg insn_id_pairs: A list containing pairs of instruction identifiers. :returns: A dictionary mapping each two-tuple of instruction identifiers From 0985a6b2bbfb569ee4f1f2e4c5a3f9d403114efe Mon Sep 17 00:00:00 2001 From: James Stevens Date: Fri, 28 Aug 2020 04:21:59 +0200 Subject: [PATCH 147/315] Apply 1 suggestion(s) to 1 file(s) --- 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 0380bd4f0..a438ca1b6 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -137,7 +137,7 @@ def generate_pairwise_schedules( # (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] = next_insn_lex_tuple[-1]+1 + next_insn_lex_tuple[-1] += 1 elif isinstance(linearization_item, (RunInstruction, Barrier)): from loopy.schedule.checker.utils import ( From 88557eedf4e17331b7d7726eb1154479920b357e Mon Sep 17 00:00:00 2001 From: James Stevens Date: Fri, 28 Aug 2020 04:22:11 +0200 Subject: [PATCH 148/315] Apply 1 suggestion(s) to 1 file(s) --- 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 a438ca1b6..6d32f36b9 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -160,7 +160,7 @@ 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[:]) + stmt_instances[lp_insn_id] = tuple(next_insn_lex_tuple) # Increment lex dim val enumerating items in current section of code next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1] + 1 From 5f9d4295a91e51507726b357001598c1a53f2f0c Mon Sep 17 00:00:00 2001 From: James Stevens Date: Fri, 28 Aug 2020 04:22:17 +0200 Subject: [PATCH 149/315] Apply 1 suggestion(s) to 1 file(s) --- 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 6d32f36b9..dec9cf24a 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -163,7 +163,7 @@ def generate_pairwise_schedules( stmt_instances[lp_insn_id] = tuple(next_insn_lex_tuple) # Increment lex dim val enumerating items in current section of code - next_insn_lex_tuple[-1] = next_insn_lex_tuple[-1] + 1 + next_insn_lex_tuple[-1] += 1 else: from loopy.schedule import (CallKernel, ReturnFromKernel) From 0b1994113c394efcd2fc59f7f8b0ee6c9bc91962 Mon Sep 17 00:00:00 2001 From: James Stevens Date: Fri, 28 Aug 2020 04:23:00 +0200 Subject: [PATCH 150/315] Apply 1 suggestion(s) to 1 file(s) --- 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 b3143a2ff..92b471f6d 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -37,7 +37,7 @@ def add_dims_to_isl_set(isl_set, dim_type, names, new_idx_start): return new_set -def map_names_match_check( +def check_that_map_names_match( obj_map, desired_names, dim_type, From a6ab09d4c2faa7aea81f15b16a54ed8153e93001 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 27 Aug 2020 21:32:42 -0500 Subject: [PATCH 151/315] change _lp_linchk_statement->_lp_linchk_stmt in doctest after renaming of module prefix --- 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 e41215897..0935e22f0 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -84,10 +84,10 @@ def get_schedules_for_statement_pairs( ... for m in schedules[("insn_a", "insn_b")] ... )) [pi, pj, pk] -> { - [_lp_linchk_statement = 0, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 0] + [_lp_linchk_stmt = 0, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 0] : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } [pi, pj, pk] -> { - [_lp_linchk_statement = 1, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 1] + [_lp_linchk_stmt = 1, i, j, k] -> [_lp_linchk_l0 = i, _lp_linchk_l1 = 1] : 0 <= i < pi and 0 <= j < pj and 0 <= k < pk } """ From 852ba31431b87859fdf0c58e7077417a0608a0f5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 27 Aug 2020 21:34:56 -0500 Subject: [PATCH 152/315] change map_names_match_check->check_that_map_names_match after renaming of function --- loopy/schedule/checker/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 92b471f6d..548ef2db2 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -80,7 +80,7 @@ def reorder_dims_by_name( """ - map_names_match_check( + check_that_map_names_match( isl_set, desired_dims_ordered, dim_type, assert_subset=True, assert_permutation=False) @@ -109,7 +109,7 @@ def ensure_dim_names_match_and_align(obj_map, tgt_map): # first make sure names match for dt in [isl.dim_type.in_, isl.dim_type.out, isl.dim_type.param]: - map_names_match_check( + check_that_map_names_match( obj_map, tgt_map.get_var_names(dt), dt, assert_permutation=True) From 88f23ead8694360d35c6b877bbc3823d18fd763d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 27 Aug 2020 21:42:42 -0500 Subject: [PATCH 153/315] rephrase docstring for linearization_items argument (the part about a partial list of linearization items) --- loopy/schedule/checker/__init__.py | 6 +++--- loopy/schedule/checker/schedule.py | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 0935e22f0..5572b03e8 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -41,9 +41,9 @@ def get_schedules_for_statement_pairs( :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. This list may be a *partial* linearization for a - kernel since this function may be used during the linearization - process. + 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. diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index dec9cf24a..4b1b4e07c 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -67,9 +67,9 @@ def generate_pairwise_schedules( :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. This list may be a *partial* linearization for a - kernel since this function may be used during the linearization - process. + 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 of two-tuples containing pairs of instruction identifiers, each of which is unique within a From d72e65375cae25e1a99252feabbcaf8096af8abc Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 27 Aug 2020 22:18:16 -0500 Subject: [PATCH 154/315] assert that all concurrent EnterLoop inames are tagged Vec or ILP, and don't warn if any such inames are found --- loopy/schedule/checker/__init__.py | 13 +++++++------ loopy/schedule/checker/schedule.py | 3 ++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index 5572b03e8..3bfb3822a 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -113,12 +113,13 @@ def get_schedules_for_statement_pairs( conc_inames, _ = partition_inames_by_concurrency(knl) enterloop_inames = get_EnterLoop_inames(linearization_items) conc_loop_inames = conc_inames & enterloop_inames - if conc_loop_inames: - from warnings import warn - warn( - "get_schedule_for_statement_pair encountered EnterLoop for inames %s " - "with ConcurrentTag(s) in linearization for kernel %s. " - "Ignoring these loops." % (conc_loop_inames, knl.name)) + + # The only concurrent EnterLoop inames should be Vec and ILP + from loopy.kernel.data import (VectorizeTag, IlpBaseTag) + for conc_iname in conc_loop_inames: + assert any( + isinstance(tag, (VectorizeTag, IlpBaseTag)) + for tag in knl.iname_to_tags[conc_iname]) # }}} diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 4b1b4e07c..15440c520 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -77,7 +77,8 @@ def generate_pairwise_schedules( :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. + 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 corresponding two-tuple containing two From 559f7781ef63128e26301ac8f138b9497d337daf Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 27 Aug 2020 22:28:10 -0500 Subject: [PATCH 155/315] simplify phrasing of insn_id_pairs arg description (to match phrasing in generate_pairwise_schedules()) --- loopy/schedule/checker/schedule.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index 15440c520..aeac8bdfc 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -71,9 +71,7 @@ def generate_pairwise_schedules( truncated (i.e. partial) linearization may be passed through this argument. - :arg insn_id_pairs: A list of two-tuples containing pairs of instruction - identifiers, each of which is unique within a - :class:`loopy.kernel.LoopKernel`. + :arg insn_id_pairs: A list containing pairs of instruction identifiers. :arg loops_to_ignore: A set of inames that will be ignored when determining the relative ordering of statements. This will typically From b992340916ee2a46a4f16316c84959ea2a758cc5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 27 Aug 2020 22:36:23 -0500 Subject: [PATCH 156/315] move function defs for _pad_tuple_with_zeros() and _simplify_lex_dims() outside of generate_pairwise_schedules() --- loopy/schedule/checker/schedule.py | 114 +++++++++++++++-------------- 1 file changed, 58 insertions(+), 56 deletions(-) diff --git a/loopy/schedule/checker/schedule.py b/loopy/schedule/checker/schedule.py index aeac8bdfc..bc71df5d8 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -47,6 +47,64 @@ STATEMENT_VAR_NAME = "%sstmt" % (LIN_CHECK_IDENTIFIER_PREFIX) +def _pad_tuple_with_zeros(tup, desired_length): + return tup[:] + tuple([0]*(desired_length-len(tup))) + + +def _simplify_lex_dims(tup0, tup1): + """Simplify a pair of lex tuples in order to reduce the complexity of + resulting maps. Remove lex tuple dimensions with matching integer values + since these do not provide information on relative ordering. Once a + dimension is found where both tuples have non-matching integer values, + remove any faster-updating lex dimensions since they are not necessary + to specify a relative ordering. + """ + + new_tup0 = [] + new_tup1 = [] + + # Loop over dims from slowest updating to fastest + for d0, d1 in zip(tup0, tup1): + if isinstance(d0, int) and isinstance(d1, int): + + # Both vals are ints for this dim + if d0 == d1: + # Do not keep this dim + continue + elif d0 > d1: + # These ints inform us about the relative ordering of + # two statements. While their values may be larger than 1 in + # the lexicographic ordering describing a larger set of + # statements, in a pairwise schedule, only ints 0 and 1 are + # necessary to specify relative order. To keep the pairwise + # schedules as simple and comprehensible as possible, use only + # integers 0 and 1 to specify this relative ordering. + # (doesn't take much extra time since we are already going + # through these to remove unnecessary lex tuple dims) + new_tup0.append(1) + new_tup1.append(0) + + # No further dims needed to fully specify ordering + break + else: # d1 > d0 + new_tup0.append(0) + new_tup1.append(1) + + # No further dims needed to fully specify ordering + break + else: + # Keep this dim without modifying + new_tup0.append(d0) + new_tup1.append(d1) + + if len(new_tup0) == 0: + # Statements map to the exact same point(s) in the lex ordering, + # which is okay, but to represent this, our lex tuple cannot be empty. + return (0, ), (0, ) + else: + return tuple(new_tup0), tuple(new_tup1) + + def generate_pairwise_schedules( knl, linearization_items, @@ -181,62 +239,6 @@ def generate_pairwise_schedules( add_dims_to_isl_set, ) - def _pad_tuple_with_zeros(tup, desired_length): - return tup[:] + tuple([0]*(desired_length-len(tup))) - - def _simplify_lex_dims(tup0, tup1): - """Simplify a pair of lex tuples in order to reduce the complexity of - resulting maps. Remove lex tuple dimensions with matching integer values - since these do not provide information on relative ordering. Once a - dimension is found where both tuples have non-matching integer values, - remove any faster-updating lex dimensions since they are not necessary - to specify a relative ordering. - """ - - new_tup0 = [] - new_tup1 = [] - - # Loop over dims from slowest updating to fastest - for d0, d1 in zip(tup0, tup1): - if isinstance(d0, int) and isinstance(d1, int): - - # Both vals are ints for this dim - if d0 == d1: - # Do not keep this dim - continue - elif d0 > d1: - # These ints inform us about the relative ordering of - # two statements. While their values may be larger than 1 in - # the lexicographic ordering describing a larger set of - # statements, in a pairwise schedule, only ints 0 and 1 are - # necessary to specify relative order. To keep the pairwise - # schedules as simple and comprehensible as possible, use only - # integers 0 and 1 to specify this relative ordering. - # (doesn't take much extra time since we are already going - # through these to remove unnecessary lex tuple dims) - new_tup0.append(1) - new_tup1.append(0) - - # No further dims needed to fully specify ordering - break - else: # d1 > d0 - new_tup0.append(0) - new_tup1.append(1) - - # No further dims needed to fully specify ordering - break - else: - # Keep this dim without modifying - new_tup0.append(d0) - new_tup1.append(d1) - - if len(new_tup0) == 0: - # Statements map to the exact same point(s) in the lex ordering, - # which is okay, but to represent this, our lex tuple cannot be empty. - return (0, ), (0, ) - else: - return tuple(new_tup0), tuple(new_tup1) - def _get_map_for_stmt_inst(insn_id, lex_points, int_sid, out_names_sched): # Get inames domain for statement instance (a BasicSet) From 0921a33b5ec57fe2779407b5b02ea2904f1eca54 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 27 Aug 2020 22:46:11 -0500 Subject: [PATCH 157/315] remove faulthandler stuff --- test/test_linearization_checker.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 6d0fd3abf..ade47f0c6 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -42,13 +42,6 @@ logger = logging.getLogger(__name__) -try: - import faulthandler -except ImportError: - pass -else: - faulthandler.enable() - def test_lexschedule_creation(): import islpy as isl From 237e7d69e000f70ab3321480d244bcd20d164930 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 27 Aug 2020 22:46:55 -0500 Subject: [PATCH 158/315] remove redundant lang_version --- test/test_linearization_checker.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index ade47f0c6..56e1c0722 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -76,7 +76,6 @@ def test_lexschedule_creation(): """, name="example", assumptions="pi,pj,pk,pt >= 1", - lang_version=(2018, 2) ) knl = lp.add_and_infer_dtypes( knl, From 74f9ee40732f0bed15d53e13cb1c471c589843bd Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 27 Aug 2020 22:59:11 -0500 Subject: [PATCH 159/315] test_lexschedule_creation(), make kernel instruction/loop order deterministic and remove machinery for handling multiple potential orderings --- test/test_linearization_checker.py | 230 ++++++++++++----------------- 1 file changed, 92 insertions(+), 138 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 56e1c0722..3c927a9ce 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -53,6 +53,8 @@ def test_lexschedule_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 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([a_lex_idx, ]), - ) - ) - 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([d_lex_idx, ]), - ) + 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, ]), ) - sched_map_after_expected = ensure_dim_names_match_and_align( - sched_map_after_expected, sched_map_after) + ) + sched_map_before_expected = ensure_dim_names_match_and_align( + sched_map_before_expected, sched_map_before) - 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_space_string([1, ]), + ) + ) + sched_map_after_expected = ensure_dim_names_match_and_align( + sched_map_after_expected, sched_map_after) - if linearized_insn_ord.index("insn_a") < linearized_insn_ord.index("insn_d"): - # insn_a was linearized first, check schedule accordingly - perform_insn_ad_checks_with(0, 1) - else: - # insn_d was linearized first, check schedule accordingly - perform_insn_ad_checks_with(1, 0) + assert sched_map_before == sched_map_before_expected + assert sched_map_after == sched_map_after_expected # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_c --------------------------------------- - # insn_b and insn_c could have been linearized in either order - def perform_insn_bc_checks_with(b_lex_idx, c_lex_idx): - # Get two maps - sched_map_before, sched_map_after = sched_maps[("insn_b", "insn_c")] + # Get two maps + sched_map_before, sched_map_after = sched_maps[("insn_b", "insn_c")] - # Create expected maps, align, compare + # Create expected maps, align, 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", b_lex_idx]), - ) - ) - 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", c_lex_idx]), - ) + 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]), ) - sched_map_after_expected = ensure_dim_names_match_and_align( - sched_map_after_expected, sched_map_after) + ) + sched_map_before_expected = ensure_dim_names_match_and_align( + sched_map_before_expected, sched_map_before) - assert sched_map_before == sched_map_before_expected - assert sched_map_after == sched_map_after_expected + 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]), + ) + ) + sched_map_after_expected = ensure_dim_names_match_and_align( + sched_map_after_expected, sched_map_after) - if linearized_insn_ord.index("insn_b") < linearized_insn_ord.index("insn_c"): - # insn_b was linearized first, check schedule accordingly - perform_insn_bc_checks_with(0, 1) - else: - # insn_c was linearized first, check schedule accordingly - perform_insn_bc_checks_with(1, 0) + assert sched_map_before == sched_map_before_expected + assert sched_map_after == sched_map_after_expected # ------------------------------------------------------------------------------ # Relationship between insn_b and insn_d --------------------------------------- - # insn_b and insn_d could have been linearized in either order - # (i loop could be before or after t loop) - def perform_insn_bd_checks_with(b_lex_idx, d_lex_idx): - # Get two maps - sched_map_before, sched_map_after = sched_maps[("insn_b", "insn_d")] + # Get two maps + sched_map_before, sched_map_after = sched_maps[("insn_b", "insn_d")] - # Create expected maps, align, compare + # Create expected maps, align, 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([b_lex_idx, ]), - ) - ) - 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([d_lex_idx, ]), - ) + 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, ]), ) - sched_map_after_expected = ensure_dim_names_match_and_align( - sched_map_after_expected, sched_map_after) + ) + sched_map_before_expected = ensure_dim_names_match_and_align( + sched_map_before_expected, sched_map_before) - 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_space_string([1, ]), + ) + ) + sched_map_after_expected = ensure_dim_names_match_and_align( + sched_map_after_expected, sched_map_after) - if linearized_insn_ord.index("insn_b") < linearized_insn_ord.index("insn_d"): - # insn_b was linearized first, check schedule accordingly - perform_insn_bd_checks_with(0, 1) - else: - # insn_d was linearized first, check schedule accordingly - perform_insn_bd_checks_with(1, 0) + assert sched_map_before == sched_map_before_expected + assert sched_map_after == sched_map_after_expected # ------------------------------------------------------------------------------ # Relationship between insn_c and insn_d --------------------------------------- - # insn_c and insn_d could have been linearized in either order - # (i loop could be before or after t loop) - def perform_insn_cd_checks_with(c_lex_idx, d_lex_idx): - # Get two maps - sched_map_before, sched_map_after = sched_maps[("insn_c", "insn_d")] + # Get two maps + sched_map_before, sched_map_after = sched_maps[("insn_c", "insn_d")] - # Create expected maps, align, compare + # Create expected maps, align, 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([c_lex_idx, ]), - ) - ) - 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([d_lex_idx, ]), - ) + 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, ]), ) - sched_map_after_expected = ensure_dim_names_match_and_align( - sched_map_after_expected, sched_map_after) + ) + sched_map_before_expected = ensure_dim_names_match_and_align( + sched_map_before_expected, sched_map_before) - 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_space_string([1, ]), + ) + ) + sched_map_after_expected = ensure_dim_names_match_and_align( + sched_map_after_expected, sched_map_after) - if linearized_insn_ord.index("insn_c") < linearized_insn_ord.index("insn_d"): - # insn_c was linearized first, check schedule accordingly - perform_insn_cd_checks_with(0, 1) - else: - # insn_d was linearized first, check schedule accordingly - perform_insn_cd_checks_with(1, 0) + assert sched_map_before == sched_map_before_expected + assert sched_map_after == sched_map_after_expected if __name__ == "__main__": From 7d34e958233ffc742a147e5e47069b17f0a6e758 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 2 Sep 2020 08:42:16 -0500 Subject: [PATCH 160/315] replace call to check_that_map_names_match() with equivalent assertion in reorder_dims_by_name() --- 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 548ef2db2..36851de44 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -80,10 +80,7 @@ def reorder_dims_by_name( """ - check_that_map_names_match( - isl_set, desired_dims_ordered, dim_type, - assert_subset=True, assert_permutation=False) - + assert set(isl_set.get_var_names(dim_type)).issubset(desired_dims_ordered) assert dim_type != isl.dim_type.param other_dim_type = isl.dim_type.param From 6f6d708fb291d12a69cc5fb9362a5d2a70ceeb46 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 2 Sep 2020 08:59:49 -0500 Subject: [PATCH 161/315] make stronger assertion in reorder_dims_by_name (just assert that sets match) --- loopy/schedule/checker/utils.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 36851de44..0953454aa 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -80,15 +80,14 @@ def reorder_dims_by_name( """ - assert set(isl_set.get_var_names(dim_type)).issubset(desired_dims_ordered) assert dim_type != isl.dim_type.param + assert set(isl_set.get_var_names(dim_type)) == set(desired_dims_ordered) other_dim_type = isl.dim_type.param other_dim_len = len(isl_set.get_var_names(other_dim_type)) new_set = isl_set.copy() for desired_idx, name in enumerate(desired_dims_ordered): - assert name in new_set.get_var_names(dim_type) current_idx = new_set.find_dim_by_name(dim_type, name) if current_idx != desired_idx: From ee4faf0f82a867f7b76586b5baefe5f234845bd0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 2 Sep 2020 09:12:00 -0500 Subject: [PATCH 162/315] remove check_that_map_names_match(), replace function call with assertion --- loopy/schedule/checker/utils.py | 35 ++++----------------------------- 1 file changed, 4 insertions(+), 31 deletions(-) diff --git a/loopy/schedule/checker/utils.py b/loopy/schedule/checker/utils.py index 0953454aa..8e2a82a01 100644 --- a/loopy/schedule/checker/utils.py +++ b/loopy/schedule/checker/utils.py @@ -37,30 +37,6 @@ def add_dims_to_isl_set(isl_set, dim_type, names, new_idx_start): return new_set -def check_that_map_names_match( - obj_map, - desired_names, - dim_type, - assert_subset=True, - assert_permutation=True, - ): - """Raise an error if names of the specified map dimension do not match - the desired names - """ - - obj_map_names = obj_map.space.get_var_names(dim_type) - if assert_permutation: - if not set(obj_map_names) == set(desired_names): - raise ValueError( - "Set of map names %s for dim %s does not match target set %s" - % (obj_map_names, dim_type, desired_names)) - elif assert_subset: - if not set(obj_map_names).issubset(desired_names): - raise ValueError( - "Map names %s for dim %s are not a subset of target names %s" - % (obj_map_names, dim_type, desired_names)) - - def reorder_dims_by_name( isl_set, dim_type, desired_dims_ordered): """Return an isl_set with the dimensions of the specified dim_type @@ -104,14 +80,11 @@ def reorder_dims_by_name( def ensure_dim_names_match_and_align(obj_map, tgt_map): # first make sure names match - for dt in [isl.dim_type.in_, isl.dim_type.out, isl.dim_type.param]: - check_that_map_names_match( - obj_map, tgt_map.get_var_names(dt), dt, - assert_permutation=True) - - aligned_obj_map = isl.align_spaces(obj_map, tgt_map) + 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 aligned_obj_map + return isl.align_spaces(obj_map, tgt_map) def sorted_union_of_names_in_isl_sets( From b8edba90e6ec31df28dc62db1cc79aedd60237c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Kl=C3=B6ckner?= Date: Fri, 4 Sep 2020 06:41:00 +0200 Subject: [PATCH 163/315] Apply 1 suggestion(s) to 1 file(s) --- 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 3bfb3822a..f9e9933c6 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -117,6 +117,8 @@ def get_schedules_for_statement_pairs( # The only concurrent EnterLoop inames should be Vec and ILP from loopy.kernel.data import (VectorizeTag, IlpBaseTag) for conc_iname in conc_loop_inames: + # Assert that there exists an ilp or vectorize tag (out of the + # potentially multiple other tags on this concurrent iname). assert any( isinstance(tag, (VectorizeTag, IlpBaseTag)) for tag in knl.iname_to_tags[conc_iname]) From 9ab0a22d1232f8dabeb0ae7bb3b2e880f808c225 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 27 Sep 2020 21:24:01 -0500 Subject: [PATCH 164/315] 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 165/315] 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 166/315] 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 167/315] 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 168/315] 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 169/315] 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 170/315] 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 171/315] 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 172/315] 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 173/315] 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 174/315] 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 175/315] 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 176/315] 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 177/315] 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 178/315] 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 179/315] 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 180/315] 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 181/315] 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 182/315] (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 183/315] 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 184/315] 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 185/315] 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 186/315] 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 187/315] 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 188/315] 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 189/315] (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 190/315] 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 191/315] 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 192/315] 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 193/315] 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 194/315] 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 195/315] 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 196/315] 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 197/315] 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 198/315] 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 199/315] 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 200/315] 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 201/315] 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 202/315] 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 203/315] 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 204/315] 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 205/315] 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 206/315] 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 207/315] 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 208/315] 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 209/315] 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 210/315] 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 211/315] 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 212/315] 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 213/315] 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 214/315] 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 215/315] 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 216/315] 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 217/315] 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 218/315] 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 219/315] 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 220/315] 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 221/315] 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 222/315] 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 223/315] 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 224/315] 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 225/315] (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 226/315] 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 227/315] 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 228/315] 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 229/315] 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 230/315] 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 231/315] 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 232/315] 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 20525dfc17c8feb1d60bb362172b584673507c36 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 14 Jul 2021 16:13:39 -0500 Subject: [PATCH 233/315] (callables update) call get_one_linearized_kernel on program[knl] --- test/test_linearization_checker.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_linearization_checker.py b/test/test_linearization_checker.py index 3c927a9ce..dff64764c 100644 --- a/test/test_linearization_checker.py +++ b/test/test_linearization_checker.py @@ -76,7 +76,6 @@ def test_lexschedule_creation(): 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( @@ -87,7 +86,7 @@ def test_lexschedule_creation(): # get a linearization knl = preprocess_kernel(knl) - knl = get_one_linearized_kernel(knl) + knl = get_one_linearized_kernel(knl["loopy_kernel"], knl.callables_table) linearization_items = knl.linearization def _lex_space_string(dim_vals): From bec6dca187c286c41b0245e257314154055f3237 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 14 Jul 2021 16:23:12 -0500 Subject: [PATCH 234/315] change default arg from set to frozenset --- 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 bc71df5d8..64dd377f2 100644 --- a/loopy/schedule/checker/schedule.py +++ b/loopy/schedule/checker/schedule.py @@ -109,7 +109,7 @@ def generate_pairwise_schedules( knl, linearization_items, insn_id_pairs, - loops_to_ignore=set(), + loops_to_ignore=frozenset(), ): 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 From b98a8de7db4f32f3ac2195f00d65cbbbf107147d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 14 Jul 2021 16:27:21 -0500 Subject: [PATCH 235/315] (callables update) call get_one_linearized_kernel on program[knl] in doctest --- loopy/schedule/checker/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/loopy/schedule/checker/__init__.py b/loopy/schedule/checker/__init__.py index f9e9933c6..51100bc92 100644 --- a/loopy/schedule/checker/__init__.py +++ b/loopy/schedule/checker/__init__.py @@ -68,8 +68,11 @@ def get_schedules_for_statement_pairs( >>> 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") + >>> # Preprocess + >>> knl = lp.preprocess_kernel(knl) >>> # Get a linearization - >>> knl = lp.get_one_linearized_kernel(lp.preprocess_kernel(knl)) + >>> knl = lp.get_one_linearized_kernel( + ... knl["loopy_kernel"], knl.callables_table) >>> # Get a pairwise schedule ----------------------------------------------- >>> from loopy.schedule.checker import get_schedules_for_statement_pairs >>> # Get two maps ---------------------------------------------------------- From 0680d4dff50ea9e62a6d9689e46b6a6af10e3330 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 14 Jul 2021 16:57:06 -0500 Subject: [PATCH 236/315] 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 237/315] 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 238/315] 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 239/315] 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 240/315] 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 241/315] 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 242/315] 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 243/315] 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 244/315] 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 245/315] 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 246/315] 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 247/315] 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 248/315] 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 249/315] 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 250/315] 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 251/315] 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 252/315] 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 253/315] 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 254/315] 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 255/315] 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 256/315] 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 257/315] 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 10a92b41011f8d347becf6b10155db29f1bf7026 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 8 Aug 2021 17:10:14 -0500 Subject: [PATCH 258/315] (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 259/315] (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 d8bc177d325ae5096ea4b9c9b837581b50ee5c2a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 12 Aug 2021 13:02:01 -0500 Subject: [PATCH 260/315] (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 261/315] 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 acd0803bd7751d9ece7da52df75ff5f4c4c8d2a2 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 13 Aug 2021 16:31:54 -0500 Subject: [PATCH 262/315] 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 263/315] 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 716f4a2ba0c217103a85569761ff52dc85776552 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 14 Aug 2021 17:12:00 -0500 Subject: [PATCH 264/315] (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 265/315] (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 266/315] (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 267/315] 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 268/315] 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 3a1778df190649df67bc754c651935b091f7396e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 24 Aug 2021 20:37:33 -0500 Subject: [PATCH 269/315] 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 270/315] (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 271/315] 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 906ef55e55a24c961525a36f598b936ed07e0626 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 31 Aug 2021 17:14:18 -0500 Subject: [PATCH 272/315] 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 273/315] (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 84da857c13866f774c35b1bb1710271e085114cb Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 2 Sep 2021 12:28:57 -0500 Subject: [PATCH 274/315] (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 275/315] (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 276/315] (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 277/315] (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 278/315] (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 279/315] 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 280/315] 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 281/315] 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 282/315] 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 283/315] 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 284/315] (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 285/315] 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 286/315] (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 287/315] 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 288/315] 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 289/315] 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 290/315] 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 291/315] 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 292/315] 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 293/315] 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 294/315] 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 295/315] 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 296/315] 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 297/315] 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 298/315] 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 299/315] 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 300/315] 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 301/315] 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 302/315] 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 303/315] 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 304/315] 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 305/315] 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 306/315] 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 307/315] 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 308/315] 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 309/315] 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 310/315] 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 311/315] 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 312/315] 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 313/315] 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 314/315] 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 315/315] 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