From ecbe138aa3c374cfa23d2d22150ff9e1e82cd379 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 6 May 2019 23:22:57 -0500 Subject: [PATCH 001/183] made package importable --- __init__.py | 0 dependency.py | 195 ++++++++++++++++++++++ dependency_check_experiments.py | 148 +++++++++++++++++ example_lex_map_creation.py | 137 ++++++++++++++++ lexicographic_order_map.py | 120 ++++++++++++++ sched_check_utils.py | 4 + schedule.py | 271 +++++++++++++++++++++++++++++++ schedule_creation_experiments.py | 219 +++++++++++++++++++++++++ version.py | 1 + 9 files changed, 1095 insertions(+) create mode 100644 __init__.py create mode 100644 dependency.py create mode 100644 dependency_check_experiments.py create mode 100644 example_lex_map_creation.py create mode 100644 lexicographic_order_map.py create mode 100644 sched_check_utils.py create mode 100644 schedule.py create mode 100644 schedule_creation_experiments.py create mode 100644 version.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/dependency.py b/dependency.py new file mode 100644 index 000000000..40ebaa99a --- /dev/null +++ b/dependency.py @@ -0,0 +1,195 @@ +import islpy as isl + + +class DependencyType: + NONE = "none" + SAME = "same" + PRIOR = "prior" + ALL = "all" + + +class Dependency(object): + def __init__( + self, + statement_before, + statement_after, + dep_type, + iname, + ): + self.statement_before = statement_before + self.statement_after = statement_after + self.dep_type = dep_type + self.iname = iname + + + def __str__(self): + return "%s -> %s {%s dep: %s}" % ( + self.statement_before, + self.statement_after, + self.iname, + self.dep_type) + + +def append_apostrophes(strings): + if not isinstance(strings, list): + raise ValueError("append_apostrophes did not receive a list") + else: + return [s+"'" for s in strings] + + +def create_equality_conjunction_set(names0, names1, islvars): + + # initialize set with constraint that is always true + eq_set = islvars[0].eq_set(islvars[0]) + for n0, n1 in zip(names0, names1): + eq_set = eq_set & islvars[n0].eq_set(islvars[n1]) + + return eq_set + + +def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): + dim_type = isl.dim_type + constraint_map = isl.Map.from_domain(constraint_set) + if src_position: + return constraint_map.move_dims(dim_type.out, 0, dim_type.in_, src_position, mv_count) + else: + return constraint_map.move_dims(dim_type.out, 0, dim_type.in_, mv_count, mv_count) + + +def _make_islvars_with_var_primes(var_names, param_names): + return isl.make_zero_and_vars( + var_names+append_apostrophes(var_names), param_names) + + +def _create_bounded_set_for_dependency_constraints( + var_names, param_names, upper_bounds): + + # TODO assumes lower bound is zero + islvars = _make_islvars_with_var_primes(var_names, param_names) + + bounded_set = islvars[0].eq_set(islvars[0]) # initialize to True + + for v, p, b in zip(var_names, param_names, upper_bounds): + # create constraint 0 <= v,v'< p = b + v_prime = v+"'" + bounded_set = bounded_set \ + & islvars[v].lt_set(islvars[p]) \ + & islvars[v_prime].lt_set(islvars[p]) \ + & (islvars[0]-1).lt_set(islvars[v]) \ + & (islvars[0]-1).lt_set(islvars[v_prime]) \ + & islvars[p].eq_set(islvars[0]+b) + + return bounded_set + + +class DependencyConstraintVars(object): + def __init__( + self, + inames, + param_names, + param_vals, + statement_var, + statement_param, + statement_param_val, + ): + self.inames = inames + self.param_names = param_names + self.param_vals = param_vals + self.statement_var = statement_var + self.statement_param = statement_param + self.statement_param_val = statement_param_val + + def get_bounds_constraint_set(self): + var_names = [self.statement_var]+self.inames + param_names = [self.statement_param]+self.param_names + param_vals = [self.statement_param_val]+self.param_vals + # TODO assumes lower bound is zero + islvars = _make_islvars_with_var_primes( + var_names, param_names) + + bounded_set = islvars[0].eq_set(islvars[0]) # initialize to True + + for v, p, b in zip(var_names, param_names, param_vals): + # create constraint 0 <= v,v'< p = b + v_prime = v+"'" + bounded_set = bounded_set \ + & islvars[v].lt_set(islvars[p]) \ + & islvars[v_prime].lt_set(islvars[p]) \ + & (islvars[0]-1).lt_set(islvars[v]) \ + & (islvars[0]-1).lt_set(islvars[v_prime]) \ + & islvars[p].eq_set(islvars[0]+b) + + return bounded_set + + def __str__(self): + return str(self.get_bounds_constraint_set()) + + +def create_dependency_constraint( + dependencies, + dep_constraint_vars, + ): + # This function uses the dependencies given to create the following constraint: + # Statement [s,i,j] comes before statement [s',i',j'] iff + + # assumes statements are numbered sequentially + # (statement_bound = max statement id + 1) + + statement_param = dep_constraint_vars.statement_param + param_names = dep_constraint_vars.param_names + all_inames = dep_constraint_vars.inames + statement_var = dep_constraint_vars.statement_var + + # make sure all dependencies involve same two statements + if len(set([dep.statement_before for dep in dependencies])) != 1 or \ + len(set([dep.statement_after for dep in dependencies])) != 1: + raise ValueError("All depencencies must be between same two statements.") + # make sure all dependencies involve different inames # TODO upate after allowing prior(i,k) + if len(set([dep.iname for dep in dependencies])) != len(dependencies): + raise ValueError("All depencencies must apply to different inames.") + + DT = DependencyType + statement_var_prime = statement_var+"'" + islvars = _make_islvars_with_var_primes( + [statement_var]+all_inames, + [statement_param]+param_names) + + # initialize constraints to False + # this will disappear as soon as we add a constraint that is not DT.NONE + all_constraints_set = islvars[0].eq_set(islvars[0] + 1) + + for dep in dependencies: + iname = dep.iname + dep_type = dep.dep_type + if dep_type == DT.NONE: + continue + + iname_prime = iname+"'" # i' + other_inames = all_inames.copy() + other_inames.remove(iname) # remaining inames, e.g., [j, k] + other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] + + # initialize constraint set with what we know about other inames (e.g., j = j', k = k') + constraint_set = create_equality_conjunction_set(other_inames, other_inames_prime, islvars) + if dep_type == DT.SAME: + constraint_set = constraint_set & islvars[iname].eq_set(islvars[iname_prime]) + elif dep_type == DT.PRIOR: + constraint_set = constraint_set & islvars[iname].lt_set(islvars[iname_prime]) + elif dep_type == DT.ALL: + constraint_set = constraint_set & islvars[0].eq_set(islvars[0]) # True + + constraint_set = constraint_set & islvars[statement_var].eq_set(islvars[0]+dep.statement_before) + constraint_set = constraint_set & islvars[statement_var_prime].eq_set(islvars[0]+dep.statement_after) + # TODO get this working + # add 'or' to indicate that this constraint doesn't apply to other statements + #remainder_set = islvars[statement_var].ne_set(islvars[0]+dep.statement_before) \ + # | islvars[statement_var_prime].ne_set(islvars[0]+dep.statement_after) + #print("remainder_set", remainder_set) + #constraint_set = constraint_set | remainder_set + + + all_constraints_set = all_constraints_set | constraint_set + + all_constraints_set = all_constraints_set & dep_constraint_vars.get_bounds_constraint_set() + + return _convert_constraint_set_to_map(all_constraints_set, len(dep_constraint_vars.inames)+1) diff --git a/dependency_check_experiments.py b/dependency_check_experiments.py new file mode 100644 index 000000000..2ef0bfce9 --- /dev/null +++ b/dependency_check_experiments.py @@ -0,0 +1,148 @@ +import islpy as isl +import loopy as lp +from schedule_checker.dependency import ( + Dependency, + DependencyType as DT, + create_dependency_constraint, + append_apostrophes, + DependencyConstraintVars, +) +from schedule_checker.lexicographic_order_map import ( + make_lex_mapping_tuple_pairs, + create_explicit_map_from_tuples, + get_statement_ordering_map, + set_space_names, + get_space, + create_symbolic_lex_mapping, +) +from schedule_checker.sched_check_utils import prettier_map_string + + +# make example kernel +knl = lp.make_kernel( + "{[i,j]: 0<=i,j<2}", + [ + "a[i,j] = b[i,j] {id=0}", + "a[i,j] = a[i,j] + 1 {id=1,dep=0}", + ], + name="example", + ) +knl = lp.tag_inames(knl, {"i": "l.0"}) +print("Kernel:") +print(knl) + +all_inames = ['i', 'j'] +iname_params = ['p0', 'p1'] +iname_param_vals = [2, 2] +statement_var = 's' +statement_param = 'ps' +statement_bound = 2 + +# example sched: +print("---------------------------------------------------------------------------") + +# i is parallel, suppose we want to enforce the following: +# for a given i, statement 0 happens before statement 1 + +params_sched = [statement_param]+iname_params +in_names_sched = [statement_var]+all_inames +out_names_sched = ['l0', 'l1'] +sched_space = get_space(params_sched, in_names_sched, out_names_sched) + +example_sched_valid = create_explicit_map_from_tuples( + [ + ((0,0,0), (0, 0)), + ((0,1,0), (0, 0)), + ((1,0,0), (0, 1)), + ((1,1,0), (0, 1)), + ((0,0,1), (1, 0)), + ((0,1,1), (1, 0)), + ((1,0,1), (1, 1)), + ((1,1,1), (1, 1)), + ], + sched_space, + ) +print("example sched (valid):") +print(prettier_map_string(example_sched_valid)) + +example_sched_invalid = create_explicit_map_from_tuples( + [ + ((0,0,0), (0, 0)), + ((0,1,0), (1, 1)), # these two are out of order, violation + ((1,0,0), (0, 1)), + ((1,1,0), (0, 1)), + ((0,0,1), (1, 0)), + ((0,1,1), (1, 0)), + ((1,0,1), (1, 1)), + ((1,1,1), (0, 0)), # these two are out of order, violation + ], + sched_space, + ) +print("example sched (invalid):") +print(prettier_map_string(example_sched_invalid)) + +# *Explicit* lexicographic mapping- map each tuple to all tuples occuring later +print("---------------------------------------------------------------------------") +lex_dim_bounds = [(0,2), (0,2)] # max vals for each dim (e.g., 0 <= i0 < max0 ...) +lex_params = [] +lex_in_names = out_names_sched +lex_out_names = append_apostrophes(out_names_sched) + +explicit_lex_map_pairs = make_lex_mapping_tuple_pairs(lex_dim_bounds) +# for pair in explicit_lex_map_pairs: +# print(pair[0], pair[1]) +lex_space_explicit = get_space(lex_params, lex_in_names, lex_out_names) +lex_map_explicit = create_explicit_map_from_tuples(explicit_lex_map_pairs, + lex_space_explicit) +print("lex_map (explicit):") +print(prettier_map_string(lex_map_explicit)) + +# Statement instance ordering (valid sched) +print("----------------------------------------------------------------------") +SIO_explicit_valid = get_statement_ordering_map( + example_sched_valid, lex_map_explicit) +print("statement instance ordering explicit (valid_sched):") +print(prettier_map_string(SIO_explicit_valid)) +# Statement instance ordering (invalid sched) +print("----------------------------------------------------------------------") +SIO_explicit_invalid = get_statement_ordering_map( + example_sched_invalid, lex_map_explicit) +print("statement instance ordering explicit (invalid_sched):") +print(prettier_map_string(SIO_explicit_invalid)) + +# Dependencies and constraints: +print("----------------------------------------------------------------------") + +dep_constraint_vars = DependencyConstraintVars( + all_inames, + iname_params, + iname_param_vals, + statement_var, + statement_param, + statement_bound, + ) + +# i is parallel, suppose we want to enforce the following: +# for a given i, statement 0 happens before statement 1 +# i dependency is none, j dependency is `prior` + +deps = [ + #Dependency(0, 1, DT.NONE, 'i'), + Dependency(0, 1, DT.SAME, 'i'), + Dependency(0, 1, DT.SAME, 'j'), + ] +print([str(dep) for dep in deps]) +constraint_map = create_dependency_constraint( + deps, dep_constraint_vars) +assert constraint_map.space == SIO_explicit_valid.space +print("constraint map:") +print(prettier_map_string(constraint_map)) + +print("is valid sched valid?") +print(constraint_map.is_subset(SIO_explicit_valid)) +#print(SIO_explicit_valid.is_subset(constraint_map)) + +print("is invalid sched valid?") +print(constraint_map.is_subset(SIO_explicit_invalid)) +#print(SIO_explicit_invalid.is_subset(constraint_map)) + diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py new file mode 100644 index 000000000..fec169ea1 --- /dev/null +++ b/example_lex_map_creation.py @@ -0,0 +1,137 @@ +import islpy as isl +from schedule_checker.dependency import ( + Dependency, + DependencyType as DT, + create_dependency_constraint, +) +from schedule_checker.lexicographic_order_map import ( + make_lex_mapping_tuple_pairs, + create_explicit_map_from_tuples, + get_statement_ordering_map, + set_space_names, + get_space, + create_symbolic_lex_mapping, +) + + +# *Symbolic* lexicographic mapping- map each tuple to all tuples occuring later + +#dim_bounds = [3, 2, 2] # max vals for each dim (e.g., 0 <= i0 <= max0 ...) +#param_names = ["p0", "p1", "p2"] +#in_names = ["i0", "i1", "i2"] +#out_names = ["o0", "o1", "o2"] +dim_bounds = [(0,2), (0,2)] # max vals for each dim (e.g., 0 <= i0 < max0 ...) +param_names = ["p0", "p1"] +in_names = ["i", "j"] +out_names = ["i'", "j'"] + +lex_map_symbolic = create_symbolic_lex_mapping(param_names, in_names, out_names, dim_bounds) +print("lex_map (symbolic):") +print(lex_map_symbolic) + + +# *Explicit* lexicographic mapping- map each tuple to all tuples occuring later + +explicit_lex_map_pairs = make_lex_mapping_tuple_pairs(dim_bounds) +# for pair in explicit_lex_map_pairs: +# print(pair[0], pair[1]) +lex_map_explicit = create_explicit_map_from_tuples(explicit_lex_map_pairs, + lex_map_symbolic.space) +print("lex_map (explicit):") +print(lex_map_explicit) + + +# Example *explicit* schedule (map statement instances to lex time) + +param_names_sched = [] +in_names_sched = ["s"] +out_names_sched = ["i", "j"] +sched_space = get_space(param_names_sched, in_names_sched, out_names_sched) +example_sched = create_explicit_map_from_tuples( + [ + #((0,), (2, 0, 0)), + #((1,), (2, 0, 1)), + #((2,), (2, 1, 0)), + #((3,), (2, 1, 1)), + ((0,), (0, 0)), + ((1,), (0, 1)), + ((2,), (1, 0)), + ((3,), (1, 1)), + ], + sched_space, + ) +print("example sched:") +print(example_sched) + +# statement ordering: +# map each statement instance to all statement instances that occur later +# S -> L -> S^-1 + +statement_instance_ordering_explicit = get_statement_ordering_map( + example_sched, lex_map_explicit) +print("statement instance ordering explicit:") +print(statement_instance_ordering_explicit) + +# TODO figure out where these "p0 >= 2 and p1 >= 2" are coming from: +statement_instance_ordering_symbolic = get_statement_ordering_map( + example_sched, lex_map_symbolic) +print("statement instance ordering symbolic:") +print(statement_instance_ordering_symbolic) + + +# example constraint test: +print("---------------------------------------------------------------------------") +""" +param_names_sched = ["ps", "p0", "p1"] +in_names_sched = ["s"] +out_names_sched = ["i", "j"] +sched_space = isl.Space.alloc(isl.DEFAULT_CONTEXT, 3, 1, 2) +sched_space = set_space_names( + sched_space, + param_names=param_names_sched, + in_names=in_names_sched, + out_names=out_names_sched) +example_sched = create_explicit_map_from_tuples( + [ + #((0,0), (0, 0)), + #((1,0), (0, 1)), + #((2,1), (1, 0)), + #((3,1), (1, 1)), + ((0,), (0, 0)), + ((1,), (0, 1)), + ((2,), (1, 0)), + ((3,), (1, 1)), + ], + sched_space, + ) +print("example sched:") +print(example_sched) +""" +param_names_sched = ["ps", "p0", "p1"] +in_names_sched = ["s","i","j"] +out_names_sched = ["l0","l1"] +sched_space = get_space(param_names_sched, in_names_sched, out_names_sched) +example_sched = create_explicit_map_from_tuples( + [ + ((0,0,0), (0, 0)), + ((0,1,0), (0, 0)), + ((1,0,0), (0, 1)), + ((1,1,0), (0, 1)), + ((0,0,1), (1, 0)), + ((0,1,1), (1, 0)), + ((1,0,1), (1, 1)), + ((1,1,1), (1, 1)), + ], + sched_space, + ) +print("example sched:") +print(example_sched) + +print("lex map explicit:") +print(lex_map_explicit) + +statement_instance_ordering_explicit = get_statement_ordering_map( + example_sched, lex_map_explicit) +print("statement instance ordering explicit:") +print(statement_instance_ordering_explicit) + diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py new file mode 100644 index 000000000..f1fe02655 --- /dev/null +++ b/lexicographic_order_map.py @@ -0,0 +1,120 @@ +import islpy as isl + + +def make_lex_mapping_tuple_pairs(dim_bounds): + + import itertools + # all lex tuples in order: + lex_tuples = list( + itertools.product(*[range(l,u) for l,u in dim_bounds])) + # TODO: is itertools.product ordering guaranteed? + + map_pairs = [] + for i, l_before in enumerate(lex_tuples): + for l_after in lex_tuples[i+1:]: + map_pairs.append((l_before, l_after)) + return map_pairs + + +def create_explicit_map_from_tuples(tuple_pairs, space): + + dim_type = isl.dim_type + individual_maps = [] + + for tup_in, tup_out in tuple_pairs: + constraints = [] + for i, val_in in enumerate(tup_in): + constraints.append( + isl.Constraint.equality_alloc(space) + .set_coefficient_val(dim_type.in_, i, 1) + .set_constant_val(-1*val_in)) + for i, val_out in enumerate(tup_out): + constraints.append( + isl.Constraint.equality_alloc(space) + .set_coefficient_val(dim_type.out, i, 1) + .set_constant_val(-1*val_out)) + individual_maps.append( + isl.Map.universe(space).add_constraints(constraints)) + + union_map = individual_maps[0] + for m in individual_maps[1:]: + union_map = union_map.union(m) + + return union_map + + +def get_statement_ordering_map(sched_map, lex_map): + # statement ordering: + # map each statement instance to all statement instances that occur later + # S -> L -> S^-1 + return sched_map.apply_range(lex_map).apply_range(sched_map.reverse()) + + +def set_space_names(space, param_names=None, in_names=None, out_names=None): + new_space = 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(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(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(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_space(param_names, in_names, out_names): + space = isl.Space.alloc(isl.DEFAULT_CONTEXT, len(param_names), len(in_names), len(out_names)) + return set_space_names(space, param_names=param_names, in_names=in_names, out_names=out_names) + + +def create_symbolic_lex_mapping(param_names, in_names, out_names, + dim_bounds): + # assumes dim vars are bounded between 0 and corresponding dim_bound + assert len(in_names) == len(out_names) + dim_type = isl.dim_type + + islvars = isl.make_zero_and_vars(in_names+out_names, param_names) + + # initialize set with constraint that is always true + lex_set_outer_bounds = islvars[0].eq_set(islvars[0]) + # make constraints to bound dim vars 0 <= ix < dim_bound_x + for i, dim_bound in enumerate(dim_bounds): + lex_set_outer_bounds = lex_set_outer_bounds \ + & islvars[0].le_set(islvars[in_names[i]]) \ + & islvars[in_names[i]].le_set(islvars[param_names[i]]-1) \ + & islvars[0].le_set(islvars[out_names[i]]) \ + & islvars[out_names[i]].le_set(islvars[param_names[i]]-1) + + # create constraint enforcing lex ordering, e.g., in the 3-dim case: + # i0 < o0 or ((i0 = o0) and (i1 < o1)) + # or ((i0 = o0) and (i1 = o1) and (i2 < o2)) + lex_set_order_bound = islvars[in_names[0]].le_set(islvars[out_names[0]]-1) + for i in range(1, len(in_names)): + lex_set_order_bound_conj = islvars[in_names[i]].le_set( + islvars[out_names[i]]-1) + for j in range(i): + lex_set_order_bound_conj = lex_set_order_bound_conj & \ + islvars[in_names[j]].eq_set(islvars[out_names[j]]) + lex_set_order_bound = lex_set_order_bound | lex_set_order_bound_conj + + lex_set = lex_set_outer_bounds & lex_set_order_bound + lex_map = isl.Map.from_domain(lex_set) + lex_map = lex_map.move_dims( + dim_type.out, 0, dim_type.in_, + len(in_names), len(out_names)) + + return lex_map + + diff --git a/sched_check_utils.py b/sched_check_utils.py new file mode 100644 index 000000000..878d42183 --- /dev/null +++ b/sched_check_utils.py @@ -0,0 +1,4 @@ + + +def prettier_map_string(isl_map): + return str(isl_map).replace("{ ", "{\n").replace(" }","\n}").replace("; ",";\n") diff --git a/schedule.py b/schedule.py new file mode 100644 index 000000000..410489d5f --- /dev/null +++ b/schedule.py @@ -0,0 +1,271 @@ +import islpy as isl +from collections import OrderedDict + + +class Statement(object): + def __init__( + self, + statement_id, + active_inames, + ): + self.statement_id = statement_id # string + self.active_inames = active_inames # [string, ] + + def __str__(self): + return "%s {%s}" % ( + self.statement_id, ",".join(self.active_inames)) + + +class StatementInstance(object): + def __init__( + self, + statement, + iname_vals, + ): + assert all( + [iname in statement.active_inames + for iname, val in iname_vals.items()]) + self.statement = statement # statement + self.iname_vals = iname_vals # dict{string:int} + + def __str__(self): + import six + return "[%s,%s]" % ( + self.statement.statement_id, ",".join( + ["%d" % (v) for k, v in sorted(six.iteritems(self.iname_vals))])) + + def __eq__(self, other): + return self.iname_vals == other.iname_vals and \ + self.statement.statement_id == other.statement.statement_id + + def __hash__(self): + return hash(str(self)) + + +class LexSchedule(object): + # TODO this should hold a map of statement instances to lex order space + def __init__( + self, + knl, + iname_bounds, + ): + self.lex_schedule = OrderedDict() # statement instance: lex point + self.inames_enumerated = [] # symbolic inames in sched that have been enumerated into explicit statement instances + self.lp_insnid_to_id = {} + + from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) + cur_nest_lex_prefix = [] + for sched_item in knl.schedule: + if isinstance(sched_item, EnterLoop): + iname = sched_item.iname + #conc_dict = get_iname_concurrency_dict([iname], knl) + #print("EnterLoop: %s" % (conc_dict)) + if self: + cur_nest_lex_prefix.append(self.get_last_lex_pt()[-1]) + else: + cur_nest_lex_prefix.append(0) + cur_nest_lex_prefix.append(iname) + elif isinstance(sched_item, LeaveLoop): + #conc_dict = get_iname_concurrency_dict([sched_item.iname], knl) + #print("LeaveLoop: %s" % (conc_dict)) + cur_nest_lex_prefix.pop() # pop loop variable + cur_nest_lex_prefix.pop() # pop insn ct variable + elif isinstance(sched_item, RunInstruction): + self.add_new_lp_insnid(sched_item.insn_id) + insn_id_int = self.lp_insnid_to_id[sched_item.insn_id] + #inames = knl.id_to_insn[insn_id].within_inames + #conc_dict = get_iname_concurrency_dict(inames, knl) + #print("RunInstruction: id: %s; inames: %s" % (sched_item.insn_id, conc_dict)) + self.append_item( + (insn_id_int,), + cur_nest_lex_prefix + [self.get_next_lex_val_in_series(cur_nest_lex_prefix, iname_bounds)]) + elif isinstance(sched_item, Barrier): + pass + else: + pass + self.pad_lex_pts_with_zeros() + + def max_lex_dims(self): + return max(len(lex_pt) for insn, lex_pt in self.items()) + + def pad_lex_pts_with_zeros(self): + max_lex_dim = self.max_lex_dims() + new_sched = OrderedDict() + for insn, lex_pt in self.items(): + new_sched[insn] = lex_pt + [0]*(max_lex_dim-len(lex_pt)) + self.lex_schedule = new_sched + + def enumerate_iname(self, iname, bound): + new_sched = OrderedDict() + iname_found = False + for insn, lex_pt in self.lex_schedule.items(): + if iname in lex_pt: + for v in range(bound[0],bound[1]): + new_sched[tuple(list(insn)+[v])] = [l if l != iname else v for l in lex_pt] + iname_found = True + else: + new_sched[insn] = lex_pt + self.lex_schedule = new_sched + if iname_found: + self.inames_enumerated.append(iname) + + def enumerate_inames(self, iname_bounds): + inames_found = [] + for iname, bound in iname_bounds.items(): + self.enumerate_iname(iname, bound) + + def add_new_lp_insnid(self, lp_insnid): + if self.lp_insnid_to_id: + self.lp_insnid_to_id[lp_insnid] = max(self.lp_insnid_to_id.values()) + 1 + else: + self.lp_insnid_to_id[lp_insnid] = 0 + + def get_sched_space(self): + params_sched = ["ps"] + ["p"+iname for iname in self.inames_enumerated] + in_names_sched = ["s"] + self.inames_enumerated + out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] + from schedule_checker.lexicographic_order_map import get_space + return get_space(params_sched, in_names_sched, out_names_sched) + + def get_max_lex_dim_vals(self): + return [max(dim_pts) for dim_pts in zip(*self.lex_schedule.values())] + + def get_min_lex_dim_vals(self): + return [min(dim_pts) for dim_pts in zip(*self.lex_schedule.values())] + + def append_item(self, sched_item, lex_pt): + self.lex_schedule[sched_item] = lex_pt + + def get_last_schedule_item(self): + return next(reversed(self.lex_schedule)) + + def get_last_lex_pt(self): + return self.lex_schedule[self.get_last_schedule_item()] + + def get_next_lex_val_in_series(self, cur_nest_lex_prefix, iname_bounds): + if not self.lex_schedule: + return 0 + last_lex_pt = self.get_last_lex_pt() + #print(last_lex_pt) + if len(last_lex_pt) == len(cur_nest_lex_prefix) + 1: + # we're still in same loop, increment current lex dim val + return last_lex_pt[-1] + 1 + elif len(last_lex_pt) > len(cur_nest_lex_prefix) + 1: + # we just ended one or more loops, increment appropriate lex dim val + return last_lex_pt[len(cur_nest_lex_prefix)] + 1 + else: # len(last_lex_pt) < cur_nest_lex_prefix + 1: + # we just entered one or more loops + #return 0 + return iname_bounds[cur_nest_lex_prefix[-1]][0] + + def create_explicit_isl_map(self, sched_space): + from schedule_checker.lexicographic_order_map import create_explicit_map_from_tuples + return create_explicit_map_from_tuples(list(self.items()), sched_space) + + def enumerate_symbolic_inames_and_create_explicit_isl_map(self, iname_bounds): + self.enumerate_inames(iname_bounds) + sched_space = self.get_sched_space() + return self.create_explicit_isl_map(sched_space) + + def get_lex_map_explicit(self): + + from schedule_checker.lexicographic_order_map import ( + make_lex_mapping_tuple_pairs, + create_explicit_map_from_tuples, + get_space, + ) + from schedule_checker.dependency import append_apostrophes + + # TODO lower bound may not be zero + lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(), + [1 + v for v in self.get_max_lex_dim_vals()])) + sched_space = self.get_sched_space() + + lex_in_names = sched_space.get_var_names(isl.dim_type.out) + lex_out_names = append_apostrophes(lex_in_names) + lex_params = [] + + # TODO lex map routines currently assume lower bound is zero, fix this + explicit_lex_map_pairs = make_lex_mapping_tuple_pairs(lex_dim_bounds) + lex_space_explicit = get_space(lex_params, lex_in_names, lex_out_names) + + return create_explicit_map_from_tuples(explicit_lex_map_pairs, + lex_space_explicit) + + #def get_isl_map(self): + def get_isl_map_str(self): + map_str = "{" + for state_inst, lex in self.lex_schedule.items(): + domain_elem = "[s=%s,%s]" % ( + state_inst.statement.statement_id, ",".join( + ["%s=%d" % (iname, val) for iname, val in state_inst.iname_vals.items()])) + range_elem = "[%s]" % (",".join("%s" % (l) for l in lex)) + map_str += "%s -> %s; " % (domain_elem, range_elem) + map_str += "}" + #TODO return map not string + return map_str + + def __bool__(self): + return bool(self.lex_schedule) + + def __nonzero__(self): + return self.__bool__() + + def __eq__(self, other): + return self.lex_schedule == other.lex_schedule + + def __iter__(self): + return iter(self.lex_schedule) + + def keys(self): + return self.lex_schedule.keys() + + def items(self): + return self.lex_schedule.items() + + def values(self): + return self.lex_schedule.values() + + #def __str__(self): + # #return str(self.get_isl_map()) + # return str(self.get_isl_map_str()) + + def __str__(self): + return str(list(self.lex_schedule)) + + # TODO remove after stripping useful parts: + """ + def add_run_instructions_within_loop_nesting( + self, + insn_ids_ordered, + nest_order, # sequential lex dims in nest order (other lex dims assumed parallel) + iname_bounds, # dict w/bounds for sequential lex dims + concurrent_inames, + ): + # TODO don't pass explicit iname bounds, get them from kernel + + # TODO for now, assuming loop nestings are not re-encountered + + # create a lex dim for this set of (sequential) insns + self.add_lex_dim("s"+"".join(str(i) for i in insn_ids_ordered)) + + nested_iname_bounds_ordered = [iname_bounds[i] for i in nest_order] + import itertools + all_iname_val_sets = list( + itertools.product(*[range(b) for b in nested_iname_bounds_ordered])) + #TODO is there an order guarantee with product? + + for n_insn, insn_id in enumerate(insn_ids_ordered): # for each statement + st = Statement(insn_id, concurrent_inames+nest_order) + new_st_instances = [] + for iname_vals in all_iname_val_sets: + iname_vals = list(iname_vals) + # TODO handle concurrent inames + concurrent_iname_vals = [-1 for iname in range(len(concurrent_inames))] + st_i = StatementInstance( + st, + dict(zip(concurrent_inames+nest_order, + concurrent_iname_vals+iname_vals))) + self.lex_schedule[st_i] = iname_vals+[n_insn] + """ + diff --git a/schedule_creation_experiments.py b/schedule_creation_experiments.py new file mode 100644 index 000000000..dc5fa5535 --- /dev/null +++ b/schedule_creation_experiments.py @@ -0,0 +1,219 @@ +import islpy as isl +import loopy as lp +import numpy as np +from schedule_checker.dependency import ( + Dependency, + DependencyType, + append_apostrophes, +) +from schedule_checker.schedule import Statement, StatementInstance, LexSchedule +from schedule_checker.sched_check_utils import prettier_map_string +from schedule_checker.lexicographic_order_map import ( + create_explicit_map_from_tuples, + get_statement_ordering_map, + #set_space_names, + get_space, + #create_symbolic_lex_mapping, +) +from schedule_checker.sched_check_utils import prettier_map_string + + +def get_iname_bounds_dict(knl, _set_arbitrary_bounds=None): + # TODO don't require explicit bounds + + if _set_arbitrary_bounds: + return dict((iname, _set_arbitrary_bounds) for iname in knl.all_inames()) + + from loopy.symbolic import aff_to_expr + int_bounds = {} + for iname in knl.all_inames(): + bounds_record = knl.get_iname_bounds(iname, constants_only=True) + (_, iname_min_aff), = bounds_record.lower_bound_pw_aff.get_pieces() + (_, iname_max_aff), = bounds_record.upper_bound_pw_aff.get_pieces() + int_bounds[iname] = [ + aff_to_expr(iname_min_aff), + aff_to_expr(iname_max_aff) + 1, + ] + assert all(isinstance(i,int) for i in int_bounds[iname]) + return int_bounds + +# make example kernel +knl = lp.make_kernel( + #"{[i,j]: 0<=i,j<2}", + "{[i,j]: 0<=i<2 and 1<=j<3}", + [ + "<>temp = b[i,j] {id=0}", + "a[i,j] = temp + 1 {id=1,dep=0}", + "c[i,j] = d[i,j] {id=2}" + ], + name="example", + lang_version=(2018, 2) + ) +knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32}) +knl = lp.tag_inames(knl, {"i": "l.0"}) +knl = lp.preprocess_kernel(knl) +knl = lp.get_one_scheduled_kernel(knl) + +# make some dependencies manually for now: +s0 = Statement("0", ["i", "j"]) +s1 = Statement("1", ["i", "j"]) +s2 = Statement("2", ["i", "j"]) +dep_s1_i = Dependency(s0, s1, "i", DependencyType.SAME) +dep_s1_j = Dependency(s0, s1, "j", DependencyType.SAME) +insn_to_deps = {"0":[], "1":[dep_s1_i, dep_s1_j], "2":[]} + +# enforce explicit iname bounds for now TODO +print("Kernel:") +print(knl) +print(lp.generate_code_v2(knl).device_code()) +print("="*80) +print("Iname tags: %s" % (knl.iname_to_tags)) +print("="*80) +print("Loopy schedule:") +for sched_item in knl.schedule: + print(sched_item) +print("="*80) + +def get_iname_concurrency_dict(inames, knl): + from loopy.kernel.data import LocalIndexTag, GroupIndexTag + conc_dict = {} + for iname in inames: + iname_tags = knl.iname_to_tags.get(iname, None) + concurrent = False + if iname_tags: + if len(iname_tags) > 1: + 1/0 + else: + iname_tag = list(iname_tags)[0] + if isinstance(iname_tag, (LocalIndexTag, GroupIndexTag)): + concurrent = True + conc_dict[iname] = "concurrent" if concurrent else "sequential" + return conc_dict + +# Get schedule ------------------------------------------------------ +iname_bounds = get_iname_bounds_dict(knl) +#iname_bounds = get_iname_bounds_dict(knl, _set_arbitrary_bounds=[0,2]) +print(iname_bounds) +sched = LexSchedule(knl, iname_bounds) +example_sched_valid = sched.enumerate_symbolic_inames_and_create_explicit_isl_map(iname_bounds) +# ------------------------------------------------------------------- + +print("example LexSched (valid):") +print(prettier_map_string(example_sched_valid)) + +# *Explicit* lexicographic mapping- map each tuple to all tuples occuring later +print("---------------------------------------------------------------------------") +lex_map_explicit = sched.get_lex_map_explicit() + +print("lex map explicit:") +print(prettier_map_string(lex_map_explicit)) + +# Statement instance ordering +print("----------------------------------------------------------------------") +SIO_explicit_valid = get_statement_ordering_map( + example_sched_valid, lex_map_explicit) +print("statement instance ordering explicit (valid_sched):") +print(prettier_map_string(SIO_explicit_valid)) + +''' +all_inames = ['i', 'j'] +iname_params = ['p0', 'p1'] +iname_param_vals = [2, 2] +statement_var = 's' +statement_param = 'ps' +statement_bound = 2 + + + +s0 = Statement("0", ["i", "j"]) +s1 = Statement("1", ["i", "j"]) +print("Statements:") +print(s0) +print(s1) + +s0_00 = StatementInstance(s0, {"i": 0, "j": 0}) +s0_10 = StatementInstance(s0, {"i": 1, "j": 0}) +s0_01 = StatementInstance(s0, {"i": 0, "j": 1}) +s0_11 = StatementInstance(s0, {"i": 1, "j": 1}) +s1_00 = StatementInstance(s1, {"i": 0, "j": 0}) +s1_10 = StatementInstance(s1, {"i": 1, "j": 0}) +s1_01 = StatementInstance(s1, {"i": 0, "j": 1}) +s1_11 = StatementInstance(s1, {"i": 1, "j": 1}) +print("Statement instances:") +print(s0_00) +print(s0_10) +print(s0_01) +print(s0_11) +print(s1_00) +print(s1_10) +print(s1_01) +print(s1_11) + +state_inst_to_lex_time_dict = { + s0_00: (0,0), + s1_00: (0,1), + s0_10: (0,0), + s1_10: (0,1), + s0_01: (1,0), + s1_01: (1,1), + s0_11: (1,0), + s1_11: (1,1), + } + +sched = LexSchedule(state_inst_to_lex_time_dict) +print("LexSchedule:") +print(sched) + +# sched map should be this: +schedule_explicit_map = isl.Map( + """{ + [s,i,j] -> [0,0] : s = 0 and i = 0 and j = 0; + [s,i,j] -> [0,1] : s = 1 and i = 0 and j = 0; + [s,i,j] -> [0,0] : s = 0 and i = 1 and j = 0; + [s,i,j] -> [0,1] : s = 1 and i = 1 and j = 0; + [s,i,j] -> [1,0] : s = 0 and i = 0 and j = 1; + [s,i,j] -> [1,1] : s = 1 and i = 0 and j = 1; + [s,i,j] -> [1,0] : s = 0 and i = 1 and j = 1; + [s,i,j] -> [1,1] : s = 1 and i = 1 and j = 1; + }""") + +schedule_general_map = isl.Map("{[s,i,j] -> [j,s]}") + +print("Map representing schedule generally:") +print(schedule_general_map) + +# the following is equivalent to explicit map above: +schedule_explicit_map2 = isl.Map( + """{ + [s=0,i=0,j=0] -> [0,0]; + [s=1,i=0,j=0] -> [0,1]; + [s=0,i=1,j=0] -> [0,0]; + [s=1,i=1,j=0] -> [0,1]; + [s=0,i=0,j=1] -> [1,0]; + [s=1,i=0,j=1] -> [1,1]; + [s=0,i=1,j=1] -> [1,0]; + [s=1,i=1,j=1] -> [1,1]; + }""") +assert schedule_explicit_map2 == schedule_explicit_map == sched.get_isl_map() + +''' + +""" +dep_i_same = Dependency(s0, s1, "i", DependencyType.SAME) +dep_i_none = Dependency(s0, s1, "i", DependencyType.NONE) +dep_i_prior = Dependency(s0, s1, "i", DependencyType.PRIOR) +dep_i_all = Dependency(s0, s1, "i", DependencyType.ALL) +dep_j_same = Dependency(s0, s1, "j", DependencyType.SAME) +dep_j_none = Dependency(s0, s1, "j", DependencyType.NONE) +dep_j_prior = Dependency(s0, s1, "j", DependencyType.PRIOR) +dep_j_all = Dependency(s0, s1, "j", DependencyType.ALL) +print("Example dependencies: ") +print(dep_i_same) +print(dep_i_none) +print(dep_i_prior) +print(dep_i_all) +print(dep_j_same) +print(dep_j_none) +print(dep_j_prior) +print(dep_j_all) +""" diff --git a/version.py b/version.py new file mode 100644 index 000000000..b6a75f587 --- /dev/null +++ b/version.py @@ -0,0 +1 @@ +VERSION_TEXT = "0.1" -- GitLab From 535c3001eb759fa507b80fe0a42a65eddcd8181f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 12 May 2019 16:51:24 -0500 Subject: [PATCH 002/183] create_symbolic_lex_mapping allows variable params and no longer requires user to provide map variable names --- example_lex_map_creation.py | 22 +++++++++++-------- lexicographic_order_map.py | 43 +++++++++++++++++++++++++++---------- 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py index fec169ea1..92bfe2930 100644 --- a/example_lex_map_creation.py +++ b/example_lex_map_creation.py @@ -3,6 +3,7 @@ from schedule_checker.dependency import ( Dependency, DependencyType as DT, create_dependency_constraint, + append_apostrophes, ) from schedule_checker.lexicographic_order_map import ( make_lex_mapping_tuple_pairs, @@ -16,22 +17,19 @@ from schedule_checker.lexicographic_order_map import ( # *Symbolic* lexicographic mapping- map each tuple to all tuples occuring later -#dim_bounds = [3, 2, 2] # max vals for each dim (e.g., 0 <= i0 <= max0 ...) -#param_names = ["p0", "p1", "p2"] -#in_names = ["i0", "i1", "i2"] -#out_names = ["o0", "o1", "o2"] dim_bounds = [(0,2), (0,2)] # max vals for each dim (e.g., 0 <= i0 < max0 ...) -param_names = ["p0", "p1"] -in_names = ["i", "j"] -out_names = ["i'", "j'"] - -lex_map_symbolic = create_symbolic_lex_mapping(param_names, in_names, out_names, dim_bounds) +#in_names = ["i", "j"] +#out_names = append_apostrophes(in_names) +n_dims = 2 #len(in_names) +lex_map_symbolic = create_symbolic_lex_mapping( + n_dims, dim_bound_vals=dim_bounds) print("lex_map (symbolic):") print(lex_map_symbolic) # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later +""" explicit_lex_map_pairs = make_lex_mapping_tuple_pairs(dim_bounds) # for pair in explicit_lex_map_pairs: # print(pair[0], pair[1]) @@ -39,6 +37,7 @@ lex_map_explicit = create_explicit_map_from_tuples(explicit_lex_map_pairs, lex_map_symbolic.space) print("lex_map (explicit):") print(lex_map_explicit) +""" # Example *explicit* schedule (map statement instances to lex time) @@ -67,10 +66,12 @@ print(example_sched) # map each statement instance to all statement instances that occur later # S -> L -> S^-1 +""" statement_instance_ordering_explicit = get_statement_ordering_map( example_sched, lex_map_explicit) print("statement instance ordering explicit:") print(statement_instance_ordering_explicit) +""" # TODO figure out where these "p0 >= 2 and p1 >= 2" are coming from: statement_instance_ordering_symbolic = get_statement_ordering_map( @@ -106,6 +107,8 @@ example_sched = create_explicit_map_from_tuples( ) print("example sched:") print(example_sched) +""" + """ param_names_sched = ["ps", "p0", "p1"] in_names_sched = ["s","i","j"] @@ -134,4 +137,5 @@ statement_instance_ordering_explicit = get_statement_ordering_map( example_sched, lex_map_explicit) print("statement instance ordering explicit:") print(statement_instance_ordering_explicit) +""" diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index f1fe02655..df1b0f894 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -79,23 +79,44 @@ def get_space(param_names, in_names, out_names): return set_space_names(space, param_names=param_names, in_names=in_names, out_names=out_names) -def create_symbolic_lex_mapping(param_names, in_names, out_names, - dim_bounds): - # assumes dim vars are bounded between 0 and corresponding dim_bound - assert len(in_names) == len(out_names) +def create_symbolic_lex_mapping( + n_dims, + param_names=None, + in_names=None, + out_names=None, + dim_bound_vals=None, + ): + if param_names is None: + param_names = [["lo%s" % (i), "up%s" % (i)] for i in range(n_dims)] + if in_names is None: + in_names = ["i%s" % (i) for i in range(n_dims)] + if out_names is None: + from schedule_checker.dependency import append_apostrophes + out_names = append_apostrophes(in_names) + if dim_bound_vals is None: + raise NotImplementedError("dim_bound_vals cannot be None") + + assert len(in_names) == len(out_names) == len(param_names) == len(dim_bound_vals) == n_dims dim_type = isl.dim_type - islvars = isl.make_zero_and_vars(in_names+out_names, param_names) + islvars = isl.make_zero_and_vars( + in_names+out_names, + [param for param_pair in param_names for param in param_pair]) # initialize set with constraint that is always true lex_set_outer_bounds = islvars[0].eq_set(islvars[0]) - # make constraints to bound dim vars 0 <= ix < dim_bound_x - for i, dim_bound in enumerate(dim_bounds): + # make constraints to bound dim vars dim_bound[0] <= ix < dim_bound[1] + #for i, dim_bound in enumerate(dim_bound_vals): + for i in range(n_dims): lex_set_outer_bounds = lex_set_outer_bounds \ - & islvars[0].le_set(islvars[in_names[i]]) \ - & islvars[in_names[i]].le_set(islvars[param_names[i]]-1) \ - & islvars[0].le_set(islvars[out_names[i]]) \ - & islvars[out_names[i]].le_set(islvars[param_names[i]]-1) + & islvars[in_names[i]].ge_set(islvars[param_names[i][0]]) \ + & islvars[in_names[i]].le_set(islvars[param_names[i][1]]-1) \ + & islvars[out_names[i]].ge_set(islvars[param_names[i][0]]) \ + & islvars[out_names[i]].le_set(islvars[param_names[i][1]]-1) + if dim_bound_vals: + lex_set_outer_bounds = lex_set_outer_bounds \ + & islvars[param_names[i][0]].eq_set(islvars[0]+dim_bound_vals[i][0]) \ + & islvars[param_names[i][1]].eq_set(islvars[0]+dim_bound_vals[i][1]) # create constraint enforcing lex ordering, e.g., in the 3-dim case: # i0 < o0 or ((i0 = o0) and (i1 < o1)) -- GitLab From 103abfccebca7c81323180015ba3f8c78f48e2b9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 12 May 2019 16:54:08 -0500 Subject: [PATCH 003/183] renaming example/experimental code files for consistency --- ...ndency_check_experiments.py => example_dependency_checking.py | 1 - schedule_creation_experiments.py => example_schedule_creation.py | 0 2 files changed, 1 deletion(-) rename dependency_check_experiments.py => example_dependency_checking.py (99%) rename schedule_creation_experiments.py => example_schedule_creation.py (100%) diff --git a/dependency_check_experiments.py b/example_dependency_checking.py similarity index 99% rename from dependency_check_experiments.py rename to example_dependency_checking.py index 2ef0bfce9..fffbd23fa 100644 --- a/dependency_check_experiments.py +++ b/example_dependency_checking.py @@ -13,7 +13,6 @@ from schedule_checker.lexicographic_order_map import ( get_statement_ordering_map, set_space_names, get_space, - create_symbolic_lex_mapping, ) from schedule_checker.sched_check_utils import prettier_map_string diff --git a/schedule_creation_experiments.py b/example_schedule_creation.py similarity index 100% rename from schedule_creation_experiments.py rename to example_schedule_creation.py -- GitLab From e93b1518093514059dafe241b404cde45ff57fe0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 May 2019 11:57:57 -0500 Subject: [PATCH 004/183] temporary hack for getting symbolic iname bounds from kernel --- example_schedule_creation.py | 48 ++++++++++++++++++++++++++++++------ schedule.py | 14 +++++++---- 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index dc5fa5535..483bfe656 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -25,28 +25,55 @@ def get_iname_bounds_dict(knl, _set_arbitrary_bounds=None): return dict((iname, _set_arbitrary_bounds) for iname in knl.all_inames()) from loopy.symbolic import aff_to_expr - int_bounds = {} + from loopy.isl_helpers import static_max_of_pw_aff + from loopy.isl_helpers import static_value_of_pw_aff + + def _param_in_expr_hack(expr, all_params): + expr_str = str(expr) + for p in all_params: + if p in expr_str: + return p + return None + + bounds = {} + all_params = knl.all_params() for iname in knl.all_inames(): - bounds_record = knl.get_iname_bounds(iname, constants_only=True) + #bounds_record = knl.get_iname_bounds(iname, constants_only=True) + bounds_record = knl.get_iname_bounds(iname) (_, iname_min_aff), = bounds_record.lower_bound_pw_aff.get_pieces() (_, iname_max_aff), = bounds_record.upper_bound_pw_aff.get_pieces() - int_bounds[iname] = [ - aff_to_expr(iname_min_aff), - aff_to_expr(iname_max_aff) + 1, + iname_min_aff = aff_to_expr(iname_min_aff) + iname_max_aff = aff_to_expr(iname_max_aff) + param_bound_min = _param_in_expr_hack(iname_min_aff, all_params) + param_bound_max = _param_in_expr_hack(iname_max_aff, all_params) + + if param_bound_min is None: + param_bound_min = int(iname_min_aff) # TODO what if this fails? + if param_bound_max is None: + param_bound_max = int(iname_max_aff) # TODO what if this fails? + + #int_bounds[iname] = [ + bounds[iname] = [ + param_bound_min, + param_bound_max, ] - assert all(isinstance(i,int) for i in int_bounds[iname]) - return int_bounds + #assert all(isinstance(i,int) for i in int_bounds[iname]) + return bounds # make example kernel knl = lp.make_kernel( #"{[i,j]: 0<=i,j<2}", - "{[i,j]: 0<=i<2 and 1<=j<3}", + #"{[i,j]: 0<=i<2 and 1<=j<3}", + #"{[i,j]: loi<=itemp = b[i,j] {id=0}", "a[i,j] = temp + 1 {id=1,dep=0}", "c[i,j] = d[i,j] {id=2}" ], name="example", + #assumptions="loi,upi,loj,upj >= 1", + assumptions="upi,upj >= 1", lang_version=(2018, 2) ) knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32}) @@ -92,9 +119,14 @@ def get_iname_concurrency_dict(inames, knl): # Get schedule ------------------------------------------------------ iname_bounds = get_iname_bounds_dict(knl) + #iname_bounds = get_iname_bounds_dict(knl, _set_arbitrary_bounds=[0,2]) print(iname_bounds) sched = LexSchedule(knl, iname_bounds) + +print(sched) +1/0 + example_sched_valid = sched.enumerate_symbolic_inames_and_create_explicit_isl_map(iname_bounds) # ------------------------------------------------------------------- diff --git a/schedule.py b/schedule.py index 410489d5f..14ac242cf 100644 --- a/schedule.py +++ b/schedule.py @@ -43,7 +43,7 @@ class StatementInstance(object): class LexSchedule(object): - # TODO this should hold a map of statement instances to lex order space + # TODO this should hold a map from statement instances to lex order space def __init__( self, knl, @@ -120,7 +120,7 @@ class LexSchedule(object): else: self.lp_insnid_to_id[lp_insnid] = 0 - def get_sched_space(self): + def get_space_for_explicit_sched(self): params_sched = ["ps"] + ["p"+iname for iname in self.inames_enumerated] in_names_sched = ["s"] + self.inames_enumerated out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] @@ -164,9 +164,13 @@ class LexSchedule(object): def enumerate_symbolic_inames_and_create_explicit_isl_map(self, iname_bounds): self.enumerate_inames(iname_bounds) - sched_space = self.get_sched_space() + sched_space = self.get_space_for_explicit_sched() return self.create_explicit_isl_map(sched_space) + def create_symbolic_isl_map(self, iname_bounds): + sched_space = self.get_space_for_symbolic_sched() + return None + def get_lex_map_explicit(self): from schedule_checker.lexicographic_order_map import ( @@ -179,7 +183,7 @@ class LexSchedule(object): # TODO lower bound may not be zero lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(), [1 + v for v in self.get_max_lex_dim_vals()])) - sched_space = self.get_sched_space() + sched_space = self.get_space_for_explicit_sched() lex_in_names = sched_space.get_var_names(isl.dim_type.out) lex_out_names = append_apostrophes(lex_in_names) @@ -231,7 +235,7 @@ class LexSchedule(object): # return str(self.get_isl_map_str()) def __str__(self): - return str(list(self.lex_schedule)) + return str(list(self.lex_schedule.items())) # TODO remove after stripping useful parts: """ -- GitLab From d3cddf5bbeb6121e82229385166ff1ddc27c2f2a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 May 2019 14:07:48 -0500 Subject: [PATCH 005/183] added flatten_2d_list --- sched_check_utils.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sched_check_utils.py b/sched_check_utils.py index 878d42183..50233e5bc 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -2,3 +2,7 @@ def prettier_map_string(isl_map): return str(isl_map).replace("{ ", "{\n").replace(" }","\n}").replace("; ",";\n") + + +def flatten_2d_list(list2d): + return [item for inner_list in list2d for item in inner_list] -- GitLab From 169e4a4c2bdc618cb94bffc2b0936dd910c3c7ba Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 May 2019 14:08:48 -0500 Subject: [PATCH 006/183] (WIP) started symbolic schedule creation (rather than explicit) and broke everything... --- example_schedule_creation.py | 44 +++++++++++++++++++++++------------ lexicographic_order_map.py | 39 ++++++++++++++++++++++++++++++- schedule.py | 45 +++++++++++++++++++++++++++++++++--- 3 files changed, 109 insertions(+), 19 deletions(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index 483bfe656..5f67232c7 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -50,7 +50,7 @@ def get_iname_bounds_dict(knl, _set_arbitrary_bounds=None): if param_bound_min is None: param_bound_min = int(iname_min_aff) # TODO what if this fails? if param_bound_max is None: - param_bound_max = int(iname_max_aff) # TODO what if this fails? + param_bound_max = int(iname_max_aff)+1 # TODO what if this fails? #int_bounds[iname] = [ bounds[iname] = [ @@ -64,16 +64,16 @@ def get_iname_bounds_dict(knl, _set_arbitrary_bounds=None): knl = lp.make_kernel( #"{[i,j]: 0<=i,j<2}", #"{[i,j]: 0<=i<2 and 1<=j<3}", - #"{[i,j]: loi<=itemp = b[i,j] {id=0}", "a[i,j] = temp + 1 {id=1,dep=0}", "c[i,j] = d[i,j] {id=2}" ], name="example", - #assumptions="loi,upi,loj,upj >= 1", - assumptions="upi,upj >= 1", + #assumptions="pi_lo,pi_up,pj_lo,pj_up >= 1", + assumptions="pi_up,pj_up >= 1", lang_version=(2018, 2) ) knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32}) @@ -121,31 +121,45 @@ def get_iname_concurrency_dict(inames, knl): iname_bounds = get_iname_bounds_dict(knl) #iname_bounds = get_iname_bounds_dict(knl, _set_arbitrary_bounds=[0,2]) +print("iname bounds:") print(iname_bounds) sched = LexSchedule(knl, iname_bounds) - +print("LexSchedule:") print(sched) + + +#example_sched_explicit = sched.enumerate_symbolic_inames_and_create_explicit_isl_map(iname_bounds) +example_sched_symbolic = sched.create_symbolic_isl_map(iname_bounds) + 1/0 -example_sched_valid = sched.enumerate_symbolic_inames_and_create_explicit_isl_map(iname_bounds) # ------------------------------------------------------------------- print("example LexSched (valid):") -print(prettier_map_string(example_sched_valid)) +#print(prettier_map_string(example_sched_explicit)) +print(prettier_map_string(example_sched_symbolic)) +1/0 # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later print("---------------------------------------------------------------------------") -lex_map_explicit = sched.get_lex_map_explicit() +#lex_map_explicit = sched.get_lex_map_explicit() +lex_map_symbolic = sched.get_lex_map_symbolic() -print("lex map explicit:") -print(prettier_map_string(lex_map_explicit)) +#print("lex map explicit:") +#print(prettier_map_string(lex_map_explicit)) +print("lex map symbolic:") +print(prettier_map_string(lex_map_symbolic)) # Statement instance ordering print("----------------------------------------------------------------------") -SIO_explicit_valid = get_statement_ordering_map( - example_sched_valid, lex_map_explicit) -print("statement instance ordering explicit (valid_sched):") -print(prettier_map_string(SIO_explicit_valid)) +#SIO_explicit_valid = get_statement_ordering_map( +# example_sched_explicit, lex_map_explicit) +#print("statement instance ordering explicit (valid_sched):") +#print(prettier_map_string(SIO_explicit_valid)) +SIO_symbolic_valid = get_statement_ordering_map( + example_sched_symbolic, lex_map_symbolic) +print("statement instance ordering symbolic (valid_sched):") +print(prettier_map_string(SIO_symbolic_valid)) ''' all_inames = ['i', 'j'] diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index df1b0f894..1ef8c741e 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -43,6 +43,41 @@ def create_explicit_map_from_tuples(tuple_pairs, space): return union_map +def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds): + + dim_type = isl.dim_type + individual_maps = [] + print(tuple_pairs) + print(space) + + for tup_in, tup_out in tuple_pairs: + constraints = [] + for i, val_in in enumerate(tup_in): + if isinstance(val_in, int): + constraints.append( + isl.Constraint.equality_alloc(space) + .set_coefficient_val(dim_type.in_, i, 1) + .set_constant_val(-1*val_in)) + for i, val_out in enumerate(tup_out): + if isinstance(val_out, int): + constraints.append( + isl.Constraint.equality_alloc(space) + .set_coefficient_val(dim_type.out, i, 1) + .set_constant_val(-1*val_out)) + # TODO left off here, problem: need to match up symbolic inames with corresponding space names and add bound constraints + # TODO maybe rewrite this code with w/more convenient islvars approach + individual_maps.append( + isl.Map.universe(space).add_constraints(constraints)) + + union_map = individual_maps[0] + for m in individual_maps[1:]: + union_map = union_map.union(m) + print(union_map) + 1/0 + + return union_map + + def get_statement_ordering_map(sched_map, lex_map): # statement ordering: # map each statement instance to all statement instances that occur later @@ -99,9 +134,11 @@ def create_symbolic_lex_mapping( assert len(in_names) == len(out_names) == len(param_names) == len(dim_bound_vals) == n_dims dim_type = isl.dim_type + from schedule_checker.sched_check_utils import flatten_2d_list islvars = isl.make_zero_and_vars( in_names+out_names, - [param for param_pair in param_names for param in param_pair]) + flatten_2d_list(param_names)) + # [param for param_pair in param_names for param in param_pair]) # initialize set with constraint that is always true lex_set_outer_bounds = islvars[0].eq_set(islvars[0]) diff --git a/schedule.py b/schedule.py index 14ac242cf..7c590c7e4 100644 --- a/schedule.py +++ b/schedule.py @@ -51,6 +51,7 @@ class LexSchedule(object): ): self.lex_schedule = OrderedDict() # statement instance: lex point self.inames_enumerated = [] # symbolic inames in sched that have been enumerated into explicit statement instances + self.inames_not_enumerated = [] # TODO better way to do this self.lp_insnid_to_id = {} from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) @@ -110,10 +111,23 @@ class LexSchedule(object): self.inames_enumerated.append(iname) def enumerate_inames(self, iname_bounds): - inames_found = [] for iname, bound in iname_bounds.items(): self.enumerate_iname(iname, bound) + def add_symbolic_inames_to_statement_instances(self, inames): + for iname in inames: + new_sched = OrderedDict() + iname_found = False + for insn, lex_pt in self.lex_schedule.items(): + if iname in lex_pt: + new_sched[tuple(list(insn)+[iname])] = lex_pt + iname_found = True + else: + new_sched[insn] = lex_pt + self.lex_schedule = new_sched + if iname_found: + self.inames_not_enumerated.append(iname) + def add_new_lp_insnid(self, lp_insnid): if self.lp_insnid_to_id: self.lp_insnid_to_id[lp_insnid] = max(self.lp_insnid_to_id.values()) + 1 @@ -127,6 +141,23 @@ class LexSchedule(object): from schedule_checker.lexicographic_order_map import get_space return get_space(params_sched, in_names_sched, out_names_sched) + def get_space_for_symbolic_sched(self, iname_bounds): + iname_bound_params = [] + for iname in self.inames_not_enumerated: + lo, up = iname_bounds[iname] + if not isinstance(lo, int): + #iname_bound_params.append("p"+iname+"up") + iname_bound_params.append(lo) + if not isinstance(up, int): + #iname_bound_params.append("p"+iname+"up") + iname_bound_params.append(up) + + params_sched = ["ps"] + iname_bound_params + in_names_sched = ["s"] + self.inames_not_enumerated + out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] + from schedule_checker.lexicographic_order_map import get_space + return get_space(params_sched, in_names_sched, out_names_sched) + def get_max_lex_dim_vals(self): return [max(dim_pts) for dim_pts in zip(*self.lex_schedule.values())] @@ -168,8 +199,16 @@ class LexSchedule(object): return self.create_explicit_isl_map(sched_space) def create_symbolic_isl_map(self, iname_bounds): - sched_space = self.get_space_for_symbolic_sched() - return None + from schedule_checker.lexicographic_order_map import create_symbolic_map_from_tuples + #from schedule_checker.lexicographic_order_map import create_explicit_map_from_tuples + from schedule_checker.sched_check_utils import flatten_2d_list + self.add_symbolic_inames_to_statement_instances(iname_bounds.keys()) + #print(self) + extra_params = [b for b in flatten_2d_list(iname_bounds.values()) + if isinstance(b,str)] + sched_space = self.get_space_for_symbolic_sched(iname_bounds) + #sched_space = self.get_space_for_explicit_sched() + return create_symbolic_map_from_tuples(list(self.items()), sched_space, iname_bounds) def get_lex_map_explicit(self): -- GitLab From e23336ed321ec68a3ccf80c559ed327a6705b24e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 May 2019 19:23:23 -0500 Subject: [PATCH 007/183] added get_islvars_from_space() --- sched_check_utils.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sched_check_utils.py b/sched_check_utils.py index 50233e5bc..6c370e5f2 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -6,3 +6,12 @@ def prettier_map_string(isl_map): def flatten_2d_list(list2d): return [item for inner_list in list2d for item in inner_list] + + +def get_islvars_from_space(space): + import islpy as isl + 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) + -- GitLab From 0d7db89017f0412fdc6b3cf541c776a98e7cc117 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 May 2019 19:24:07 -0500 Subject: [PATCH 008/183] (WIP) more work on symbolic schedule,;still broken --- lexicographic_order_map.py | 42 +++++++++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 1ef8c741e..d8a7c54f0 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -50,6 +50,37 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds): print(tuple_pairs) print(space) + from schedule_checker.sched_check_utils import get_islvars_from_space + #param_names = space.get_var_names(isl.dim_type.param) + out_names = space.get_var_names(dim_type.out) + in_names = space.get_var_names(isl.dim_type.in_) + + islvars = get_islvars_from_space(space) + + # initialize set with constraint that is always false + constraints_set = islvars[0].eq_set(islvars[0] + 1) + for tup_in, tup_out in tuple_pairs: + # initialize set with constraint that is always true + constraint = islvars[0].eq_set(islvars[0]) + for i, val_in in enumerate(tup_in): + if isinstance(val_in, int): + constraint = constraint \ + & islvars[in_names[i]].eq_set(islvars[0]+val_in) + #& islvars[out_names[i]].eq_set(islvars[0]+val_in) + else: + constraint = constraint \ + & islvars[in_names[i]].eq_set(islvars[val_in]) + #& islvars[out_names[i]].eq_set(islvars[val_in]) + for i, val_out in enumerate(tup_out): + if isinstance(val_out, int): + constraint = constraint \ + & islvars[out_names[i]].eq_set(islvars[0]+val_out) + else: + constraint = constraint \ + & islvars[out_names[i]].eq_set(islvars[val_out]) + print(constraint) + constraints_set = constraints_set | constraint + """ for tup_in, tup_out in tuple_pairs: constraints = [] for i, val_in in enumerate(tup_in): @@ -64,15 +95,20 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds): isl.Constraint.equality_alloc(space) .set_coefficient_val(dim_type.out, i, 1) .set_constant_val(-1*val_out)) - # TODO left off here, problem: need to match up symbolic inames with corresponding space names and add bound constraints - # TODO maybe rewrite this code with w/more convenient islvars approach individual_maps.append( isl.Map.universe(space).add_constraints(constraints)) - union_map = individual_maps[0] for m in individual_maps[1:]: union_map = union_map.union(m) print(union_map) + """ + # TODO left off here, problem: need to match up symbolic inames with corresponding space names and add bound constraints + + result_map = isl.Map.from_domain(constraints_set) + result_map = result_map.move_dims( + dim_type.out, 0, dim_type.in_, + len(in_names), len(out_names)) + print(result_map) 1/0 return union_map -- GitLab From 9274af76e60905d0c3d11857c3bf61aec3951980 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 19 May 2019 22:31:00 -0500 Subject: [PATCH 009/183] got symbolic schedule creation working...? --- example_schedule_creation.py | 39 +++++++++++++++++++++++++++++------- lexicographic_order_map.py | 35 +++----------------------------- sched_check_utils.py | 5 +++-- schedule.py | 35 ++++++++++++++++++++++++++------ 4 files changed, 67 insertions(+), 47 deletions(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index 5f67232c7..cd787029d 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -52,6 +52,8 @@ def get_iname_bounds_dict(knl, _set_arbitrary_bounds=None): if param_bound_max is None: param_bound_max = int(iname_max_aff)+1 # TODO what if this fails? + dom = knl.get_inames_domain(iname) + #int_bounds[iname] = [ bounds[iname] = [ param_bound_min, @@ -60,6 +62,26 @@ def get_iname_bounds_dict(knl, _set_arbitrary_bounds=None): #assert all(isinstance(i,int) for i in int_bounds[iname]) return bounds +def get_iname_to_param_dict(knl): + from loopy.symbolic import aff_to_expr + bounds = {} + all_params = knl.all_params() + for iname in knl.all_inames(): + #bounds_record = knl.get_iname_bounds(iname, constants_only=True) + bounds_record = knl.get_iname_bounds(iname) + (_, iname_min_aff), = bounds_record.lower_bound_pw_aff.get_pieces() + (_, iname_max_aff), = bounds_record.upper_bound_pw_aff.get_pieces() + iname_min_aff = aff_to_expr(iname_min_aff) + iname_max_aff = aff_to_expr(iname_max_aff) + bounds_strs = str(iname_min_aff)+str(iname_max_aff) + params_found = [] + for param in all_params: + if param in bounds_strs: + params_found.append(param) + + bounds[iname] = params_found + return bounds + # make example kernel knl = lp.make_kernel( #"{[i,j]: 0<=i,j<2}", @@ -120,25 +142,26 @@ def get_iname_concurrency_dict(inames, knl): # Get schedule ------------------------------------------------------ iname_bounds = get_iname_bounds_dict(knl) +domains = {} +for iname in knl.all_inames(): + domains[iname] = knl.get_inames_domain(iname) + #iname_bounds = get_iname_bounds_dict(knl, _set_arbitrary_bounds=[0,2]) print("iname bounds:") print(iname_bounds) sched = LexSchedule(knl, iname_bounds) -print("LexSchedule:") +print("LexSchedule before processing:") print(sched) - +iname_to_params_dict = get_iname_to_param_dict(knl) #example_sched_explicit = sched.enumerate_symbolic_inames_and_create_explicit_isl_map(iname_bounds) -example_sched_symbolic = sched.create_symbolic_isl_map(iname_bounds) - -1/0 +example_sched_symbolic = sched.create_symbolic_isl_map(iname_bounds, domains, iname_to_params_dict) # TODO don't need all of these # ------------------------------------------------------------------- -print("example LexSched (valid):") +print("LexSched (valid):") #print(prettier_map_string(example_sched_explicit)) print(prettier_map_string(example_sched_symbolic)) -1/0 # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later print("---------------------------------------------------------------------------") @@ -150,6 +173,8 @@ lex_map_symbolic = sched.get_lex_map_symbolic() print("lex map symbolic:") print(prettier_map_string(lex_map_symbolic)) +1/0 + # Statement instance ordering print("----------------------------------------------------------------------") #SIO_explicit_valid = get_statement_ordering_map( diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index d8a7c54f0..3aea1bdfc 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -43,12 +43,11 @@ def create_explicit_map_from_tuples(tuple_pairs, space): return union_map -def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds): +#def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds, var_to_domain_dict, var_to_params_dict): +def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds, domain_to_intersect): dim_type = isl.dim_type individual_maps = [] - print(tuple_pairs) - print(space) from schedule_checker.sched_check_utils import get_islvars_from_space #param_names = space.get_var_names(isl.dim_type.param) @@ -66,11 +65,9 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds): if isinstance(val_in, int): constraint = constraint \ & islvars[in_names[i]].eq_set(islvars[0]+val_in) - #& islvars[out_names[i]].eq_set(islvars[0]+val_in) else: constraint = constraint \ & islvars[in_names[i]].eq_set(islvars[val_in]) - #& islvars[out_names[i]].eq_set(islvars[val_in]) for i, val_out in enumerate(tup_out): if isinstance(val_out, int): constraint = constraint \ @@ -78,40 +75,14 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds): else: constraint = constraint \ & islvars[out_names[i]].eq_set(islvars[val_out]) - print(constraint) constraints_set = constraints_set | constraint - """ - for tup_in, tup_out in tuple_pairs: - constraints = [] - for i, val_in in enumerate(tup_in): - if isinstance(val_in, int): - constraints.append( - isl.Constraint.equality_alloc(space) - .set_coefficient_val(dim_type.in_, i, 1) - .set_constant_val(-1*val_in)) - for i, val_out in enumerate(tup_out): - if isinstance(val_out, int): - constraints.append( - isl.Constraint.equality_alloc(space) - .set_coefficient_val(dim_type.out, i, 1) - .set_constant_val(-1*val_out)) - individual_maps.append( - isl.Map.universe(space).add_constraints(constraints)) - union_map = individual_maps[0] - for m in individual_maps[1:]: - union_map = union_map.union(m) - print(union_map) - """ - # TODO left off here, problem: need to match up symbolic inames with corresponding space names and add bound constraints result_map = isl.Map.from_domain(constraints_set) result_map = result_map.move_dims( dim_type.out, 0, dim_type.in_, len(in_names), len(out_names)) - print(result_map) - 1/0 - return union_map + return result_map.intersect_domain(domain_to_intersect) def get_statement_ordering_map(sched_map, lex_map): diff --git a/sched_check_utils.py b/sched_check_utils.py index 6c370e5f2..4e9faeb67 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -1,4 +1,4 @@ - +import islpy as isl def prettier_map_string(isl_map): return str(isl_map).replace("{ ", "{\n").replace(" }","\n}").replace("; ",";\n") @@ -9,9 +9,10 @@ def flatten_2d_list(list2d): def get_islvars_from_space(space): - import islpy as isl 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 get_dim_for_isl_space_param(space, param): + return space.get_var_names(isl.dim_type.param).index(param) diff --git a/schedule.py b/schedule.py index 7c590c7e4..6baf4c99d 100644 --- a/schedule.py +++ b/schedule.py @@ -198,17 +198,40 @@ class LexSchedule(object): sched_space = self.get_space_for_explicit_sched() return self.create_explicit_isl_map(sched_space) - def create_symbolic_isl_map(self, iname_bounds): + def create_symbolic_isl_map(self, iname_bounds, domains, iname_to_params_dict): # TODO don't need all of these + # TODO assumes all knl inames included in iname_bounds from schedule_checker.lexicographic_order_map import create_symbolic_map_from_tuples - #from schedule_checker.lexicographic_order_map import create_explicit_map_from_tuples - from schedule_checker.sched_check_utils import flatten_2d_list - self.add_symbolic_inames_to_statement_instances(iname_bounds.keys()) - #print(self) + from schedule_checker.sched_check_utils import flatten_2d_list, get_dim_for_isl_space_param + all_inames = list(iname_bounds.keys()) + self.add_symbolic_inames_to_statement_instances(all_inames) extra_params = [b for b in flatten_2d_list(iname_bounds.values()) if isinstance(b,str)] sched_space = self.get_space_for_symbolic_sched(iname_bounds) #sched_space = self.get_space_for_explicit_sched() - return create_symbolic_map_from_tuples(list(self.items()), sched_space, iname_bounds) + + # intersect all domains for symbolic (non-enumerated) inames found in statement instances + domain_intersection = domains[self.inames_not_enumerated[0]] + #TODO what if self.inames_not_enumerated is empty? + for iname in self.inames_not_enumerated[1:]: + domain_intersection = domain_intersection.intersect(domains[iname]) + + # inames not found in statement instance tuples should be removed + inames_to_remove_from_domains = all_inames.copy() + for iname in self.inames_not_enumerated: + inames_to_remove_from_domains.remove(iname) + + #dom = domains['j'] # TODO which domains(s) do we use? + #vars_to_remove = ['i'] # TODO where do we get this? in_names? + domain_stripped = domain_intersection.copy() + for iname in inames_to_remove_from_domains: + for p in iname_to_params_dict[iname]: + domain_stripped = domain_intersection.remove_dims( + isl.dim_type.param, + get_dim_for_isl_space_param(domain_intersection.space, p), + 1) + # TODO is projecting out iname necessary? + + return create_symbolic_map_from_tuples(list(self.items()), sched_space, iname_bounds, domain_stripped) def get_lex_map_explicit(self): -- GitLab From bba229d9b5fab602f5d63235a6632af33455ca91 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 May 2019 18:39:21 -0500 Subject: [PATCH 010/183] got symbolic lex map with variable iname bounds working --- example_schedule_creation.py | 3 ++- lexicographic_order_map.py | 48 ++++++++++++++++++++++++++++-------- schedule.py | 43 ++++++++++++++++++++++++++------ 3 files changed, 76 insertions(+), 18 deletions(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index cd787029d..4ab2fe106 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -166,13 +166,14 @@ print(prettier_map_string(example_sched_symbolic)) # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later print("---------------------------------------------------------------------------") #lex_map_explicit = sched.get_lex_map_explicit() -lex_map_symbolic = sched.get_lex_map_symbolic() +lex_map_symbolic = sched.get_lex_map_symbolic(iname_bounds) #print("lex map explicit:") #print(prettier_map_string(lex_map_explicit)) print("lex map symbolic:") print(prettier_map_string(lex_map_symbolic)) +# TODO left off here 1/0 # Statement instance ordering diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 3aea1bdfc..c8b5f2789 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -7,6 +7,7 @@ def make_lex_mapping_tuple_pairs(dim_bounds): # all lex tuples in order: lex_tuples = list( itertools.product(*[range(l,u) for l,u in dim_bounds])) + # goes up to u-1 because u is a non-inclusive upper bound # TODO: is itertools.product ordering guaranteed? map_pairs = [] @@ -121,6 +122,10 @@ def get_space(param_names, in_names, out_names): return set_space_names(space, param_names=param_names, in_names=in_names, out_names=out_names) +#TODO rename these functions for clarity +#(distinguish betwen map representing lex order from all before pts to all after pts +# from map representing a schedule +# from other things...) def create_symbolic_lex_mapping( n_dims, param_names=None, @@ -140,11 +145,18 @@ def create_symbolic_lex_mapping( assert len(in_names) == len(out_names) == len(param_names) == len(dim_bound_vals) == n_dims dim_type = isl.dim_type - from schedule_checker.sched_check_utils import flatten_2d_list + + #TODO left off here, need to add params from dim_bounds to islvars? + params_in_dim_bounds = [] + for v in flatten_2d_list(dim_bound_vals): + if not isinstance(v, int): + params_in_dim_bounds.append(v) + islvars = isl.make_zero_and_vars( in_names+out_names, - flatten_2d_list(param_names)) + #flatten_2d_list(param_names)) + flatten_2d_list(param_names)+params_in_dim_bounds) # [param for param_pair in param_names for param in param_pair]) # initialize set with constraint that is always true @@ -154,21 +166,37 @@ def create_symbolic_lex_mapping( for i in range(n_dims): lex_set_outer_bounds = lex_set_outer_bounds \ & islvars[in_names[i]].ge_set(islvars[param_names[i][0]]) \ - & islvars[in_names[i]].le_set(islvars[param_names[i][1]]-1) \ + & islvars[in_names[i]].lt_set(islvars[param_names[i][1]]) \ & islvars[out_names[i]].ge_set(islvars[param_names[i][0]]) \ - & islvars[out_names[i]].le_set(islvars[param_names[i][1]]-1) + & islvars[out_names[i]].lt_set(islvars[param_names[i][1]]) if dim_bound_vals: - lex_set_outer_bounds = lex_set_outer_bounds \ - & islvars[param_names[i][0]].eq_set(islvars[0]+dim_bound_vals[i][0]) \ - & islvars[param_names[i][1]].eq_set(islvars[0]+dim_bound_vals[i][1]) + #lex_set_outer_bounds = lex_set_outer_bounds \ + # & islvars[param_names[i][0]].eq_set(islvars[0]+dim_bound_vals[i][0]) \ + # & islvars[param_names[i][1]].eq_set(islvars[0]+dim_bound_vals[i][1]) + lower_bound = dim_bound_vals[i][0] + upper_bound = dim_bound_vals[i][1] + if isinstance(lower_bound, int): + lex_set_outer_bounds = lex_set_outer_bounds \ + & islvars[param_names[i][0]].eq_set(islvars[0]+lower_bound) + else: + # lower bound is variable + lex_set_outer_bounds = lex_set_outer_bounds \ + & islvars[param_names[i][0]].eq_set(islvars[lower_bound]) + if isinstance(upper_bound, int): + lex_set_outer_bounds = lex_set_outer_bounds \ + & islvars[param_names[i][1]].eq_set(islvars[0]+upper_bound) + else: + # upper bound is variable + lex_set_outer_bounds = lex_set_outer_bounds \ + & islvars[param_names[i][1]].eq_set(islvars[upper_bound]) # create constraint enforcing lex ordering, e.g., in the 3-dim case: # i0 < o0 or ((i0 = o0) and (i1 < o1)) # or ((i0 = o0) and (i1 = o1) and (i2 < o2)) - lex_set_order_bound = islvars[in_names[0]].le_set(islvars[out_names[0]]-1) + lex_set_order_bound = islvars[in_names[0]].lt_set(islvars[out_names[0]]) for i in range(1, len(in_names)): - lex_set_order_bound_conj = islvars[in_names[i]].le_set( - islvars[out_names[i]]-1) + lex_set_order_bound_conj = islvars[in_names[i]].lt_set( + islvars[out_names[i]]) for j in range(i): lex_set_order_bound_conj = lex_set_order_bound_conj & \ islvars[in_names[j]].eq_set(islvars[out_names[j]]) diff --git a/schedule.py b/schedule.py index 6baf4c99d..992a0726d 100644 --- a/schedule.py +++ b/schedule.py @@ -158,11 +158,29 @@ class LexSchedule(object): from schedule_checker.lexicographic_order_map import get_space return get_space(params_sched, in_names_sched, out_names_sched) - def get_max_lex_dim_vals(self): - return [max(dim_pts) for dim_pts in zip(*self.lex_schedule.values())] - - def get_min_lex_dim_vals(self): - return [min(dim_pts) for dim_pts in zip(*self.lex_schedule.values())] + def get_max_lex_dim_bounds(self, var_bounds_dict): + # this only works for integer lex pts (no symbolic vars) + #return [max(dim_pts) for dim_pts in zip(*self.lex_schedule.values())] + result = [] + for dim_pts in zip(*self.lex_schedule.values()): + if all(isinstance(pt, int) for pt in dim_pts): + result.append(max(dim_pts) + 1) # +1 because this is the non-inclusive upper bound + else: + assert all(pt == dim_pts[0] for pt in dim_pts) + result.append(var_bounds_dict[dim_pts[0]][1]) # upper bound for this variable + return result + + def get_min_lex_dim_vals(self, var_bounds_dict): + # this only works for integer lex pts (no symbolic vars) + #return [min(dim_pts) for dim_pts in zip(*self.lex_schedule.values())] + result = [] + for dim_pts in zip(*self.lex_schedule.values()): + if all(isinstance(pt, int) for pt in dim_pts): + result.append(min(dim_pts)) + else: + assert all(pt == dim_pts[0] for pt in dim_pts) + result.append(var_bounds_dict[dim_pts[0]][0]) # lower bound for this variable + return result def append_item(self, sched_item, lex_pt): self.lex_schedule[sched_item] = lex_pt @@ -244,20 +262,31 @@ class LexSchedule(object): # TODO lower bound may not be zero lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(), - [1 + v for v in self.get_max_lex_dim_vals()])) + self.get_max_lex_dim_vals())) sched_space = self.get_space_for_explicit_sched() lex_in_names = sched_space.get_var_names(isl.dim_type.out) lex_out_names = append_apostrophes(lex_in_names) lex_params = [] - # TODO lex map routines currently assume lower bound is zero, fix this explicit_lex_map_pairs = make_lex_mapping_tuple_pairs(lex_dim_bounds) lex_space_explicit = get_space(lex_params, lex_in_names, lex_out_names) return create_explicit_map_from_tuples(explicit_lex_map_pairs, lex_space_explicit) + def get_lex_map_symbolic(self, var_bounds_dict): + from schedule_checker.lexicographic_order_map import ( + create_symbolic_lex_mapping, + ) + + n_dims = self.max_lex_dims() + #lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(), + # [1 + v for v in self.get_max_lex_dim_vals()])) + lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(var_bounds_dict), + self.get_max_lex_dim_bounds(var_bounds_dict))) + return create_symbolic_lex_mapping(n_dims, dim_bound_vals=lex_dim_bounds) + #def get_isl_map(self): def get_isl_map_str(self): map_str = "{" -- GitLab From c76305b4fd88b59e04cf52e3bae8448bb3ba88fb Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 May 2019 21:34:41 -0500 Subject: [PATCH 011/183] statement instance ordering creation from symbolic schedule w/variable bounds seems to be working --- example_schedule_creation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index 4ab2fe106..fac0fedff 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -173,8 +173,6 @@ lex_map_symbolic = sched.get_lex_map_symbolic(iname_bounds) print("lex map symbolic:") print(prettier_map_string(lex_map_symbolic)) -# TODO left off here -1/0 # Statement instance ordering print("----------------------------------------------------------------------") @@ -187,6 +185,8 @@ SIO_symbolic_valid = get_statement_ordering_map( print("statement instance ordering symbolic (valid_sched):") print(prettier_map_string(SIO_symbolic_valid)) +# TODO left off here + ''' all_inames = ['i', 'j'] iname_params = ['p0', 'p1'] -- GitLab From 85071a7343b30166aa3624f8aad81ac44f772c51 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 May 2019 22:54:52 -0500 Subject: [PATCH 012/183] dependency logic now allows upper+lower symbolic bounds on variables --- dependency.py | 56 +++++++++++++++++++++++++++++----- example_dependency_checking.py | 8 +++-- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/dependency.py b/dependency.py index 40ebaa99a..76ec7d321 100644 --- a/dependency.py +++ b/dependency.py @@ -93,23 +93,22 @@ class DependencyConstraintVars(object): statement_param_val, ): self.inames = inames - self.param_names = param_names - self.param_vals = param_vals + self.param_names = param_names # TODO rename, these are pairs of bound vars + self.param_vals = param_vals # TODO rename, these are pairs of bound vals self.statement_var = statement_var self.statement_param = statement_param self.statement_param_val = statement_param_val def get_bounds_constraint_set(self): var_names = [self.statement_var]+self.inames - param_names = [self.statement_param]+self.param_names - param_vals = [self.statement_param_val]+self.param_vals - # TODO assumes lower bound is zero + param_names = [self.statement_param]+self.list_param_names() islvars = _make_islvars_with_var_primes( var_names, param_names) bounded_set = islvars[0].eq_set(islvars[0]) # initialize to True - + """ for v, p, b in zip(var_names, param_names, param_vals): + #TODO each iname could have multiple param names # create constraint 0 <= v,v'< p = b v_prime = v+"'" bounded_set = bounded_set \ @@ -118,9 +117,51 @@ class DependencyConstraintVars(object): & (islvars[0]-1).lt_set(islvars[v]) \ & (islvars[0]-1).lt_set(islvars[v_prime]) \ & islvars[p].eq_set(islvars[0]+b) + """ + v = self.statement_var + v_prime = self.statement_var+"'" + p = self.statement_param + b = self.statement_param_val + + bounded_set = bounded_set \ + & islvars[v].lt_set(islvars[p]) \ + & islvars[v_prime].lt_set(islvars[p]) \ + & (islvars[0]).le_set(islvars[v]) \ + & (islvars[0]).le_set(islvars[v_prime]) \ + & islvars[p].eq_set(islvars[0]+b) + + for v, (p_low, p_up), (pval_low, pval_up) in zip( + self.inames, self.param_names, self.param_vals): + # create constraint pval_low = p_low <= v,v'< p_up = pval_up + if p_low is None: + assert isinstance(pval_low, int) + lower_bound = islvars[0] + pval_low + else: + lower_bound = islvars[p_low] + if not pval_low is None: + bounded_set = bounded_set & lower_bound.eq_set(islvars[0]+pval_low) + + if p_up is None: + assert isinstance(pval_up, int) + upper_bound = islvars[0] + pval_up + else: + upper_bound = islvars[p_up] + if not pval_up is None: + bounded_set = bounded_set & upper_bound.eq_set(islvars[0]+pval_up) + + v_prime = v+"'" + bounded_set = bounded_set \ + & islvars[v].lt_set(upper_bound) \ + & islvars[v_prime].lt_set(upper_bound) \ + & lower_bound.le_set(islvars[v]) \ + & lower_bound.le_set(islvars[v_prime]) return bounded_set + def list_param_names(self): + from schedule_checker.sched_check_utils import flatten_2d_list + return [p for p in flatten_2d_list(self.param_names) if not p is None] + def __str__(self): return str(self.get_bounds_constraint_set()) @@ -136,7 +177,8 @@ def create_dependency_constraint( # (statement_bound = max statement id + 1) statement_param = dep_constraint_vars.statement_param - param_names = dep_constraint_vars.param_names + #param_names = dep_constraint_vars.param_names + param_names = dep_constraint_vars.list_param_names() all_inames = dep_constraint_vars.inames statement_var = dep_constraint_vars.statement_var diff --git a/example_dependency_checking.py b/example_dependency_checking.py index fffbd23fa..01cb9b013 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -30,9 +30,11 @@ knl = lp.tag_inames(knl, {"i": "l.0"}) print("Kernel:") print(knl) +from schedule_checker.sched_check_utils import flatten_2d_list all_inames = ['i', 'j'] -iname_params = ['p0', 'p1'] -iname_param_vals = [2, 2] +iname_params = [(None, 'p0'), (None, 'p1')] +param_names_listed = [p for p in flatten_2d_list(iname_params) if not p is None] +iname_param_vals = [(0, 2), (0, 2)] statement_var = 's' statement_param = 'ps' statement_bound = 2 @@ -43,7 +45,7 @@ print("------------------------------------------------------------------------- # i is parallel, suppose we want to enforce the following: # for a given i, statement 0 happens before statement 1 -params_sched = [statement_param]+iname_params +params_sched = [statement_param]+param_names_listed in_names_sched = [statement_var]+all_inames out_names_sched = ['l0', 'l1'] sched_space = get_space(params_sched, in_names_sched, out_names_sched) -- GitLab From 72cbdf94ec3f8697801cc2d7aed087e331c60500 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 May 2019 23:04:12 -0500 Subject: [PATCH 013/183] creating example constraint map to test new symbolic statement instance ordering; constraint map space and SIO space don't match yet so can't compare... --- dependency.py | 18 ++++--------- example_schedule_creation.py | 51 +++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/dependency.py b/dependency.py index 76ec7d321..b2688ebbe 100644 --- a/dependency.py +++ b/dependency.py @@ -106,23 +106,12 @@ class DependencyConstraintVars(object): var_names, param_names) bounded_set = islvars[0].eq_set(islvars[0]) # initialize to True - """ - for v, p, b in zip(var_names, param_names, param_vals): - #TODO each iname could have multiple param names - # create constraint 0 <= v,v'< p = b - v_prime = v+"'" - bounded_set = bounded_set \ - & islvars[v].lt_set(islvars[p]) \ - & islvars[v_prime].lt_set(islvars[p]) \ - & (islvars[0]-1).lt_set(islvars[v]) \ - & (islvars[0]-1).lt_set(islvars[v_prime]) \ - & islvars[p].eq_set(islvars[0]+b) - """ + + # bound the statement variable v = self.statement_var v_prime = self.statement_var+"'" p = self.statement_param b = self.statement_param_val - bounded_set = bounded_set \ & islvars[v].lt_set(islvars[p]) \ & islvars[v_prime].lt_set(islvars[p]) \ @@ -130,9 +119,12 @@ class DependencyConstraintVars(object): & (islvars[0]).le_set(islvars[v_prime]) \ & islvars[p].eq_set(islvars[0]+b) + # bound the other variables for v, (p_low, p_up), (pval_low, pval_up) in zip( self.inames, self.param_names, self.param_vals): + # create constraint pval_low = p_low <= v,v'< p_up = pval_up + if p_low is None: assert isinstance(pval_low, int) lower_bound = islvars[0] + pval_low diff --git a/example_schedule_creation.py b/example_schedule_creation.py index fac0fedff..31e361bab 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -153,9 +153,11 @@ sched = LexSchedule(knl, iname_bounds) print("LexSchedule before processing:") print(sched) +# TODO a lot of this could be cleaner if we just create a set for each iname domain and pass it around instead of messing with all these individual bounds + iname_to_params_dict = get_iname_to_param_dict(knl) #example_sched_explicit = sched.enumerate_symbolic_inames_and_create_explicit_isl_map(iname_bounds) -example_sched_symbolic = sched.create_symbolic_isl_map(iname_bounds, domains, iname_to_params_dict) # TODO don't need all of these +example_sched_symbolic = sched.create_symbolic_isl_map(iname_bounds, domains, iname_to_params_dict) # TODO don't need all of these args # ------------------------------------------------------------------- @@ -186,6 +188,53 @@ print("statement instance ordering symbolic (valid_sched):") print(prettier_map_string(SIO_symbolic_valid)) # TODO left off here +sched_inames = ['j'] +iname_params = [(None, 'pj_up')] +iname_param_vals = [(0, None)] +statement_var = 's' +statement_param = 'ps' +statement_bound = 3 + +from schedule_checker.dependency import ( + Dependency, + DependencyType as DT, + create_dependency_constraint, + append_apostrophes, + DependencyConstraintVars, +) + +dep_constraint_vars = DependencyConstraintVars( + sched_inames, + iname_params, + iname_param_vals, + statement_var, + statement_param, + statement_bound, + ) + +# i is parallel, suppose we want to enforce the following: +# for a given i, statement 0 happens before statement 1 +# i dependency is none, j dependency is `prior` + +deps = [ + Dependency(0, 1, DT.SAME, 'j'), + ] +print([str(dep) for dep in deps]) +constraint_map = create_dependency_constraint( + deps, dep_constraint_vars) +print("constraint map:") +print(prettier_map_string(constraint_map)) + +# TODO left off here, these spaces need to match and they don't + +#assert constraint_map.space == SIO_symbolic_valid.space +#1/0 + +#print("is valid sched valid?") +#print(constraint_map.is_subset(SIO_symbolic_valid)) + + + ''' all_inames = ['i', 'j'] -- GitLab From aaecadb0071839848265dafacf291de939345422 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 20 May 2019 23:28:50 -0500 Subject: [PATCH 014/183] changing example_sched_symbolic->sched-map-symbolic for clarity --- example_schedule_creation.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index 31e361bab..26670937d 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -157,13 +157,13 @@ print(sched) iname_to_params_dict = get_iname_to_param_dict(knl) #example_sched_explicit = sched.enumerate_symbolic_inames_and_create_explicit_isl_map(iname_bounds) -example_sched_symbolic = sched.create_symbolic_isl_map(iname_bounds, domains, iname_to_params_dict) # TODO don't need all of these args +sched_map_symbolic = sched.create_symbolic_isl_map(iname_bounds, domains, iname_to_params_dict) # TODO don't need all of these args # ------------------------------------------------------------------- print("LexSched (valid):") #print(prettier_map_string(example_sched_explicit)) -print(prettier_map_string(example_sched_symbolic)) +print(prettier_map_string(sched_map_symbolic)) # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later print("---------------------------------------------------------------------------") @@ -183,7 +183,7 @@ print("----------------------------------------------------------------------") #print("statement instance ordering explicit (valid_sched):") #print(prettier_map_string(SIO_explicit_valid)) SIO_symbolic_valid = get_statement_ordering_map( - example_sched_symbolic, lex_map_symbolic) + sched_map_symbolic, lex_map_symbolic) print("statement instance ordering symbolic (valid_sched):") print(prettier_map_string(SIO_symbolic_valid)) @@ -217,7 +217,7 @@ dep_constraint_vars = DependencyConstraintVars( # i dependency is none, j dependency is `prior` deps = [ - Dependency(0, 1, DT.SAME, 'j'), + Dependency(1, 0, DT.SAME, 'j'), ] print([str(dep) for dep in deps]) constraint_map = create_dependency_constraint( @@ -229,7 +229,6 @@ print(prettier_map_string(constraint_map)) #assert constraint_map.space == SIO_symbolic_valid.space #1/0 - #print("is valid sched valid?") #print(constraint_map.is_subset(SIO_symbolic_valid)) -- GitLab From 2a9047505138e18798d37cace470b908464f72a1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 May 2019 18:54:03 -0500 Subject: [PATCH 015/183] using only kernel domain (rather than iname bound variables) to convert schedule tuples into symbolic schedule map --- example_schedule_creation.py | 37 +++++++++++++++-------- lexicographic_order_map.py | 6 ++-- sched_check_utils.py | 10 +++++-- schedule.py | 58 +++++++++++++++++------------------- 4 files changed, 65 insertions(+), 46 deletions(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index 26670937d..31e307556 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -112,9 +112,9 @@ dep_s1_j = Dependency(s0, s1, "j", DependencyType.SAME) insn_to_deps = {"0":[], "1":[dep_s1_i, dep_s1_j], "2":[]} # enforce explicit iname bounds for now TODO -print("Kernel:") -print(knl) -print(lp.generate_code_v2(knl).device_code()) +#print("Kernel:") +#print(knl) +#print(lp.generate_code_v2(knl).device_code()) print("="*80) print("Iname tags: %s" % (knl.iname_to_tags)) print("="*80) @@ -145,25 +145,30 @@ iname_bounds = get_iname_bounds_dict(knl) domains = {} for iname in knl.all_inames(): domains[iname] = knl.get_inames_domain(iname) +print("domains:") +print(domains) -#iname_bounds = get_iname_bounds_dict(knl, _set_arbitrary_bounds=[0,2]) print("iname bounds:") print(iname_bounds) -sched = LexSchedule(knl, iname_bounds) -print("LexSchedule before processing:") -print(sched) - -# TODO a lot of this could be cleaner if we just create a set for each iname domain and pass it around instead of messing with all these individual bounds +sched = LexSchedule(knl, iname_bounds) # TODO do we really need iname bounds here? +#print("LexSchedule before processing:") +#print(sched) iname_to_params_dict = get_iname_to_param_dict(knl) #example_sched_explicit = sched.enumerate_symbolic_inames_and_create_explicit_isl_map(iname_bounds) -sched_map_symbolic = sched.create_symbolic_isl_map(iname_bounds, domains, iname_to_params_dict) # TODO don't need all of these args +sched_map_symbolic = sched.create_symbolic_isl_map(domains) +print("LexSchedule after processing:") +print(sched) # ------------------------------------------------------------------- print("LexSched (valid):") #print(prettier_map_string(example_sched_explicit)) print(prettier_map_string(sched_map_symbolic)) +print("space (statement instances -> lex time):") +print(sched_map_symbolic.space) + +1/0 # left off here # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later print("---------------------------------------------------------------------------") @@ -174,6 +179,8 @@ lex_map_symbolic = sched.get_lex_map_symbolic(iname_bounds) #print(prettier_map_string(lex_map_explicit)) print("lex map symbolic:") print(prettier_map_string(lex_map_symbolic)) +print("space (lex time -> lex time):") +print(lex_map_symbolic.space) # Statement instance ordering @@ -186,6 +193,8 @@ SIO_symbolic_valid = get_statement_ordering_map( sched_map_symbolic, lex_map_symbolic) print("statement instance ordering symbolic (valid_sched):") print(prettier_map_string(SIO_symbolic_valid)) +print("space (statement instances -> statement instances):") +print(SIO_symbolic_valid.space) # TODO left off here sched_inames = ['j'] @@ -218,19 +227,23 @@ dep_constraint_vars = DependencyConstraintVars( deps = [ Dependency(1, 0, DT.SAME, 'j'), + #Dependency(1, 0, DT.NONE, 'j'), ] +print("----------------------------------------------------------------------") print([str(dep) for dep in deps]) constraint_map = create_dependency_constraint( deps, dep_constraint_vars) print("constraint map:") print(prettier_map_string(constraint_map)) +print("space (statment instances -> statement instances):") +print(constraint_map.space) # TODO left off here, these spaces need to match and they don't #assert constraint_map.space == SIO_symbolic_valid.space #1/0 -#print("is valid sched valid?") -#print(constraint_map.is_subset(SIO_symbolic_valid)) +print("is valid sched valid? constraint map subset of SIO?") +print(constraint_map.is_subset(SIO_symbolic_valid)) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index c8b5f2789..a33a50967 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -44,8 +44,8 @@ def create_explicit_map_from_tuples(tuple_pairs, space): return union_map -#def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds, var_to_domain_dict, var_to_params_dict): -def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds, domain_to_intersect): +#def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds, domain_to_intersect): +def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): dim_type = isl.dim_type individual_maps = [] @@ -77,6 +77,8 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds, domain_to_in constraint = constraint \ & islvars[out_names[i]].eq_set(islvars[val_out]) constraints_set = constraints_set | constraint + # TODO temp hack for testing: + #constraints_set = constraints_set & islvars['ps'].eq_set(islvars[0]+3) # TODO remove result_map = isl.Map.from_domain(constraints_set) result_map = result_map.move_dims( diff --git a/sched_check_utils.py b/sched_check_utils.py index 4e9faeb67..2d5a454ee 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -14,5 +14,11 @@ def get_islvars_from_space(space): out_names = space.get_var_names(isl.dim_type.out) return isl.make_zero_and_vars(in_names+out_names, param_names) -def get_dim_for_isl_space_param(space, param): - return space.get_var_names(isl.dim_type.param).index(param) +def get_dim_for_isl_space_var(space, dim_type, var): + return space.get_var_names(dim_type).index(param) + +def add_and_name_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 diff --git a/schedule.py b/schedule.py index 992a0726d..528d99b63 100644 --- a/schedule.py +++ b/schedule.py @@ -141,7 +141,9 @@ class LexSchedule(object): from schedule_checker.lexicographic_order_map import get_space return get_space(params_sched, in_names_sched, out_names_sched) - def get_space_for_symbolic_sched(self, iname_bounds): + #def get_space_for_symbolic_sched(self, iname_bounds): + def get_space_for_symbolic_sched(self): + """ iname_bound_params = [] for iname in self.inames_not_enumerated: lo, up = iname_bounds[iname] @@ -151,8 +153,9 @@ class LexSchedule(object): if not isinstance(up, int): #iname_bound_params.append("p"+iname+"up") iname_bound_params.append(up) - - params_sched = ["ps"] + iname_bound_params + """ + #params_sched = ["ps"] + iname_bound_params + params_sched = [] in_names_sched = ["s"] + self.inames_not_enumerated out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] from schedule_checker.lexicographic_order_map import get_space @@ -216,40 +219,35 @@ class LexSchedule(object): sched_space = self.get_space_for_explicit_sched() return self.create_explicit_isl_map(sched_space) - def create_symbolic_isl_map(self, iname_bounds, domains, iname_to_params_dict): # TODO don't need all of these - # TODO assumes all knl inames included in iname_bounds - from schedule_checker.lexicographic_order_map import create_symbolic_map_from_tuples - from schedule_checker.sched_check_utils import flatten_2d_list, get_dim_for_isl_space_param - all_inames = list(iname_bounds.keys()) + def create_symbolic_isl_map(self, domains): + from schedule_checker.lexicographic_order_map import ( + create_symbolic_map_from_tuples, + ) + from schedule_checker.sched_check_utils import ( + add_and_name_dims_to_isl_set + ) + all_inames = list(domains.keys()) self.add_symbolic_inames_to_statement_instances(all_inames) - extra_params = [b for b in flatten_2d_list(iname_bounds.values()) - if isinstance(b,str)] - sched_space = self.get_space_for_symbolic_sched(iname_bounds) - #sched_space = self.get_space_for_explicit_sched() + sched_space = self.get_space_for_symbolic_sched() - # intersect all domains for symbolic (non-enumerated) inames found in statement instances + # intersect all domains for symbolic (non-enumerated) + # inames found in statement instances domain_intersection = domains[self.inames_not_enumerated[0]] #TODO what if self.inames_not_enumerated is empty? for iname in self.inames_not_enumerated[1:]: domain_intersection = domain_intersection.intersect(domains[iname]) - # inames not found in statement instance tuples should be removed - inames_to_remove_from_domains = all_inames.copy() - for iname in self.inames_not_enumerated: - inames_to_remove_from_domains.remove(iname) - - #dom = domains['j'] # TODO which domains(s) do we use? - #vars_to_remove = ['i'] # TODO where do we get this? in_names? - domain_stripped = domain_intersection.copy() - for iname in inames_to_remove_from_domains: - for p in iname_to_params_dict[iname]: - domain_stripped = domain_intersection.remove_dims( - isl.dim_type.param, - get_dim_for_isl_space_param(domain_intersection.space, p), - 1) - # TODO is projecting out iname necessary? - - return create_symbolic_map_from_tuples(list(self.items()), sched_space, iname_bounds, domain_stripped) + domain_stripped = domain_intersection.project_out_except( + self.inames_not_enumerated, + [isl.dim_type.set] + ) + new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' + domain_to_intersect = add_and_name_dims_to_isl_set( + domain_stripped, isl.dim_type.out, ['s'], new_pose) # TODO don't hardcode 's' + + # TODO this map needs 'ps' = # ?? + return create_symbolic_map_from_tuples( + list(self.items()), sched_space, domain_to_intersect) def get_lex_map_explicit(self): -- GitLab From abac82deff8cb2792ca527132d40d93372291697 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 May 2019 19:03:24 -0500 Subject: [PATCH 016/183] removed bounds variables from symbolic lex order map --- example_schedule_creation.py | 4 ++-- lexicographic_order_map.py | 22 +++++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index 31e307556..4c80cbd5f 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -168,8 +168,6 @@ print(prettier_map_string(sched_map_symbolic)) print("space (statement instances -> lex time):") print(sched_map_symbolic.space) -1/0 # left off here - # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later print("---------------------------------------------------------------------------") #lex_map_explicit = sched.get_lex_map_explicit() @@ -182,6 +180,8 @@ print(prettier_map_string(lex_map_symbolic)) print("space (lex time -> lex time):") print(lex_map_symbolic.space) +1/0 # left off here + # Statement instance ordering print("----------------------------------------------------------------------") diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index a33a50967..a212e2027 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -44,7 +44,6 @@ def create_explicit_map_from_tuples(tuple_pairs, space): return union_map -#def create_symbolic_map_from_tuples(tuple_pairs, space, var_bounds, domain_to_intersect): def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): dim_type = isl.dim_type @@ -130,13 +129,13 @@ def get_space(param_names, in_names, out_names): # from other things...) def create_symbolic_lex_mapping( n_dims, - param_names=None, + #param_names=None, in_names=None, out_names=None, dim_bound_vals=None, ): - if param_names is None: - param_names = [["lo%s" % (i), "up%s" % (i)] for i in range(n_dims)] + #if param_names is None: + # param_names = [["lo%s" % (i), "up%s" % (i)] for i in range(n_dims)] if in_names is None: in_names = ["i%s" % (i) for i in range(n_dims)] if out_names is None: @@ -145,7 +144,8 @@ def create_symbolic_lex_mapping( if dim_bound_vals is None: raise NotImplementedError("dim_bound_vals cannot be None") - assert len(in_names) == len(out_names) == len(param_names) == len(dim_bound_vals) == n_dims + #assert len(in_names) == len(out_names) == len(param_names) == len(dim_bound_vals) == n_dims + assert len(in_names) == len(out_names) == len(dim_bound_vals) == n_dims dim_type = isl.dim_type from schedule_checker.sched_check_utils import flatten_2d_list @@ -158,13 +158,15 @@ def create_symbolic_lex_mapping( islvars = isl.make_zero_and_vars( in_names+out_names, #flatten_2d_list(param_names)) - flatten_2d_list(param_names)+params_in_dim_bounds) + #flatten_2d_list(param_names)+params_in_dim_bounds) + params_in_dim_bounds) # [param for param_pair in param_names for param in param_pair]) # initialize set with constraint that is always true - lex_set_outer_bounds = islvars[0].eq_set(islvars[0]) + #lex_set_outer_bounds = islvars[0].eq_set(islvars[0]) # make constraints to bound dim vars dim_bound[0] <= ix < dim_bound[1] #for i, dim_bound in enumerate(dim_bound_vals): + """ for i in range(n_dims): lex_set_outer_bounds = lex_set_outer_bounds \ & islvars[in_names[i]].ge_set(islvars[param_names[i][0]]) \ @@ -191,6 +193,7 @@ def create_symbolic_lex_mapping( # upper bound is variable lex_set_outer_bounds = lex_set_outer_bounds \ & islvars[param_names[i][1]].eq_set(islvars[upper_bound]) + """ # create constraint enforcing lex ordering, e.g., in the 3-dim case: # i0 < o0 or ((i0 = o0) and (i1 < o1)) @@ -204,8 +207,9 @@ def create_symbolic_lex_mapping( islvars[in_names[j]].eq_set(islvars[out_names[j]]) lex_set_order_bound = lex_set_order_bound | lex_set_order_bound_conj - lex_set = lex_set_outer_bounds & lex_set_order_bound - lex_map = isl.Map.from_domain(lex_set) + #lex_set = lex_set_outer_bounds & lex_set_order_bound + #lex_map = isl.Map.from_domain(lex_set) + lex_map = isl.Map.from_domain(lex_set_order_bound) lex_map = lex_map.move_dims( dim_type.out, 0, dim_type.in_, len(in_names), len(out_names)) -- GitLab From f3bfc25e477731008aff9d677c79e86a89185e0c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 May 2019 19:07:45 -0500 Subject: [PATCH 017/183] no longer passing unnecessary iname bounds around for lex order map creation --- example_schedule_creation.py | 2 +- lexicographic_order_map.py | 22 +++++++++++----------- schedule.py | 12 ++++++------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index 4c80cbd5f..af36b9764 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -171,7 +171,7 @@ print(sched_map_symbolic.space) # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later print("---------------------------------------------------------------------------") #lex_map_explicit = sched.get_lex_map_explicit() -lex_map_symbolic = sched.get_lex_map_symbolic(iname_bounds) +lex_map_symbolic = sched.get_lex_map_symbolic(list(iname_bounds.keys())) #print("lex map explicit:") #print(prettier_map_string(lex_map_explicit)) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index a212e2027..f75249a1f 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -132,7 +132,8 @@ def create_symbolic_lex_mapping( #param_names=None, in_names=None, out_names=None, - dim_bound_vals=None, + #dim_bound_vals=None, + extra_params=None, ): #if param_names is None: # param_names = [["lo%s" % (i), "up%s" % (i)] for i in range(n_dims)] @@ -141,25 +142,24 @@ def create_symbolic_lex_mapping( if out_names is None: from schedule_checker.dependency import append_apostrophes out_names = append_apostrophes(in_names) - if dim_bound_vals is None: - raise NotImplementedError("dim_bound_vals cannot be None") + #if dim_bound_vals is None: + # raise NotImplementedError("dim_bound_vals cannot be None") #assert len(in_names) == len(out_names) == len(param_names) == len(dim_bound_vals) == n_dims - assert len(in_names) == len(out_names) == len(dim_bound_vals) == n_dims + assert len(in_names) == len(out_names) == n_dims dim_type = isl.dim_type - from schedule_checker.sched_check_utils import flatten_2d_list + #from schedule_checker.sched_check_utils import flatten_2d_list - #TODO left off here, need to add params from dim_bounds to islvars? - params_in_dim_bounds = [] - for v in flatten_2d_list(dim_bound_vals): - if not isinstance(v, int): - params_in_dim_bounds.append(v) + #params_in_dim_bounds = [] + #for v in flatten_2d_list(dim_bound_vals): + # if not isinstance(v, int): + # params_in_dim_bounds.append(v) islvars = isl.make_zero_and_vars( in_names+out_names, #flatten_2d_list(param_names)) #flatten_2d_list(param_names)+params_in_dim_bounds) - params_in_dim_bounds) + extra_params) # [param for param_pair in param_names for param in param_pair]) # initialize set with constraint that is always true diff --git a/schedule.py b/schedule.py index 528d99b63..ce530924d 100644 --- a/schedule.py +++ b/schedule.py @@ -273,17 +273,17 @@ class LexSchedule(object): return create_explicit_map_from_tuples(explicit_lex_map_pairs, lex_space_explicit) - def get_lex_map_symbolic(self, var_bounds_dict): + #def get_lex_map_symbolic(self, var_bounds_dict): + def get_lex_map_symbolic(self, extra_params): from schedule_checker.lexicographic_order_map import ( create_symbolic_lex_mapping, ) n_dims = self.max_lex_dims() - #lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(), - # [1 + v for v in self.get_max_lex_dim_vals()])) - lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(var_bounds_dict), - self.get_max_lex_dim_bounds(var_bounds_dict))) - return create_symbolic_lex_mapping(n_dims, dim_bound_vals=lex_dim_bounds) + #lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(var_bounds_dict), + # self.get_max_lex_dim_bounds(var_bounds_dict))) + #return create_symbolic_lex_mapping(n_dims, dim_bound_vals=lex_dim_bounds) + return create_symbolic_lex_mapping(n_dims, extra_params=extra_params) #def get_isl_map(self): def get_isl_map_str(self): -- GitLab From cb5cdd94b47708efb3d2e77001833f8529901aba Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 May 2019 19:13:00 -0500 Subject: [PATCH 018/183] fixing bug- passing correct parameters to symbolic lex order map creator --- example_schedule_creation.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index af36b9764..f095c9c54 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -171,7 +171,14 @@ print(sched_map_symbolic.space) # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later print("---------------------------------------------------------------------------") #lex_map_explicit = sched.get_lex_map_explicit() -lex_map_symbolic = sched.get_lex_map_symbolic(list(iname_bounds.keys())) + +params_in_dim_bounds = [] +from schedule_checker.sched_check_utils import flatten_2d_list +# TODO need better way to incorporate these params into lex map... do we even need them? +for v in flatten_2d_list(dim_bound_vals): + if not isinstance(v, int): + params_in_dim_bounds.append(v) +lex_map_symbolic = sched.get_lex_map_symbolic(params_in_dim_bounds) #print("lex map explicit:") #print(prettier_map_string(lex_map_explicit)) -- GitLab From 4b5aa81b79f1d7a4cd364a0abb4de5313cca378f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 26 May 2019 19:22:42 -0500 Subject: [PATCH 019/183] completely removing extra params from symbolic lex ordering, don't think they're necessary --- example_schedule_creation.py | 19 +++++++++--------- lexicographic_order_map.py | 38 +++--------------------------------- schedule.py | 6 ++++-- 3 files changed, 16 insertions(+), 47 deletions(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index f095c9c54..c5ee01f23 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -172,13 +172,13 @@ print(sched_map_symbolic.space) print("---------------------------------------------------------------------------") #lex_map_explicit = sched.get_lex_map_explicit() -params_in_dim_bounds = [] -from schedule_checker.sched_check_utils import flatten_2d_list -# TODO need better way to incorporate these params into lex map... do we even need them? -for v in flatten_2d_list(dim_bound_vals): - if not isinstance(v, int): - params_in_dim_bounds.append(v) -lex_map_symbolic = sched.get_lex_map_symbolic(params_in_dim_bounds) +#params_in_dim_bounds = [] +#from schedule_checker.sched_check_utils import flatten_2d_list +#for v in flatten_2d_list(iname_bounds.values()): +# if not isinstance(v, int): +# params_in_dim_bounds.append(v) +#lex_map_symbolic = sched.get_lex_map_symbolic(params_in_dim_bounds) +lex_map_symbolic = sched.get_lex_map_symbolic() #print("lex map explicit:") #print(prettier_map_string(lex_map_explicit)) @@ -187,9 +187,6 @@ print(prettier_map_string(lex_map_symbolic)) print("space (lex time -> lex time):") print(lex_map_symbolic.space) -1/0 # left off here - - # Statement instance ordering print("----------------------------------------------------------------------") #SIO_explicit_valid = get_statement_ordering_map( @@ -203,6 +200,8 @@ print(prettier_map_string(SIO_symbolic_valid)) print("space (statement instances -> statement instances):") print(SIO_symbolic_valid.space) +1/0 # left off here + # TODO left off here sched_inames = ['j'] iname_params = [(None, 'pj_up')] diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index f75249a1f..7b7721e98 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -133,7 +133,7 @@ def create_symbolic_lex_mapping( in_names=None, out_names=None, #dim_bound_vals=None, - extra_params=None, + #extra_params=None, ): #if param_names is None: # param_names = [["lo%s" % (i), "up%s" % (i)] for i in range(n_dims)] @@ -159,42 +159,10 @@ def create_symbolic_lex_mapping( in_names+out_names, #flatten_2d_list(param_names)) #flatten_2d_list(param_names)+params_in_dim_bounds) - extra_params) + #extra_params) + []) # [param for param_pair in param_names for param in param_pair]) - # initialize set with constraint that is always true - #lex_set_outer_bounds = islvars[0].eq_set(islvars[0]) - # make constraints to bound dim vars dim_bound[0] <= ix < dim_bound[1] - #for i, dim_bound in enumerate(dim_bound_vals): - """ - for i in range(n_dims): - lex_set_outer_bounds = lex_set_outer_bounds \ - & islvars[in_names[i]].ge_set(islvars[param_names[i][0]]) \ - & islvars[in_names[i]].lt_set(islvars[param_names[i][1]]) \ - & islvars[out_names[i]].ge_set(islvars[param_names[i][0]]) \ - & islvars[out_names[i]].lt_set(islvars[param_names[i][1]]) - if dim_bound_vals: - #lex_set_outer_bounds = lex_set_outer_bounds \ - # & islvars[param_names[i][0]].eq_set(islvars[0]+dim_bound_vals[i][0]) \ - # & islvars[param_names[i][1]].eq_set(islvars[0]+dim_bound_vals[i][1]) - lower_bound = dim_bound_vals[i][0] - upper_bound = dim_bound_vals[i][1] - if isinstance(lower_bound, int): - lex_set_outer_bounds = lex_set_outer_bounds \ - & islvars[param_names[i][0]].eq_set(islvars[0]+lower_bound) - else: - # lower bound is variable - lex_set_outer_bounds = lex_set_outer_bounds \ - & islvars[param_names[i][0]].eq_set(islvars[lower_bound]) - if isinstance(upper_bound, int): - lex_set_outer_bounds = lex_set_outer_bounds \ - & islvars[param_names[i][1]].eq_set(islvars[0]+upper_bound) - else: - # upper bound is variable - lex_set_outer_bounds = lex_set_outer_bounds \ - & islvars[param_names[i][1]].eq_set(islvars[upper_bound]) - """ - # create constraint enforcing lex ordering, e.g., in the 3-dim case: # i0 < o0 or ((i0 = o0) and (i1 < o1)) # or ((i0 = o0) and (i1 = o1) and (i2 < o2)) diff --git a/schedule.py b/schedule.py index ce530924d..a03f0d646 100644 --- a/schedule.py +++ b/schedule.py @@ -274,7 +274,8 @@ class LexSchedule(object): lex_space_explicit) #def get_lex_map_symbolic(self, var_bounds_dict): - def get_lex_map_symbolic(self, extra_params): + #def get_lex_map_symbolic(self, extra_params): + def get_lex_map_symbolic(self): from schedule_checker.lexicographic_order_map import ( create_symbolic_lex_mapping, ) @@ -283,7 +284,8 @@ class LexSchedule(object): #lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(var_bounds_dict), # self.get_max_lex_dim_bounds(var_bounds_dict))) #return create_symbolic_lex_mapping(n_dims, dim_bound_vals=lex_dim_bounds) - return create_symbolic_lex_mapping(n_dims, extra_params=extra_params) + #return create_symbolic_lex_mapping(n_dims, extra_params=extra_params) + return create_symbolic_lex_mapping(n_dims) #def get_isl_map(self): def get_isl_map_str(self): -- GitLab From 21b310e5663050aa8ce23617ad3ed2ed760aa8b6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 27 May 2019 20:30:07 -0500 Subject: [PATCH 020/183] added function create_new_set_with_primes() which just appends apostrophe to all set vars; added function add_missing_set_dims_to_map_indims(map,set) which adds dims to map so that its in-dims include the set dims --- sched_check_utils.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/sched_check_utils.py b/sched_check_utils.py index 2d5a454ee..8bb95c7d2 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -22,3 +22,33 @@ def add_and_name_dims_to_isl_set(isl_set, dim_type, names, new_pose_start): 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 create_new_set_with_primes(old_set): + new_set = old_set.copy() + for i in range(old_set.n_dim()): + new_set = new_set.set_dim_name(isl.dim_type.out, i, old_set.get_dim_name(isl.dim_type.out, i)+"'") + return new_set + +def add_missing_set_dims_to_map_indims(islmap, islset): + new_map = islmap.copy() + for i in range(islset.n_dim()): + new_dim_name = islset.get_dim_name(isl.dim_type.out, i) + + old_map_in_names = new_map.get_var_names(isl.dim_type.in_) + if len(old_map_in_names) > i and old_map_in_names[i] == new_dim_name: + continue + else: + new_map = new_map.insert_dims(isl.dim_type.in_, i, 1) + new_map = new_map.set_dim_name(isl.dim_type.in_, i, new_dim_name) + """ + old_map_out_names = new_map.get_var_names(isl.dim_type.out) + if len(old_map_out_names) > i and old_map_out_names[i] == new_dim_name: + continue + else: + new_map = new_map.insert_dims(isl.dim_type.out, i, 1) + new_map = new_map.set_dim_name(isl.dim_type.out, i, new_dim_name) + """ + return new_map + + + -- GitLab From a54bae7ec3da8f66e57252d026324e219e9e3438 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 27 May 2019 20:30:25 -0500 Subject: [PATCH 021/183] added concurrent inames (ignored in initial sched creation) into lex order map --- lexicographic_order_map.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 7b7721e98..25ab708b9 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -76,14 +76,15 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): constraint = constraint \ & islvars[out_names[i]].eq_set(islvars[val_out]) constraints_set = constraints_set | constraint - # TODO temp hack for testing: - #constraints_set = constraints_set & islvars['ps'].eq_set(islvars[0]+3) # TODO remove result_map = isl.Map.from_domain(constraints_set) result_map = result_map.move_dims( dim_type.out, 0, dim_type.in_, len(in_names), len(out_names)) + from schedule_checker.sched_check_utils import add_missing_set_dims_to_map_indims + result_map = add_missing_set_dims_to_map_indims(result_map, domain_to_intersect) + return result_map.intersect_domain(domain_to_intersect) -- GitLab From ca934cfda91e192e96a1727f7e73580b3423f62c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 27 May 2019 20:30:45 -0500 Subject: [PATCH 022/183] no longer projecting out concurrent inames (ignored in initial sched creation) when creating sched map --- schedule.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/schedule.py b/schedule.py index a03f0d646..c9c7a0491 100644 --- a/schedule.py +++ b/schedule.py @@ -5,15 +5,15 @@ from collections import OrderedDict class Statement(object): def __init__( self, - statement_id, + sid, active_inames, ): - self.statement_id = statement_id # string + self.sid = sid # string self.active_inames = active_inames # [string, ] def __str__(self): return "%s {%s}" % ( - self.statement_id, ",".join(self.active_inames)) + self.sid, ",".join(self.active_inames)) class StatementInstance(object): @@ -31,12 +31,12 @@ class StatementInstance(object): def __str__(self): import six return "[%s,%s]" % ( - self.statement.statement_id, ",".join( + self.statement.sid, ",".join( ["%d" % (v) for k, v in sorted(six.iteritems(self.iname_vals))])) def __eq__(self, other): return self.iname_vals == other.iname_vals and \ - self.statement.statement_id == other.statement.statement_id + self.statement.sid == other.statement.sid def __hash__(self): return hash(str(self)) @@ -52,7 +52,7 @@ class LexSchedule(object): self.lex_schedule = OrderedDict() # statement instance: lex point self.inames_enumerated = [] # symbolic inames in sched that have been enumerated into explicit statement instances self.inames_not_enumerated = [] # TODO better way to do this - self.lp_insnid_to_id = {} + self.lp_insnid_to_int_sid = {} from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) cur_nest_lex_prefix = [] @@ -73,7 +73,7 @@ class LexSchedule(object): cur_nest_lex_prefix.pop() # pop insn ct variable elif isinstance(sched_item, RunInstruction): self.add_new_lp_insnid(sched_item.insn_id) - insn_id_int = self.lp_insnid_to_id[sched_item.insn_id] + insn_id_int = self.lp_insnid_to_int_sid[sched_item.insn_id] #inames = knl.id_to_insn[insn_id].within_inames #conc_dict = get_iname_concurrency_dict(inames, knl) #print("RunInstruction: id: %s; inames: %s" % (sched_item.insn_id, conc_dict)) @@ -129,10 +129,10 @@ class LexSchedule(object): self.inames_not_enumerated.append(iname) def add_new_lp_insnid(self, lp_insnid): - if self.lp_insnid_to_id: - self.lp_insnid_to_id[lp_insnid] = max(self.lp_insnid_to_id.values()) + 1 + if self.lp_insnid_to_int_sid: + self.lp_insnid_to_int_sid[lp_insnid] = max(self.lp_insnid_to_int_sid.values()) + 1 else: - self.lp_insnid_to_id[lp_insnid] = 0 + self.lp_insnid_to_int_sid[lp_insnid] = 0 def get_space_for_explicit_sched(self): params_sched = ["ps"] + ["p"+iname for iname in self.inames_enumerated] @@ -237,15 +237,17 @@ class LexSchedule(object): for iname in self.inames_not_enumerated[1:]: domain_intersection = domain_intersection.intersect(domains[iname]) + # TODO maybe don't project this out, constraints may involve any iname later... + """ domain_stripped = domain_intersection.project_out_except( self.inames_not_enumerated, [isl.dim_type.set] ) + """ new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' domain_to_intersect = add_and_name_dims_to_isl_set( - domain_stripped, isl.dim_type.out, ['s'], new_pose) # TODO don't hardcode 's' + domain_intersection, isl.dim_type.out, ['s'], new_pose) # TODO don't hardcode 's' - # TODO this map needs 'ps' = # ?? return create_symbolic_map_from_tuples( list(self.items()), sched_space, domain_to_intersect) @@ -292,7 +294,7 @@ class LexSchedule(object): map_str = "{" for state_inst, lex in self.lex_schedule.items(): domain_elem = "[s=%s,%s]" % ( - state_inst.statement.statement_id, ",".join( + state_inst.statement.sid, ",".join( ["%s=%d" % (iname, val) for iname, val in state_inst.iname_vals.items()])) range_elem = "[%s]" % (",".join("%s" % (l) for l in lex)) map_str += "%s -> %s; " % (domain_elem, range_elem) -- GitLab From b77133caf5add075622fe0fa2772a254fc6a5e37 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 27 May 2019 20:31:31 -0500 Subject: [PATCH 023/183] removed unnecessary class DependencyConstraintVars, enforced consistent iname ordering, applied loopy kernel loop domain to dependency constraint map --- dependency.py | 131 ++++++++------------------------- example_dependency_checking.py | 60 +++++++++------ example_lex_map_creation.py | 4 +- example_schedule_creation.py | 107 ++++++++------------------- 4 files changed, 102 insertions(+), 200 deletions(-) diff --git a/dependency.py b/dependency.py index b2688ebbe..491e296ee 100644 --- a/dependency.py +++ b/dependency.py @@ -82,85 +82,12 @@ def _create_bounded_set_for_dependency_constraints( return bounded_set -class DependencyConstraintVars(object): - def __init__( - self, - inames, - param_names, - param_vals, - statement_var, - statement_param, - statement_param_val, - ): - self.inames = inames - self.param_names = param_names # TODO rename, these are pairs of bound vars - self.param_vals = param_vals # TODO rename, these are pairs of bound vals - self.statement_var = statement_var - self.statement_param = statement_param - self.statement_param_val = statement_param_val - - def get_bounds_constraint_set(self): - var_names = [self.statement_var]+self.inames - param_names = [self.statement_param]+self.list_param_names() - islvars = _make_islvars_with_var_primes( - var_names, param_names) - - bounded_set = islvars[0].eq_set(islvars[0]) # initialize to True - - # bound the statement variable - v = self.statement_var - v_prime = self.statement_var+"'" - p = self.statement_param - b = self.statement_param_val - bounded_set = bounded_set \ - & islvars[v].lt_set(islvars[p]) \ - & islvars[v_prime].lt_set(islvars[p]) \ - & (islvars[0]).le_set(islvars[v]) \ - & (islvars[0]).le_set(islvars[v_prime]) \ - & islvars[p].eq_set(islvars[0]+b) - - # bound the other variables - for v, (p_low, p_up), (pval_low, pval_up) in zip( - self.inames, self.param_names, self.param_vals): - - # create constraint pval_low = p_low <= v,v'< p_up = pval_up - - if p_low is None: - assert isinstance(pval_low, int) - lower_bound = islvars[0] + pval_low - else: - lower_bound = islvars[p_low] - if not pval_low is None: - bounded_set = bounded_set & lower_bound.eq_set(islvars[0]+pval_low) - - if p_up is None: - assert isinstance(pval_up, int) - upper_bound = islvars[0] + pval_up - else: - upper_bound = islvars[p_up] - if not pval_up is None: - bounded_set = bounded_set & upper_bound.eq_set(islvars[0]+pval_up) - - v_prime = v+"'" - bounded_set = bounded_set \ - & islvars[v].lt_set(upper_bound) \ - & islvars[v_prime].lt_set(upper_bound) \ - & lower_bound.le_set(islvars[v]) \ - & lower_bound.le_set(islvars[v_prime]) - - return bounded_set - - def list_param_names(self): - from schedule_checker.sched_check_utils import flatten_2d_list - return [p for p in flatten_2d_list(self.param_names) if not p is None] - - def __str__(self): - return str(self.get_bounds_constraint_set()) - - def create_dependency_constraint( dependencies, - dep_constraint_vars, + all_inames_ordered, + statement_var, + domain_constraint_set, + sid_to_int, ): # This function uses the dependencies given to create the following constraint: # Statement [s,i,j] comes before statement [s',i',j'] iff @@ -168,25 +95,19 @@ def create_dependency_constraint( # assumes statements are numbered sequentially # (statement_bound = max statement id + 1) - statement_param = dep_constraint_vars.statement_param - #param_names = dep_constraint_vars.param_names - param_names = dep_constraint_vars.list_param_names() - all_inames = dep_constraint_vars.inames - statement_var = dep_constraint_vars.statement_var - # make sure all dependencies involve same two statements - if len(set([dep.statement_before for dep in dependencies])) != 1 or \ - len(set([dep.statement_after for dep in dependencies])) != 1: + if len(set([dep.statement_before.sid for dep in dependencies])) != 1 or \ + len(set([dep.statement_after.sid for dep in dependencies])) != 1: raise ValueError("All depencencies must be between same two statements.") # make sure all dependencies involve different inames # TODO upate after allowing prior(i,k) if len(set([dep.iname for dep in dependencies])) != len(dependencies): raise ValueError("All depencencies must apply to different inames.") - DT = DependencyType statement_var_prime = statement_var+"'" + DT = DependencyType islvars = _make_islvars_with_var_primes( - [statement_var]+all_inames, - [statement_param]+param_names) + [statement_var]+all_inames_ordered, + []) # initialize constraints to False # this will disappear as soon as we add a constraint that is not DT.NONE @@ -199,7 +120,7 @@ def create_dependency_constraint( continue iname_prime = iname+"'" # i' - other_inames = all_inames.copy() + other_inames = all_inames_ordered.copy() other_inames.remove(iname) # remaining inames, e.g., [j, k] other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] @@ -212,18 +133,28 @@ def create_dependency_constraint( elif dep_type == DT.ALL: constraint_set = constraint_set & islvars[0].eq_set(islvars[0]) # True - constraint_set = constraint_set & islvars[statement_var].eq_set(islvars[0]+dep.statement_before) - constraint_set = constraint_set & islvars[statement_var_prime].eq_set(islvars[0]+dep.statement_after) - # TODO get this working - # add 'or' to indicate that this constraint doesn't apply to other statements - #remainder_set = islvars[statement_var].ne_set(islvars[0]+dep.statement_before) \ - # | islvars[statement_var_prime].ne_set(islvars[0]+dep.statement_after) - #print("remainder_set", remainder_set) - #constraint_set = constraint_set | remainder_set - + s_before_int = sid_to_int[dep.statement_before.sid] + s_after_int = sid_to_int[dep.statement_after.sid] + constraint_set = constraint_set & islvars[statement_var].eq_set(islvars[0]+s_before_int) + constraint_set = constraint_set & islvars[statement_var_prime].eq_set(islvars[0]+s_after_int) all_constraints_set = all_constraints_set | constraint_set - all_constraints_set = all_constraints_set & dep_constraint_vars.get_bounds_constraint_set() + all_constraints_map = _convert_constraint_set_to_map(all_constraints_set, len(all_inames_ordered)+1) + + from schedule_checker.sched_check_utils import create_new_set_with_primes + range_constraint_set = create_new_set_with_primes(domain_constraint_set) + + from schedule_checker.sched_check_utils import ( + add_and_name_dims_to_isl_set + ) + new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' + domain_to_intersect = add_and_name_dims_to_isl_set( + domain_constraint_set, isl.dim_type.out, ["s"], new_pose) # TODO don't hardcode 's' + range_to_intersect = add_and_name_dims_to_isl_set( + range_constraint_set, isl.dim_type.out, ["s'"], new_pose) # TODO don't hardcode 's' - return _convert_constraint_set_to_map(all_constraints_set, len(dep_constraint_vars.inames)+1) + map_with_loop_domain_constraints = all_constraints_map.intersect_domain(domain_to_intersect).intersect_range(range_to_intersect) + #blah2 = isl.Map("[pi_up, pj_up] -> { [s = 1, i, j] -> [s' = 0, i' = i, j'] : 0 <= i < pi_up and 0 <= j < pj_up and j' > j and 0 <= j' < pj_up}") + #assert blah2 == map_with_loop_domain_constraints + return map_with_loop_domain_constraints diff --git a/example_dependency_checking.py b/example_dependency_checking.py index 01cb9b013..0b3444c49 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -5,7 +5,6 @@ from schedule_checker.dependency import ( DependencyType as DT, create_dependency_constraint, append_apostrophes, - DependencyConstraintVars, ) from schedule_checker.lexicographic_order_map import ( make_lex_mapping_tuple_pairs, @@ -14,6 +13,7 @@ from schedule_checker.lexicographic_order_map import ( set_space_names, get_space, ) +from schedule_checker.schedule import Statement from schedule_checker.sched_check_utils import prettier_map_string @@ -31,13 +31,9 @@ print("Kernel:") print(knl) from schedule_checker.sched_check_utils import flatten_2d_list -all_inames = ['i', 'j'] -iname_params = [(None, 'p0'), (None, 'p1')] -param_names_listed = [p for p in flatten_2d_list(iname_params) if not p is None] -iname_param_vals = [(0, 2), (0, 2)] +all_inames_ordered = ['i', 'j'] +#all_inames_ordered = sorted(list(knl.all_inames())) statement_var = 's' -statement_param = 'ps' -statement_bound = 2 # example sched: print("---------------------------------------------------------------------------") @@ -45,8 +41,8 @@ print("------------------------------------------------------------------------- # i is parallel, suppose we want to enforce the following: # for a given i, statement 0 happens before statement 1 -params_sched = [statement_param]+param_names_listed -in_names_sched = [statement_var]+all_inames +params_sched = ['p0', 'p1'] +in_names_sched = [statement_var]+all_inames_ordered out_names_sched = ['l0', 'l1'] sched_space = get_space(params_sched, in_names_sched, out_names_sched) @@ -114,28 +110,46 @@ print(prettier_map_string(SIO_explicit_invalid)) # Dependencies and constraints: print("----------------------------------------------------------------------") -dep_constraint_vars = DependencyConstraintVars( - all_inames, - iname_params, - iname_param_vals, - statement_var, - statement_param, - statement_bound, - ) - # i is parallel, suppose we want to enforce the following: # for a given i, statement 0 happens before statement 1 # i dependency is none, j dependency is `prior` +statement_var = 's' + +domains = {} +for iname in all_inames_ordered: + domains[iname] = knl.get_inames_domain(iname) +domains_list = list(domains.values()) +domain_union = domains_list[0] +#TODO is union the right thing to do here? +for dom in domains_list[1:]: + domain_union = domain_union.union(dom) +print("domain union:") +print(domain_union) + +# make some dependencies manually for now: +s0 = Statement("0", ["i", "j"]) +s1 = Statement("1", ["i", "j"]) +insnid_to_int_sid = {"0": 0, "1": 1} + deps = [ - #Dependency(0, 1, DT.NONE, 'i'), - Dependency(0, 1, DT.SAME, 'i'), - Dependency(0, 1, DT.SAME, 'j'), + Dependency(s0, s1, DT.SAME, "i"), + Dependency(s0, s1, DT.SAME, "j"), ] + print([str(dep) for dep in deps]) constraint_map = create_dependency_constraint( - deps, dep_constraint_vars) -assert constraint_map.space == SIO_explicit_valid.space + deps, + all_inames_ordered, + statement_var, + domain_union, + insnid_to_int_sid, + ) +print("constraint map space:") +print(constraint_map.space) +print("SIO space:") +print(SIO_explicit_valid.space) +#assert constraint_map.space == SIO_explicit_valid.space print("constraint map:") print(prettier_map_string(constraint_map)) diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py index 92bfe2930..d26b268a0 100644 --- a/example_lex_map_creation.py +++ b/example_lex_map_creation.py @@ -17,12 +17,11 @@ from schedule_checker.lexicographic_order_map import ( # *Symbolic* lexicographic mapping- map each tuple to all tuples occuring later -dim_bounds = [(0,2), (0,2)] # max vals for each dim (e.g., 0 <= i0 < max0 ...) #in_names = ["i", "j"] #out_names = append_apostrophes(in_names) n_dims = 2 #len(in_names) lex_map_symbolic = create_symbolic_lex_mapping( - n_dims, dim_bound_vals=dim_bounds) + n_dims) print("lex_map (symbolic):") print(lex_map_symbolic) @@ -30,6 +29,7 @@ print(lex_map_symbolic) # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later """ +dim_bounds = [(0,2), (0,2)] # max vals for each dim (e.g., 0 <= i0 < max0 ...) explicit_lex_map_pairs = make_lex_mapping_tuple_pairs(dim_bounds) # for pair in explicit_lex_map_pairs: # print(pair[0], pair[1]) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index c5ee01f23..f8aa90788 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -3,26 +3,23 @@ import loopy as lp import numpy as np from schedule_checker.dependency import ( Dependency, - DependencyType, - append_apostrophes, + DependencyType as DT, ) from schedule_checker.schedule import Statement, StatementInstance, LexSchedule from schedule_checker.sched_check_utils import prettier_map_string from schedule_checker.lexicographic_order_map import ( create_explicit_map_from_tuples, get_statement_ordering_map, - #set_space_names, get_space, - #create_symbolic_lex_mapping, ) from schedule_checker.sched_check_utils import prettier_map_string -def get_iname_bounds_dict(knl, _set_arbitrary_bounds=None): +def get_iname_bounds_dict(knl, all_inames_ordered, _set_arbitrary_bounds=None): # TODO don't require explicit bounds if _set_arbitrary_bounds: - return dict((iname, _set_arbitrary_bounds) for iname in knl.all_inames()) + return dict((iname, _set_arbitrary_bounds) for iname in all_inames_ordered) from loopy.symbolic import aff_to_expr from loopy.isl_helpers import static_max_of_pw_aff @@ -37,7 +34,7 @@ def get_iname_bounds_dict(knl, _set_arbitrary_bounds=None): bounds = {} all_params = knl.all_params() - for iname in knl.all_inames(): + for iname in all_inames_ordered: #bounds_record = knl.get_iname_bounds(iname, constants_only=True) bounds_record = knl.get_iname_bounds(iname) (_, iname_min_aff), = bounds_record.lower_bound_pw_aff.get_pieces() @@ -62,26 +59,6 @@ def get_iname_bounds_dict(knl, _set_arbitrary_bounds=None): #assert all(isinstance(i,int) for i in int_bounds[iname]) return bounds -def get_iname_to_param_dict(knl): - from loopy.symbolic import aff_to_expr - bounds = {} - all_params = knl.all_params() - for iname in knl.all_inames(): - #bounds_record = knl.get_iname_bounds(iname, constants_only=True) - bounds_record = knl.get_iname_bounds(iname) - (_, iname_min_aff), = bounds_record.lower_bound_pw_aff.get_pieces() - (_, iname_max_aff), = bounds_record.upper_bound_pw_aff.get_pieces() - iname_min_aff = aff_to_expr(iname_min_aff) - iname_max_aff = aff_to_expr(iname_max_aff) - bounds_strs = str(iname_min_aff)+str(iname_max_aff) - params_found = [] - for param in all_params: - if param in bounds_strs: - params_found.append(param) - - bounds[iname] = params_found - return bounds - # make example kernel knl = lp.make_kernel( #"{[i,j]: 0<=i,j<2}", @@ -103,15 +80,9 @@ knl = lp.tag_inames(knl, {"i": "l.0"}) knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) -# make some dependencies manually for now: -s0 = Statement("0", ["i", "j"]) -s1 = Statement("1", ["i", "j"]) -s2 = Statement("2", ["i", "j"]) -dep_s1_i = Dependency(s0, s1, "i", DependencyType.SAME) -dep_s1_j = Dependency(s0, s1, "j", DependencyType.SAME) -insn_to_deps = {"0":[], "1":[dep_s1_i, dep_s1_j], "2":[]} +# get all inames in consistent ordering: +all_inames_ordered = sorted(list(knl.all_inames())) -# enforce explicit iname bounds for now TODO #print("Kernel:") #print(knl) #print(lp.generate_code_v2(knl).device_code()) @@ -140,10 +111,10 @@ def get_iname_concurrency_dict(inames, knl): return conc_dict # Get schedule ------------------------------------------------------ -iname_bounds = get_iname_bounds_dict(knl) +iname_bounds = get_iname_bounds_dict(knl, all_inames_ordered) domains = {} -for iname in knl.all_inames(): +for iname in all_inames_ordered: domains[iname] = knl.get_inames_domain(iname) print("domains:") print(domains) @@ -154,7 +125,6 @@ sched = LexSchedule(knl, iname_bounds) # TODO do we really need iname bounds he #print("LexSchedule before processing:") #print(sched) -iname_to_params_dict = get_iname_to_param_dict(knl) #example_sched_explicit = sched.enumerate_symbolic_inames_and_create_explicit_isl_map(iname_bounds) sched_map_symbolic = sched.create_symbolic_isl_map(domains) print("LexSchedule after processing:") @@ -172,12 +142,6 @@ print(sched_map_symbolic.space) print("---------------------------------------------------------------------------") #lex_map_explicit = sched.get_lex_map_explicit() -#params_in_dim_bounds = [] -#from schedule_checker.sched_check_utils import flatten_2d_list -#for v in flatten_2d_list(iname_bounds.values()): -# if not isinstance(v, int): -# params_in_dim_bounds.append(v) -#lex_map_symbolic = sched.get_lex_map_symbolic(params_in_dim_bounds) lex_map_symbolic = sched.get_lex_map_symbolic() #print("lex map explicit:") @@ -200,60 +164,53 @@ print(prettier_map_string(SIO_symbolic_valid)) print("space (statement instances -> statement instances):") print(SIO_symbolic_valid.space) -1/0 # left off here - -# TODO left off here -sched_inames = ['j'] -iname_params = [(None, 'pj_up')] -iname_param_vals = [(0, None)] -statement_var = 's' -statement_param = 'ps' -statement_bound = 3 - from schedule_checker.dependency import ( - Dependency, - DependencyType as DT, create_dependency_constraint, - append_apostrophes, - DependencyConstraintVars, ) -dep_constraint_vars = DependencyConstraintVars( - sched_inames, - iname_params, - iname_param_vals, - statement_var, - statement_param, - statement_bound, - ) +statement_var = 's' + +domains_list = list(domains.values()) +domain_union = domains_list[0] +#TODO is union the right thing to do here? +for dom in domains_list[1:]: + domain_union = domain_union.union(dom) # i is parallel, suppose we want to enforce the following: # for a given i, statement 0 happens before statement 1 # i dependency is none, j dependency is `prior` +# make some dependencies manually for now: +s0 = Statement("0", ["i", "j"]) +s1 = Statement("1", ["i", "j"]) +s2 = Statement("2", ["i", "j"]) +#dep_s1_i = Dependency(s0, s1, DT.NONE, "i") +#dep_s1_j = Dependency(s0, s1, DT.PRIOR, "j") +#insn_to_deps = {"0":[], "1":[dep_s1_i, dep_s1_j], "2":[]} + deps = [ - Dependency(1, 0, DT.SAME, 'j'), - #Dependency(1, 0, DT.NONE, 'j'), + Dependency(s0, s1, DT.NONE, "i"), + Dependency(s0, s1, DT.PRIOR, "j"), ] print("----------------------------------------------------------------------") print([str(dep) for dep in deps]) constraint_map = create_dependency_constraint( - deps, dep_constraint_vars) + deps, + all_inames_ordered, + statement_var, + domain_union, + sched.lp_insnid_to_int_sid, + ) print("constraint map:") print(prettier_map_string(constraint_map)) print("space (statment instances -> statement instances):") print(constraint_map.space) -# TODO left off here, these spaces need to match and they don't - -#assert constraint_map.space == SIO_symbolic_valid.space -#1/0 +assert constraint_map.space == SIO_symbolic_valid.space print("is valid sched valid? constraint map subset of SIO?") print(constraint_map.is_subset(SIO_symbolic_valid)) - - ''' all_inames = ['i', 'j'] iname_params = ['p0', 'p1'] -- GitLab From f368ed8a8c4db23fb99961775f1eb09e8f90d22b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 27 May 2019 20:39:18 -0500 Subject: [PATCH 024/183] moved no-longer-used function to utils for now --- dependency.py | 21 --------------------- sched_check_utils.py | 18 ++++++++++++++++++ schedule.py | 7 ------- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/dependency.py b/dependency.py index 491e296ee..f85ed2fdc 100644 --- a/dependency.py +++ b/dependency.py @@ -61,27 +61,6 @@ def _make_islvars_with_var_primes(var_names, param_names): var_names+append_apostrophes(var_names), param_names) -def _create_bounded_set_for_dependency_constraints( - var_names, param_names, upper_bounds): - - # TODO assumes lower bound is zero - islvars = _make_islvars_with_var_primes(var_names, param_names) - - bounded_set = islvars[0].eq_set(islvars[0]) # initialize to True - - for v, p, b in zip(var_names, param_names, upper_bounds): - # create constraint 0 <= v,v'< p = b - v_prime = v+"'" - bounded_set = bounded_set \ - & islvars[v].lt_set(islvars[p]) \ - & islvars[v_prime].lt_set(islvars[p]) \ - & (islvars[0]-1).lt_set(islvars[v]) \ - & (islvars[0]-1).lt_set(islvars[v_prime]) \ - & islvars[p].eq_set(islvars[0]+b) - - return bounded_set - - def create_dependency_constraint( dependencies, all_inames_ordered, diff --git a/sched_check_utils.py b/sched_check_utils.py index 8bb95c7d2..e1b9eb7cb 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -51,4 +51,22 @@ def add_missing_set_dims_to_map_indims(islmap, islset): return new_map +def _create_positive_set_with_bounds( + var_names, param_names, upper_bounds): + # TODO assumes lower bound is zero + islvars = _make_islvars_with_var_primes(var_names, param_names) + + bounded_set = islvars[0].eq_set(islvars[0]) # initialize to True + + for v, p, b in zip(var_names, param_names, upper_bounds): + # create constraint 0 <= v,v'< p = b + v_prime = v+"'" + bounded_set = bounded_set \ + & islvars[v].lt_set(islvars[p]) \ + & islvars[v_prime].lt_set(islvars[p]) \ + & (islvars[0]-1).lt_set(islvars[v]) \ + & (islvars[0]-1).lt_set(islvars[v_prime]) \ + & islvars[p].eq_set(islvars[0]+b) + + return bounded_set diff --git a/schedule.py b/schedule.py index c9c7a0491..1cf2a93a1 100644 --- a/schedule.py +++ b/schedule.py @@ -275,21 +275,14 @@ class LexSchedule(object): return create_explicit_map_from_tuples(explicit_lex_map_pairs, lex_space_explicit) - #def get_lex_map_symbolic(self, var_bounds_dict): - #def get_lex_map_symbolic(self, extra_params): def get_lex_map_symbolic(self): from schedule_checker.lexicographic_order_map import ( create_symbolic_lex_mapping, ) n_dims = self.max_lex_dims() - #lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(var_bounds_dict), - # self.get_max_lex_dim_bounds(var_bounds_dict))) - #return create_symbolic_lex_mapping(n_dims, dim_bound_vals=lex_dim_bounds) - #return create_symbolic_lex_mapping(n_dims, extra_params=extra_params) return create_symbolic_lex_mapping(n_dims) - #def get_isl_map(self): def get_isl_map_str(self): map_str = "{" for state_inst, lex in self.lex_schedule.items(): -- GitLab From cefc8d6e7c90c35355b14850655e5571edc8a54a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 27 May 2019 20:48:10 -0500 Subject: [PATCH 025/183] moved append_apostrophes() and make_islvars_with_var_primes() into utils --- dependency.py | 24 +++++++----------------- example_dependency_checking.py | 7 ++++--- example_lex_map_creation.py | 1 - lexicographic_order_map.py | 2 +- sched_check_utils.py | 14 +++++++++++++- schedule.py | 2 +- 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/dependency.py b/dependency.py index f85ed2fdc..2c9884f3f 100644 --- a/dependency.py +++ b/dependency.py @@ -30,13 +30,6 @@ class Dependency(object): self.dep_type) -def append_apostrophes(strings): - if not isinstance(strings, list): - raise ValueError("append_apostrophes did not receive a list") - else: - return [s+"'" for s in strings] - - def create_equality_conjunction_set(names0, names1, islvars): # initialize set with constraint that is always true @@ -56,11 +49,6 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): return constraint_map.move_dims(dim_type.out, 0, dim_type.in_, mv_count, mv_count) -def _make_islvars_with_var_primes(var_names, param_names): - return isl.make_zero_and_vars( - var_names+append_apostrophes(var_names), param_names) - - def create_dependency_constraint( dependencies, all_inames_ordered, @@ -68,6 +56,12 @@ def create_dependency_constraint( domain_constraint_set, sid_to_int, ): + from schedule_checker.sched_check_utils import ( + make_islvars_with_var_primes, + append_apostrophes, + add_and_name_dims_to_isl_set, + create_new_set_with_primes, + ) # This function uses the dependencies given to create the following constraint: # Statement [s,i,j] comes before statement [s',i',j'] iff @@ -84,7 +78,7 @@ def create_dependency_constraint( statement_var_prime = statement_var+"'" DT = DependencyType - islvars = _make_islvars_with_var_primes( + islvars = make_islvars_with_var_primes( [statement_var]+all_inames_ordered, []) @@ -121,12 +115,8 @@ def create_dependency_constraint( all_constraints_map = _convert_constraint_set_to_map(all_constraints_set, len(all_inames_ordered)+1) - from schedule_checker.sched_check_utils import create_new_set_with_primes range_constraint_set = create_new_set_with_primes(domain_constraint_set) - from schedule_checker.sched_check_utils import ( - add_and_name_dims_to_isl_set - ) new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' domain_to_intersect = add_and_name_dims_to_isl_set( domain_constraint_set, isl.dim_type.out, ["s"], new_pose) # TODO don't hardcode 's' diff --git a/example_dependency_checking.py b/example_dependency_checking.py index 0b3444c49..e394e779b 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -4,7 +4,6 @@ from schedule_checker.dependency import ( Dependency, DependencyType as DT, create_dependency_constraint, - append_apostrophes, ) from schedule_checker.lexicographic_order_map import ( make_lex_mapping_tuple_pairs, @@ -14,8 +13,10 @@ from schedule_checker.lexicographic_order_map import ( get_space, ) from schedule_checker.schedule import Statement -from schedule_checker.sched_check_utils import prettier_map_string - +from schedule_checker.sched_check_utils import ( + prettier_map_string, + append_apostrophes, +) # make example kernel knl = lp.make_kernel( diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py index d26b268a0..00c26e1b3 100644 --- a/example_lex_map_creation.py +++ b/example_lex_map_creation.py @@ -3,7 +3,6 @@ from schedule_checker.dependency import ( Dependency, DependencyType as DT, create_dependency_constraint, - append_apostrophes, ) from schedule_checker.lexicographic_order_map import ( make_lex_mapping_tuple_pairs, diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 25ab708b9..41377485f 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -141,7 +141,7 @@ def create_symbolic_lex_mapping( if in_names is None: in_names = ["i%s" % (i) for i in range(n_dims)] if out_names is None: - from schedule_checker.dependency import append_apostrophes + from schedule_checker.sched_check_utils import append_apostrophes out_names = append_apostrophes(in_names) #if dim_bound_vals is None: # raise NotImplementedError("dim_bound_vals cannot be None") diff --git a/sched_check_utils.py b/sched_check_utils.py index e1b9eb7cb..37fb3843a 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -51,11 +51,16 @@ def add_missing_set_dims_to_map_indims(islmap, islset): return new_map +def make_islvars_with_var_primes(var_names, param_names): + return isl.make_zero_and_vars( + var_names+append_apostrophes(var_names), param_names) + + def _create_positive_set_with_bounds( var_names, param_names, upper_bounds): # TODO assumes lower bound is zero - islvars = _make_islvars_with_var_primes(var_names, param_names) + islvars = make_islvars_with_var_primes(var_names, param_names) bounded_set = islvars[0].eq_set(islvars[0]) # initialize to True @@ -70,3 +75,10 @@ def _create_positive_set_with_bounds( & islvars[p].eq_set(islvars[0]+b) return bounded_set + + +def append_apostrophes(strings): + if not isinstance(strings, list): + raise ValueError("append_apostrophes did not receive a list") + else: + return [s+"'" for s in strings] diff --git a/schedule.py b/schedule.py index 1cf2a93a1..d1613e7bf 100644 --- a/schedule.py +++ b/schedule.py @@ -258,7 +258,7 @@ class LexSchedule(object): create_explicit_map_from_tuples, get_space, ) - from schedule_checker.dependency import append_apostrophes + from schedule_checker.sched_check_utils import append_apostrophes # TODO lower bound may not be zero lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(), -- GitLab From 3b8a3c4dcab7a1501e4b5c150ec2adad8f40d741 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 28 May 2019 02:20:57 -0500 Subject: [PATCH 026/183] fixed bugs in loopy schedule traversal for lex schedule creation, and removed final unnecessary iname bound gathering/usage --- example_schedule_creation.py | 72 +++++---------------------- schedule.py | 95 +++++------------------------------- 2 files changed, 25 insertions(+), 142 deletions(-) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index f8aa90788..d8d2db29d 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -15,67 +15,27 @@ from schedule_checker.lexicographic_order_map import ( from schedule_checker.sched_check_utils import prettier_map_string -def get_iname_bounds_dict(knl, all_inames_ordered, _set_arbitrary_bounds=None): - # TODO don't require explicit bounds - - if _set_arbitrary_bounds: - return dict((iname, _set_arbitrary_bounds) for iname in all_inames_ordered) - - from loopy.symbolic import aff_to_expr - from loopy.isl_helpers import static_max_of_pw_aff - from loopy.isl_helpers import static_value_of_pw_aff - - def _param_in_expr_hack(expr, all_params): - expr_str = str(expr) - for p in all_params: - if p in expr_str: - return p - return None - - bounds = {} - all_params = knl.all_params() - for iname in all_inames_ordered: - #bounds_record = knl.get_iname_bounds(iname, constants_only=True) - bounds_record = knl.get_iname_bounds(iname) - (_, iname_min_aff), = bounds_record.lower_bound_pw_aff.get_pieces() - (_, iname_max_aff), = bounds_record.upper_bound_pw_aff.get_pieces() - iname_min_aff = aff_to_expr(iname_min_aff) - iname_max_aff = aff_to_expr(iname_max_aff) - param_bound_min = _param_in_expr_hack(iname_min_aff, all_params) - param_bound_max = _param_in_expr_hack(iname_max_aff, all_params) - - if param_bound_min is None: - param_bound_min = int(iname_min_aff) # TODO what if this fails? - if param_bound_max is None: - param_bound_max = int(iname_max_aff)+1 # TODO what if this fails? - - dom = knl.get_inames_domain(iname) - - #int_bounds[iname] = [ - bounds[iname] = [ - param_bound_min, - param_bound_max, - ] - #assert all(isinstance(i,int) for i in int_bounds[iname]) - return bounds - # make example kernel knl = lp.make_kernel( - #"{[i,j]: 0<=i,j<2}", #"{[i,j]: 0<=i<2 and 1<=j<3}", #"{[i,j]: pi_lo<=itemp = b[i,j] {id=0}", "a[i,j] = temp + 1 {id=1,dep=0}", - "c[i,j] = d[i,j] {id=2}" + "c[i,j] = d[i,j] {id=2}", + "out[t,tt] = in[t,tt] {id=3}", ], - name="example", + name="example_blah", #assumptions="pi_lo,pi_up,pj_lo,pj_up >= 1", - assumptions="pi_up,pj_up >= 1", + #assumptions="pi_up,pj_up >= 1", + #assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", + assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", lang_version=(2018, 2) ) -knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32}) +#knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32}) +knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32, "in": np.float32}) knl = lp.tag_inames(knl, {"i": "l.0"}) knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) @@ -111,25 +71,19 @@ def get_iname_concurrency_dict(inames, knl): return conc_dict # Get schedule ------------------------------------------------------ -iname_bounds = get_iname_bounds_dict(knl, all_inames_ordered) - domains = {} for iname in all_inames_ordered: domains[iname] = knl.get_inames_domain(iname) print("domains:") print(domains) -print("iname bounds:") -print(iname_bounds) -sched = LexSchedule(knl, iname_bounds) # TODO do we really need iname bounds here? -#print("LexSchedule before processing:") -#print(sched) +sched = LexSchedule(knl) +print("LexSchedule before processing:") +print(sched) -#example_sched_explicit = sched.enumerate_symbolic_inames_and_create_explicit_isl_map(iname_bounds) sched_map_symbolic = sched.create_symbolic_isl_map(domains) print("LexSchedule after processing:") print(sched) - # ------------------------------------------------------------------- print("LexSched (valid):") diff --git a/schedule.py b/schedule.py index d1613e7bf..34ce1553f 100644 --- a/schedule.py +++ b/schedule.py @@ -47,39 +47,33 @@ class LexSchedule(object): def __init__( self, knl, - iname_bounds, ): self.lex_schedule = OrderedDict() # statement instance: lex point self.inames_enumerated = [] # symbolic inames in sched that have been enumerated into explicit statement instances self.inames_not_enumerated = [] # TODO better way to do this self.lp_insnid_to_int_sid = {} + assert not any(iname == 's' for iname in knl.all_inames()) from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) - cur_nest_lex_prefix = [] + next_insn_lex_pt = [0] + # TODO assumes perfect loop nesting for sched_item in knl.schedule: if isinstance(sched_item, EnterLoop): iname = sched_item.iname - #conc_dict = get_iname_concurrency_dict([iname], knl) - #print("EnterLoop: %s" % (conc_dict)) if self: - cur_nest_lex_prefix.append(self.get_last_lex_pt()[-1]) - else: - cur_nest_lex_prefix.append(0) - cur_nest_lex_prefix.append(iname) + next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 + next_insn_lex_pt.append(iname) + next_insn_lex_pt.append(0) elif isinstance(sched_item, LeaveLoop): - #conc_dict = get_iname_concurrency_dict([sched_item.iname], knl) - #print("LeaveLoop: %s" % (conc_dict)) - cur_nest_lex_prefix.pop() # pop loop variable - cur_nest_lex_prefix.pop() # pop insn ct variable + next_insn_lex_pt.pop() + next_insn_lex_pt.pop() + next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 elif isinstance(sched_item, RunInstruction): self.add_new_lp_insnid(sched_item.insn_id) insn_id_int = self.lp_insnid_to_int_sid[sched_item.insn_id] - #inames = knl.id_to_insn[insn_id].within_inames - #conc_dict = get_iname_concurrency_dict(inames, knl) - #print("RunInstruction: id: %s; inames: %s" % (sched_item.insn_id, conc_dict)) - self.append_item( - (insn_id_int,), - cur_nest_lex_prefix + [self.get_next_lex_val_in_series(cur_nest_lex_prefix, iname_bounds)]) + + self.append_item((insn_id_int,), next_insn_lex_pt[:]) + next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 elif isinstance(sched_item, Barrier): pass else: @@ -141,20 +135,7 @@ class LexSchedule(object): from schedule_checker.lexicographic_order_map import get_space return get_space(params_sched, in_names_sched, out_names_sched) - #def get_space_for_symbolic_sched(self, iname_bounds): def get_space_for_symbolic_sched(self): - """ - iname_bound_params = [] - for iname in self.inames_not_enumerated: - lo, up = iname_bounds[iname] - if not isinstance(lo, int): - #iname_bound_params.append("p"+iname+"up") - iname_bound_params.append(lo) - if not isinstance(up, int): - #iname_bound_params.append("p"+iname+"up") - iname_bound_params.append(up) - """ - #params_sched = ["ps"] + iname_bound_params params_sched = [] in_names_sched = ["s"] + self.inames_not_enumerated out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] @@ -194,22 +175,6 @@ class LexSchedule(object): def get_last_lex_pt(self): return self.lex_schedule[self.get_last_schedule_item()] - def get_next_lex_val_in_series(self, cur_nest_lex_prefix, iname_bounds): - if not self.lex_schedule: - return 0 - last_lex_pt = self.get_last_lex_pt() - #print(last_lex_pt) - if len(last_lex_pt) == len(cur_nest_lex_prefix) + 1: - # we're still in same loop, increment current lex dim val - return last_lex_pt[-1] + 1 - elif len(last_lex_pt) > len(cur_nest_lex_prefix) + 1: - # we just ended one or more loops, increment appropriate lex dim val - return last_lex_pt[len(cur_nest_lex_prefix)] + 1 - else: # len(last_lex_pt) < cur_nest_lex_prefix + 1: - # we just entered one or more loops - #return 0 - return iname_bounds[cur_nest_lex_prefix[-1]][0] - def create_explicit_isl_map(self, sched_space): from schedule_checker.lexicographic_order_map import create_explicit_map_from_tuples return create_explicit_map_from_tuples(list(self.items()), sched_space) @@ -323,39 +288,3 @@ class LexSchedule(object): def __str__(self): return str(list(self.lex_schedule.items())) - # TODO remove after stripping useful parts: - """ - def add_run_instructions_within_loop_nesting( - self, - insn_ids_ordered, - nest_order, # sequential lex dims in nest order (other lex dims assumed parallel) - iname_bounds, # dict w/bounds for sequential lex dims - concurrent_inames, - ): - # TODO don't pass explicit iname bounds, get them from kernel - - # TODO for now, assuming loop nestings are not re-encountered - - # create a lex dim for this set of (sequential) insns - self.add_lex_dim("s"+"".join(str(i) for i in insn_ids_ordered)) - - nested_iname_bounds_ordered = [iname_bounds[i] for i in nest_order] - import itertools - all_iname_val_sets = list( - itertools.product(*[range(b) for b in nested_iname_bounds_ordered])) - #TODO is there an order guarantee with product? - - for n_insn, insn_id in enumerate(insn_ids_ordered): # for each statement - st = Statement(insn_id, concurrent_inames+nest_order) - new_st_instances = [] - for iname_vals in all_iname_val_sets: - iname_vals = list(iname_vals) - # TODO handle concurrent inames - concurrent_iname_vals = [-1 for iname in range(len(concurrent_inames))] - st_i = StatementInstance( - st, - dict(zip(concurrent_inames+nest_order, - concurrent_iname_vals+iname_vals))) - self.lex_schedule[st_i] = iname_vals+[n_insn] - """ - -- GitLab From 1a8c83b1555979811e9a1862a1dde23412fefdd6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 28 May 2019 05:48:21 -0500 Subject: [PATCH 027/183] removed get_dim_for_isl_space_var() because found redundant islpy function; improved add_missing_set_dims_to_map_indims() (error when names out of order); added _get_knl_domain_for_sched_checking() and order_var_names_to_match_islset() --- sched_check_utils.py | 47 +++++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 37fb3843a..3b4a28d0d 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -14,10 +14,7 @@ def get_islvars_from_space(space): out_names = space.get_var_names(isl.dim_type.out) return isl.make_zero_and_vars(in_names+out_names, param_names) -def get_dim_for_isl_space_var(space, dim_type, var): - return space.get_var_names(dim_type).index(param) - -def add_and_name_dims_to_isl_set(isl_set, dim_type, names, new_pose_start): +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) @@ -33,21 +30,22 @@ def add_missing_set_dims_to_map_indims(islmap, islset): new_map = islmap.copy() for i in range(islset.n_dim()): new_dim_name = islset.get_dim_name(isl.dim_type.out, i) - - old_map_in_names = new_map.get_var_names(isl.dim_type.in_) - if len(old_map_in_names) > i and old_map_in_names[i] == new_dim_name: - continue - else: + # does new_dim_name already exist in map? + dim_idx = new_map.find_dim_by_name(isl.dim_type.in_, new_dim_name) + if dim_idx == -1: + # new map needs dim, insert it new_map = new_map.insert_dims(isl.dim_type.in_, i, 1) new_map = new_map.set_dim_name(isl.dim_type.in_, i, new_dim_name) - """ - old_map_out_names = new_map.get_var_names(isl.dim_type.out) - if len(old_map_out_names) > i and old_map_out_names[i] == new_dim_name: - continue else: - new_map = new_map.insert_dims(isl.dim_type.out, i, 1) - new_map = new_map.set_dim_name(isl.dim_type.out, i, new_dim_name) - """ + # new_map already has new_dim_name + if dim_idx == i: + # and it's already in the right spot + continue + else: + # move it + # TODO how do we move these? move_dims doesn't work for same dim_type + print("%s not in right spot" % (new_dim_name)) + raise ValueError("(this should not happen)") return new_map @@ -82,3 +80,20 @@ def append_apostrophes(strings): raise ValueError("append_apostrophes did not receive a list") else: return [s+"'" for s in strings] + + +def _get_knl_domain_for_sched_checking(knl): + all_inames = list(knl.all_inames()) + domain_union = knl.get_inames_domain(all_inames[0]) + for iname in all_inames[1:]: + domain_union = domain_union.union(knl.get_inames_domain(iname)) + return domain_union + + +def order_var_names_to_match_islset(var_names, islset): + name_order = islset.get_var_names(isl.dim_type.out) + names_ordered_to_match_islset = [] + for v in name_order: + if v in var_names: + names_ordered_to_match_islset.append(v) + return names_ordered_to_match_islset -- GitLab From 4014ed06c4a38eb3f231cb9962a688898016e2e1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 28 May 2019 05:49:07 -0500 Subject: [PATCH 028/183] make sure iname ordering in lex sched matches iname ordering in domain; also new example knl (mm) for sched testing --- dependency.py | 6 +-- example_schedule_creation.py | 100 ++++++++++++++++++++--------------- lexicographic_order_map.py | 2 +- schedule.py | 25 +++++---- 4 files changed, 73 insertions(+), 60 deletions(-) diff --git a/dependency.py b/dependency.py index 2c9884f3f..4eb518809 100644 --- a/dependency.py +++ b/dependency.py @@ -59,7 +59,7 @@ def create_dependency_constraint( from schedule_checker.sched_check_utils import ( make_islvars_with_var_primes, append_apostrophes, - add_and_name_dims_to_isl_set, + add_dims_to_isl_set, create_new_set_with_primes, ) # This function uses the dependencies given to create the following constraint: @@ -118,9 +118,9 @@ def create_dependency_constraint( range_constraint_set = create_new_set_with_primes(domain_constraint_set) new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' - domain_to_intersect = add_and_name_dims_to_isl_set( + domain_to_intersect = add_dims_to_isl_set( domain_constraint_set, isl.dim_type.out, ["s"], new_pose) # TODO don't hardcode 's' - range_to_intersect = add_and_name_dims_to_isl_set( + range_to_intersect = add_dims_to_isl_set( range_constraint_set, isl.dim_type.out, ["s'"], new_pose) # TODO don't hardcode 's' map_with_loop_domain_constraints = all_constraints_map.intersect_domain(domain_to_intersect).intersect_range(range_to_intersect) diff --git a/example_schedule_creation.py b/example_schedule_creation.py index d8d2db29d..c231227b9 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -12,36 +12,60 @@ from schedule_checker.lexicographic_order_map import ( get_statement_ordering_map, get_space, ) -from schedule_checker.sched_check_utils import prettier_map_string - +from schedule_checker.sched_check_utils import ( + prettier_map_string, + _get_knl_domain_for_sched_checking, + order_var_names_to_match_islset, +) -# make example kernel -knl = lp.make_kernel( - #"{[i,j]: 0<=i<2 and 1<=j<3}", - #"{[i,j]: pi_lo<=itemp = b[i,j] {id=0}", - "a[i,j] = temp + 1 {id=1,dep=0}", - "c[i,j] = d[i,j] {id=2}", - "out[t,tt] = in[t,tt] {id=3}", - ], - name="example_blah", - #assumptions="pi_lo,pi_up,pj_lo,pj_up >= 1", - #assumptions="pi_up,pj_up >= 1", - #assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", - assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", - lang_version=(2018, 2) - ) -#knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32}) -knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32, "in": np.float32}) -knl = lp.tag_inames(knl, {"i": "l.0"}) -knl = lp.preprocess_kernel(knl) -knl = lp.get_one_scheduled_kernel(knl) +knl_choice = "example" +#knl_choice = "matmul" + +if knl_choice == "example": + # make example kernel + knl = lp.make_kernel( + #"{[i,j]: 0<=i<2 and 1<=j<3}", + #"{[i,j]: pi_lo<=itemp = b[i,j] {id=0}", + "a[i,j] = temp + 1 {id=1,dep=0}", + "c[i,j] = d[i,j] {id=2}", + "out[t,tt] = in[t,tt] {id=3}", + ], + name="example", + #assumptions="pi_lo,pi_up,pj_lo,pj_up >= 1", + #assumptions="pi_up,pj_up >= 1", + #assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", + assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", + lang_version=(2018, 2) + ) + #knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32}) + knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32, "in": np.float32}) + knl = lp.tag_inames(knl, {"i": "l.0"}) + knl = lp.preprocess_kernel(knl) + knl = lp.get_one_scheduled_kernel(knl) +elif knl_choice == "matmul": + bsize = 16 + knl = lp.make_kernel( + "{[i,k,j]: 0<=i lex time):") print(sched_map_symbolic.space) @@ -98,8 +120,6 @@ print("------------------------------------------------------------------------- lex_map_symbolic = sched.get_lex_map_symbolic() -#print("lex map explicit:") -#print(prettier_map_string(lex_map_explicit)) print("lex map symbolic:") print(prettier_map_string(lex_map_symbolic)) print("space (lex time -> lex time):") @@ -124,12 +144,6 @@ from schedule_checker.dependency import ( statement_var = 's' -domains_list = list(domains.values()) -domain_union = domains_list[0] -#TODO is union the right thing to do here? -for dom in domains_list[1:]: - domain_union = domain_union.union(dom) - # i is parallel, suppose we want to enforce the following: # for a given i, statement 0 happens before statement 1 # i dependency is none, j dependency is `prior` diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 41377485f..cfbe938e2 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -83,8 +83,8 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): len(in_names), len(out_names)) from schedule_checker.sched_check_utils import add_missing_set_dims_to_map_indims + # TODO make sure these always align properly result_map = add_missing_set_dims_to_map_indims(result_map, domain_to_intersect) - return result_map.intersect_domain(domain_to_intersect) diff --git a/schedule.py b/schedule.py index 34ce1553f..481c7125f 100644 --- a/schedule.py +++ b/schedule.py @@ -184,24 +184,23 @@ class LexSchedule(object): sched_space = self.get_space_for_explicit_sched() return self.create_explicit_isl_map(sched_space) - def create_symbolic_isl_map(self, domains): + def create_symbolic_isl_map(self, domain, inames): + # TODO if inames will always match domain out vars, don't need to pass them from schedule_checker.lexicographic_order_map import ( create_symbolic_map_from_tuples, ) from schedule_checker.sched_check_utils import ( - add_and_name_dims_to_isl_set + add_dims_to_isl_set ) - all_inames = list(domains.keys()) - self.add_symbolic_inames_to_statement_instances(all_inames) + domain_iname_order = domain.get_var_names(isl.dim_type.out) + inames_ordered_to_match_domain = [] + for iname in domain_iname_order: + if iname in inames: + inames_ordered_to_match_domain.append(iname) + self.add_symbolic_inames_to_statement_instances( + inames_ordered_to_match_domain) sched_space = self.get_space_for_symbolic_sched() - # intersect all domains for symbolic (non-enumerated) - # inames found in statement instances - domain_intersection = domains[self.inames_not_enumerated[0]] - #TODO what if self.inames_not_enumerated is empty? - for iname in self.inames_not_enumerated[1:]: - domain_intersection = domain_intersection.intersect(domains[iname]) - # TODO maybe don't project this out, constraints may involve any iname later... """ domain_stripped = domain_intersection.project_out_except( @@ -210,8 +209,8 @@ class LexSchedule(object): ) """ new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' - domain_to_intersect = add_and_name_dims_to_isl_set( - domain_intersection, isl.dim_type.out, ['s'], new_pose) # TODO don't hardcode 's' + domain_to_intersect = add_dims_to_isl_set( + domain, isl.dim_type.out, ['s'], new_pose) # TODO don't hardcode 's' return create_symbolic_map_from_tuples( list(self.items()), sched_space, domain_to_intersect) -- GitLab From fb412e90c5bb36c4eda9521399831d32b8a50fb0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 28 May 2019 07:32:34 -0500 Subject: [PATCH 029/183] made mechanism for gathering dependencies from legacy loopy kernels --- dependency.py | 44 ++++++++++++++++++ example_lex_map_creation.py | 1 - example_schedule_creation.py | 87 +++++++++++++++++++----------------- 3 files changed, 90 insertions(+), 42 deletions(-) diff --git a/dependency.py b/dependency.py index 4eb518809..0f5a0cb48 100644 --- a/dependency.py +++ b/dependency.py @@ -49,6 +49,7 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): return constraint_map.move_dims(dim_type.out, 0, dim_type.in_, mv_count, mv_count) +# TODO make this take in a set of dep sets and intersect all the constraints def create_dependency_constraint( dependencies, all_inames_ordered, @@ -127,3 +128,46 @@ def create_dependency_constraint( #blah2 = isl.Map("[pi_up, pj_up] -> { [s = 1, i, j] -> [s' = 0, i' = i, j'] : 0 <= i < pi_up and 0 <= j < pj_up and j' > j and 0 <= j' < pj_up}") #assert blah2 == map_with_loop_domain_constraints return map_with_loop_domain_constraints + + +def get_concurrent_inames(knl): + from loopy.kernel.data import LocalIndexTag, GroupIndexTag + conc_inames = set() + all_inames = knl.all_inames() + for iname in all_inames: + iname_tags = knl.iname_to_tags.get(iname, None) + if iname_tags and any( + isinstance(tag, (LocalIndexTag, GroupIndexTag)) for tag in iname_tags): + conc_inames.add(iname) + return conc_inames, all_inames-conc_inames + + +def create_dependencies_from_legacy_knl(knl): + from schedule_checker.schedule import Statement + from schedule_checker.dependency import ( + Dependency, + DependencyType as DT, + ) + conc_inames, non_conc_inames = get_concurrent_inames(knl) + all_inames = list(knl.all_inames()) + dep_sets = [] + for insn_after in knl.instructions: + for insn_before_id in insn_after.depends_on: + dep_set = [] + insn_before = knl.id_to_insn[insn_before_id] + insn_before_inames = insn_before.within_inames + insn_after_inames = insn_after.within_inames + #print("%s (%s) -> %s (%s)" % ( + # insn_before.id, insn_before_inames, insn_after.id, insn_after_inames)) + shared_inames = insn_before_inames & insn_after_inames + shared_conc_inames = shared_inames & conc_inames + shared_non_conc_inames = shared_inames & non_conc_inames + #print("shared conc/non-conc %s/%s" % (shared_conc_inames, shared_non_conc_inames)) + s_before = Statement(insn_before.id, all_inames) + s_after = Statement(insn_after.id, all_inames) + for non_conc_iname in shared_non_conc_inames: + dep_set.append(Dependency(s_before, s_after, DT.SAME, non_conc_iname)) + for conc_iname in shared_conc_inames: + dep_set.append(Dependency(s_before, s_after, DT.ALL, conc_iname)) + dep_sets.append(dep_set) + return dep_sets diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py index 00c26e1b3..d94d4b313 100644 --- a/example_lex_map_creation.py +++ b/example_lex_map_creation.py @@ -2,7 +2,6 @@ import islpy as isl from schedule_checker.dependency import ( Dependency, DependencyType as DT, - create_dependency_constraint, ) from schedule_checker.lexicographic_order_map import ( make_lex_mapping_tuple_pairs, diff --git a/example_schedule_creation.py b/example_schedule_creation.py index c231227b9..b598ff99f 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation.py @@ -4,6 +4,8 @@ import numpy as np from schedule_checker.dependency import ( Dependency, DependencyType as DT, + create_dependencies_from_legacy_knl, + create_dependency_constraint, ) from schedule_checker.schedule import Statement, StatementInstance, LexSchedule from schedule_checker.sched_check_utils import prettier_map_string @@ -18,8 +20,8 @@ from schedule_checker.sched_check_utils import ( order_var_names_to_match_islset, ) -knl_choice = "example" -#knl_choice = "matmul" +#knl_choice = "example" +knl_choice = "matmul" if knl_choice == "example": # make example kernel @@ -29,10 +31,10 @@ if knl_choice == "example": #"{[i,j]: 0<=itemp = b[i,j] {id=0}", - "a[i,j] = temp + 1 {id=1,dep=0}", - "c[i,j] = d[i,j] {id=2}", - "out[t,tt] = in[t,tt] {id=3}", + "<>temp = b[i,j] {id=insn_a}", + "a[i,j] = temp + 1 {id=insn_b,dep=insn_a}", + "c[i,j] = d[i,j] {id=insn_c}", + "out[t,tt] = in[t,tt] {id=insn_d}", ], name="example", #assumptions="pi_lo,pi_up,pj_lo,pj_up >= 1", @@ -78,22 +80,6 @@ for sched_item in knl.schedule: print(sched_item) print("="*80) -def get_iname_concurrency_dict(inames, knl): - from loopy.kernel.data import LocalIndexTag, GroupIndexTag - conc_dict = {} - for iname in inames: - iname_tags = knl.iname_to_tags.get(iname, None) - concurrent = False - if iname_tags: - if len(iname_tags) > 1: - 1/0 - else: - iname_tag = list(iname_tags)[0] - if isinstance(iname_tag, (LocalIndexTag, GroupIndexTag)): - concurrent = True - conc_dict[iname] = "concurrent" if concurrent else "sequential" - return conc_dict - # Get schedule ------------------------------------------------------ domain_union = _get_knl_domain_for_sched_checking(knl) @@ -138,12 +124,9 @@ print(prettier_map_string(SIO_symbolic_valid)) print("space (statement instances -> statement instances):") print(SIO_symbolic_valid.space) -from schedule_checker.dependency import ( - create_dependency_constraint, -) -statement_var = 's' +""" # i is parallel, suppose we want to enforce the following: # for a given i, statement 0 happens before statement 1 # i dependency is none, j dependency is `prior` @@ -160,23 +143,45 @@ deps = [ Dependency(s0, s1, DT.NONE, "i"), Dependency(s0, s1, DT.PRIOR, "j"), ] +""" + +#For every shared (between depender and dependee) non-concurrent iname Introduce a same dep +# (Perform voodoo guesswork to determine whether a ‘prior’ dep is needed) +#For every shared (between depender and dependee) concurrent iname Introduce an all dep + +print("----------------------------------------------------------------------") +dep_sets = create_dependencies_from_legacy_knl(knl) +print("Dependency sets:") +for dep_set in dep_sets: + for dep in dep_set: + print(dep) + print("") print("----------------------------------------------------------------------") -print([str(dep) for dep in deps]) -constraint_map = create_dependency_constraint( - deps, - all_inames_ordered, - statement_var, - domain_union, - sched.lp_insnid_to_int_sid, - ) -print("constraint map:") -print(prettier_map_string(constraint_map)) -print("space (statment instances -> statement instances):") -print(constraint_map.space) - -assert constraint_map.space == SIO_symbolic_valid.space +print("dict{lp insn id : sched sid int}:") +print(sched.lp_insnid_to_int_sid) +print("----------------------------------------------------------------------") +statement_var = 's' +sched_is_valid = True +for dep_set in dep_sets: + # TODO make create_dep_constraint accept whole set of dep_sets + constraint_map = create_dependency_constraint( + dep_set, + all_inames_ordered, + statement_var, + domain_union, + sched.lp_insnid_to_int_sid, + ) + #print("constraint map:") + #print(prettier_map_string(constraint_map)) + #print("space (statment instances -> statement instances):") + #print(constraint_map.space) + + assert constraint_map.space == SIO_symbolic_valid.space + if not constraint_map.is_subset(SIO_symbolic_valid): + sched_is_valid = False + print("is valid sched valid? constraint map subset of SIO?") -print(constraint_map.is_subset(SIO_symbolic_valid)) +print(sched_is_valid) ''' -- GitLab From 4174d9349dd9fd05bb9bf86928f9490379a13130 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 10 Jun 2019 23:54:11 -0500 Subject: [PATCH 030/183] removed unused code from symbolic lex map creatoin --- lexicographic_order_map.py | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index cfbe938e2..f4c51f68c 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -81,7 +81,11 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): result_map = result_map.move_dims( dim_type.out, 0, dim_type.in_, len(in_names), len(out_names)) - + """ + result_map_vars_in = result_map.space.get_var_names(isl.dim_type.in_) + domain_stripped = domain_to_intersect.project_out_except(result_map_vars_in, [isl.dim_type.set]) + return result_map.intersect_domain(domain_stripped) + """ from schedule_checker.sched_check_utils import add_missing_set_dims_to_map_indims # TODO make sure these always align properly result_map = add_missing_set_dims_to_map_indims(result_map, domain_to_intersect) @@ -130,39 +134,21 @@ def get_space(param_names, in_names, out_names): # from other things...) def create_symbolic_lex_mapping( n_dims, - #param_names=None, in_names=None, out_names=None, - #dim_bound_vals=None, - #extra_params=None, ): - #if param_names is None: - # param_names = [["lo%s" % (i), "up%s" % (i)] for i in range(n_dims)] if in_names is None: in_names = ["i%s" % (i) for i in range(n_dims)] if out_names is None: from schedule_checker.sched_check_utils import append_apostrophes out_names = append_apostrophes(in_names) - #if dim_bound_vals is None: - # raise NotImplementedError("dim_bound_vals cannot be None") - #assert len(in_names) == len(out_names) == len(param_names) == len(dim_bound_vals) == n_dims assert len(in_names) == len(out_names) == n_dims dim_type = isl.dim_type - #from schedule_checker.sched_check_utils import flatten_2d_list - - #params_in_dim_bounds = [] - #for v in flatten_2d_list(dim_bound_vals): - # if not isinstance(v, int): - # params_in_dim_bounds.append(v) islvars = isl.make_zero_and_vars( in_names+out_names, - #flatten_2d_list(param_names)) - #flatten_2d_list(param_names)+params_in_dim_bounds) - #extra_params) []) - # [param for param_pair in param_names for param in param_pair]) # create constraint enforcing lex ordering, e.g., in the 3-dim case: # i0 < o0 or ((i0 = o0) and (i1 < o1)) -- GitLab From c1576ce8eb330264fcda096a9cf1c12dc6942c99 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 10 Jun 2019 23:55:33 -0500 Subject: [PATCH 031/183] added option in sched creation to only include specific insns --- schedule.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/schedule.py b/schedule.py index 481c7125f..a314b8b51 100644 --- a/schedule.py +++ b/schedule.py @@ -47,8 +47,9 @@ class LexSchedule(object): def __init__( self, knl, + include_only_insn_ids=None, ): - self.lex_schedule = OrderedDict() # statement instance: lex point + self.lex_schedule = OrderedDict() # statement instance: lex point self.inames_enumerated = [] # symbolic inames in sched that have been enumerated into explicit statement instances self.inames_not_enumerated = [] # TODO better way to do this self.lp_insnid_to_int_sid = {} @@ -69,11 +70,12 @@ class LexSchedule(object): next_insn_lex_pt.pop() next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 elif isinstance(sched_item, RunInstruction): - self.add_new_lp_insnid(sched_item.insn_id) - insn_id_int = self.lp_insnid_to_int_sid[sched_item.insn_id] + if include_only_insn_ids is None or sched_item.insn_id in include_only_insn_ids: + self.add_new_lp_insnid(sched_item.insn_id) + insn_id_int = self.lp_insnid_to_int_sid[sched_item.insn_id] - self.append_item((insn_id_int,), next_insn_lex_pt[:]) - next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 + self.append_item((insn_id_int,), next_insn_lex_pt[:]) + next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 elif isinstance(sched_item, Barrier): pass else: -- GitLab From 2d6c1c30b83e35587e0630d874911388ab4785c4 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 10 Jun 2019 23:56:41 -0500 Subject: [PATCH 032/183] added all_iname_domains_equal(knl) fn --- sched_check_utils.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 3b4a28d0d..48109a301 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -82,7 +82,14 @@ def append_apostrophes(strings): return [s+"'" for s in strings] -def _get_knl_domain_for_sched_checking(knl): +def _union_of_sets(set_list): + union = set_list[0] + for s in set_list[1:]: + union = union.union(s) + return union + + +def _union_inames_domains(knl): all_inames = list(knl.all_inames()) domain_union = knl.get_inames_domain(all_inames[0]) for iname in all_inames[1:]: @@ -90,6 +97,16 @@ def _get_knl_domain_for_sched_checking(knl): return domain_union +def all_iname_domains_equal(knl): + all_inames = list(knl.all_inames()) + + first = knl.get_inames_domain(all_inames[0]) + for iname in all_inames[1:]: + if knl.get_inames_domain(iname) != first: + return False + return True + + def order_var_names_to_match_islset(var_names, islset): name_order = islset.get_var_names(isl.dim_type.out) names_ordered_to_match_islset = [] -- GitLab From c73839bfd341329ad714d0289d5bb6631347fa0a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 11 Jun 2019 00:02:06 -0500 Subject: [PATCH 033/183] created StatementDependency (and updated other relevant functions), possibly to replace Dependency, which holds all individual iname deps for a given pair of statements --- dependency.py | 135 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 133 insertions(+), 2 deletions(-) diff --git a/dependency.py b/dependency.py index 0f5a0cb48..0e2ad13e2 100644 --- a/dependency.py +++ b/dependency.py @@ -8,6 +8,7 @@ class DependencyType: ALL = "all" +# TODO remove old dep class class Dependency(object): def __init__( self, @@ -30,6 +31,26 @@ class Dependency(object): self.dep_type) +class StatementDependency(object): + def __init__( + self, + statement_before, + statement_after, + iname_deps, # {iname: dep_type} + ): + self.statement_before = statement_before + self.statement_after = statement_after + self.iname_deps = iname_deps + + + def __str__(self): + result = "%s --before->\n%s iff\n " % ( + self.statement_before, self.statement_after) + return result + " and\n ".join( + ["(%s dep: %s)" % (iname, dep_type) + for iname, dep_type in self.iname_deps.items()]) + + def create_equality_conjunction_set(names0, names1, islvars): # initialize set with constraint that is always true @@ -50,7 +71,7 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): # TODO make this take in a set of dep sets and intersect all the constraints -def create_dependency_constraint( +def create_dependency_constraint_old( dependencies, all_inames_ordered, statement_var, @@ -130,6 +151,81 @@ def create_dependency_constraint( return map_with_loop_domain_constraints +def create_dependency_constraint( + statement_dep, + all_inames_ordered, + statement_var, + domain_constraint_set, + sid_to_int, + ): + from schedule_checker.sched_check_utils import ( + make_islvars_with_var_primes, + append_apostrophes, + add_dims_to_isl_set, + create_new_set_with_primes, + ) + # This function uses the dependency given to create the following constraint: + # Statement [s,i,j] comes before statement [s',i',j'] iff + + # assumes statements are numbered sequentially + # (statement_bound = max statement id + 1) + + # make sure all dependencies involve different inames # TODO upate after allowing prior(i,k) + if len(set(statement_dep.iname_deps.keys()) + ) != len(statement_dep.iname_deps.keys()): + raise ValueError("All depencencies must apply to different inames.") + + statement_var_prime = statement_var+"'" + DT = DependencyType + islvars = make_islvars_with_var_primes( + [statement_var]+all_inames_ordered, + []) + + # initialize constraints to False + # this will disappear as soon as we add a constraint that is not DT.NONE + all_constraints_set = islvars[0].eq_set(islvars[0] + 1) + + for iname, dep_type in statement_dep.iname_deps.items(): + if dep_type == DT.NONE: + continue + + iname_prime = iname+"'" # i' + other_inames = all_inames_ordered.copy() + other_inames.remove(iname) # remaining inames, e.g., [j, k] + other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] + + # initialize constraint set with what we know about other inames (e.g., j = j', k = k') + constraint_set = create_equality_conjunction_set(other_inames, other_inames_prime, islvars) + if dep_type == DT.SAME: + constraint_set = constraint_set & islvars[iname].eq_set(islvars[iname_prime]) + elif dep_type == DT.PRIOR: + constraint_set = constraint_set & islvars[iname].lt_set(islvars[iname_prime]) + elif dep_type == DT.ALL: + constraint_set = constraint_set & islvars[0].eq_set(islvars[0]) # True + + s_before_int = sid_to_int[statement_dep.statement_before.sid] + s_after_int = sid_to_int[statement_dep.statement_after.sid] + constraint_set = constraint_set & islvars[statement_var].eq_set(islvars[0]+s_before_int) + constraint_set = constraint_set & islvars[statement_var_prime].eq_set(islvars[0]+s_after_int) + + all_constraints_set = all_constraints_set | constraint_set + + all_constraints_map = _convert_constraint_set_to_map(all_constraints_set, len(all_inames_ordered)+1) + + range_constraint_set = create_new_set_with_primes(domain_constraint_set) + + new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' + domain_to_intersect = add_dims_to_isl_set( + domain_constraint_set, isl.dim_type.out, ["s"], new_pose) # TODO don't hardcode 's' + range_to_intersect = add_dims_to_isl_set( + range_constraint_set, isl.dim_type.out, ["s'"], new_pose) # TODO don't hardcode 's' + + map_with_loop_domain_constraints = all_constraints_map.intersect_domain(domain_to_intersect).intersect_range(range_to_intersect) + #blah2 = isl.Map("[pi_up, pj_up] -> { [s = 1, i, j] -> [s' = 0, i' = i, j'] : 0 <= i < pi_up and 0 <= j < pj_up and j' > j and 0 <= j' < pj_up}") + #assert blah2 == map_with_loop_domain_constraints + return map_with_loop_domain_constraints + + def get_concurrent_inames(knl): from loopy.kernel.data import LocalIndexTag, GroupIndexTag conc_inames = set() @@ -142,7 +238,7 @@ def get_concurrent_inames(knl): return conc_inames, all_inames-conc_inames -def create_dependencies_from_legacy_knl(knl): +def create_dependencies_from_legacy_knl_old(knl): from schedule_checker.schedule import Statement from schedule_checker.dependency import ( Dependency, @@ -171,3 +267,38 @@ def create_dependencies_from_legacy_knl(knl): dep_set.append(Dependency(s_before, s_after, DT.ALL, conc_iname)) dep_sets.append(dep_set) return dep_sets + + +def create_dependencies_from_legacy_knl(knl): + from schedule_checker.schedule import Statement + DT = DependencyType + conc_inames, non_conc_inames = get_concurrent_inames(knl) + all_inames = list(knl.all_inames()) + deps = [] + for insn_after in knl.instructions: + for insn_before_id in insn_after.depends_on: + iname_deps = {} + insn_before = knl.id_to_insn[insn_before_id] + insn_before_inames = insn_before.within_inames + insn_after_inames = insn_after.within_inames + #print("%s (%s) -> %s (%s)" % ( + # insn_before.id, insn_before_inames, insn_after.id, insn_after_inames)) + shared_inames = insn_before_inames & insn_after_inames + shared_conc_inames = shared_inames & conc_inames + shared_non_conc_inames = shared_inames & non_conc_inames + #print("shared conc/non-conc %s/%s" % (shared_conc_inames, shared_non_conc_inames)) + s_before = Statement(insn_before.id, all_inames) + s_after = Statement(insn_after.id, all_inames) + #TODO should this be all_inames or within_inames? + #s_before = Statement(insn_before.id, insn_before_inames) + #s_after = Statement(insn_after.id, insn_after_inames) + # TODO or union? + #s_before = Statement(insn_before.id, insn_before_inames | insn_after_inames) + #s_after = Statement(insn_after.id, insn_before_inames | insn_after_inames) + + for non_conc_iname in shared_non_conc_inames: + iname_deps[non_conc_iname] = DT.SAME + for conc_iname in shared_conc_inames: + iname_deps[conc_iname] = DT.ALL + deps.append(StatementDependency(s_before, s_after, iname_deps)) + return deps -- GitLab From 3ef3a863989cc23ea2090c50a3e0fa7b92add151 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 11 Jun 2019 00:04:54 -0500 Subject: [PATCH 034/183] renamed example_sched_creation.py -> example_schedule_creation_old.py --- ...ion.py => example_schedule_creation_old.py | 50 +++++++++++++++---- 1 file changed, 40 insertions(+), 10 deletions(-) rename example_schedule_creation.py => example_schedule_creation_old.py (85%) diff --git a/example_schedule_creation.py b/example_schedule_creation_old.py similarity index 85% rename from example_schedule_creation.py rename to example_schedule_creation_old.py index b598ff99f..47876b51c 100644 --- a/example_schedule_creation.py +++ b/example_schedule_creation_old.py @@ -4,8 +4,8 @@ import numpy as np from schedule_checker.dependency import ( Dependency, DependencyType as DT, - create_dependencies_from_legacy_knl, - create_dependency_constraint, + create_dependencies_from_legacy_knl_old, + create_dependency_constraint_old, ) from schedule_checker.schedule import Statement, StatementInstance, LexSchedule from schedule_checker.sched_check_utils import prettier_map_string @@ -16,12 +16,14 @@ from schedule_checker.lexicographic_order_map import ( ) from schedule_checker.sched_check_utils import ( prettier_map_string, - _get_knl_domain_for_sched_checking, + _union_inames_domains, + all_iname_domains_equal, order_var_names_to_match_islset, ) -#knl_choice = "example" -knl_choice = "matmul" +knl_choice = "example" +#knl_choice = "matmul" +#knl_choice = "scan" if knl_choice == "example": # make example kernel @@ -67,7 +69,22 @@ elif knl_choice == "matmul": knl = lp.add_prefetch(knl, "b", ["j_inner", "k_inner"], default_tag="l.auto") knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) +elif knl_choice == "scan": + stride = 1 + n_scan = 16 + knl = lp.make_kernel( + "[n] -> {[i,j]: 0<=i statement instances):") #print(constraint_map.space) -- GitLab From 51074677a01d75506351193088f2b1d8ed6b26d5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 11 Jun 2019 00:05:55 -0500 Subject: [PATCH 035/183] new exampleschedule creation where pairs of statements with dependencies are tested individually --- example_dep_pairwise_schedule_creation.py | 349 ++++++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 example_dep_pairwise_schedule_creation.py diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py new file mode 100644 index 000000000..8fc92aebf --- /dev/null +++ b/example_dep_pairwise_schedule_creation.py @@ -0,0 +1,349 @@ +import islpy as isl +import loopy as lp +import numpy as np +from schedule_checker.dependency import ( + Dependency, + DependencyType as DT, + create_dependencies_from_legacy_knl, + create_dependency_constraint, +) +from schedule_checker.schedule import Statement, StatementInstance, LexSchedule +from schedule_checker.sched_check_utils import prettier_map_string +from schedule_checker.lexicographic_order_map import ( + create_explicit_map_from_tuples, + get_statement_ordering_map, + get_space, +) +from schedule_checker.sched_check_utils import ( + prettier_map_string, + _union_inames_domains, + all_iname_domains_equal, + order_var_names_to_match_islset, +) + +#knl_choice = "example" +#knl_choice = "matmul" +knl_choice = "scan" +#knl_choice = "dependent_domain" + +if knl_choice == "example": + # make example kernel + knl = lp.make_kernel( + #"{[i,j]: 0<=i<2 and 1<=j<3}", + #"{[i,j]: pi_lo<=itemp = b[i,j] {id=insn_a}", + "a[i,j] = temp + 1 {id=insn_b,dep=insn_a}", + "c[i,j] = d[i,j] {id=insn_c}", + "out[t,tt] = in[t,tt] {id=insn_d}", + ], + name="example", + #assumptions="pi_lo,pi_up,pj_lo,pj_up >= 1", + #assumptions="pi_up,pj_up >= 1", + #assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", + assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", + lang_version=(2018, 2) + ) + #knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32}) + knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32, "in": np.float32}) + knl = lp.tag_inames(knl, {"i": "l.0"}) + knl = lp.preprocess_kernel(knl) + knl = lp.get_one_scheduled_kernel(knl) +elif knl_choice == "matmul": + bsize = 16 + knl = lp.make_kernel( + "{[i,k,j]: 0<=i {[i,j]: 0<=i {[i]: 0<=i lex time):") + print(sched_map_symbolic.space) + + # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later + print("---------------------------------------------------------------------------") + #lex_map_explicit = sched.get_lex_map_explicit() + + lex_map_symbolic = sched.get_lex_map_symbolic() + + print("lex map symbolic:") + print(prettier_map_string(lex_map_symbolic)) + print("space (lex time -> lex time):") + print(lex_map_symbolic.space) + + # Statement instance ordering + print("----------------------------------------------------------------------") + #SIO_explicit_valid = get_statement_ordering_map( + # example_sched_explicit, lex_map_explicit) + #print("statement instance ordering explicit (valid_sched):") + #print(prettier_map_string(SIO_explicit_valid)) + SIO_symbolic_valid = get_statement_ordering_map( + sched_map_symbolic, lex_map_symbolic) + print("statement instance ordering symbolic (valid_sched):") + print(prettier_map_string(SIO_symbolic_valid)) + print("space (statement instances -> statement instances):") + print(SIO_symbolic_valid.space) + """ + # i is parallel, suppose we want to enforce the following: + # for a given i, statement 0 happens before statement 1 + # i dependency is none, j dependency is `prior` + + # make some dependencies manually for now: + s0 = Statement("0", ["i", "j"]) + s1 = Statement("1", ["i", "j"]) + s2 = Statement("2", ["i", "j"]) + #dep_s1_i = Dependency(s0, s1, DT.NONE, "i") + #dep_s1_j = Dependency(s0, s1, DT.PRIOR, "j") + #insn_to_deps = {"0":[], "1":[dep_s1_i, dep_s1_j], "2":[]} + + deps = [ + Dependency(s0, s1, DT.NONE, "i"), + Dependency(s0, s1, DT.PRIOR, "j"), + ] + """ + + print("----------------------------------------------------------------------") + print("dict{lp insn id : sched sid int}:") + print(sched.lp_insnid_to_int_sid) + print("----------------------------------------------------------------------") + + statement_var = 's' + # TODO make create_dep_constraint accept whole set of dep_sets + constraint_map = create_dependency_constraint( + statement_dep, + all_inames_ordered, + statement_var, + dom, + sched.lp_insnid_to_int_sid, + ) + print("constraint map:") + print(prettier_map_string(constraint_map)) + #print("space (statment instances -> statement instances):") + #print(constraint_map.space) + + assert constraint_map.space == SIO_symbolic_valid.space + if not constraint_map.is_subset(SIO_symbolic_valid): + sched_is_valid = False + +print("is valid sched valid? constraint map subset of SIO?") +print(sched_is_valid) + + +''' +all_inames = ['i', 'j'] +iname_params = ['p0', 'p1'] +iname_param_vals = [2, 2] +statement_var = 's' +statement_param = 'ps' +statement_bound = 2 + + + +s0 = Statement("0", ["i", "j"]) +s1 = Statement("1", ["i", "j"]) +print("Statements:") +print(s0) +print(s1) + +s0_00 = StatementInstance(s0, {"i": 0, "j": 0}) +s0_10 = StatementInstance(s0, {"i": 1, "j": 0}) +s0_01 = StatementInstance(s0, {"i": 0, "j": 1}) +s0_11 = StatementInstance(s0, {"i": 1, "j": 1}) +s1_00 = StatementInstance(s1, {"i": 0, "j": 0}) +s1_10 = StatementInstance(s1, {"i": 1, "j": 0}) +s1_01 = StatementInstance(s1, {"i": 0, "j": 1}) +s1_11 = StatementInstance(s1, {"i": 1, "j": 1}) +print("Statement instances:") +print(s0_00) +print(s0_10) +print(s0_01) +print(s0_11) +print(s1_00) +print(s1_10) +print(s1_01) +print(s1_11) + +state_inst_to_lex_time_dict = { + s0_00: (0,0), + s1_00: (0,1), + s0_10: (0,0), + s1_10: (0,1), + s0_01: (1,0), + s1_01: (1,1), + s0_11: (1,0), + s1_11: (1,1), + } + +sched = LexSchedule(state_inst_to_lex_time_dict) +print("LexSchedule:") +print(sched) + +# sched map should be this: +schedule_explicit_map = isl.Map( + """{ + [s,i,j] -> [0,0] : s = 0 and i = 0 and j = 0; + [s,i,j] -> [0,1] : s = 1 and i = 0 and j = 0; + [s,i,j] -> [0,0] : s = 0 and i = 1 and j = 0; + [s,i,j] -> [0,1] : s = 1 and i = 1 and j = 0; + [s,i,j] -> [1,0] : s = 0 and i = 0 and j = 1; + [s,i,j] -> [1,1] : s = 1 and i = 0 and j = 1; + [s,i,j] -> [1,0] : s = 0 and i = 1 and j = 1; + [s,i,j] -> [1,1] : s = 1 and i = 1 and j = 1; + }""") + +schedule_general_map = isl.Map("{[s,i,j] -> [j,s]}") + +print("Map representing schedule generally:") +print(schedule_general_map) + +# the following is equivalent to explicit map above: +schedule_explicit_map2 = isl.Map( + """{ + [s=0,i=0,j=0] -> [0,0]; + [s=1,i=0,j=0] -> [0,1]; + [s=0,i=1,j=0] -> [0,0]; + [s=1,i=1,j=0] -> [0,1]; + [s=0,i=0,j=1] -> [1,0]; + [s=1,i=0,j=1] -> [1,1]; + [s=0,i=1,j=1] -> [1,0]; + [s=1,i=1,j=1] -> [1,1]; + }""") +assert schedule_explicit_map2 == schedule_explicit_map == sched.get_isl_map() + +''' + +""" +dep_i_same = Dependency(s0, s1, "i", DependencyType.SAME) +dep_i_none = Dependency(s0, s1, "i", DependencyType.NONE) +dep_i_prior = Dependency(s0, s1, "i", DependencyType.PRIOR) +dep_i_all = Dependency(s0, s1, "i", DependencyType.ALL) +dep_j_same = Dependency(s0, s1, "j", DependencyType.SAME) +dep_j_none = Dependency(s0, s1, "j", DependencyType.NONE) +dep_j_prior = Dependency(s0, s1, "j", DependencyType.PRIOR) +dep_j_all = Dependency(s0, s1, "j", DependencyType.ALL) +print("Example dependencies: ") +print(dep_i_same) +print(dep_i_none) +print(dep_i_prior) +print(dep_i_all) +print(dep_j_same) +print(dep_j_none) +print(dep_j_prior) +print(dep_j_all) +""" -- GitLab From a0b4f9293943737cebd3b0cae69673c28e6340f6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 21 Jun 2019 17:59:06 -0500 Subject: [PATCH 036/183] for creating constraints for deps in legacy kernels, apply existing dep constraint creation logic only to set of inames that is *shared* between both instructions; for any non-shared inames, create a pseudo-ALL dep constraint that requires insn0 before insn1 iff True and s0=s0' and ... sn=sn' for all shared inames s0...sn; as a result, if there are no shared inames, insn0 always happens before insn1 --- dependency.py | 46 +++++++++++++++-------- example_dep_pairwise_schedule_creation.py | 13 ++++--- 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/dependency.py b/dependency.py index 0e2ad13e2..10f090798 100644 --- a/dependency.py +++ b/dependency.py @@ -185,24 +185,40 @@ def create_dependency_constraint( # this will disappear as soon as we add a constraint that is not DT.NONE all_constraints_set = islvars[0].eq_set(islvars[0] + 1) + before_inames = statement_dep.statement_before.active_inames + after_inames = statement_dep.statement_after.active_inames + shared_inames = before_inames & after_inames + #non_shared_inames = (before_inames | after_inames) - shared_inames + + # for each (iname, dep_type) pair, create a constraint, + # all_constraints_set will be the union of all these constraints for iname, dep_type in statement_dep.iname_deps.items(): if dep_type == DT.NONE: continue iname_prime = iname+"'" # i' - other_inames = all_inames_ordered.copy() - other_inames.remove(iname) # remaining inames, e.g., [j, k] - other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] - # initialize constraint set with what we know about other inames (e.g., j = j', k = k') - constraint_set = create_equality_conjunction_set(other_inames, other_inames_prime, islvars) + #other_inames = all_inames_ordered.copy() + #other_inames.remove(iname) # remaining inames, e.g., [j, k] + #other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] + other_shared_inames = list(shared_inames - {iname}) # remaining shared inames, e.g., [j, k] + other_shared_inames_prime = append_apostrophes(other_shared_inames) # e.g., [j', k'] + + # initialize constraint set with what we know about other shared inames (e.g., j = j', k = k') + # will be True if no shared inames + constraint_set = create_equality_conjunction_set( + other_shared_inames, other_shared_inames_prime, islvars) if dep_type == DT.SAME: - constraint_set = constraint_set & islvars[iname].eq_set(islvars[iname_prime]) + constraint_set = constraint_set & islvars[iname].eq_set( + islvars[iname_prime]) elif dep_type == DT.PRIOR: - constraint_set = constraint_set & islvars[iname].lt_set(islvars[iname_prime]) + constraint_set = constraint_set & islvars[iname].lt_set( + islvars[iname_prime]) elif dep_type == DT.ALL: - constraint_set = constraint_set & islvars[0].eq_set(islvars[0]) # True + constraint_set = constraint_set & islvars[0].eq_set( + islvars[0]) # True + # enforce statement_var == statement # s_before_int = sid_to_int[statement_dep.statement_before.sid] s_after_int = sid_to_int[statement_dep.statement_after.sid] constraint_set = constraint_set & islvars[statement_var].eq_set(islvars[0]+s_before_int) @@ -284,21 +300,19 @@ def create_dependencies_from_legacy_knl(knl): #print("%s (%s) -> %s (%s)" % ( # insn_before.id, insn_before_inames, insn_after.id, insn_after_inames)) shared_inames = insn_before_inames & insn_after_inames + non_shared_inames = (insn_before_inames | insn_after_inames) - shared_inames shared_conc_inames = shared_inames & conc_inames shared_non_conc_inames = shared_inames & non_conc_inames #print("shared conc/non-conc %s/%s" % (shared_conc_inames, shared_non_conc_inames)) - s_before = Statement(insn_before.id, all_inames) - s_after = Statement(insn_after.id, all_inames) - #TODO should this be all_inames or within_inames? - #s_before = Statement(insn_before.id, insn_before_inames) - #s_after = Statement(insn_after.id, insn_after_inames) - # TODO or union? - #s_before = Statement(insn_before.id, insn_before_inames | insn_after_inames) - #s_after = Statement(insn_after.id, insn_before_inames | insn_after_inames) + s_before = Statement(insn_before.id, insn_before_inames) + s_after = Statement(insn_after.id, insn_after_inames) for non_conc_iname in shared_non_conc_inames: iname_deps[non_conc_iname] = DT.SAME for conc_iname in shared_conc_inames: iname_deps[conc_iname] = DT.ALL + for non_shared_iname in non_shared_inames: + iname_deps[non_shared_iname] = DT.ALL + deps.append(StatementDependency(s_before, s_after, iname_deps)) return deps diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py index 8fc92aebf..561d05ae7 100644 --- a/example_dep_pairwise_schedule_creation.py +++ b/example_dep_pairwise_schedule_creation.py @@ -23,8 +23,8 @@ from schedule_checker.sched_check_utils import ( #knl_choice = "example" #knl_choice = "matmul" -knl_choice = "scan" -#knl_choice = "dependent_domain" +#knl_choice = "scan" +knl_choice = "dependent_domain" if knl_choice == "example": # make example kernel @@ -103,8 +103,8 @@ elif knl_choice == "dependent_domain": knl = lp.get_one_scheduled_kernel(knl) -#print("Kernel:") -#print(knl) +print("Kernel:") +print(knl) #print(lp.generate_code_v2(knl).device_code()) print("="*80) print("Iname tags: %s" % (knl.iname_to_tags)) @@ -134,8 +134,9 @@ for sd in statement_deps: deps_and_domains = [] for sd in statement_deps: - assert sd.statement_before.active_inames == sd.statement_after.active_inames # TODO does this need to be true? - deps_and_domains.append([sd, knl.get_inames_domain(sd.statement_before.active_inames)]) + deps_and_domains.append([sd, knl.get_inames_domain(sd.statement_before.active_inames | sd.statement_after.active_inames)]) + # TODO need to have separate domains for separate instructions? ...domain for after distinct from before + #1/0 print("----------------------------------------------------------------------") print("StatementDependencies w/domains:") -- GitLab From f65a9791b7993cf864ddca717dd08b06019fec3a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 21 Jun 2019 18:10:04 -0500 Subject: [PATCH 037/183] added stroud test kernel --- example_dep_pairwise_schedule_creation.py | 48 ++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py index 561d05ae7..c17ab9d27 100644 --- a/example_dep_pairwise_schedule_creation.py +++ b/example_dep_pairwise_schedule_creation.py @@ -24,7 +24,8 @@ from schedule_checker.sched_check_utils import ( #knl_choice = "example" #knl_choice = "matmul" #knl_choice = "scan" -knl_choice = "dependent_domain" +#knl_choice = "dependent_domain" +knl_choice = "stroud" if knl_choice == "example": # make example kernel @@ -101,6 +102,51 @@ elif knl_choice == "dependent_domain": knl = lp.realize_reduction(knl, force_scan=True) knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) +elif knl_choice == "stroud": + knl = lp.make_kernel( + "{[el, i2, alpha1,alpha2]: \ + 0 <= el < nels and \ + 0 <= i2 < nqp1d and \ + 0 <= alpha1 <= deg and 0 <= alpha2 <= deg-alpha1 }", + """ + for el,i2 + <> xi = qpts[1, i2] + <> s = 1-xi + <> r = xi/s + <> aind = 0 {id=aind_init} + + for alpha1 + <> w = s**(deg-alpha1) {id=init_w} + + for alpha2 + tmp[el,alpha1,i2] = tmp[el,alpha1,i2] + w * coeffs[aind] \ + {id=write_tmp,dep=init_w:aind_init} + w = w * r * ( deg - alpha1 - alpha2 ) / (1 + alpha2) \ + {id=update_w,dep=init_w:write_tmp} + aind = aind + 1 \ + {id=aind_incr,dep=aind_init:write_tmp:update_w} + end + end + end + """, + [ + # Must declare coeffs to have "no" shape, to keep loopy + # from trying to figure it out the shape automatically. + + lp.GlobalArg("coeffs", None, shape=None), + "..." + ], + name="stroud", + assumptions="deg>=0 and nels>=1" + ) + + knl = lp.fix_parameters(knl, nqp1d=7, deg=4) + knl = lp.split_iname(knl, "el", 16, inner_tag="l.0") + knl = lp.split_iname(knl, "el_outer", 2, outer_tag="g.0", inner_tag="ilp", + slabs=(0, 1)) + knl = lp.tag_inames(knl, dict(i2="l.1", alpha1="unr", alpha2="unr")) + knl = lp.preprocess_kernel(knl) + knl = lp.get_one_scheduled_kernel(knl) print("Kernel:") -- GitLab From 1ba3d784f72cc00a0dededf75ceceaad45ab56c7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 21 Jun 2019 18:44:57 -0500 Subject: [PATCH 038/183] printing info about invalid schedules --- dependency.py | 1 + example_dep_pairwise_schedule_creation.py | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/dependency.py b/dependency.py index 10f090798..efcb776f7 100644 --- a/dependency.py +++ b/dependency.py @@ -228,6 +228,7 @@ def create_dependency_constraint( all_constraints_map = _convert_constraint_set_to_map(all_constraints_set, len(all_inames_ordered)+1) + # TODO use separate domain for before and after insns range_constraint_set = create_new_set_with_primes(domain_constraint_set) new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py index c17ab9d27..6cd5c0977 100644 --- a/example_dep_pairwise_schedule_creation.py +++ b/example_dep_pairwise_schedule_creation.py @@ -6,6 +6,7 @@ from schedule_checker.dependency import ( DependencyType as DT, create_dependencies_from_legacy_knl, create_dependency_constraint, + get_concurrent_inames, ) from schedule_checker.schedule import Statement, StatementInstance, LexSchedule from schedule_checker.sched_check_utils import prettier_map_string @@ -193,6 +194,7 @@ for sd, dom in deps_and_domains: sched_is_valid = True # check each statement pair individually for statement_dep, dom in deps_and_domains: + # TODO separate dom for before and after insns s_before = statement_dep.statement_before s_after = statement_dep.statement_after @@ -244,7 +246,7 @@ for statement_dep, dom in deps_and_domains: sched_map_symbolic, lex_map_symbolic) print("statement instance ordering symbolic (valid_sched):") print(prettier_map_string(SIO_symbolic_valid)) - print("space (statement instances -> statement instances):") + print("SIO space (statement instances -> statement instances):") print(SIO_symbolic_valid.space) """ # i is parallel, suppose we want to enforce the following: @@ -287,6 +289,24 @@ for statement_dep, dom in deps_and_domains: assert constraint_map.space == SIO_symbolic_valid.space if not constraint_map.is_subset(SIO_symbolic_valid): sched_is_valid = False + conc_inames, non_conc_inames = get_concurrent_inames(knl) + print("================ constraint check failure =================") + print("constraint map not subset of SIO") + print("dependency:") + print(statement_dep) + print("concurrent inames:", conc_inames) + print("sequential inames:", non_conc_inames) + print("constraint map space (statment instances -> statement instances):") + print(constraint_map.space) + print("SIO space (statement instances -> statement instances):") + print(SIO_symbolic_valid.space) + print("constraint map:") + print(prettier_map_string(constraint_map)) + print("statement instance ordering:") + print(prettier_map_string(SIO_symbolic_valid)) + print("{insn id -> sched sid int} dict:") + print(sched.lp_insnid_to_int_sid) + print("===========================================================") print("is valid sched valid? constraint map subset of SIO?") print(sched_is_valid) -- GitLab From db06cbee6c99439f83a8c140b38969b306267eb9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 21 Jun 2019 23:10:14 -0500 Subject: [PATCH 039/183] started separating depender vs. dependee domains, then commented out most changes because not sure if this is right approach --- dependency.py | 12 +++-- example_dep_pairwise_schedule_creation.py | 58 +++++++++++++++++++---- schedule.py | 12 ++++- 3 files changed, 67 insertions(+), 15 deletions(-) diff --git a/dependency.py b/dependency.py index efcb776f7..dbf35073b 100644 --- a/dependency.py +++ b/dependency.py @@ -70,7 +70,6 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): return constraint_map.move_dims(dim_type.out, 0, dim_type.in_, mv_count, mv_count) -# TODO make this take in a set of dep sets and intersect all the constraints def create_dependency_constraint_old( dependencies, all_inames_ordered, @@ -156,6 +155,8 @@ def create_dependency_constraint( all_inames_ordered, statement_var, domain_constraint_set, + #dom_before_constraint_set, + #dom_after_constraint_set, sid_to_int, ): from schedule_checker.sched_check_utils import ( @@ -228,14 +229,19 @@ def create_dependency_constraint( all_constraints_map = _convert_constraint_set_to_map(all_constraints_set, len(all_inames_ordered)+1) - # TODO use separate domain for before and after insns + # TODO use separate domain for before and after insns? range_constraint_set = create_new_set_with_primes(domain_constraint_set) - new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' domain_to_intersect = add_dims_to_isl_set( domain_constraint_set, isl.dim_type.out, ["s"], new_pose) # TODO don't hardcode 's' range_to_intersect = add_dims_to_isl_set( range_constraint_set, isl.dim_type.out, ["s'"], new_pose) # TODO don't hardcode 's' + #new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' + #domain_to_intersect = add_dims_to_isl_set( + # dom_before_constraint_set, isl.dim_type.out, ["s"], new_pose) # TODO don't hardcode 's' + #range_constraint_set = create_new_set_with_primes(dom_after_constraint_set) + #range_to_intersect = add_dims_to_isl_set( + # range_constraint_set, isl.dim_type.out, ["s'"], new_pose) # TODO don't hardcode 's' map_with_loop_domain_constraints = all_constraints_map.intersect_domain(domain_to_intersect).intersect_range(range_to_intersect) #blah2 = isl.Map("[pi_up, pj_up] -> { [s = 1, i, j] -> [s' = 0, i' = i, j'] : 0 <= i < pi_up and 0 <= j < pj_up and j' > j and 0 <= j' < pj_up}") diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py index 6cd5c0977..40f5004ab 100644 --- a/example_dep_pairwise_schedule_creation.py +++ b/example_dep_pairwise_schedule_creation.py @@ -148,6 +148,28 @@ elif knl_choice == "stroud": knl = lp.tag_inames(knl, dict(i2="l.1", alpha1="unr", alpha2="unr")) knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) +if knl_choice == "add_barrier": + np.random.seed(17) + a = np.random.randn(16) + cnst = np.random.randn(16) + knl = lp.make_kernel( + "{[i, ii]: 0<=i, ii Date: Fri, 21 Jun 2019 23:46:50 -0500 Subject: [PATCH 040/183] barriers can be part of a dependency pair; treating them just like a RunInstruction --- example_dep_pairwise_schedule_creation.py | 5 +++-- schedule.py | 8 +++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py index 40f5004ab..d8550c15b 100644 --- a/example_dep_pairwise_schedule_creation.py +++ b/example_dep_pairwise_schedule_creation.py @@ -22,11 +22,12 @@ from schedule_checker.sched_check_utils import ( order_var_names_to_match_islset, ) -#knl_choice = "example" +knl_choice = "example" #knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" -knl_choice = "stroud" +#knl_choice = "stroud" +#knl_choice = "add_barrier" if knl_choice == "example": # make example kernel diff --git a/schedule.py b/schedule.py index fde888649..2fa8eb54c 100644 --- a/schedule.py +++ b/schedule.py @@ -77,7 +77,13 @@ class LexSchedule(object): self.append_item((insn_id_int,), next_insn_lex_pt[:]) next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 elif isinstance(sched_item, Barrier): - pass + # TODO barriers can be part of a dependency... how should these be handled? + if include_only_insn_ids is None or sched_item.originating_insn_id in include_only_insn_ids: + self.add_new_lp_insnid(sched_item.originating_insn_id) + insn_id_int = self.lp_insnid_to_int_sid[sched_item.originating_insn_id] + + self.append_item((insn_id_int,), next_insn_lex_pt[:]) + next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 else: pass self.pad_lex_pts_with_zeros() -- GitLab From 4b7163667a3e73bb133530218fc28f1ca9e867a0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 22 Jun 2019 01:12:30 -0500 Subject: [PATCH 041/183] added nop and nest example kernels --- example_dep_pairwise_schedule_creation.py | 55 ++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py index d8550c15b..b060bf8cb 100644 --- a/example_dep_pairwise_schedule_creation.py +++ b/example_dep_pairwise_schedule_creation.py @@ -22,12 +22,14 @@ from schedule_checker.sched_check_utils import ( order_var_names_to_match_islset, ) -knl_choice = "example" +#knl_choice = "example" #knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" #knl_choice = "stroud" #knl_choice = "add_barrier" +#knl_choice = "nop" #TODO +knl_choice = "nest" if knl_choice == "example": # make example kernel @@ -170,7 +172,58 @@ if knl_choice == "add_barrier": knl = lp.split_iname(knl, "ii", 2, outer_tag="g.0", inner_tag="l.0") knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) +if knl_choice == "nop": + knl = lp.make_kernel( + [ + "{[a]: 0<=a<10}", + "{[b]: b_start<=b b_start = 1 + <> b_end = 2 + for b + <> c_start = 1 + <> c_end = 2 + + for c + ... nop + end + + <>t[idim] = 1 + end + end + """, + "...", + seq_dependencies=True) + knl = lp.fix_parameters(knl, dim=3) + knl = lp.preprocess_kernel(knl) + knl = lp.get_one_scheduled_kernel(knl) +if knl_choice == "nest": + knl = lp.make_kernel( + "{[i,j,k]: 0<=i,j,kfoo = 0 {id=insn0} + for i + <>acc = 0 {id=insn1} + for j + for k + acc = acc + j + k {id=insn2,dep=insn1} + end + end + foo = foo + acc {id=insn3,dep=insn2} + end + <>bar = foo {id=insn4,dep=insn3} + """, + name="nest", + assumptions="n >= 1", + lang_version=(2018, 2) + ) + + knl = lp.preprocess_kernel(knl) + knl = lp.get_one_scheduled_kernel(knl) print("Kernel:") -- GitLab From a48db945c0266a44a97a409d85dff5f178b0d3f6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 19:23:14 -0500 Subject: [PATCH 042/183] fixed pep8 issues --- example_dep_pairwise_schedule_creation.py | 60 ++++++++++++----------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py index b060bf8cb..2f995eb3e 100644 --- a/example_dep_pairwise_schedule_creation.py +++ b/example_dep_pairwise_schedule_creation.py @@ -1,35 +1,28 @@ -import islpy as isl import loopy as lp import numpy as np from schedule_checker.dependency import ( - Dependency, - DependencyType as DT, create_dependencies_from_legacy_knl, create_dependency_constraint, get_concurrent_inames, ) -from schedule_checker.schedule import Statement, StatementInstance, LexSchedule -from schedule_checker.sched_check_utils import prettier_map_string +from schedule_checker.schedule import LexSchedule from schedule_checker.lexicographic_order_map import ( - create_explicit_map_from_tuples, + #create_explicit_map_from_tuples, get_statement_ordering_map, - get_space, ) from schedule_checker.sched_check_utils import ( prettier_map_string, - _union_inames_domains, - all_iname_domains_equal, order_var_names_to_match_islset, ) #knl_choice = "example" #knl_choice = "matmul" -#knl_choice = "scan" +knl_choice = "scan" #knl_choice = "dependent_domain" #knl_choice = "stroud" #knl_choice = "add_barrier" #knl_choice = "nop" #TODO -knl_choice = "nest" +#knl_choice = "nest" if knl_choice == "example": # make example kernel @@ -52,7 +45,9 @@ if knl_choice == "example": lang_version=(2018, 2) ) #knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32}) - knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32, "in": np.float32}) + knl = lp.add_and_infer_dtypes( + knl, + {"b": np.float32, "d": np.float32, "in": np.float32}) knl = lp.tag_inames(knl, {"i": "l.0"}) knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) @@ -71,7 +66,7 @@ elif knl_choice == "matmul": knl = lp.split_iname(knl, "i", bsize, outer_tag="g.0", inner_tag="l.1") knl = lp.split_iname(knl, "j", bsize, outer_tag="g.1", inner_tag="l.0") knl = lp.split_iname(knl, "k", bsize) - knl = lp.add_prefetch(knl, "a", ["k_inner", "i_inner"], default_tag="l.auto") + knl = lp.add_prefetch(knl, "a", ["k_inner", "i_inner"], default_tag="l.auto") knl = lp.add_prefetch(knl, "b", ["j_inner", "k_inner"], default_tag="l.auto") knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) @@ -244,11 +239,11 @@ if not all_iname_domains_equal(knl): "get_inames_domain(iname) is not same for all inames") """ -#For every shared (between depender and dependee) non-concurrent iname Introduce a same dep +#For every shared (b/t depender and dependee) non-concurrent iname Introduce SAME dep # (Perform voodoo guesswork to determine whether a ‘prior’ dep is needed) -#For every shared (between depender and dependee) concurrent iname Introduce an all dep +#For every shared (b/t depender and dependee) concurrent iname Introduce an ALL dep -print("----------------------------------------------------------------------") +print("-"*85) statement_deps = create_dependencies_from_legacy_knl(knl) print("Statement Dependencies:") for sd in statement_deps: @@ -257,15 +252,18 @@ for sd in statement_deps: deps_and_domains = [] for sd in statement_deps: - #deps_and_domains.append([sd, knl.get_inames_domain(sd.statement_before.active_inames | sd.statement_after.active_inames)]) - # TODO need to have separate domains for separate instructions? ...domain for after distinct from before + #deps_and_domains.append([ + # sd, knl.get_inames_domain( + # sd.statement_before.active_inames | sd.statement_after.active_inames)]) + # TODO need to have separate domains for separate instructions? + # ...domain for after distinct from before deps_and_domains.append([ sd, knl.get_inames_domain(sd.statement_before.active_inames), knl.get_inames_domain(sd.statement_after.active_inames) ]) -print("----------------------------------------------------------------------") +print("-"*85) print("StatementDependencies w/domains:") #for sd, dom in deps_and_domains: for sd, dom_before, dom_after in deps_and_domains: @@ -289,15 +287,18 @@ for statement_dep, dom_before, dom_after in deps_and_domains: ) # get all inames in consistent ordering: - all_inames_ordered = order_var_names_to_match_islset(knl.all_inames(), combined_doms) # should separate doms? + all_inames_ordered = order_var_names_to_match_islset( + knl.all_inames(), combined_doms) # should separate doms? sched = LexSchedule(knl, include_only_insn_ids=[s_before.sid, s_after.sid]) - print("----------------------------------------------------------------------") + print("-"*85) print("LexSchedule before processing:") print(sched) - sched_map_symbolic = sched.create_symbolic_isl_map(combined_doms, all_inames_ordered) # should separate doms? - #sched_map_symbolic = sched.create_symbolic_isl_map(dom_before, dom_after, all_inames_ordered) + sched_map_symbolic = sched.create_symbolic_isl_map( + combined_doms, all_inames_ordered) # should separate doms? + #sched_map_symbolic = sched.create_symbolic_isl_map( + # dom_before, dom_after, all_inames_ordered) print("LexSchedule after processing:") print(sched) # ------------------------------------------------------------------- @@ -307,7 +308,8 @@ for statement_dep, dom_before, dom_after in deps_and_domains: domain_w_s = add_dims_to_isl_set( domain_union, isl.dim_type.out, ['s'], new_pose) # TODO don't hardcode 's' sched_map_vars_in = sched_map_symbolic.space.get_var_names(isl.dim_type.in_) - domain_stripped = domain_w_s.project_out_except(sched_map_vars_in, [isl.dim_type.set]) + domain_stripped = domain_w_s.project_out_except( + sched_map_vars_in, [isl.dim_type.set]) """ # ------------------------------------------------------------------- @@ -317,7 +319,7 @@ for statement_dep, dom_before, dom_after in deps_and_domains: print(sched_map_symbolic.space) # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later - print("---------------------------------------------------------------------------") + print("-"*85) #lex_map_explicit = sched.get_lex_map_explicit() lex_map_symbolic = sched.get_lex_map_symbolic() @@ -328,7 +330,7 @@ for statement_dep, dom_before, dom_after in deps_and_domains: print(lex_map_symbolic.space) # Statement instance ordering - print("----------------------------------------------------------------------") + print("-"*85) #SIO_explicit_valid = get_statement_ordering_map( # example_sched_explicit, lex_map_explicit) #print("statement instance ordering explicit (valid_sched):") @@ -358,17 +360,17 @@ for statement_dep, dom_before, dom_after in deps_and_domains: ] """ - print("----------------------------------------------------------------------") + print("-"*85) print("dict{lp insn id : sched sid int}:") print(sched.lp_insnid_to_int_sid) - print("----------------------------------------------------------------------") + print("-"*85) statement_var = 's' constraint_map = create_dependency_constraint( statement_dep, all_inames_ordered, # TODO separate lists for separate doms? statement_var, - combined_doms, # TODO separate domains for before/after + combined_doms, # TODO separate domains for before/after #dom_before, #dom_after, sched.lp_insnid_to_int_sid, -- GitLab From 20e1b99e485959453ac8d34b8482afa4c2df3539 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 19:37:20 -0500 Subject: [PATCH 043/183] fixing pep8 issues --- dependency.py | 148 ++++++++++++++++++++++++++------------------------ 1 file changed, 78 insertions(+), 70 deletions(-) diff --git a/dependency.py b/dependency.py index dbf35073b..07ad15112 100644 --- a/dependency.py +++ b/dependency.py @@ -22,7 +22,6 @@ class Dependency(object): self.dep_type = dep_type self.iname = iname - def __str__(self): return "%s -> %s {%s dep: %s}" % ( self.statement_before, @@ -36,13 +35,12 @@ class StatementDependency(object): self, statement_before, statement_after, - iname_deps, # {iname: dep_type} + iname_deps, # {iname: dep_type} ): self.statement_before = statement_before self.statement_after = statement_after self.iname_deps = iname_deps - def __str__(self): result = "%s --before->\n%s iff\n " % ( self.statement_before, self.statement_after) @@ -65,9 +63,11 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): dim_type = isl.dim_type constraint_map = isl.Map.from_domain(constraint_set) if src_position: - return constraint_map.move_dims(dim_type.out, 0, dim_type.in_, src_position, mv_count) + return constraint_map.move_dims( + dim_type.out, 0, dim_type.in_, src_position, mv_count) else: - return constraint_map.move_dims(dim_type.out, 0, dim_type.in_, mv_count, mv_count) + return constraint_map.move_dims( + dim_type.out, 0, dim_type.in_, mv_count, mv_count) def create_dependency_constraint_old( @@ -91,26 +91,26 @@ def create_dependency_constraint_old( # make sure all dependencies involve same two statements if len(set([dep.statement_before.sid for dep in dependencies])) != 1 or \ - len(set([dep.statement_after.sid for dep in dependencies])) != 1: + len(set([dep.statement_after.sid for dep in dependencies])) != 1: raise ValueError("All depencencies must be between same two statements.") - # make sure all dependencies involve different inames # TODO upate after allowing prior(i,k) + # make sure all dependencies involve different inames if len(set([dep.iname for dep in dependencies])) != len(dependencies): raise ValueError("All depencencies must apply to different inames.") statement_var_prime = statement_var+"'" - DT = DependencyType + dt = DependencyType islvars = make_islvars_with_var_primes( [statement_var]+all_inames_ordered, []) # initialize constraints to False - # this will disappear as soon as we add a constraint that is not DT.NONE + # this will disappear as soon as we add a constraint that is not dt.NONE all_constraints_set = islvars[0].eq_set(islvars[0] + 1) for dep in dependencies: iname = dep.iname dep_type = dep.dep_type - if dep_type == DT.NONE: + if dep_type == dt.NONE: continue iname_prime = iname+"'" # i' @@ -118,35 +118,41 @@ def create_dependency_constraint_old( other_inames.remove(iname) # remaining inames, e.g., [j, k] other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] - # initialize constraint set with what we know about other inames (e.g., j = j', k = k') - constraint_set = create_equality_conjunction_set(other_inames, other_inames_prime, islvars) - if dep_type == DT.SAME: - constraint_set = constraint_set & islvars[iname].eq_set(islvars[iname_prime]) - elif dep_type == DT.PRIOR: - constraint_set = constraint_set & islvars[iname].lt_set(islvars[iname_prime]) - elif dep_type == DT.ALL: - constraint_set = constraint_set & islvars[0].eq_set(islvars[0]) # True + # initialize constraint set with what we know about other inames + # (e.g., j = j', k = k') + constraint_set = create_equality_conjunction_set( + other_inames, other_inames_prime, islvars) + if dep_type == dt.SAME: + constraint_set = constraint_set & islvars[iname].eq_set( + islvars[iname_prime]) + elif dep_type == dt.PRIOR: + constraint_set = constraint_set & islvars[iname].lt_set( + islvars[iname_prime]) + elif dep_type == dt.ALL: + constraint_set = constraint_set & islvars[0].eq_set(islvars[0]) # True s_before_int = sid_to_int[dep.statement_before.sid] s_after_int = sid_to_int[dep.statement_after.sid] - constraint_set = constraint_set & islvars[statement_var].eq_set(islvars[0]+s_before_int) - constraint_set = constraint_set & islvars[statement_var_prime].eq_set(islvars[0]+s_after_int) + constraint_set = constraint_set & islvars[statement_var].eq_set( + islvars[0]+s_before_int) + constraint_set = constraint_set & islvars[statement_var_prime].eq_set( + islvars[0]+s_after_int) all_constraints_set = all_constraints_set | constraint_set - all_constraints_map = _convert_constraint_set_to_map(all_constraints_set, len(all_inames_ordered)+1) + all_constraints_map = _convert_constraint_set_to_map( + all_constraints_set, len(all_inames_ordered)+1) range_constraint_set = create_new_set_with_primes(domain_constraint_set) - new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' + new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' domain_to_intersect = add_dims_to_isl_set( - domain_constraint_set, isl.dim_type.out, ["s"], new_pose) # TODO don't hardcode 's' + domain_constraint_set, isl.dim_type.out, ["s"], new_pose) range_to_intersect = add_dims_to_isl_set( - range_constraint_set, isl.dim_type.out, ["s'"], new_pose) # TODO don't hardcode 's' + range_constraint_set, isl.dim_type.out, ["s'"], new_pose) - map_with_loop_domain_constraints = all_constraints_map.intersect_domain(domain_to_intersect).intersect_range(range_to_intersect) - #blah2 = isl.Map("[pi_up, pj_up] -> { [s = 1, i, j] -> [s' = 0, i' = i, j'] : 0 <= i < pi_up and 0 <= j < pj_up and j' > j and 0 <= j' < pj_up}") - #assert blah2 == map_with_loop_domain_constraints + map_with_loop_domain_constraints = all_constraints_map.intersect_domain( + domain_to_intersect).intersect_range(range_to_intersect) return map_with_loop_domain_constraints @@ -171,19 +177,19 @@ def create_dependency_constraint( # assumes statements are numbered sequentially # (statement_bound = max statement id + 1) - # make sure all dependencies involve different inames # TODO upate after allowing prior(i,k) - if len(set(statement_dep.iname_deps.keys()) - ) != len(statement_dep.iname_deps.keys()): + # make sure all dependencies involve different inames + if len(set(statement_dep.iname_deps.keys())) != len( + statement_dep.iname_deps.keys()): raise ValueError("All depencencies must apply to different inames.") statement_var_prime = statement_var+"'" - DT = DependencyType + dt = DependencyType islvars = make_islvars_with_var_primes( [statement_var]+all_inames_ordered, []) # initialize constraints to False - # this will disappear as soon as we add a constraint that is not DT.NONE + # this will disappear as soon as we add a constraint that is not dt.NONE all_constraints_set = islvars[0].eq_set(islvars[0] + 1) before_inames = statement_dep.statement_before.active_inames @@ -194,7 +200,7 @@ def create_dependency_constraint( # for each (iname, dep_type) pair, create a constraint, # all_constraints_set will be the union of all these constraints for iname, dep_type in statement_dep.iname_deps.items(): - if dep_type == DT.NONE: + if dep_type == dt.NONE: continue iname_prime = iname+"'" # i' @@ -202,50 +208,57 @@ def create_dependency_constraint( #other_inames = all_inames_ordered.copy() #other_inames.remove(iname) # remaining inames, e.g., [j, k] #other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] - other_shared_inames = list(shared_inames - {iname}) # remaining shared inames, e.g., [j, k] - other_shared_inames_prime = append_apostrophes(other_shared_inames) # e.g., [j', k'] - # initialize constraint set with what we know about other shared inames (e.g., j = j', k = k') + # remaining shared inames, e.g., [j, k] + other_shared_inames = list(shared_inames - {iname}) + + other_shared_inames_prime = append_apostrophes(other_shared_inames) + # e.g., [j', k'] + + # initialize constraint set with what we know about other shared inames + # (e.g., j = j', k = k') # will be True if no shared inames constraint_set = create_equality_conjunction_set( other_shared_inames, other_shared_inames_prime, islvars) - if dep_type == DT.SAME: + if dep_type == dt.SAME: constraint_set = constraint_set & islvars[iname].eq_set( islvars[iname_prime]) - elif dep_type == DT.PRIOR: + elif dep_type == dt.PRIOR: constraint_set = constraint_set & islvars[iname].lt_set( islvars[iname_prime]) - elif dep_type == DT.ALL: + elif dep_type == dt.ALL: constraint_set = constraint_set & islvars[0].eq_set( - islvars[0]) # True + islvars[0]) # True # enforce statement_var == statement # s_before_int = sid_to_int[statement_dep.statement_before.sid] s_after_int = sid_to_int[statement_dep.statement_after.sid] - constraint_set = constraint_set & islvars[statement_var].eq_set(islvars[0]+s_before_int) - constraint_set = constraint_set & islvars[statement_var_prime].eq_set(islvars[0]+s_after_int) + constraint_set = constraint_set & islvars[statement_var].eq_set( + islvars[0]+s_before_int) + constraint_set = constraint_set & islvars[statement_var_prime].eq_set( + islvars[0]+s_after_int) all_constraints_set = all_constraints_set | constraint_set - all_constraints_map = _convert_constraint_set_to_map(all_constraints_set, len(all_inames_ordered)+1) + all_constraints_map = _convert_constraint_set_to_map( + all_constraints_set, len(all_inames_ordered)+1) # TODO use separate domain for before and after insns? range_constraint_set = create_new_set_with_primes(domain_constraint_set) - new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' + new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' domain_to_intersect = add_dims_to_isl_set( - domain_constraint_set, isl.dim_type.out, ["s"], new_pose) # TODO don't hardcode 's' + domain_constraint_set, isl.dim_type.out, ["s"], new_pose) range_to_intersect = add_dims_to_isl_set( - range_constraint_set, isl.dim_type.out, ["s'"], new_pose) # TODO don't hardcode 's' + range_constraint_set, isl.dim_type.out, ["s'"], new_pose) #new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' #domain_to_intersect = add_dims_to_isl_set( - # dom_before_constraint_set, isl.dim_type.out, ["s"], new_pose) # TODO don't hardcode 's' + # dom_before_constraint_set, isl.dim_type.out, ["s"], new_pose) #range_constraint_set = create_new_set_with_primes(dom_after_constraint_set) #range_to_intersect = add_dims_to_isl_set( - # range_constraint_set, isl.dim_type.out, ["s'"], new_pose) # TODO don't hardcode 's' + # range_constraint_set, isl.dim_type.out, ["s'"], new_pose) - map_with_loop_domain_constraints = all_constraints_map.intersect_domain(domain_to_intersect).intersect_range(range_to_intersect) - #blah2 = isl.Map("[pi_up, pj_up] -> { [s = 1, i, j] -> [s' = 0, i' = i, j'] : 0 <= i < pi_up and 0 <= j < pj_up and j' > j and 0 <= j' < pj_up}") - #assert blah2 == map_with_loop_domain_constraints + map_with_loop_domain_constraints = all_constraints_map.intersect_domain( + domain_to_intersect).intersect_range(range_to_intersect) return map_with_loop_domain_constraints @@ -256,17 +269,15 @@ def get_concurrent_inames(knl): for iname in all_inames: iname_tags = knl.iname_to_tags.get(iname, None) if iname_tags and any( - isinstance(tag, (LocalIndexTag, GroupIndexTag)) for tag in iname_tags): + isinstance(tag, (LocalIndexTag, GroupIndexTag)) + for tag in iname_tags): conc_inames.add(iname) return conc_inames, all_inames-conc_inames def create_dependencies_from_legacy_knl_old(knl): from schedule_checker.schedule import Statement - from schedule_checker.dependency import ( - Dependency, - DependencyType as DT, - ) + dt = DependencyType conc_inames, non_conc_inames = get_concurrent_inames(knl) all_inames = list(knl.all_inames()) dep_sets = [] @@ -276,27 +287,26 @@ def create_dependencies_from_legacy_knl_old(knl): insn_before = knl.id_to_insn[insn_before_id] insn_before_inames = insn_before.within_inames insn_after_inames = insn_after.within_inames - #print("%s (%s) -> %s (%s)" % ( - # insn_before.id, insn_before_inames, insn_after.id, insn_after_inames)) shared_inames = insn_before_inames & insn_after_inames shared_conc_inames = shared_inames & conc_inames shared_non_conc_inames = shared_inames & non_conc_inames - #print("shared conc/non-conc %s/%s" % (shared_conc_inames, shared_non_conc_inames)) s_before = Statement(insn_before.id, all_inames) s_after = Statement(insn_after.id, all_inames) for non_conc_iname in shared_non_conc_inames: - dep_set.append(Dependency(s_before, s_after, DT.SAME, non_conc_iname)) + dep_set.append( + Dependency(s_before, s_after, dt.SAME, non_conc_iname)) for conc_iname in shared_conc_inames: - dep_set.append(Dependency(s_before, s_after, DT.ALL, conc_iname)) + dep_set.append( + Dependency(s_before, s_after, dt.ALL, conc_iname)) dep_sets.append(dep_set) return dep_sets def create_dependencies_from_legacy_knl(knl): from schedule_checker.schedule import Statement - DT = DependencyType + dt = DependencyType conc_inames, non_conc_inames = get_concurrent_inames(knl) - all_inames = list(knl.all_inames()) + #all_inames = list(knl.all_inames()) deps = [] for insn_after in knl.instructions: for insn_before_id in insn_after.depends_on: @@ -304,22 +314,20 @@ def create_dependencies_from_legacy_knl(knl): insn_before = knl.id_to_insn[insn_before_id] insn_before_inames = insn_before.within_inames insn_after_inames = insn_after.within_inames - #print("%s (%s) -> %s (%s)" % ( - # insn_before.id, insn_before_inames, insn_after.id, insn_after_inames)) shared_inames = insn_before_inames & insn_after_inames - non_shared_inames = (insn_before_inames | insn_after_inames) - shared_inames + non_shared_inames = (insn_before_inames | insn_after_inames + ) - shared_inames shared_conc_inames = shared_inames & conc_inames shared_non_conc_inames = shared_inames & non_conc_inames - #print("shared conc/non-conc %s/%s" % (shared_conc_inames, shared_non_conc_inames)) s_before = Statement(insn_before.id, insn_before_inames) s_after = Statement(insn_after.id, insn_after_inames) for non_conc_iname in shared_non_conc_inames: - iname_deps[non_conc_iname] = DT.SAME + iname_deps[non_conc_iname] = dt.SAME for conc_iname in shared_conc_inames: - iname_deps[conc_iname] = DT.ALL + iname_deps[conc_iname] = dt.ALL for non_shared_iname in non_shared_inames: - iname_deps[non_shared_iname] = DT.ALL + iname_deps[non_shared_iname] = dt.ALL deps.append(StatementDependency(s_before, s_after, iname_deps)) return deps -- GitLab From e1f2bee691b8530f8a26c298b7bd4bfa8c50fef3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 19:49:11 -0500 Subject: [PATCH 044/183] fixing pep8 issues --- schedule.py | 60 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/schedule.py b/schedule.py index 2fa8eb54c..2371c40a1 100644 --- a/schedule.py +++ b/schedule.py @@ -43,21 +43,26 @@ class StatementInstance(object): class LexSchedule(object): - # TODO this should hold a map from statement instances to lex order space def __init__( self, knl, include_only_insn_ids=None, ): - self.lex_schedule = OrderedDict() # statement instance: lex point - self.inames_enumerated = [] # symbolic inames in sched that have been enumerated into explicit statement instances + self.lex_schedule = OrderedDict() # {statement instance: lex point} + + # symbolic inames in sched that have been enumerated + # into explicit statement instances + self.inames_enumerated = [] + self.inames_not_enumerated = [] # TODO better way to do this + self.lp_insnid_to_int_sid = {} + assert not any(iname == 's' for iname in knl.all_inames()) from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) next_insn_lex_pt = [0] - # TODO assumes perfect loop nesting + # TODO originally assumed perfect loop nesting, still the case? for sched_item in knl.schedule: if isinstance(sched_item, EnterLoop): iname = sched_item.iname @@ -70,17 +75,19 @@ class LexSchedule(object): next_insn_lex_pt.pop() next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 elif isinstance(sched_item, RunInstruction): - if include_only_insn_ids is None or sched_item.insn_id in include_only_insn_ids: + if (include_only_insn_ids is None + or sched_item.insn_id in include_only_insn_ids): self.add_new_lp_insnid(sched_item.insn_id) insn_id_int = self.lp_insnid_to_int_sid[sched_item.insn_id] self.append_item((insn_id_int,), next_insn_lex_pt[:]) next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 elif isinstance(sched_item, Barrier): - # TODO barriers can be part of a dependency... how should these be handled? - if include_only_insn_ids is None or sched_item.originating_insn_id in include_only_insn_ids: + if (include_only_insn_ids is None + or sched_item.originating_insn_id in include_only_insn_ids): self.add_new_lp_insnid(sched_item.originating_insn_id) - insn_id_int = self.lp_insnid_to_int_sid[sched_item.originating_insn_id] + insn_id_int = self.lp_insnid_to_int_sid[ + sched_item.originating_insn_id] self.append_item((insn_id_int,), next_insn_lex_pt[:]) next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 @@ -89,7 +96,7 @@ class LexSchedule(object): self.pad_lex_pts_with_zeros() def max_lex_dims(self): - return max(len(lex_pt) for insn, lex_pt in self.items()) + return max(len(lex_pt) for insn, lex_pt in self.items()) def pad_lex_pts_with_zeros(self): max_lex_dim = self.max_lex_dims() @@ -103,8 +110,9 @@ class LexSchedule(object): iname_found = False for insn, lex_pt in self.lex_schedule.items(): if iname in lex_pt: - for v in range(bound[0],bound[1]): - new_sched[tuple(list(insn)+[v])] = [l if l != iname else v for l in lex_pt] + for v in range(bound[0], bound[1]): + new_sched[tuple(list(insn)+[v])] = [ + lx if lx != iname else v for lx in lex_pt] iname_found = True else: new_sched[insn] = lex_pt @@ -132,7 +140,8 @@ class LexSchedule(object): def add_new_lp_insnid(self, lp_insnid): if self.lp_insnid_to_int_sid: - self.lp_insnid_to_int_sid[lp_insnid] = max(self.lp_insnid_to_int_sid.values()) + 1 + self.lp_insnid_to_int_sid[lp_insnid] = max( + self.lp_insnid_to_int_sid.values()) + 1 else: self.lp_insnid_to_int_sid[lp_insnid] = 0 @@ -156,10 +165,12 @@ class LexSchedule(object): result = [] for dim_pts in zip(*self.lex_schedule.values()): if all(isinstance(pt, int) for pt in dim_pts): - result.append(max(dim_pts) + 1) # +1 because this is the non-inclusive upper bound + result.append(max(dim_pts) + 1) + # +1 b/c this is the non-inclusive upper bound else: assert all(pt == dim_pts[0] for pt in dim_pts) - result.append(var_bounds_dict[dim_pts[0]][1]) # upper bound for this variable + # append upper bound for this variable + result.append(var_bounds_dict[dim_pts[0]][1]) return result def get_min_lex_dim_vals(self, var_bounds_dict): @@ -171,7 +182,8 @@ class LexSchedule(object): result.append(min(dim_pts)) else: assert all(pt == dim_pts[0] for pt in dim_pts) - result.append(var_bounds_dict[dim_pts[0]][0]) # lower bound for this variable + # append lower bound for this variable + result.append(var_bounds_dict[dim_pts[0]][0]) return result def append_item(self, sched_item, lex_pt): @@ -184,7 +196,9 @@ class LexSchedule(object): return self.lex_schedule[self.get_last_schedule_item()] def create_explicit_isl_map(self, sched_space): - from schedule_checker.lexicographic_order_map import create_explicit_map_from_tuples + from schedule_checker.lexicographic_order_map import ( + create_explicit_map_from_tuples + ) return create_explicit_map_from_tuples(list(self.items()), sched_space) def enumerate_symbolic_inames_and_create_explicit_isl_map(self, iname_bounds): @@ -192,8 +206,8 @@ class LexSchedule(object): sched_space = self.get_space_for_explicit_sched() return self.create_explicit_isl_map(sched_space) - def create_symbolic_isl_map(self, domain, inames): #def create_symbolic_isl_map(self, dom_before, dom_after, inames): + def create_symbolic_isl_map(self, domain, inames): # TODO if inames will always match domain out vars, don't need to pass them from schedule_checker.lexicographic_order_map import ( create_symbolic_map_from_tuples, @@ -211,25 +225,25 @@ class LexSchedule(object): sched_space = self.get_space_for_symbolic_sched() """ - # TODO maybe don't project this out, constraints may involve any iname later... + # TODO maybe don't project this out, constraints may involve any iname later? domain_stripped = domain_intersection.project_out_except( self.inames_not_enumerated, [isl.dim_type.set] ) """ # TODO first need to make sure statement var name isn't already being used - new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' + new_pose = 0 # insert 's' at beginning domain_to_intersect = add_dims_to_isl_set( - domain, isl.dim_type.out, ['s'], new_pose) # TODO don't hardcode 's' + domain, isl.dim_type.out, ['s'], new_pose) #dom_before_to_intersect = add_dims_to_isl_set( # dom_before, isl.dim_type.out, ['s'], new_pose) #dom_after_to_intersect = add_dims_to_isl_set( # dom_before, isl.dim_type.out, ['s'], new_pose) return create_symbolic_map_from_tuples( - list(self.items()), sched_space, domain_to_intersect) #list(self.items()), sched_space, #dom_before_to_intersect, dom_after_to_intersect) + list(self.items()), sched_space, domain_to_intersect) def get_lex_map_explicit(self): @@ -268,7 +282,8 @@ class LexSchedule(object): for state_inst, lex in self.lex_schedule.items(): domain_elem = "[s=%s,%s]" % ( state_inst.statement.sid, ",".join( - ["%s=%d" % (iname, val) for iname, val in state_inst.iname_vals.items()])) + ["%s=%d" % (iname, val) + for iname, val in state_inst.iname_vals.items()])) range_elem = "[%s]" % (",".join("%s" % (l) for l in lex)) map_str += "%s -> %s; " % (domain_elem, range_elem) map_str += "}" @@ -302,4 +317,3 @@ class LexSchedule(object): def __str__(self): return str(list(self.lex_schedule.items())) - -- GitLab From b3577727f05bc7f72ef1a0933b07d42ad738e101 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 19:51:15 -0500 Subject: [PATCH 045/183] fixing pep8 issues --- lexicographic_order_map.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index f4c51f68c..32c33cbf6 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -6,7 +6,7 @@ def make_lex_mapping_tuple_pairs(dim_bounds): import itertools # all lex tuples in order: lex_tuples = list( - itertools.product(*[range(l,u) for l,u in dim_bounds])) + itertools.product(*[range(l, u) for l, u in dim_bounds])) # goes up to u-1 because u is a non-inclusive upper bound # TODO: is itertools.product ordering guaranteed? @@ -47,7 +47,6 @@ def create_explicit_map_from_tuples(tuple_pairs, space): def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): dim_type = isl.dim_type - individual_maps = [] from schedule_checker.sched_check_utils import get_islvars_from_space #param_names = space.get_var_names(isl.dim_type.param) @@ -83,7 +82,8 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): len(in_names), len(out_names)) """ result_map_vars_in = result_map.space.get_var_names(isl.dim_type.in_) - domain_stripped = domain_to_intersect.project_out_except(result_map_vars_in, [isl.dim_type.set]) + domain_stripped = domain_to_intersect.project_out_except( + result_map_vars_in, [isl.dim_type.set]) return result_map.intersect_domain(domain_stripped) """ from schedule_checker.sched_check_utils import add_missing_set_dims_to_map_indims @@ -124,8 +124,10 @@ def set_space_names(space, param_names=None, in_names=None, out_names=None): def get_space(param_names, in_names, out_names): - space = isl.Space.alloc(isl.DEFAULT_CONTEXT, len(param_names), len(in_names), len(out_names)) - return set_space_names(space, param_names=param_names, in_names=in_names, out_names=out_names) + space = isl.Space.alloc( + isl.DEFAULT_CONTEXT, len(param_names), len(in_names), len(out_names)) + return set_space_names( + space, param_names=param_names, in_names=in_names, out_names=out_names) #TODO rename these functions for clarity @@ -170,5 +172,3 @@ def create_symbolic_lex_mapping( len(in_names), len(out_names)) return lex_map - - -- GitLab From b26b3b1479ec216566fd4b0def61200fd1eb16e0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 19:53:19 -0500 Subject: [PATCH 046/183] fixing pep8 issues --- sched_check_utils.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 48109a301..dd9d636ab 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -1,7 +1,9 @@ import islpy as isl + def prettier_map_string(isl_map): - return str(isl_map).replace("{ ", "{\n").replace(" }","\n}").replace("; ",";\n") + return str(isl_map + ).replace("{ ", "{\n").replace(" }", "\n}").replace("; ", ";\n") def flatten_2d_list(list2d): @@ -14,18 +16,23 @@ def get_islvars_from_space(space): 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]) + 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 create_new_set_with_primes(old_set): new_set = old_set.copy() for i in range(old_set.n_dim()): - new_set = new_set.set_dim_name(isl.dim_type.out, i, old_set.get_dim_name(isl.dim_type.out, i)+"'") + new_set = new_set.set_dim_name(isl.dim_type.out, i, old_set.get_dim_name( + isl.dim_type.out, i)+"'") return new_set + def add_missing_set_dims_to_map_indims(islmap, islset): new_map = islmap.copy() for i in range(islset.n_dim()): -- GitLab From 6c6d08b881f5189c3120905632f05d9709f5582f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 20:07:21 -0500 Subject: [PATCH 047/183] added some todos to clean up examples --- dependency.py | 2 ++ example_dep_pairwise_schedule_creation.py | 1 + example_dependency_checking.py | 3 ++- example_lex_map_creation.py | 1 + example_schedule_creation_old.py | 3 +++ 5 files changed, 9 insertions(+), 1 deletion(-) diff --git a/dependency.py b/dependency.py index 07ad15112..a491ff347 100644 --- a/dependency.py +++ b/dependency.py @@ -70,6 +70,7 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): dim_type.out, 0, dim_type.in_, mv_count, mv_count) +""" def create_dependency_constraint_old( dependencies, all_inames_ordered, @@ -154,6 +155,7 @@ def create_dependency_constraint_old( map_with_loop_domain_constraints = all_constraints_map.intersect_domain( domain_to_intersect).intersect_range(range_to_intersect) return map_with_loop_domain_constraints +""" def create_dependency_constraint( diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py index 2f995eb3e..1befbce3b 100644 --- a/example_dep_pairwise_schedule_creation.py +++ b/example_dep_pairwise_schedule_creation.py @@ -406,6 +406,7 @@ print("is valid sched valid? constraint map subset of SIO?") print(sched_is_valid) +# TODO create example with simple explicit sched ''' all_inames = ['i', 'j'] iname_params = ['p0', 'p1'] diff --git a/example_dependency_checking.py b/example_dependency_checking.py index e394e779b..b9d2b96dc 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -1,4 +1,3 @@ -import islpy as isl import loopy as lp from schedule_checker.dependency import ( Dependency, @@ -18,6 +17,8 @@ from schedule_checker.sched_check_utils import ( append_apostrophes, ) +# TODO update these examples to work with dep code changes + # make example kernel knl = lp.make_kernel( "{[i,j]: 0<=i,j<2}", diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py index d94d4b313..aebe48cd0 100644 --- a/example_lex_map_creation.py +++ b/example_lex_map_creation.py @@ -12,6 +12,7 @@ from schedule_checker.lexicographic_order_map import ( create_symbolic_lex_mapping, ) +# TODO update to work with new changes to lex code # *Symbolic* lexicographic mapping- map each tuple to all tuples occuring later diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index 47876b51c..53337ac65 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -21,6 +21,9 @@ from schedule_checker.sched_check_utils import ( order_var_names_to_match_islset, ) +# TODO either remove this file or update and keep as an example of full schedule creation +# (rather than the usual pairwise schedule creation) + knl_choice = "example" #knl_choice = "matmul" #knl_choice = "scan" -- GitLab From 12389aaf14e25ea55d6266d8987ad4b645556ed6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 20:47:44 -0500 Subject: [PATCH 048/183] removed unused function --- sched_check_utils.py | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index dd9d636ab..e14c5e12c 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -61,27 +61,6 @@ def make_islvars_with_var_primes(var_names, param_names): var_names+append_apostrophes(var_names), param_names) -def _create_positive_set_with_bounds( - var_names, param_names, upper_bounds): - - # TODO assumes lower bound is zero - islvars = make_islvars_with_var_primes(var_names, param_names) - - bounded_set = islvars[0].eq_set(islvars[0]) # initialize to True - - for v, p, b in zip(var_names, param_names, upper_bounds): - # create constraint 0 <= v,v'< p = b - v_prime = v+"'" - bounded_set = bounded_set \ - & islvars[v].lt_set(islvars[p]) \ - & islvars[v_prime].lt_set(islvars[p]) \ - & (islvars[0]-1).lt_set(islvars[v]) \ - & (islvars[0]-1).lt_set(islvars[v_prime]) \ - & islvars[p].eq_set(islvars[0]+b) - - return bounded_set - - def append_apostrophes(strings): if not isinstance(strings, list): raise ValueError("append_apostrophes did not receive a list") -- GitLab From 1f81864635e0d1fbb6fee032c01c74ed0c0af9f1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 20:49:01 -0500 Subject: [PATCH 049/183] temporarily uncommenting out old dep creation function to keep old example working; will remove later --- dependency.py | 175 ++++++++++++++++----------------- example_dependency_checking.py | 4 +- 2 files changed, 89 insertions(+), 90 deletions(-) diff --git a/dependency.py b/dependency.py index a491ff347..7a35cd901 100644 --- a/dependency.py +++ b/dependency.py @@ -70,94 +70,6 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): dim_type.out, 0, dim_type.in_, mv_count, mv_count) -""" -def create_dependency_constraint_old( - dependencies, - all_inames_ordered, - statement_var, - domain_constraint_set, - sid_to_int, - ): - from schedule_checker.sched_check_utils import ( - make_islvars_with_var_primes, - append_apostrophes, - add_dims_to_isl_set, - create_new_set_with_primes, - ) - # This function uses the dependencies given to create the following constraint: - # Statement [s,i,j] comes before statement [s',i',j'] iff - - # assumes statements are numbered sequentially - # (statement_bound = max statement id + 1) - - # make sure all dependencies involve same two statements - if len(set([dep.statement_before.sid for dep in dependencies])) != 1 or \ - len(set([dep.statement_after.sid for dep in dependencies])) != 1: - raise ValueError("All depencencies must be between same two statements.") - # make sure all dependencies involve different inames - if len(set([dep.iname for dep in dependencies])) != len(dependencies): - raise ValueError("All depencencies must apply to different inames.") - - statement_var_prime = statement_var+"'" - dt = DependencyType - islvars = make_islvars_with_var_primes( - [statement_var]+all_inames_ordered, - []) - - # initialize constraints to False - # this will disappear as soon as we add a constraint that is not dt.NONE - all_constraints_set = islvars[0].eq_set(islvars[0] + 1) - - for dep in dependencies: - iname = dep.iname - dep_type = dep.dep_type - if dep_type == dt.NONE: - continue - - iname_prime = iname+"'" # i' - other_inames = all_inames_ordered.copy() - other_inames.remove(iname) # remaining inames, e.g., [j, k] - other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] - - # initialize constraint set with what we know about other inames - # (e.g., j = j', k = k') - constraint_set = create_equality_conjunction_set( - other_inames, other_inames_prime, islvars) - if dep_type == dt.SAME: - constraint_set = constraint_set & islvars[iname].eq_set( - islvars[iname_prime]) - elif dep_type == dt.PRIOR: - constraint_set = constraint_set & islvars[iname].lt_set( - islvars[iname_prime]) - elif dep_type == dt.ALL: - constraint_set = constraint_set & islvars[0].eq_set(islvars[0]) # True - - s_before_int = sid_to_int[dep.statement_before.sid] - s_after_int = sid_to_int[dep.statement_after.sid] - constraint_set = constraint_set & islvars[statement_var].eq_set( - islvars[0]+s_before_int) - constraint_set = constraint_set & islvars[statement_var_prime].eq_set( - islvars[0]+s_after_int) - - all_constraints_set = all_constraints_set | constraint_set - - all_constraints_map = _convert_constraint_set_to_map( - all_constraints_set, len(all_inames_ordered)+1) - - range_constraint_set = create_new_set_with_primes(domain_constraint_set) - - new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' - domain_to_intersect = add_dims_to_isl_set( - domain_constraint_set, isl.dim_type.out, ["s"], new_pose) - range_to_intersect = add_dims_to_isl_set( - range_constraint_set, isl.dim_type.out, ["s'"], new_pose) - - map_with_loop_domain_constraints = all_constraints_map.intersect_domain( - domain_to_intersect).intersect_range(range_to_intersect) - return map_with_loop_domain_constraints -""" - - def create_dependency_constraint( statement_dep, all_inames_ordered, @@ -333,3 +245,90 @@ def create_dependencies_from_legacy_knl(knl): deps.append(StatementDependency(s_before, s_after, iname_deps)) return deps + + +# TODO update previous calls to this to use new function, then remove this +def create_dependency_constraint_old( + dependencies, + all_inames_ordered, + statement_var, + domain_constraint_set, + sid_to_int, + ): + from schedule_checker.sched_check_utils import ( + make_islvars_with_var_primes, + append_apostrophes, + add_dims_to_isl_set, + create_new_set_with_primes, + ) + # This function uses the dependencies given to create the following constraint: + # Statement [s,i,j] comes before statement [s',i',j'] iff + + # assumes statements are numbered sequentially + # (statement_bound = max statement id + 1) + + # make sure all dependencies involve same two statements + if len(set([dep.statement_before.sid for dep in dependencies])) != 1 or \ + len(set([dep.statement_after.sid for dep in dependencies])) != 1: + raise ValueError("All depencencies must be between same two statements.") + # make sure all dependencies involve different inames + if len(set([dep.iname for dep in dependencies])) != len(dependencies): + raise ValueError("All depencencies must apply to different inames.") + + statement_var_prime = statement_var+"'" + dt = DependencyType + islvars = make_islvars_with_var_primes( + [statement_var]+all_inames_ordered, + []) + + # initialize constraints to False + # this will disappear as soon as we add a constraint that is not dt.NONE + all_constraints_set = islvars[0].eq_set(islvars[0] + 1) + + for dep in dependencies: + iname = dep.iname + dep_type = dep.dep_type + if dep_type == dt.NONE: + continue + + iname_prime = iname+"'" # i' + other_inames = all_inames_ordered.copy() + other_inames.remove(iname) # remaining inames, e.g., [j, k] + other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] + + # initialize constraint set with what we know about other inames + # (e.g., j = j', k = k') + constraint_set = create_equality_conjunction_set( + other_inames, other_inames_prime, islvars) + if dep_type == dt.SAME: + constraint_set = constraint_set & islvars[iname].eq_set( + islvars[iname_prime]) + elif dep_type == dt.PRIOR: + constraint_set = constraint_set & islvars[iname].lt_set( + islvars[iname_prime]) + elif dep_type == dt.ALL: + constraint_set = constraint_set & islvars[0].eq_set(islvars[0]) # True + + s_before_int = sid_to_int[dep.statement_before.sid] + s_after_int = sid_to_int[dep.statement_after.sid] + constraint_set = constraint_set & islvars[statement_var].eq_set( + islvars[0]+s_before_int) + constraint_set = constraint_set & islvars[statement_var_prime].eq_set( + islvars[0]+s_after_int) + + all_constraints_set = all_constraints_set | constraint_set + + all_constraints_map = _convert_constraint_set_to_map( + all_constraints_set, len(all_inames_ordered)+1) + + range_constraint_set = create_new_set_with_primes(domain_constraint_set) + + new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' + domain_to_intersect = add_dims_to_isl_set( + domain_constraint_set, isl.dim_type.out, ["s"], new_pose) + range_to_intersect = add_dims_to_isl_set( + range_constraint_set, isl.dim_type.out, ["s'"], new_pose) + + map_with_loop_domain_constraints = all_constraints_map.intersect_domain( + domain_to_intersect).intersect_range(range_to_intersect) + return map_with_loop_domain_constraints diff --git a/example_dependency_checking.py b/example_dependency_checking.py index b9d2b96dc..d91facebd 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -2,7 +2,7 @@ import loopy as lp from schedule_checker.dependency import ( Dependency, DependencyType as DT, - create_dependency_constraint, + create_dependency_constraint_old, ) from schedule_checker.lexicographic_order_map import ( make_lex_mapping_tuple_pairs, @@ -140,7 +140,7 @@ deps = [ ] print([str(dep) for dep in deps]) -constraint_map = create_dependency_constraint( +constraint_map = create_dependency_constraint_old( deps, all_inames_ordered, statement_var, -- GitLab From b72cf2d8eaa267d7168c89a31964e0b9ecf27ca6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 20:49:55 -0500 Subject: [PATCH 050/183] clarifying make_lex_mapping_tuple_pairs() with some comments and better variable names --- lexicographic_order_map.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 32c33cbf6..ad99db010 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -3,6 +3,14 @@ import islpy as isl def make_lex_mapping_tuple_pairs(dim_bounds): + # Given list of integer dimension bound pairs + # [(lower0, upper0), (lower1, upper1) ... ], + # create a list of tuple pairs [(x0, x1, ...), (y0, y1, ...)] + # representing a relation that maps from each point + # to every point that comes after that point in a lexicographic ordering + + # lower bounds are inclusive, upper bounds are exclusive + import itertools # all lex tuples in order: lex_tuples = list( @@ -155,18 +163,18 @@ def create_symbolic_lex_mapping( # create constraint enforcing lex ordering, e.g., in the 3-dim case: # i0 < o0 or ((i0 = o0) and (i1 < o1)) # or ((i0 = o0) and (i1 = o1) and (i2 < o2)) - lex_set_order_bound = islvars[in_names[0]].lt_set(islvars[out_names[0]]) + lex_order_constraint = islvars[in_names[0]].lt_set(islvars[out_names[0]]) for i in range(1, len(in_names)): - lex_set_order_bound_conj = islvars[in_names[i]].lt_set( + lex_order_constraint_conj = islvars[in_names[i]].lt_set( islvars[out_names[i]]) for j in range(i): - lex_set_order_bound_conj = lex_set_order_bound_conj & \ + lex_order_constraint_conj = lex_order_constraint_conj & \ islvars[in_names[j]].eq_set(islvars[out_names[j]]) - lex_set_order_bound = lex_set_order_bound | lex_set_order_bound_conj + lex_order_constraint = lex_order_constraint | lex_order_constraint_conj - #lex_set = lex_set_outer_bounds & lex_set_order_bound + #lex_set = lex_set_outer_bounds & lex_order_constraint #lex_map = isl.Map.from_domain(lex_set) - lex_map = isl.Map.from_domain(lex_set_order_bound) + lex_map = isl.Map.from_domain(lex_order_constraint) lex_map = lex_map.move_dims( dim_type.out, 0, dim_type.in_, len(in_names), len(out_names)) -- GitLab From 37475dcb8bd3a4dcfe3630c3d91f2bb1c3c2d930 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 20:50:38 -0500 Subject: [PATCH 051/183] moving methods for creating explicit schedules to end of file; may remove soon --- schedule.py | 166 ++++++++++++++++++++++++---------------------------- 1 file changed, 78 insertions(+), 88 deletions(-) diff --git a/schedule.py b/schedule.py index 2371c40a1..306ffd5de 100644 --- a/schedule.py +++ b/schedule.py @@ -105,25 +105,6 @@ class LexSchedule(object): new_sched[insn] = lex_pt + [0]*(max_lex_dim-len(lex_pt)) self.lex_schedule = new_sched - def enumerate_iname(self, iname, bound): - new_sched = OrderedDict() - iname_found = False - for insn, lex_pt in self.lex_schedule.items(): - if iname in lex_pt: - for v in range(bound[0], bound[1]): - new_sched[tuple(list(insn)+[v])] = [ - lx if lx != iname else v for lx in lex_pt] - iname_found = True - else: - new_sched[insn] = lex_pt - self.lex_schedule = new_sched - if iname_found: - self.inames_enumerated.append(iname) - - def enumerate_inames(self, iname_bounds): - for iname, bound in iname_bounds.items(): - self.enumerate_iname(iname, bound) - def add_symbolic_inames_to_statement_instances(self, inames): for iname in inames: new_sched = OrderedDict() @@ -145,13 +126,6 @@ class LexSchedule(object): else: self.lp_insnid_to_int_sid[lp_insnid] = 0 - def get_space_for_explicit_sched(self): - params_sched = ["ps"] + ["p"+iname for iname in self.inames_enumerated] - in_names_sched = ["s"] + self.inames_enumerated - out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] - from schedule_checker.lexicographic_order_map import get_space - return get_space(params_sched, in_names_sched, out_names_sched) - def get_space_for_symbolic_sched(self): params_sched = [] in_names_sched = ["s"] + self.inames_not_enumerated @@ -159,33 +133,6 @@ class LexSchedule(object): from schedule_checker.lexicographic_order_map import get_space return get_space(params_sched, in_names_sched, out_names_sched) - def get_max_lex_dim_bounds(self, var_bounds_dict): - # this only works for integer lex pts (no symbolic vars) - #return [max(dim_pts) for dim_pts in zip(*self.lex_schedule.values())] - result = [] - for dim_pts in zip(*self.lex_schedule.values()): - if all(isinstance(pt, int) for pt in dim_pts): - result.append(max(dim_pts) + 1) - # +1 b/c this is the non-inclusive upper bound - else: - assert all(pt == dim_pts[0] for pt in dim_pts) - # append upper bound for this variable - result.append(var_bounds_dict[dim_pts[0]][1]) - return result - - def get_min_lex_dim_vals(self, var_bounds_dict): - # this only works for integer lex pts (no symbolic vars) - #return [min(dim_pts) for dim_pts in zip(*self.lex_schedule.values())] - result = [] - for dim_pts in zip(*self.lex_schedule.values()): - if all(isinstance(pt, int) for pt in dim_pts): - result.append(min(dim_pts)) - else: - assert all(pt == dim_pts[0] for pt in dim_pts) - # append lower bound for this variable - result.append(var_bounds_dict[dim_pts[0]][0]) - return result - def append_item(self, sched_item, lex_pt): self.lex_schedule[sched_item] = lex_pt @@ -195,17 +142,6 @@ class LexSchedule(object): def get_last_lex_pt(self): return self.lex_schedule[self.get_last_schedule_item()] - def create_explicit_isl_map(self, sched_space): - from schedule_checker.lexicographic_order_map import ( - create_explicit_map_from_tuples - ) - return create_explicit_map_from_tuples(list(self.items()), sched_space) - - def enumerate_symbolic_inames_and_create_explicit_isl_map(self, iname_bounds): - self.enumerate_inames(iname_bounds) - sched_space = self.get_space_for_explicit_sched() - return self.create_explicit_isl_map(sched_space) - #def create_symbolic_isl_map(self, dom_before, dom_after, inames): def create_symbolic_isl_map(self, domain, inames): # TODO if inames will always match domain out vars, don't need to pass them @@ -245,30 +181,6 @@ class LexSchedule(object): #dom_before_to_intersect, dom_after_to_intersect) list(self.items()), sched_space, domain_to_intersect) - def get_lex_map_explicit(self): - - from schedule_checker.lexicographic_order_map import ( - make_lex_mapping_tuple_pairs, - create_explicit_map_from_tuples, - get_space, - ) - from schedule_checker.sched_check_utils import append_apostrophes - - # TODO lower bound may not be zero - lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(), - self.get_max_lex_dim_vals())) - sched_space = self.get_space_for_explicit_sched() - - lex_in_names = sched_space.get_var_names(isl.dim_type.out) - lex_out_names = append_apostrophes(lex_in_names) - lex_params = [] - - explicit_lex_map_pairs = make_lex_mapping_tuple_pairs(lex_dim_bounds) - lex_space_explicit = get_space(lex_params, lex_in_names, lex_out_names) - - return create_explicit_map_from_tuples(explicit_lex_map_pairs, - lex_space_explicit) - def get_lex_map_symbolic(self): from schedule_checker.lexicographic_order_map import ( create_symbolic_lex_mapping, @@ -317,3 +229,81 @@ class LexSchedule(object): def __str__(self): return str(list(self.lex_schedule.items())) + + # Methods related to *explicit* schedule/map creation ------------------ + # TODO consider removing these + + def get_min_lex_dim_vals(self, var_bounds_dict): + + # this only works for integer lex pts (no symbolic vars): + #return [min(dim_pts) for dim_pts in zip(*self.lex_schedule.values())] + result = [] + for dim_pts in zip(*self.lex_schedule.values()): + if all(isinstance(pt, int) for pt in dim_pts): + result.append(min(dim_pts)) + else: + assert all(pt == dim_pts[0] for pt in dim_pts) + # append lower bound for this variable + result.append(var_bounds_dict[dim_pts[0]][0]) + return result + + def enumerate_iname(self, iname, bound): + new_sched = OrderedDict() + iname_found = False + for insn, lex_pt in self.lex_schedule.items(): + if iname in lex_pt: + for v in range(bound[0], bound[1]): + new_sched[tuple(list(insn)+[v])] = [ + lx if lx != iname else v for lx in lex_pt] + iname_found = True + else: + new_sched[insn] = lex_pt + self.lex_schedule = new_sched + if iname_found: + self.inames_enumerated.append(iname) + + def enumerate_inames(self, iname_bounds): + for iname, bound in iname_bounds.items(): + self.enumerate_iname(iname, bound) + + def get_space_for_explicit_sched(self): + params_sched = ["ps"] + ["p"+iname for iname in self.inames_enumerated] + in_names_sched = ["s"] + self.inames_enumerated + out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] + from schedule_checker.lexicographic_order_map import get_space + return get_space(params_sched, in_names_sched, out_names_sched) + + def create_explicit_isl_map(self, sched_space): + from schedule_checker.lexicographic_order_map import ( + create_explicit_map_from_tuples + ) + return create_explicit_map_from_tuples(list(self.items()), sched_space) + + def enumerate_symbolic_inames_and_create_explicit_isl_map(self, iname_bounds): + self.enumerate_inames(iname_bounds) + sched_space = self.get_space_for_explicit_sched() + return self.create_explicit_isl_map(sched_space) + + def get_lex_map_explicit(self): + + from schedule_checker.lexicographic_order_map import ( + make_lex_mapping_tuple_pairs, + create_explicit_map_from_tuples, + get_space, + ) + from schedule_checker.sched_check_utils import append_apostrophes + + # TODO lower bound may not be zero + lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(), + self.get_max_lex_dim_vals())) + sched_space = self.get_space_for_explicit_sched() + + lex_in_names = sched_space.get_var_names(isl.dim_type.out) + lex_out_names = append_apostrophes(lex_in_names) + lex_params = [] + + explicit_lex_map_pairs = make_lex_mapping_tuple_pairs(lex_dim_bounds) + lex_space_explicit = get_space(lex_params, lex_in_names, lex_out_names) + + return create_explicit_map_from_tuples(explicit_lex_map_pairs, + lex_space_explicit) -- GitLab From 6b4f07a41083808a0e05344e5452687fd8086f36 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 21:19:11 -0500 Subject: [PATCH 052/183] converted dependency example to use new dependency class --- dependency.py | 88 +------------------------------- example_dependency_checking.py | 25 ++++----- example_schedule_creation_old.py | 3 +- 3 files changed, 16 insertions(+), 100 deletions(-) diff --git a/dependency.py b/dependency.py index 7a35cd901..f186f95e2 100644 --- a/dependency.py +++ b/dependency.py @@ -189,6 +189,7 @@ def get_concurrent_inames(knl): return conc_inames, all_inames-conc_inames +# TODO remove after updating example def create_dependencies_from_legacy_knl_old(knl): from schedule_checker.schedule import Statement dt = DependencyType @@ -245,90 +246,3 @@ def create_dependencies_from_legacy_knl(knl): deps.append(StatementDependency(s_before, s_after, iname_deps)) return deps - - -# TODO update previous calls to this to use new function, then remove this -def create_dependency_constraint_old( - dependencies, - all_inames_ordered, - statement_var, - domain_constraint_set, - sid_to_int, - ): - from schedule_checker.sched_check_utils import ( - make_islvars_with_var_primes, - append_apostrophes, - add_dims_to_isl_set, - create_new_set_with_primes, - ) - # This function uses the dependencies given to create the following constraint: - # Statement [s,i,j] comes before statement [s',i',j'] iff - - # assumes statements are numbered sequentially - # (statement_bound = max statement id + 1) - - # make sure all dependencies involve same two statements - if len(set([dep.statement_before.sid for dep in dependencies])) != 1 or \ - len(set([dep.statement_after.sid for dep in dependencies])) != 1: - raise ValueError("All depencencies must be between same two statements.") - # make sure all dependencies involve different inames - if len(set([dep.iname for dep in dependencies])) != len(dependencies): - raise ValueError("All depencencies must apply to different inames.") - - statement_var_prime = statement_var+"'" - dt = DependencyType - islvars = make_islvars_with_var_primes( - [statement_var]+all_inames_ordered, - []) - - # initialize constraints to False - # this will disappear as soon as we add a constraint that is not dt.NONE - all_constraints_set = islvars[0].eq_set(islvars[0] + 1) - - for dep in dependencies: - iname = dep.iname - dep_type = dep.dep_type - if dep_type == dt.NONE: - continue - - iname_prime = iname+"'" # i' - other_inames = all_inames_ordered.copy() - other_inames.remove(iname) # remaining inames, e.g., [j, k] - other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] - - # initialize constraint set with what we know about other inames - # (e.g., j = j', k = k') - constraint_set = create_equality_conjunction_set( - other_inames, other_inames_prime, islvars) - if dep_type == dt.SAME: - constraint_set = constraint_set & islvars[iname].eq_set( - islvars[iname_prime]) - elif dep_type == dt.PRIOR: - constraint_set = constraint_set & islvars[iname].lt_set( - islvars[iname_prime]) - elif dep_type == dt.ALL: - constraint_set = constraint_set & islvars[0].eq_set(islvars[0]) # True - - s_before_int = sid_to_int[dep.statement_before.sid] - s_after_int = sid_to_int[dep.statement_after.sid] - constraint_set = constraint_set & islvars[statement_var].eq_set( - islvars[0]+s_before_int) - constraint_set = constraint_set & islvars[statement_var_prime].eq_set( - islvars[0]+s_after_int) - - all_constraints_set = all_constraints_set | constraint_set - - all_constraints_map = _convert_constraint_set_to_map( - all_constraints_set, len(all_inames_ordered)+1) - - range_constraint_set = create_new_set_with_primes(domain_constraint_set) - - new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' - domain_to_intersect = add_dims_to_isl_set( - domain_constraint_set, isl.dim_type.out, ["s"], new_pose) - range_to_intersect = add_dims_to_isl_set( - range_constraint_set, isl.dim_type.out, ["s'"], new_pose) - - map_with_loop_domain_constraints = all_constraints_map.intersect_domain( - domain_to_intersect).intersect_range(range_to_intersect) - return map_with_loop_domain_constraints diff --git a/example_dependency_checking.py b/example_dependency_checking.py index d91facebd..373cd7d9d 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -1,8 +1,8 @@ import loopy as lp from schedule_checker.dependency import ( - Dependency, + StatementDependency, DependencyType as DT, - create_dependency_constraint_old, + create_dependency_constraint, ) from schedule_checker.lexicographic_order_map import ( make_lex_mapping_tuple_pairs, @@ -130,21 +130,22 @@ print("domain union:") print(domain_union) # make some dependencies manually for now: -s0 = Statement("0", ["i", "j"]) -s1 = Statement("1", ["i", "j"]) +s0 = Statement("0", {"i", "j"}) +s1 = Statement("1", {"i", "j"}) insnid_to_int_sid = {"0": 0, "1": 1} -deps = [ - Dependency(s0, s1, DT.SAME, "i"), - Dependency(s0, s1, DT.SAME, "j"), - ] +statement_dep = StatementDependency(s0, s1, {"i": DT.SAME, "j": DT.SAME}) +print(statement_dep) +combined_doms = knl.get_inames_domain( + statement_dep.statement_before.active_inames | + statement_dep.statement_after.active_inames + ) -print([str(dep) for dep in deps]) -constraint_map = create_dependency_constraint_old( - deps, +constraint_map = create_dependency_constraint( + statement_dep, all_inames_ordered, statement_var, - domain_union, + combined_doms, insnid_to_int_sid, ) print("constraint map space:") diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index 53337ac65..3dd456b84 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -5,7 +5,7 @@ from schedule_checker.dependency import ( Dependency, DependencyType as DT, create_dependencies_from_legacy_knl_old, - create_dependency_constraint_old, + create_dependency_constraint, ) from schedule_checker.schedule import Statement, StatementInstance, LexSchedule from schedule_checker.sched_check_utils import prettier_map_string @@ -183,6 +183,7 @@ deps = [ #For every shared (between depender and dependee) concurrent iname Introduce an all dep print("----------------------------------------------------------------------") +# TODO use new version of this function dep_sets = create_dependencies_from_legacy_knl_old(knl) print("Dependency sets:") for dep_set in dep_sets: -- GitLab From f867424a365c5876d09b68c5aed7f7ffa2d410e9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 22:05:30 -0500 Subject: [PATCH 053/183] updated old sched creation example to use new StatementDependency class --- example_schedule_creation_old.py | 187 +++++-------------------------- 1 file changed, 30 insertions(+), 157 deletions(-) diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index 3dd456b84..944c17b93 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -1,18 +1,12 @@ -import islpy as isl import loopy as lp import numpy as np from schedule_checker.dependency import ( - Dependency, - DependencyType as DT, - create_dependencies_from_legacy_knl_old, + create_dependencies_from_legacy_knl, create_dependency_constraint, ) -from schedule_checker.schedule import Statement, StatementInstance, LexSchedule -from schedule_checker.sched_check_utils import prettier_map_string +from schedule_checker.schedule import LexSchedule from schedule_checker.lexicographic_order_map import ( - create_explicit_map_from_tuples, get_statement_ordering_map, - get_space, ) from schedule_checker.sched_check_utils import ( prettier_map_string, @@ -21,7 +15,7 @@ from schedule_checker.sched_check_utils import ( order_var_names_to_match_islset, ) -# TODO either remove this file or update and keep as an example of full schedule creation +# TODO either remove this file or update as an example of full sched creation # (rather than the usual pairwise schedule creation) knl_choice = "example" @@ -49,7 +43,8 @@ if knl_choice == "example": lang_version=(2018, 2) ) #knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32}) - knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32, "in": np.float32}) + knl = lp.add_and_infer_dtypes(knl, + {"b": np.float32, "d": np.float32, "in": np.float32}) knl = lp.tag_inames(knl, {"i": "l.0"}) knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) @@ -68,7 +63,7 @@ elif knl_choice == "matmul": knl = lp.split_iname(knl, "i", bsize, outer_tag="g.0", inner_tag="l.1") knl = lp.split_iname(knl, "j", bsize, outer_tag="g.1", inner_tag="l.0") knl = lp.split_iname(knl, "k", bsize) - knl = lp.add_prefetch(knl, "a", ["k_inner", "i_inner"], default_tag="l.auto") + knl = lp.add_prefetch(knl, "a", ["k_inner", "i_inner"], default_tag="l.auto") knl = lp.add_prefetch(knl, "b", ["j_inner", "k_inner"], default_tag="l.auto") knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) @@ -118,15 +113,6 @@ sched_map_symbolic = sched.create_symbolic_isl_map(domain_union, all_inames_orde print("LexSchedule after processing:") print(sched) # ------------------------------------------------------------------- -""" -from schedule_checker.sched_check_utils import (add_dims_to_isl_set) -new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' -domain_w_s = add_dims_to_isl_set( - domain_union, isl.dim_type.out, ['s'], new_pose) # TODO don't hardcode 's' -sched_map_vars_in = sched_map_symbolic.space.get_var_names(isl.dim_type.in_) -domain_stripped = domain_w_s.project_out_except(sched_map_vars_in, [isl.dim_type.set]) -""" -# ------------------------------------------------------------------- print("LexSched (valid):") print(prettier_map_string(sched_map_symbolic)) @@ -157,38 +143,23 @@ print(prettier_map_string(SIO_symbolic_valid)) print("space (statement instances -> statement instances):") print(SIO_symbolic_valid.space) - - -""" -# i is parallel, suppose we want to enforce the following: -# for a given i, statement 0 happens before statement 1 -# i dependency is none, j dependency is `prior` - -# make some dependencies manually for now: -s0 = Statement("0", ["i", "j"]) -s1 = Statement("1", ["i", "j"]) -s2 = Statement("2", ["i", "j"]) -#dep_s1_i = Dependency(s0, s1, DT.NONE, "i") -#dep_s1_j = Dependency(s0, s1, DT.PRIOR, "j") -#insn_to_deps = {"0":[], "1":[dep_s1_i, dep_s1_j], "2":[]} - -deps = [ - Dependency(s0, s1, DT.NONE, "i"), - Dependency(s0, s1, DT.PRIOR, "j"), - ] -""" - -#For every shared (between depender and dependee) non-concurrent iname Introduce a same dep +# For every shared (between depender and dependee) non-concurrent iname, +# Introduce a same dep # (Perform voodoo guesswork to determine whether a ‘prior’ dep is needed) -#For every shared (between depender and dependee) concurrent iname Introduce an all dep +# For every shared (between depender and dependee) concurrent iname, +# Introduce an all dep print("----------------------------------------------------------------------") # TODO use new version of this function -dep_sets = create_dependencies_from_legacy_knl_old(knl) -print("Dependency sets:") -for dep_set in dep_sets: - for dep in dep_set: - print(dep) +statement_deps = create_dependencies_from_legacy_knl(knl) +#print("Dependency sets:") +#for dep_set in dep_sets: +# for dep in dep_set: +# print(dep) +# print("") +print("Statement Dependencies:") +for sd in statement_deps: + print(sd) print("") print("----------------------------------------------------------------------") print("dict{lp insn id : sched sid int}:") @@ -196,13 +167,19 @@ print(sched.lp_insnid_to_int_sid) print("----------------------------------------------------------------------") statement_var = 's' sched_is_valid = True -for dep_set in dep_sets: - # TODO make create_dep_constraint accept whole set of dep_sets - constraint_map = create_dependency_constraint_old( - dep_set, +for statement_dep in statement_deps: + + # TODO is using this union in creating schedule (not deps) okay? + combined_doms = knl.get_inames_domain( + statement_dep.statement_before.active_inames | + statement_dep.statement_after.active_inames + ) + + constraint_map = create_dependency_constraint( + statement_dep, all_inames_ordered, statement_var, - domain_union, + combined_doms, sched.lp_insnid_to_int_sid, ) print("constraint map:") @@ -216,107 +193,3 @@ for dep_set in dep_sets: print("is valid sched valid? constraint map subset of SIO?") print(sched_is_valid) - - -''' -all_inames = ['i', 'j'] -iname_params = ['p0', 'p1'] -iname_param_vals = [2, 2] -statement_var = 's' -statement_param = 'ps' -statement_bound = 2 - - - -s0 = Statement("0", ["i", "j"]) -s1 = Statement("1", ["i", "j"]) -print("Statements:") -print(s0) -print(s1) - -s0_00 = StatementInstance(s0, {"i": 0, "j": 0}) -s0_10 = StatementInstance(s0, {"i": 1, "j": 0}) -s0_01 = StatementInstance(s0, {"i": 0, "j": 1}) -s0_11 = StatementInstance(s0, {"i": 1, "j": 1}) -s1_00 = StatementInstance(s1, {"i": 0, "j": 0}) -s1_10 = StatementInstance(s1, {"i": 1, "j": 0}) -s1_01 = StatementInstance(s1, {"i": 0, "j": 1}) -s1_11 = StatementInstance(s1, {"i": 1, "j": 1}) -print("Statement instances:") -print(s0_00) -print(s0_10) -print(s0_01) -print(s0_11) -print(s1_00) -print(s1_10) -print(s1_01) -print(s1_11) - -state_inst_to_lex_time_dict = { - s0_00: (0,0), - s1_00: (0,1), - s0_10: (0,0), - s1_10: (0,1), - s0_01: (1,0), - s1_01: (1,1), - s0_11: (1,0), - s1_11: (1,1), - } - -sched = LexSchedule(state_inst_to_lex_time_dict) -print("LexSchedule:") -print(sched) - -# sched map should be this: -schedule_explicit_map = isl.Map( - """{ - [s,i,j] -> [0,0] : s = 0 and i = 0 and j = 0; - [s,i,j] -> [0,1] : s = 1 and i = 0 and j = 0; - [s,i,j] -> [0,0] : s = 0 and i = 1 and j = 0; - [s,i,j] -> [0,1] : s = 1 and i = 1 and j = 0; - [s,i,j] -> [1,0] : s = 0 and i = 0 and j = 1; - [s,i,j] -> [1,1] : s = 1 and i = 0 and j = 1; - [s,i,j] -> [1,0] : s = 0 and i = 1 and j = 1; - [s,i,j] -> [1,1] : s = 1 and i = 1 and j = 1; - }""") - -schedule_general_map = isl.Map("{[s,i,j] -> [j,s]}") - -print("Map representing schedule generally:") -print(schedule_general_map) - -# the following is equivalent to explicit map above: -schedule_explicit_map2 = isl.Map( - """{ - [s=0,i=0,j=0] -> [0,0]; - [s=1,i=0,j=0] -> [0,1]; - [s=0,i=1,j=0] -> [0,0]; - [s=1,i=1,j=0] -> [0,1]; - [s=0,i=0,j=1] -> [1,0]; - [s=1,i=0,j=1] -> [1,1]; - [s=0,i=1,j=1] -> [1,0]; - [s=1,i=1,j=1] -> [1,1]; - }""") -assert schedule_explicit_map2 == schedule_explicit_map == sched.get_isl_map() - -''' - -""" -dep_i_same = Dependency(s0, s1, "i", DependencyType.SAME) -dep_i_none = Dependency(s0, s1, "i", DependencyType.NONE) -dep_i_prior = Dependency(s0, s1, "i", DependencyType.PRIOR) -dep_i_all = Dependency(s0, s1, "i", DependencyType.ALL) -dep_j_same = Dependency(s0, s1, "j", DependencyType.SAME) -dep_j_none = Dependency(s0, s1, "j", DependencyType.NONE) -dep_j_prior = Dependency(s0, s1, "j", DependencyType.PRIOR) -dep_j_all = Dependency(s0, s1, "j", DependencyType.ALL) -print("Example dependencies: ") -print(dep_i_same) -print(dep_i_none) -print(dep_i_prior) -print(dep_i_all) -print(dep_j_same) -print(dep_j_none) -print(dep_j_prior) -print(dep_j_all) -""" -- GitLab From 16616622cc442e07d99d49ab507205a92b66d451 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 22:08:15 -0500 Subject: [PATCH 054/183] removed create_dependencies_from_legacy_knl_old --- dependency.py | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/dependency.py b/dependency.py index f186f95e2..53b2bae0d 100644 --- a/dependency.py +++ b/dependency.py @@ -189,34 +189,6 @@ def get_concurrent_inames(knl): return conc_inames, all_inames-conc_inames -# TODO remove after updating example -def create_dependencies_from_legacy_knl_old(knl): - from schedule_checker.schedule import Statement - dt = DependencyType - conc_inames, non_conc_inames = get_concurrent_inames(knl) - all_inames = list(knl.all_inames()) - dep_sets = [] - for insn_after in knl.instructions: - for insn_before_id in insn_after.depends_on: - dep_set = [] - insn_before = knl.id_to_insn[insn_before_id] - insn_before_inames = insn_before.within_inames - insn_after_inames = insn_after.within_inames - shared_inames = insn_before_inames & insn_after_inames - shared_conc_inames = shared_inames & conc_inames - shared_non_conc_inames = shared_inames & non_conc_inames - s_before = Statement(insn_before.id, all_inames) - s_after = Statement(insn_after.id, all_inames) - for non_conc_iname in shared_non_conc_inames: - dep_set.append( - Dependency(s_before, s_after, dt.SAME, non_conc_iname)) - for conc_iname in shared_conc_inames: - dep_set.append( - Dependency(s_before, s_after, dt.ALL, conc_iname)) - dep_sets.append(dep_set) - return dep_sets - - def create_dependencies_from_legacy_knl(knl): from schedule_checker.schedule import Statement dt = DependencyType -- GitLab From 2724a066954e0485a34b08c9a5a7920539d32efc Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 22:12:22 -0500 Subject: [PATCH 055/183] removed old Dependency class --- dependency.py | 22 ----------- example_dep_pairwise_schedule_creation.py | 47 ----------------------- 2 files changed, 69 deletions(-) diff --git a/dependency.py b/dependency.py index 53b2bae0d..b736474f2 100644 --- a/dependency.py +++ b/dependency.py @@ -8,28 +8,6 @@ class DependencyType: ALL = "all" -# TODO remove old dep class -class Dependency(object): - def __init__( - self, - statement_before, - statement_after, - dep_type, - iname, - ): - self.statement_before = statement_before - self.statement_after = statement_after - self.dep_type = dep_type - self.iname = iname - - def __str__(self): - return "%s -> %s {%s dep: %s}" % ( - self.statement_before, - self.statement_after, - self.iname, - self.dep_type) - - class StatementDependency(object): def __init__( self, diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py index 1befbce3b..bc6d59ee6 100644 --- a/example_dep_pairwise_schedule_creation.py +++ b/example_dep_pairwise_schedule_creation.py @@ -302,16 +302,6 @@ for statement_dep, dom_before, dom_after in deps_and_domains: print("LexSchedule after processing:") print(sched) # ------------------------------------------------------------------- - """ - from schedule_checker.sched_check_utils import (add_dims_to_isl_set) - new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' - domain_w_s = add_dims_to_isl_set( - domain_union, isl.dim_type.out, ['s'], new_pose) # TODO don't hardcode 's' - sched_map_vars_in = sched_map_symbolic.space.get_var_names(isl.dim_type.in_) - domain_stripped = domain_w_s.project_out_except( - sched_map_vars_in, [isl.dim_type.set]) - """ - # ------------------------------------------------------------------- print("LexSched (valid):") print(prettier_map_string(sched_map_symbolic)) @@ -341,24 +331,6 @@ for statement_dep, dom_before, dom_after in deps_and_domains: print(prettier_map_string(SIO_symbolic_valid)) print("SIO space (statement instances -> statement instances):") print(SIO_symbolic_valid.space) - """ - # i is parallel, suppose we want to enforce the following: - # for a given i, statement 0 happens before statement 1 - # i dependency is none, j dependency is `prior` - - # make some dependencies manually for now: - s0 = Statement("0", ["i", "j"]) - s1 = Statement("1", ["i", "j"]) - s2 = Statement("2", ["i", "j"]) - #dep_s1_i = Dependency(s0, s1, DT.NONE, "i") - #dep_s1_j = Dependency(s0, s1, DT.PRIOR, "j") - #insn_to_deps = {"0":[], "1":[dep_s1_i, dep_s1_j], "2":[]} - - deps = [ - Dependency(s0, s1, DT.NONE, "i"), - Dependency(s0, s1, DT.PRIOR, "j"), - ] - """ print("-"*85) print("dict{lp insn id : sched sid int}:") @@ -490,22 +462,3 @@ assert schedule_explicit_map2 == schedule_explicit_map == sched.get_isl_map() ''' -""" -dep_i_same = Dependency(s0, s1, "i", DependencyType.SAME) -dep_i_none = Dependency(s0, s1, "i", DependencyType.NONE) -dep_i_prior = Dependency(s0, s1, "i", DependencyType.PRIOR) -dep_i_all = Dependency(s0, s1, "i", DependencyType.ALL) -dep_j_same = Dependency(s0, s1, "j", DependencyType.SAME) -dep_j_none = Dependency(s0, s1, "j", DependencyType.NONE) -dep_j_prior = Dependency(s0, s1, "j", DependencyType.PRIOR) -dep_j_all = Dependency(s0, s1, "j", DependencyType.ALL) -print("Example dependencies: ") -print(dep_i_same) -print(dep_i_none) -print(dep_i_prior) -print(dep_i_all) -print(dep_j_same) -print(dep_j_none) -print(dep_j_prior) -print(dep_j_all) -""" -- GitLab From a9c3f748f9b0619d7c08e661ba1aebb9ca5af0d5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 22:17:00 -0500 Subject: [PATCH 056/183] fixing pep8 issues --- example_dependency_checking.py | 42 +++++++++++++++------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/example_dependency_checking.py b/example_dependency_checking.py index 373cd7d9d..c236cc144 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -1,14 +1,13 @@ import loopy as lp from schedule_checker.dependency import ( StatementDependency, - DependencyType as DT, + DependencyType as dt, create_dependency_constraint, ) from schedule_checker.lexicographic_order_map import ( make_lex_mapping_tuple_pairs, create_explicit_map_from_tuples, get_statement_ordering_map, - set_space_names, get_space, ) from schedule_checker.schedule import Statement @@ -17,7 +16,6 @@ from schedule_checker.sched_check_utils import ( append_apostrophes, ) -# TODO update these examples to work with dep code changes # make example kernel knl = lp.make_kernel( @@ -32,7 +30,6 @@ knl = lp.tag_inames(knl, {"i": "l.0"}) print("Kernel:") print(knl) -from schedule_checker.sched_check_utils import flatten_2d_list all_inames_ordered = ['i', 'j'] #all_inames_ordered = sorted(list(knl.all_inames())) statement_var = 's' @@ -50,14 +47,14 @@ sched_space = get_space(params_sched, in_names_sched, out_names_sched) example_sched_valid = create_explicit_map_from_tuples( [ - ((0,0,0), (0, 0)), - ((0,1,0), (0, 0)), - ((1,0,0), (0, 1)), - ((1,1,0), (0, 1)), - ((0,0,1), (1, 0)), - ((0,1,1), (1, 0)), - ((1,0,1), (1, 1)), - ((1,1,1), (1, 1)), + ((0, 0, 0), (0, 0)), + ((0, 1, 0), (0, 0)), + ((1, 0, 0), (0, 1)), + ((1, 1, 0), (0, 1)), + ((0, 0, 1), (1, 0)), + ((0, 1, 1), (1, 0)), + ((1, 0, 1), (1, 1)), + ((1, 1, 1), (1, 1)), ], sched_space, ) @@ -66,14 +63,14 @@ print(prettier_map_string(example_sched_valid)) example_sched_invalid = create_explicit_map_from_tuples( [ - ((0,0,0), (0, 0)), - ((0,1,0), (1, 1)), # these two are out of order, violation - ((1,0,0), (0, 1)), - ((1,1,0), (0, 1)), - ((0,0,1), (1, 0)), - ((0,1,1), (1, 0)), - ((1,0,1), (1, 1)), - ((1,1,1), (0, 0)), # these two are out of order, violation + ((0, 0, 0), (0, 0)), + ((0, 1, 0), (1, 1)), # these two are out of order, violation + ((1, 0, 0), (0, 1)), + ((1, 1, 0), (0, 1)), + ((0, 0, 1), (1, 0)), + ((0, 1, 1), (1, 0)), + ((1, 0, 1), (1, 1)), + ((1, 1, 1), (0, 0)), # these two are out of order, violation ], sched_space, ) @@ -82,7 +79,7 @@ print(prettier_map_string(example_sched_invalid)) # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later print("---------------------------------------------------------------------------") -lex_dim_bounds = [(0,2), (0,2)] # max vals for each dim (e.g., 0 <= i0 < max0 ...) +lex_dim_bounds = [(0, 2), (0, 2)] # max vals for each dim (e.g., 0 <= i0 < max0 ...) lex_params = [] lex_in_names = out_names_sched lex_out_names = append_apostrophes(out_names_sched) @@ -134,7 +131,7 @@ s0 = Statement("0", {"i", "j"}) s1 = Statement("1", {"i", "j"}) insnid_to_int_sid = {"0": 0, "1": 1} -statement_dep = StatementDependency(s0, s1, {"i": DT.SAME, "j": DT.SAME}) +statement_dep = StatementDependency(s0, s1, {"i": dt.SAME, "j": dt.SAME}) print(statement_dep) combined_doms = knl.get_inames_domain( statement_dep.statement_before.active_inames | @@ -163,4 +160,3 @@ print(constraint_map.is_subset(SIO_explicit_valid)) print("is invalid sched valid?") print(constraint_map.is_subset(SIO_explicit_invalid)) #print(SIO_explicit_invalid.is_subset(constraint_map)) - -- GitLab From dda8f89abcd7c47a202393ba96dbc4cc5322c2a9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 22:47:53 -0500 Subject: [PATCH 057/183] renamed some functions to clarify difference between lex ordering map and schedule (statement->lex_pt map); also cleaned up some TODOs --- example_dep_pairwise_schedule_creation.py | 4 ++-- example_dependency_checking.py | 14 ++++---------- example_lex_map_creation.py | 19 ++++--------------- example_schedule_creation_old.py | 10 ++-------- lexicographic_order_map.py | 8 ++------ schedule.py | 16 ++++++++-------- 6 files changed, 22 insertions(+), 49 deletions(-) diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py index bc6d59ee6..a667638ea 100644 --- a/example_dep_pairwise_schedule_creation.py +++ b/example_dep_pairwise_schedule_creation.py @@ -310,9 +310,9 @@ for statement_dep, dom_before, dom_after in deps_and_domains: # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later print("-"*85) - #lex_map_explicit = sched.get_lex_map_explicit() + #lex_map_explicit = sched.get_explicit_sched_map() - lex_map_symbolic = sched.get_lex_map_symbolic() + lex_map_symbolic = sched.get_symbolic_sched_map() print("lex map symbolic:") print(prettier_map_string(lex_map_symbolic)) diff --git a/example_dependency_checking.py b/example_dependency_checking.py index c236cc144..bd083947c 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -1,11 +1,11 @@ import loopy as lp -from schedule_checker.dependency import ( +from schedule_checker.dependency import ( # noqa StatementDependency, DependencyType as dt, create_dependency_constraint, ) from schedule_checker.lexicographic_order_map import ( - make_lex_mapping_tuple_pairs, + make_lex_order_map_tuple_pairs, create_explicit_map_from_tuples, get_statement_ordering_map, get_space, @@ -84,7 +84,7 @@ lex_params = [] lex_in_names = out_names_sched lex_out_names = append_apostrophes(out_names_sched) -explicit_lex_map_pairs = make_lex_mapping_tuple_pairs(lex_dim_bounds) +explicit_lex_map_pairs = make_lex_order_map_tuple_pairs(lex_dim_bounds) # for pair in explicit_lex_map_pairs: # print(pair[0], pair[1]) lex_space_explicit = get_space(lex_params, lex_in_names, lex_out_names) @@ -119,12 +119,6 @@ domains = {} for iname in all_inames_ordered: domains[iname] = knl.get_inames_domain(iname) domains_list = list(domains.values()) -domain_union = domains_list[0] -#TODO is union the right thing to do here? -for dom in domains_list[1:]: - domain_union = domain_union.union(dom) -print("domain union:") -print(domain_union) # make some dependencies manually for now: s0 = Statement("0", {"i", "j"}) @@ -134,7 +128,7 @@ insnid_to_int_sid = {"0": 0, "1": 1} statement_dep = StatementDependency(s0, s1, {"i": dt.SAME, "j": dt.SAME}) print(statement_dep) combined_doms = knl.get_inames_domain( - statement_dep.statement_before.active_inames | + statement_dep.statement_before.active_inames | # noqa statement_dep.statement_after.active_inames ) diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py index aebe48cd0..fc9482a9f 100644 --- a/example_lex_map_creation.py +++ b/example_lex_map_creation.py @@ -1,25 +1,16 @@ -import islpy as isl -from schedule_checker.dependency import ( - Dependency, - DependencyType as DT, -) from schedule_checker.lexicographic_order_map import ( - make_lex_mapping_tuple_pairs, create_explicit_map_from_tuples, get_statement_ordering_map, - set_space_names, get_space, - create_symbolic_lex_mapping, + create_symbolic_lex_order_map, ) -# TODO update to work with new changes to lex code - # *Symbolic* lexicographic mapping- map each tuple to all tuples occuring later #in_names = ["i", "j"] #out_names = append_apostrophes(in_names) -n_dims = 2 #len(in_names) -lex_map_symbolic = create_symbolic_lex_mapping( +n_dims = 2 # len(in_names) +lex_map_symbolic = create_symbolic_lex_order_map( n_dims) print("lex_map (symbolic):") print(lex_map_symbolic) @@ -29,7 +20,7 @@ print(lex_map_symbolic) """ dim_bounds = [(0,2), (0,2)] # max vals for each dim (e.g., 0 <= i0 < max0 ...) -explicit_lex_map_pairs = make_lex_mapping_tuple_pairs(dim_bounds) +explicit_lex_map_pairs = make_lex_order_map_tuple_pairs(dim_bounds) # for pair in explicit_lex_map_pairs: # print(pair[0], pair[1]) lex_map_explicit = create_explicit_map_from_tuples(explicit_lex_map_pairs, @@ -72,7 +63,6 @@ print("statement instance ordering explicit:") print(statement_instance_ordering_explicit) """ -# TODO figure out where these "p0 >= 2 and p1 >= 2" are coming from: statement_instance_ordering_symbolic = get_statement_ordering_map( example_sched, lex_map_symbolic) print("statement instance ordering symbolic:") @@ -137,4 +127,3 @@ statement_instance_ordering_explicit = get_statement_ordering_map( print("statement instance ordering explicit:") print(statement_instance_ordering_explicit) """ - diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index 944c17b93..2656062c9 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -121,9 +121,9 @@ print(sched_map_symbolic.space) # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later print("---------------------------------------------------------------------------") -#lex_map_explicit = sched.get_lex_map_explicit() +#lex_map_explicit = sched.get_explicit_sched_map() -lex_map_symbolic = sched.get_lex_map_symbolic() +lex_map_symbolic = sched.get_symbolic_sched_map() print("lex map symbolic:") print(prettier_map_string(lex_map_symbolic)) @@ -150,13 +150,7 @@ print(SIO_symbolic_valid.space) # Introduce an all dep print("----------------------------------------------------------------------") -# TODO use new version of this function statement_deps = create_dependencies_from_legacy_knl(knl) -#print("Dependency sets:") -#for dep_set in dep_sets: -# for dep in dep_set: -# print(dep) -# print("") print("Statement Dependencies:") for sd in statement_deps: print(sd) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index ad99db010..e9596b1bc 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -1,7 +1,7 @@ import islpy as isl -def make_lex_mapping_tuple_pairs(dim_bounds): +def make_lex_order_map_tuple_pairs(dim_bounds): # Given list of integer dimension bound pairs # [(lower0, upper0), (lower1, upper1) ... ], @@ -138,11 +138,7 @@ def get_space(param_names, in_names, out_names): space, param_names=param_names, in_names=in_names, out_names=out_names) -#TODO rename these functions for clarity -#(distinguish betwen map representing lex order from all before pts to all after pts -# from map representing a schedule -# from other things...) -def create_symbolic_lex_mapping( +def create_symbolic_lex_order_map( n_dims, in_names=None, out_names=None, diff --git a/schedule.py b/schedule.py index 306ffd5de..ad2c970d7 100644 --- a/schedule.py +++ b/schedule.py @@ -181,22 +181,22 @@ class LexSchedule(object): #dom_before_to_intersect, dom_after_to_intersect) list(self.items()), sched_space, domain_to_intersect) - def get_lex_map_symbolic(self): + def get_symbolic_sched_map(self): from schedule_checker.lexicographic_order_map import ( - create_symbolic_lex_mapping, + create_symbolic_lex_order_map, ) n_dims = self.max_lex_dims() - return create_symbolic_lex_mapping(n_dims) + return create_symbolic_lex_order_map(n_dims) def get_isl_map_str(self): map_str = "{" - for state_inst, lex in self.lex_schedule.items(): + for state_inst, lex_pt in self.lex_schedule.items(): domain_elem = "[s=%s,%s]" % ( state_inst.statement.sid, ",".join( ["%s=%d" % (iname, val) for iname, val in state_inst.iname_vals.items()])) - range_elem = "[%s]" % (",".join("%s" % (l) for l in lex)) + range_elem = "[%s]" % (",".join("%s" % (lx) for lx in lex_pt)) map_str += "%s -> %s; " % (domain_elem, range_elem) map_str += "}" #TODO return map not string @@ -284,10 +284,10 @@ class LexSchedule(object): sched_space = self.get_space_for_explicit_sched() return self.create_explicit_isl_map(sched_space) - def get_lex_map_explicit(self): + def get_explicit_sched_map(self): from schedule_checker.lexicographic_order_map import ( - make_lex_mapping_tuple_pairs, + make_lex_order_map_tuple_pairs, create_explicit_map_from_tuples, get_space, ) @@ -302,7 +302,7 @@ class LexSchedule(object): lex_out_names = append_apostrophes(lex_in_names) lex_params = [] - explicit_lex_map_pairs = make_lex_mapping_tuple_pairs(lex_dim_bounds) + explicit_lex_map_pairs = make_lex_order_map_tuple_pairs(lex_dim_bounds) lex_space_explicit = get_space(lex_params, lex_in_names, lex_out_names) return create_explicit_map_from_tuples(explicit_lex_map_pairs, -- GitLab From aea7333f680ae26823137c2bd8a4dec5ab825b61 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 24 Jun 2019 23:12:43 -0500 Subject: [PATCH 058/183] moved functions that belong in utils to utils --- dependency.py | 14 +-- example_dep_pairwise_schedule_creation.py | 2 +- example_dependency_checking.py | 4 +- example_lex_map_creation.py | 6 +- lexicographic_order_map.py | 106 ------------------- sched_check_utils.py | 118 ++++++++++++++++++++++ schedule.py | 16 +-- 7 files changed, 134 insertions(+), 132 deletions(-) diff --git a/dependency.py b/dependency.py index b736474f2..be5651177 100644 --- a/dependency.py +++ b/dependency.py @@ -154,20 +154,8 @@ def create_dependency_constraint( return map_with_loop_domain_constraints -def get_concurrent_inames(knl): - from loopy.kernel.data import LocalIndexTag, GroupIndexTag - conc_inames = set() - all_inames = knl.all_inames() - for iname in all_inames: - iname_tags = knl.iname_to_tags.get(iname, None) - if iname_tags and any( - isinstance(tag, (LocalIndexTag, GroupIndexTag)) - for tag in iname_tags): - conc_inames.add(iname) - return conc_inames, all_inames-conc_inames - - def create_dependencies_from_legacy_knl(knl): + from schedule_checker.sched_check_utils import get_concurrent_inames from schedule_checker.schedule import Statement dt = DependencyType conc_inames, non_conc_inames = get_concurrent_inames(knl) diff --git a/example_dep_pairwise_schedule_creation.py b/example_dep_pairwise_schedule_creation.py index a667638ea..0a69d569e 100644 --- a/example_dep_pairwise_schedule_creation.py +++ b/example_dep_pairwise_schedule_creation.py @@ -3,7 +3,6 @@ import numpy as np from schedule_checker.dependency import ( create_dependencies_from_legacy_knl, create_dependency_constraint, - get_concurrent_inames, ) from schedule_checker.schedule import LexSchedule from schedule_checker.lexicographic_order_map import ( @@ -11,6 +10,7 @@ from schedule_checker.lexicographic_order_map import ( get_statement_ordering_map, ) from schedule_checker.sched_check_utils import ( + get_concurrent_inames, prettier_map_string, order_var_names_to_match_islset, ) diff --git a/example_dependency_checking.py b/example_dependency_checking.py index bd083947c..4c9c29e8c 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -6,14 +6,14 @@ from schedule_checker.dependency import ( # noqa ) from schedule_checker.lexicographic_order_map import ( make_lex_order_map_tuple_pairs, - create_explicit_map_from_tuples, get_statement_ordering_map, - get_space, ) from schedule_checker.schedule import Statement from schedule_checker.sched_check_utils import ( prettier_map_string, append_apostrophes, + create_explicit_map_from_tuples, + get_space, ) diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py index fc9482a9f..8cf947fb9 100644 --- a/example_lex_map_creation.py +++ b/example_lex_map_creation.py @@ -1,9 +1,11 @@ from schedule_checker.lexicographic_order_map import ( - create_explicit_map_from_tuples, get_statement_ordering_map, - get_space, create_symbolic_lex_order_map, ) +from schedule_checker.sched_check_utils import( + create_explicit_map_from_tuples, + get_space, +) # *Symbolic* lexicographic mapping- map each tuple to all tuples occuring later diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index e9596b1bc..7b34d190b 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -25,81 +25,6 @@ def make_lex_order_map_tuple_pairs(dim_bounds): return map_pairs -def create_explicit_map_from_tuples(tuple_pairs, space): - - dim_type = isl.dim_type - individual_maps = [] - - for tup_in, tup_out in tuple_pairs: - constraints = [] - for i, val_in in enumerate(tup_in): - constraints.append( - isl.Constraint.equality_alloc(space) - .set_coefficient_val(dim_type.in_, i, 1) - .set_constant_val(-1*val_in)) - for i, val_out in enumerate(tup_out): - constraints.append( - isl.Constraint.equality_alloc(space) - .set_coefficient_val(dim_type.out, i, 1) - .set_constant_val(-1*val_out)) - individual_maps.append( - isl.Map.universe(space).add_constraints(constraints)) - - union_map = individual_maps[0] - for m in individual_maps[1:]: - union_map = union_map.union(m) - - return union_map - - -def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): - - dim_type = isl.dim_type - - from schedule_checker.sched_check_utils import get_islvars_from_space - #param_names = space.get_var_names(isl.dim_type.param) - out_names = space.get_var_names(dim_type.out) - in_names = space.get_var_names(isl.dim_type.in_) - - islvars = get_islvars_from_space(space) - - # initialize set with constraint that is always false - constraints_set = islvars[0].eq_set(islvars[0] + 1) - for tup_in, tup_out in tuple_pairs: - # initialize set with constraint that is always true - constraint = islvars[0].eq_set(islvars[0]) - for i, val_in in enumerate(tup_in): - if isinstance(val_in, int): - constraint = constraint \ - & islvars[in_names[i]].eq_set(islvars[0]+val_in) - else: - constraint = constraint \ - & islvars[in_names[i]].eq_set(islvars[val_in]) - for i, val_out in enumerate(tup_out): - if isinstance(val_out, int): - constraint = constraint \ - & islvars[out_names[i]].eq_set(islvars[0]+val_out) - else: - constraint = constraint \ - & islvars[out_names[i]].eq_set(islvars[val_out]) - constraints_set = constraints_set | constraint - - result_map = isl.Map.from_domain(constraints_set) - result_map = result_map.move_dims( - dim_type.out, 0, dim_type.in_, - len(in_names), len(out_names)) - """ - result_map_vars_in = result_map.space.get_var_names(isl.dim_type.in_) - domain_stripped = domain_to_intersect.project_out_except( - result_map_vars_in, [isl.dim_type.set]) - return result_map.intersect_domain(domain_stripped) - """ - from schedule_checker.sched_check_utils import add_missing_set_dims_to_map_indims - # TODO make sure these always align properly - result_map = add_missing_set_dims_to_map_indims(result_map, domain_to_intersect) - return result_map.intersect_domain(domain_to_intersect) - - def get_statement_ordering_map(sched_map, lex_map): # statement ordering: # map each statement instance to all statement instances that occur later @@ -107,37 +32,6 @@ def get_statement_ordering_map(sched_map, lex_map): return sched_map.apply_range(lex_map).apply_range(sched_map.reverse()) -def set_space_names(space, param_names=None, in_names=None, out_names=None): - new_space = 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(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(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(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_space(param_names, in_names, out_names): - space = isl.Space.alloc( - isl.DEFAULT_CONTEXT, len(param_names), len(in_names), len(out_names)) - return set_space_names( - space, param_names=param_names, in_names=in_names, out_names=out_names) - - def create_symbolic_lex_order_map( n_dims, in_names=None, diff --git a/sched_check_utils.py b/sched_check_utils.py index e14c5e12c..764edce26 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -100,3 +100,121 @@ def order_var_names_to_match_islset(var_names, islset): if v in var_names: names_ordered_to_match_islset.append(v) return names_ordered_to_match_islset + + +def create_explicit_map_from_tuples(tuple_pairs, space): + + dim_type = isl.dim_type + individual_maps = [] + + for tup_in, tup_out in tuple_pairs: + constraints = [] + for i, val_in in enumerate(tup_in): + constraints.append( + isl.Constraint.equality_alloc(space) + .set_coefficient_val(dim_type.in_, i, 1) + .set_constant_val(-1*val_in)) + for i, val_out in enumerate(tup_out): + constraints.append( + isl.Constraint.equality_alloc(space) + .set_coefficient_val(dim_type.out, i, 1) + .set_constant_val(-1*val_out)) + individual_maps.append( + isl.Map.universe(space).add_constraints(constraints)) + + union_map = individual_maps[0] + for m in individual_maps[1:]: + union_map = union_map.union(m) + + return union_map + + +def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): + + dim_type = isl.dim_type + + from schedule_checker.sched_check_utils import get_islvars_from_space + #param_names = space.get_var_names(isl.dim_type.param) + out_names = space.get_var_names(dim_type.out) + in_names = space.get_var_names(isl.dim_type.in_) + + islvars = get_islvars_from_space(space) + + # initialize set with constraint that is always false + constraints_set = islvars[0].eq_set(islvars[0] + 1) + for tup_in, tup_out in tuple_pairs: + # initialize set with constraint that is always true + constraint = islvars[0].eq_set(islvars[0]) + for i, val_in in enumerate(tup_in): + if isinstance(val_in, int): + constraint = constraint \ + & islvars[in_names[i]].eq_set(islvars[0]+val_in) + else: + constraint = constraint \ + & islvars[in_names[i]].eq_set(islvars[val_in]) + for i, val_out in enumerate(tup_out): + if isinstance(val_out, int): + constraint = constraint \ + & islvars[out_names[i]].eq_set(islvars[0]+val_out) + else: + constraint = constraint \ + & islvars[out_names[i]].eq_set(islvars[val_out]) + constraints_set = constraints_set | constraint + + result_map = isl.Map.from_domain(constraints_set) + result_map = result_map.move_dims( + dim_type.out, 0, dim_type.in_, + len(in_names), len(out_names)) + ''' + result_map_vars_in = result_map.space.get_var_names(isl.dim_type.in_) + domain_stripped = domain_to_intersect.project_out_except( + result_map_vars_in, [isl.dim_type.set]) + return result_map.intersect_domain(domain_stripped) + ''' + from schedule_checker.sched_check_utils import add_missing_set_dims_to_map_indims + # TODO make sure these always align properly + result_map = add_missing_set_dims_to_map_indims(result_map, domain_to_intersect) + return result_map.intersect_domain(domain_to_intersect) + + +def set_space_names(space, param_names=None, in_names=None, out_names=None): + new_space = 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(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(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(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_space(param_names, in_names, out_names): + space = isl.Space.alloc( + isl.DEFAULT_CONTEXT, len(param_names), len(in_names), len(out_names)) + return set_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 LocalIndexTag, GroupIndexTag + conc_inames = set() + all_inames = knl.all_inames() + for iname in all_inames: + iname_tags = knl.iname_to_tags.get(iname, None) + if iname_tags and any( + isinstance(tag, (LocalIndexTag, GroupIndexTag)) + for tag in iname_tags): + conc_inames.add(iname) + return conc_inames, all_inames-conc_inames diff --git a/schedule.py b/schedule.py index ad2c970d7..08de95c75 100644 --- a/schedule.py +++ b/schedule.py @@ -130,7 +130,7 @@ class LexSchedule(object): params_sched = [] in_names_sched = ["s"] + self.inames_not_enumerated out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] - from schedule_checker.lexicographic_order_map import get_space + from schedule_checker.sched_check_utils import get_space return get_space(params_sched, in_names_sched, out_names_sched) def append_item(self, sched_item, lex_pt): @@ -145,11 +145,9 @@ class LexSchedule(object): #def create_symbolic_isl_map(self, dom_before, dom_after, inames): def create_symbolic_isl_map(self, domain, inames): # TODO if inames will always match domain out vars, don't need to pass them - from schedule_checker.lexicographic_order_map import ( - create_symbolic_map_from_tuples, - ) from schedule_checker.sched_check_utils import ( - add_dims_to_isl_set + create_symbolic_map_from_tuples, + add_dims_to_isl_set ) domain_iname_order = domain.get_var_names(isl.dim_type.out) inames_ordered_to_match_domain = [] @@ -270,11 +268,11 @@ class LexSchedule(object): params_sched = ["ps"] + ["p"+iname for iname in self.inames_enumerated] in_names_sched = ["s"] + self.inames_enumerated out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] - from schedule_checker.lexicographic_order_map import get_space + from schedule_checker.sched_check_utils import get_space return get_space(params_sched, in_names_sched, out_names_sched) def create_explicit_isl_map(self, sched_space): - from schedule_checker.lexicographic_order_map import ( + from schedule_checker.sched_check_utils import ( create_explicit_map_from_tuples ) return create_explicit_map_from_tuples(list(self.items()), sched_space) @@ -288,10 +286,12 @@ class LexSchedule(object): from schedule_checker.lexicographic_order_map import ( make_lex_order_map_tuple_pairs, + ) + from schedule_checker.sched_check_utils import ( create_explicit_map_from_tuples, get_space, + append_apostrophes ) - from schedule_checker.sched_check_utils import append_apostrophes # TODO lower bound may not be zero lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(), -- GitLab From 204c0cdf137484a4173b2647646f32baf7891391 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 25 Jun 2019 20:46:57 -0500 Subject: [PATCH 059/183] renamed example --- ..._schedule_creation.py => example_pairwise_schedule_validity.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename example_dep_pairwise_schedule_creation.py => example_pairwise_schedule_validity.py (100%) diff --git a/example_dep_pairwise_schedule_creation.py b/example_pairwise_schedule_validity.py similarity index 100% rename from example_dep_pairwise_schedule_creation.py rename to example_pairwise_schedule_validity.py -- GitLab From 3a6d624f5931edf21c81a97b8fd6b7c3bdba63c2 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 26 Jun 2019 00:20:30 -0500 Subject: [PATCH 060/183] removed unnecessary functions, changed func/var names for clarity, added lots of comments --- dependency.py | 25 +++-- example_dependency_checking.py | 6 +- example_lex_map_creation.py | 6 +- example_pairwise_schedule_validity.py | 92 +++++++++--------- example_schedule_creation_old.py | 2 +- sched_check_utils.py | 44 ++++++--- schedule.py | 128 ++++++++++++++++++-------- 7 files changed, 196 insertions(+), 107 deletions(-) diff --git a/dependency.py b/dependency.py index be5651177..77440cb52 100644 --- a/dependency.py +++ b/dependency.py @@ -67,15 +67,14 @@ def create_dependency_constraint( # Statement [s,i,j] comes before statement [s',i',j'] iff # assumes statements are numbered sequentially - # (statement_bound = max statement id + 1) # make sure all dependencies involve different inames if len(set(statement_dep.iname_deps.keys())) != len( statement_dep.iname_deps.keys()): raise ValueError("All depencencies must apply to different inames.") + # create some isl vars to use, e.g., {s, i, j, s', i', j'} statement_var_prime = statement_var+"'" - dt = DependencyType islvars = make_islvars_with_var_primes( [statement_var]+all_inames_ordered, []) @@ -84,13 +83,15 @@ def create_dependency_constraint( # this will disappear as soon as we add a constraint that is not dt.NONE all_constraints_set = islvars[0].eq_set(islvars[0] + 1) + # determine which inames are shared between instructions before_inames = statement_dep.statement_before.active_inames after_inames = statement_dep.statement_after.active_inames shared_inames = before_inames & after_inames #non_shared_inames = (before_inames | after_inames) - shared_inames - # for each (iname, dep_type) pair, create a constraint, + # for each (iname, dep_type) pair, create 'happens before' constraint, # all_constraints_set will be the union of all these constraints + dt = DependencyType for iname, dep_type in statement_dep.iname_deps.items(): if dep_type == dt.NONE: continue @@ -101,15 +102,14 @@ def create_dependency_constraint( #other_inames.remove(iname) # remaining inames, e.g., [j, k] #other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] - # remaining shared inames, e.g., [j, k] + # get inames shared between instructions that are not this iname other_shared_inames = list(shared_inames - {iname}) - other_shared_inames_prime = append_apostrophes(other_shared_inames) # e.g., [j', k'] # initialize constraint set with what we know about other shared inames # (e.g., j = j', k = k') - # will be True if no shared inames + # if no shared inames present, constraint_set will be True constraint_set = create_equality_conjunction_set( other_shared_inames, other_shared_inames_prime, islvars) if dep_type == dt.SAME: @@ -122,7 +122,7 @@ def create_dependency_constraint( constraint_set = constraint_set & islvars[0].eq_set( islvars[0]) # True - # enforce statement_var == statement # + # set statement_var == statement # s_before_int = sid_to_int[statement_dep.statement_before.sid] s_after_int = sid_to_int[statement_dep.statement_after.sid] constraint_set = constraint_set & islvars[statement_var].eq_set( @@ -130,11 +130,15 @@ def create_dependency_constraint( constraint_set = constraint_set & islvars[statement_var_prime].eq_set( islvars[0]+s_after_int) + # union this constraint_set with all_constraints_set all_constraints_set = all_constraints_set | constraint_set + # convert constraint set to map all_constraints_map = _convert_constraint_set_to_map( all_constraints_set, len(all_inames_ordered)+1) + # now apply domain to constraint variables + # TODO use separate domain for before and after insns? range_constraint_set = create_new_set_with_primes(domain_constraint_set) new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' @@ -155,6 +159,12 @@ def create_dependency_constraint( def create_dependencies_from_legacy_knl(knl): + # Compare insn.within inames for each insn involved in the dep + # For every shared, non-concurrent iname, introduce SAME dep + # (Perform voodoo guesswork to determine whether a ‘prior’ dep is needed) + # For every shared, concurrent iname, introduce an ALL dep + # For every non-shared iname, introduce pseudo-ALL dep + from schedule_checker.sched_check_utils import get_concurrent_inames from schedule_checker.schedule import Statement dt = DependencyType @@ -183,4 +193,5 @@ def create_dependencies_from_legacy_knl(knl): iname_deps[non_shared_iname] = dt.ALL deps.append(StatementDependency(s_before, s_after, iname_deps)) + return deps diff --git a/example_dependency_checking.py b/example_dependency_checking.py index 4c9c29e8c..c718d6562 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -13,7 +13,7 @@ from schedule_checker.sched_check_utils import ( prettier_map_string, append_apostrophes, create_explicit_map_from_tuples, - get_space, + get_isl_space, ) @@ -43,7 +43,7 @@ print("------------------------------------------------------------------------- params_sched = ['p0', 'p1'] in_names_sched = [statement_var]+all_inames_ordered out_names_sched = ['l0', 'l1'] -sched_space = get_space(params_sched, in_names_sched, out_names_sched) +sched_space = get_isl_space(params_sched, in_names_sched, out_names_sched) example_sched_valid = create_explicit_map_from_tuples( [ @@ -87,7 +87,7 @@ lex_out_names = append_apostrophes(out_names_sched) explicit_lex_map_pairs = make_lex_order_map_tuple_pairs(lex_dim_bounds) # for pair in explicit_lex_map_pairs: # print(pair[0], pair[1]) -lex_space_explicit = get_space(lex_params, lex_in_names, lex_out_names) +lex_space_explicit = get_isl_space(lex_params, lex_in_names, lex_out_names) lex_map_explicit = create_explicit_map_from_tuples(explicit_lex_map_pairs, lex_space_explicit) print("lex_map (explicit):") diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py index 8cf947fb9..527d97869 100644 --- a/example_lex_map_creation.py +++ b/example_lex_map_creation.py @@ -4,7 +4,7 @@ from schedule_checker.lexicographic_order_map import ( ) from schedule_checker.sched_check_utils import( create_explicit_map_from_tuples, - get_space, + get_isl_space, ) # *Symbolic* lexicographic mapping- map each tuple to all tuples occuring later @@ -37,7 +37,7 @@ print(lex_map_explicit) param_names_sched = [] in_names_sched = ["s"] out_names_sched = ["i", "j"] -sched_space = get_space(param_names_sched, in_names_sched, out_names_sched) +sched_space = get_isl_space(param_names_sched, in_names_sched, out_names_sched) example_sched = create_explicit_map_from_tuples( [ #((0,), (2, 0, 0)), @@ -104,7 +104,7 @@ print(example_sched) param_names_sched = ["ps", "p0", "p1"] in_names_sched = ["s","i","j"] out_names_sched = ["l0","l1"] -sched_space = get_space(param_names_sched, in_names_sched, out_names_sched) +sched_space = get_isl_space(param_names_sched, in_names_sched, out_names_sched) example_sched = create_explicit_map_from_tuples( [ ((0,0,0), (0, 0)), diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 0a69d569e..66225fadb 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -6,7 +6,6 @@ from schedule_checker.dependency import ( ) from schedule_checker.schedule import LexSchedule from schedule_checker.lexicographic_order_map import ( - #create_explicit_map_from_tuples, get_statement_ordering_map, ) from schedule_checker.sched_check_utils import ( @@ -15,6 +14,8 @@ from schedule_checker.sched_check_utils import ( order_var_names_to_match_islset, ) +# Choose kernel ---------------------------------------------------------- + #knl_choice = "example" #knl_choice = "matmul" knl_choice = "scan" @@ -25,7 +26,6 @@ knl_choice = "scan" #knl_choice = "nest" if knl_choice == "example": - # make example kernel knl = lp.make_kernel( #"{[i,j]: 0<=i<2 and 1<=j<3}", #"{[i,j]: pi_lo<=i lex time):") print(sched_map_symbolic.space) + print("-"*85) # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later - print("-"*85) #lex_map_explicit = sched.get_explicit_sched_map() - lex_map_symbolic = sched.get_symbolic_sched_map() - + # get map representing lexicographic ordering + lex_order_map_symbolic = sched.get_lex_order_map_for_symbolic_sched() print("lex map symbolic:") - print(prettier_map_string(lex_map_symbolic)) + print(prettier_map_string(lex_order_map_symbolic)) print("space (lex time -> lex time):") - print(lex_map_symbolic.space) - - # Statement instance ordering + print(lex_order_map_symbolic.space) print("-"*85) - #SIO_explicit_valid = get_statement_ordering_map( + + # create statement instance ordering, + # maps each statement instance to all statement instances occuring later + #SIO_explicit = get_statement_ordering_map( # example_sched_explicit, lex_map_explicit) - #print("statement instance ordering explicit (valid_sched):") - #print(prettier_map_string(SIO_explicit_valid)) - SIO_symbolic_valid = get_statement_ordering_map( - sched_map_symbolic, lex_map_symbolic) - print("statement instance ordering symbolic (valid_sched):") - print(prettier_map_string(SIO_symbolic_valid)) + #print("statement instance ordering explicit:") + #print(prettier_map_string(SIO_explicit)) + SIO_symbolic = get_statement_ordering_map( + sched_map_symbolic, lex_order_map_symbolic) + print("statement instance ordering symbolic:") + print(prettier_map_string(SIO_symbolic)) print("SIO space (statement instances -> statement instances):") - print(SIO_symbolic_valid.space) - + print(SIO_symbolic.space) print("-"*85) + print("dict{lp insn id : sched sid int}:") print(sched.lp_insnid_to_int_sid) print("-"*85) + # create a map representing constraints from the dependency, + # maps each statement instance to all statement instances that must occur later statement_var = 's' constraint_map = create_dependency_constraint( statement_dep, @@ -352,8 +356,8 @@ for statement_dep, dom_before, dom_after in deps_and_domains: #print("space (statment instances -> statement instances):") #print(constraint_map.space) - assert constraint_map.space == SIO_symbolic_valid.space - if not constraint_map.is_subset(SIO_symbolic_valid): + assert constraint_map.space == SIO_symbolic.space + if not constraint_map.is_subset(SIO_symbolic): # TODO is this the right question? sched_is_valid = False conc_inames, non_conc_inames = get_concurrent_inames(knl) print("================ constraint check failure =================") @@ -365,16 +369,16 @@ for statement_dep, dom_before, dom_after in deps_and_domains: print("constraint map space (statment instances -> statement instances):") print(constraint_map.space) print("SIO space (statement instances -> statement instances):") - print(SIO_symbolic_valid.space) + print(SIO_symbolic.space) print("constraint map:") print(prettier_map_string(constraint_map)) print("statement instance ordering:") - print(prettier_map_string(SIO_symbolic_valid)) + print(prettier_map_string(SIO_symbolic)) print("{insn id -> sched sid int} dict:") print(sched.lp_insnid_to_int_sid) print("===========================================================") -print("is valid sched valid? constraint map subset of SIO?") +print("is sched valid? constraint map subset of SIO?") print(sched_is_valid) diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index 2656062c9..5f1af3a22 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -123,7 +123,7 @@ print(sched_map_symbolic.space) print("---------------------------------------------------------------------------") #lex_map_explicit = sched.get_explicit_sched_map() -lex_map_symbolic = sched.get_symbolic_sched_map() +lex_map_symbolic = sched.get_lex_order_map_for_symbolic_sched() print("lex map symbolic:") print(prettier_map_string(lex_map_symbolic)) diff --git a/sched_check_utils.py b/sched_check_utils.py index 764edce26..9be7ca4dd 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -94,6 +94,8 @@ def all_iname_domains_equal(knl): def order_var_names_to_match_islset(var_names, islset): + # returns subset of var_names found in islset in + # order matching the islset variables name_order = islset.get_var_names(isl.dim_type.out) names_ordered_to_match_islset = [] for v in name_order: @@ -129,7 +131,10 @@ def create_explicit_map_from_tuples(tuple_pairs, space): return union_map -def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): +def create_symbolic_isl_map_from_tuples(tuple_pairs, space, domain_to_intersect): + + # given a list of pairs of ((input), (output)) tuples, create an isl map + # and intersect that map with domain_to_intersect dim_type = isl.dim_type @@ -140,11 +145,16 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): islvars = get_islvars_from_space(space) + # loop through pairs and create a set that will later be converted to a map + # initialize set with constraint that is always false constraints_set = islvars[0].eq_set(islvars[0] + 1) for tup_in, tup_out in tuple_pairs: - # initialize set with constraint that is always true + + # initialize constraint with true constraint = islvars[0].eq_set(islvars[0]) + + # set values for 'in' dimension using tuple vals for i, val_in in enumerate(tup_in): if isinstance(val_in, int): constraint = constraint \ @@ -152,6 +162,7 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): else: constraint = constraint \ & islvars[in_names[i]].eq_set(islvars[val_in]) + # set values for 'out' dimension using tuple vals for i, val_out in enumerate(tup_out): if isinstance(val_out, int): constraint = constraint \ @@ -159,8 +170,11 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): else: constraint = constraint \ & islvars[out_names[i]].eq_set(islvars[val_out]) + + # union this constraint with full set of constraints constraints_set = constraints_set | constraint + # convert set to map by moving dimensions around result_map = isl.Map.from_domain(constraints_set) result_map = result_map.move_dims( dim_type.out, 0, dim_type.in_, @@ -171,6 +185,9 @@ def create_symbolic_map_from_tuples(tuple_pairs, space, domain_to_intersect): result_map_vars_in, [isl.dim_type.set]) return result_map.intersect_domain(domain_stripped) ''' + + # if there are any dimensions in domain_to_intersect that are missing from + # result_map, insert these dimensions so that we can intersect the domain from schedule_checker.sched_check_utils import add_missing_set_dims_to_map_indims # TODO make sure these always align properly result_map = add_missing_set_dims_to_map_indims(result_map, domain_to_intersect) @@ -201,20 +218,21 @@ def set_space_names(space, param_names=None, in_names=None, out_names=None): return new_space -def get_space(param_names, in_names, out_names): +def get_isl_space(param_names, in_names, out_names): space = isl.Space.alloc( isl.DEFAULT_CONTEXT, len(param_names), len(in_names), len(out_names)) return set_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 LocalIndexTag, GroupIndexTag - conc_inames = set() - all_inames = knl.all_inames() - for iname in all_inames: - iname_tags = knl.iname_to_tags.get(iname, None) - if iname_tags and any( - isinstance(tag, (LocalIndexTag, GroupIndexTag)) - for tag in iname_tags): - conc_inames.add(iname) - return conc_inames, all_inames-conc_inames + from loopy.kernel.data import LocalIndexTag, GroupIndexTag + conc_inames = set() + all_inames = knl.all_inames() + for iname in all_inames: + iname_tags = knl.iname_to_tags.get(iname, None) + if iname_tags and any( + isinstance(tag, (LocalIndexTag, GroupIndexTag)) + for tag in iname_tags): + conc_inames.add(iname) + return conc_inames, all_inames-conc_inames diff --git a/schedule.py b/schedule.py index 08de95c75..9a46f3338 100644 --- a/schedule.py +++ b/schedule.py @@ -43,62 +43,100 @@ class StatementInstance(object): class LexSchedule(object): + + # contains a mapping of {statement instance: lex point} + def __init__( self, knl, include_only_insn_ids=None, ): - self.lex_schedule = OrderedDict() # {statement instance: lex point} + + # mapping of {statement instance: lex point} + self.lex_schedule = OrderedDict() # symbolic inames in sched that have been enumerated # into explicit statement instances self.inames_enumerated = [] - self.inames_not_enumerated = [] # TODO better way to do this + # symbolic inames added to statement instances in sched + # that have *not* been enumerated into explicit statement instances + self.inames_added_to_statement_instances = [] + # map from loopy insn_id strings to statement id ints self.lp_insnid_to_int_sid = {} + # since 's' will be used to represent statement numbering, make sure + # we don't have an iname named 's' + # TODO change to var less common than 's' and/or generate something unique? assert not any(iname == 's' for iname in knl.all_inames()) from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) + + # go through knl.schedule 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] # TODO originally assumed perfect loop nesting, still the case? for sched_item in knl.schedule: if isinstance(sched_item, EnterLoop): iname = sched_item.iname - if self: + # if the schedule is empty, this is the first schedule item, so + # don't increment lex dim val enumerating items in current code block, + # otherwise, this loop is next item in current code block, so + # increment lex dim val enumerating items in current code block + if self.lex_schedule: # if the schedule is not empty + # this lex value will correspond to everything inside this loop + # we will add new lex dimensions to enuerate items inside loop next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 + + # upon entering a loop, we enter a new (deeper) code block, so + # add one lex dimension for the loop variable, and + # add a second lex dim to enumerate code blocks within the new loop next_insn_lex_pt.append(iname) next_insn_lex_pt.append(0) elif isinstance(sched_item, LeaveLoop): + # 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() next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 - elif isinstance(sched_item, RunInstruction): + elif isinstance(sched_item, (RunInstruction, Barrier)): + if isinstance(sched_item, RunInstruction): + lp_insn_id = sched_item.insn_id + else: # Barrier + lp_insn_id = sched_item.originating_insn_id + + # if include_only_insn_ids list was passed, + # only process insns found in list, + # otherwise process all instructions if (include_only_insn_ids is None - or sched_item.insn_id in include_only_insn_ids): - self.add_new_lp_insnid(sched_item.insn_id) - insn_id_int = self.lp_insnid_to_int_sid[sched_item.insn_id] + or lp_insn_id in include_only_insn_ids): + # create an int representing this instruction and + # update the map from loopy insn_ids to statement ids + self.add_new_lp_insnid(lp_insn_id) + insn_id_int = self.lp_insnid_to_int_sid[lp_insn_id] - self.append_item((insn_id_int,), next_insn_lex_pt[:]) - next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 - elif isinstance(sched_item, Barrier): - if (include_only_insn_ids is None - or sched_item.originating_insn_id in include_only_insn_ids): - self.add_new_lp_insnid(sched_item.originating_insn_id) - insn_id_int = self.lp_insnid_to_int_sid[ - sched_item.originating_insn_id] + # add ((sid,), lex_pt) pair to lex schedule + self.lex_schedule[(insn_id_int,)] = next_insn_lex_pt[:] - self.append_item((insn_id_int,), 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 else: pass + + # 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 max_lex_dims(self): return max(len(lex_pt) for insn, lex_pt in self.items()) def pad_lex_pts_with_zeros(self): + # pad lex points with zeros so that all points have same number of dims max_lex_dim = self.max_lex_dims() new_sched = OrderedDict() for insn, lex_pt in self.items(): @@ -117,24 +155,29 @@ class LexSchedule(object): new_sched[insn] = lex_pt self.lex_schedule = new_sched if iname_found: - self.inames_not_enumerated.append(iname) + self.inames_added_to_statement_instances.append(iname) def add_new_lp_insnid(self, lp_insnid): + # create an int representing this instruction and + # update the map from loopy insn_ids to statement ids if self.lp_insnid_to_int_sid: self.lp_insnid_to_int_sid[lp_insnid] = max( self.lp_insnid_to_int_sid.values()) + 1 else: self.lp_insnid_to_int_sid[lp_insnid] = 0 - def get_space_for_symbolic_sched(self): + def get_isl_space_for_symbolic_sched(self): + # create an isl space + # {('s', ) -> + # (lexicographic ordering dims)} + params_sched = [] - in_names_sched = ["s"] + self.inames_not_enumerated + # TODO make "s" a variable for consistency + in_names_sched = ["s"] + self.inames_added_to_statement_instances + # TODO make "l" a variable for consistency out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] - from schedule_checker.sched_check_utils import get_space - return get_space(params_sched, in_names_sched, out_names_sched) - - def append_item(self, sched_item, lex_pt): - self.lex_schedule[sched_item] = lex_pt + from schedule_checker.sched_check_utils import get_isl_space + return get_isl_space(params_sched, in_names_sched, out_names_sched) def get_last_schedule_item(self): return next(reversed(self.lex_schedule)) @@ -144,11 +187,17 @@ class LexSchedule(object): #def create_symbolic_isl_map(self, dom_before, dom_after, inames): def create_symbolic_isl_map(self, domain, inames): + + # create isl map representing lex schedule + # TODO if inames will always match domain out vars, don't need to pass them from schedule_checker.sched_check_utils import ( - create_symbolic_map_from_tuples, + create_symbolic_isl_map_from_tuples, add_dims_to_isl_set ) + + # Get all inames now in order to maintain list with consistent ordering + # This will help keep isl maps/sets compatible domain_iname_order = domain.get_var_names(isl.dim_type.out) inames_ordered_to_match_domain = [] for iname in domain_iname_order: @@ -157,14 +206,20 @@ class LexSchedule(object): self.add_symbolic_inames_to_statement_instances( inames_ordered_to_match_domain) - sched_space = self.get_space_for_symbolic_sched() + # create an isl space + # {('s', ) -> + # (lexicographic ordering dims)} + sched_space = self.get_isl_space_for_symbolic_sched() """ # TODO maybe don't project this out, constraints may involve any iname later? domain_stripped = domain_intersection.project_out_except( - self.inames_not_enumerated, + self.inames_added_to_statement_instances, [isl.dim_type.set] ) """ + + # insert 's' dim into domain so that its space allows for + # intersection with sched map later # TODO first need to make sure statement var name isn't already being used new_pose = 0 # insert 's' at beginning domain_to_intersect = add_dims_to_isl_set( @@ -174,12 +229,13 @@ class LexSchedule(object): #dom_after_to_intersect = add_dims_to_isl_set( # dom_before, isl.dim_type.out, ['s'], new_pose) - return create_symbolic_map_from_tuples( + # create isl map + return create_symbolic_isl_map_from_tuples( #list(self.items()), sched_space, #dom_before_to_intersect, dom_after_to_intersect) list(self.items()), sched_space, domain_to_intersect) - def get_symbolic_sched_map(self): + def get_lex_order_map_for_symbolic_sched(self): from schedule_checker.lexicographic_order_map import ( create_symbolic_lex_order_map, ) @@ -264,12 +320,12 @@ class LexSchedule(object): for iname, bound in iname_bounds.items(): self.enumerate_iname(iname, bound) - def get_space_for_explicit_sched(self): + def get_isl_space_for_explicit_sched(self): params_sched = ["ps"] + ["p"+iname for iname in self.inames_enumerated] in_names_sched = ["s"] + self.inames_enumerated out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] - from schedule_checker.sched_check_utils import get_space - return get_space(params_sched, in_names_sched, out_names_sched) + from schedule_checker.sched_check_utils import get_isl_space + return get_isl_space(params_sched, in_names_sched, out_names_sched) def create_explicit_isl_map(self, sched_space): from schedule_checker.sched_check_utils import ( @@ -279,7 +335,7 @@ class LexSchedule(object): def enumerate_symbolic_inames_and_create_explicit_isl_map(self, iname_bounds): self.enumerate_inames(iname_bounds) - sched_space = self.get_space_for_explicit_sched() + sched_space = self.get_isl_space_for_explicit_sched() return self.create_explicit_isl_map(sched_space) def get_explicit_sched_map(self): @@ -289,21 +345,21 @@ class LexSchedule(object): ) from schedule_checker.sched_check_utils import ( create_explicit_map_from_tuples, - get_space, + get_isl_space, append_apostrophes ) # TODO lower bound may not be zero lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(), self.get_max_lex_dim_vals())) - sched_space = self.get_space_for_explicit_sched() + sched_space = self.get_isl_space_for_explicit_sched() lex_in_names = sched_space.get_var_names(isl.dim_type.out) lex_out_names = append_apostrophes(lex_in_names) lex_params = [] explicit_lex_map_pairs = make_lex_order_map_tuple_pairs(lex_dim_bounds) - lex_space_explicit = get_space(lex_params, lex_in_names, lex_out_names) + lex_space_explicit = get_isl_space(lex_params, lex_in_names, lex_out_names) return create_explicit_map_from_tuples(explicit_lex_map_pairs, lex_space_explicit) -- GitLab From 37522e1e422d225b4c8fb23fa9824157c30bc962 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 1 Jul 2019 11:43:15 -0500 Subject: [PATCH 061/183] simplified legacy dep creation logic- got rid of PRIOR and ALL, now introducing SAME dep for set of shared non-concurrent inames; also renamed StatementDependency->StatementDependencySet (and related variable names) for clarity --- dependency.py | 97 +++++++++++---------------- example_dependency_checking.py | 12 ++-- example_pairwise_schedule_validity.py | 56 ++++++++-------- example_schedule_creation_old.py | 14 ++-- 4 files changed, 78 insertions(+), 101 deletions(-) diff --git a/dependency.py b/dependency.py index 77440cb52..0cab987f7 100644 --- a/dependency.py +++ b/dependency.py @@ -4,30 +4,30 @@ import islpy as isl class DependencyType: NONE = "none" SAME = "same" - PRIOR = "prior" - ALL = "all" + #PRIOR = "prior" + #ALL = "all" -class StatementDependency(object): +class StatementDependencySet(object): def __init__( self, statement_before, statement_after, - iname_deps, # {iname: dep_type} + deps, # {dep_type: iname} ): self.statement_before = statement_before self.statement_after = statement_after - self.iname_deps = iname_deps + self.deps = deps def __str__(self): result = "%s --before->\n%s iff\n " % ( self.statement_before, self.statement_after) return result + " and\n ".join( - ["(%s dep: %s)" % (iname, dep_type) - for iname, dep_type in self.iname_deps.items()]) + ["(%s : %s)" % (dep_type, inames) + for dep_type, inames in self.deps.items()]) -def create_equality_conjunction_set(names0, names1, islvars): +def create_elementwise_equality_conjunction_set(names0, names1, islvars): # initialize set with constraint that is always true eq_set = islvars[0].eq_set(islvars[0]) @@ -49,7 +49,7 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): def create_dependency_constraint( - statement_dep, + statement_dep_set, all_inames_ordered, statement_var, domain_constraint_set, @@ -68,11 +68,6 @@ def create_dependency_constraint( # assumes statements are numbered sequentially - # make sure all dependencies involve different inames - if len(set(statement_dep.iname_deps.keys())) != len( - statement_dep.iname_deps.keys()): - raise ValueError("All depencencies must apply to different inames.") - # create some isl vars to use, e.g., {s, i, j, s', i', j'} statement_var_prime = statement_var+"'" islvars = make_islvars_with_var_primes( @@ -83,48 +78,37 @@ def create_dependency_constraint( # this will disappear as soon as we add a constraint that is not dt.NONE all_constraints_set = islvars[0].eq_set(islvars[0] + 1) - # determine which inames are shared between instructions - before_inames = statement_dep.statement_before.active_inames - after_inames = statement_dep.statement_after.active_inames - shared_inames = before_inames & after_inames - #non_shared_inames = (before_inames | after_inames) - shared_inames - - # for each (iname, dep_type) pair, create 'happens before' constraint, + # for each (dep_type, inames) pair, create 'happens before' constraint, # all_constraints_set will be the union of all these constraints dt = DependencyType - for iname, dep_type in statement_dep.iname_deps.items(): + for dep_type, inames in statement_dep_set.deps.items(): if dep_type == dt.NONE: continue - iname_prime = iname+"'" # i' - - #other_inames = all_inames_ordered.copy() - #other_inames.remove(iname) # remaining inames, e.g., [j, k] - #other_inames_prime = append_apostrophes(other_inames) # e.g., [j', k'] + # need to put inames in a list so that order of inames and inames' + # matches when calling create_elementwise_equality_conj... + if not isinstance(inames, list): + inames_list = list(inames) + else: + inames_list = inames[:] + inames_prime = append_apostrophes(inames_list) # e.g., [j', k'] - # get inames shared between instructions that are not this iname - other_shared_inames = list(shared_inames - {iname}) - other_shared_inames_prime = append_apostrophes(other_shared_inames) - # e.g., [j', k'] - - # initialize constraint set with what we know about other shared inames - # (e.g., j = j', k = k') - # if no shared inames present, constraint_set will be True - constraint_set = create_equality_conjunction_set( - other_shared_inames, other_shared_inames_prime, islvars) if dep_type == dt.SAME: - constraint_set = constraint_set & islvars[iname].eq_set( - islvars[iname_prime]) + constraint_set = create_elementwise_equality_conjunction_set( + inames_list, inames_prime, islvars) + """ + # TODO define these if useful, otherwise remove elif dep_type == dt.PRIOR: constraint_set = constraint_set & islvars[iname].lt_set( islvars[iname_prime]) elif dep_type == dt.ALL: constraint_set = constraint_set & islvars[0].eq_set( islvars[0]) # True + """ # set statement_var == statement # - s_before_int = sid_to_int[statement_dep.statement_before.sid] - s_after_int = sid_to_int[statement_dep.statement_after.sid] + s_before_int = sid_to_int[statement_dep_set.statement_before.sid] + s_after_int = sid_to_int[statement_dep_set.statement_after.sid] constraint_set = constraint_set & islvars[statement_var].eq_set( islvars[0]+s_before_int) constraint_set = constraint_set & islvars[statement_var_prime].eq_set( @@ -159,39 +143,34 @@ def create_dependency_constraint( def create_dependencies_from_legacy_knl(knl): - # Compare insn.within inames for each insn involved in the dep - # For every shared, non-concurrent iname, introduce SAME dep - # (Perform voodoo guesswork to determine whether a ‘prior’ dep is needed) - # For every shared, concurrent iname, introduce an ALL dep - # For every non-shared iname, introduce pseudo-ALL dep + # Introduce SAME dep for set of shared, non-concurrent inames from schedule_checker.sched_check_utils import get_concurrent_inames from schedule_checker.schedule import Statement dt = DependencyType conc_inames, non_conc_inames = get_concurrent_inames(knl) #all_inames = list(knl.all_inames()) - deps = [] + statement_dep_sets = [] for insn_after in knl.instructions: for insn_before_id in insn_after.depends_on: - iname_deps = {} + dep_dict = {} insn_before = knl.id_to_insn[insn_before_id] insn_before_inames = insn_before.within_inames insn_after_inames = insn_after.within_inames shared_inames = insn_before_inames & insn_after_inames - non_shared_inames = (insn_before_inames | insn_after_inames - ) - shared_inames - shared_conc_inames = shared_inames & conc_inames shared_non_conc_inames = shared_inames & non_conc_inames - s_before = Statement(insn_before.id, insn_before_inames) - s_after = Statement(insn_after.id, insn_after_inames) - for non_conc_iname in shared_non_conc_inames: - iname_deps[non_conc_iname] = dt.SAME + dep_dict[dt.SAME] = shared_non_conc_inames + """ for conc_iname in shared_conc_inames: - iname_deps[conc_iname] = dt.ALL + dep_dict[conc_iname] = dt.ALL for non_shared_iname in non_shared_inames: - iname_deps[non_shared_iname] = dt.ALL + dep_dict[non_shared_iname] = dt.ALL + """ - deps.append(StatementDependency(s_before, s_after, iname_deps)) + s_before = Statement(insn_before.id, insn_before_inames) + s_after = Statement(insn_after.id, insn_after_inames) + statement_dep_sets.append( + StatementDependencySet(s_before, s_after, dep_dict)) - return deps + return statement_dep_sets diff --git a/example_dependency_checking.py b/example_dependency_checking.py index c718d6562..739e01091 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -1,6 +1,6 @@ import loopy as lp from schedule_checker.dependency import ( # noqa - StatementDependency, + StatementDependencySet, DependencyType as dt, create_dependency_constraint, ) @@ -125,15 +125,15 @@ s0 = Statement("0", {"i", "j"}) s1 = Statement("1", {"i", "j"}) insnid_to_int_sid = {"0": 0, "1": 1} -statement_dep = StatementDependency(s0, s1, {"i": dt.SAME, "j": dt.SAME}) -print(statement_dep) +statement_dep_set = StatementDependencySet(s0, s1, {dt.SAME: ["i", "j"]}) +print(statement_dep_set) combined_doms = knl.get_inames_domain( - statement_dep.statement_before.active_inames | # noqa - statement_dep.statement_after.active_inames + statement_dep_set.statement_before.active_inames | # noqa + statement_dep_set.statement_after.active_inames ) constraint_map = create_dependency_constraint( - statement_dep, + statement_dep_set, all_inames_ordered, statement_var, combined_doms, diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 66225fadb..cde2bfddb 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -16,13 +16,13 @@ from schedule_checker.sched_check_utils import ( # Choose kernel ---------------------------------------------------------- -#knl_choice = "example" +knl_choice = "example" #knl_choice = "matmul" -knl_choice = "scan" +#knl_choice = "scan" #knl_choice = "dependent_domain" -#knl_choice = "stroud" +#knl_choice = "stroud" # TODO invalid sched? #knl_choice = "add_barrier" -#knl_choice = "nop" #TODO +#knl_choice = "nop" #TODO nop not in sched... error #knl_choice = "nest" if knl_choice == "example": @@ -232,52 +232,50 @@ for sched_item in knl.schedule: print(sched_item) print("="*80) -# Create StatementDependency(s) from kernel dependencies ----------------- - -# Compare insn.within inames for each insn involved in the dep -# For every shared, non-concurrent iname, introduce SAME dep -# (Perform voodoo guesswork to determine whether a ‘prior’ dep is needed) -# For every shared, concurrent iname, introduce an ALL dep -# For every non-shared iname, introduce pseudo-ALL dep +# Create StatementDependencySet(s) from kernel dependencies ----------------- +# Introduce SAME dep for set of shared, non-concurrent inames print("-"*85) -statement_deps = create_dependencies_from_legacy_knl(knl) +statement_dep_sets = create_dependencies_from_legacy_knl(knl) print("Statement Dependencies:") -for sd in statement_deps: - print(sd) +for dep_set in statement_dep_sets: + print(dep_set) print("") # get separate domains for before.active_inames and after.active_inames deps_and_domains = [] -for sd in statement_deps: +for dep_set in statement_dep_sets: #deps_and_domains.append([ - # sd, knl.get_inames_domain( - # sd.statement_before.active_inames | sd.statement_after.active_inames)]) + # dep_set, knl.get_inames_domain( + # dep_set.statement_before.active_inames | + # dep_set.statement_after.active_inames)]) # TODO need to have separate domains for separate instructions? # ...domain for after distinct from before deps_and_domains.append([ - sd, - knl.get_inames_domain(sd.statement_before.active_inames), - knl.get_inames_domain(sd.statement_after.active_inames) + dep_set, + knl.get_inames_domain(dep_set.statement_before.active_inames), + knl.get_inames_domain(dep_set.statement_after.active_inames) ]) print("-"*85) print("StatementDependencies w/domains:") -for sd, dom_before, dom_after in deps_and_domains: - print(sd) +for dep_set, dom_before, dom_after in deps_and_domains: + print(dep_set) print(dom_before) print(dom_after) # For each dependency, create+test schedule containing pair of insns------ sched_is_valid = True -for statement_dep, dom_before, dom_after in deps_and_domains: +for statement_dep_set, dom_before, dom_after in deps_and_domains: + s_before = statement_dep_set.statement_before + s_after = statement_dep_set.statement_after # TODO separate dom for before and after insns # TODO is using this union in creating schedule (not deps) okay? combined_doms = knl.get_inames_domain( - statement_dep.statement_before.active_inames | - statement_dep.statement_after.active_inames + s_before.active_inames | + s_after.active_inames ) # Get all inames now in order to maintain list with consistent ordering @@ -289,8 +287,8 @@ for statement_dep, dom_before, dom_after in deps_and_domains: # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency sched = LexSchedule(knl, include_only_insn_ids=[ - statement_dep.statement_before.sid, - statement_dep.statement_after.sid + s_before.sid, + s_after.sid ]) print("-"*85) print("LexSchedule before processing:") @@ -343,7 +341,7 @@ for statement_dep, dom_before, dom_after in deps_and_domains: # maps each statement instance to all statement instances that must occur later statement_var = 's' constraint_map = create_dependency_constraint( - statement_dep, + statement_dep_set, all_inames_ordered, # TODO separate lists for separate doms? statement_var, combined_doms, # TODO separate domains for before/after @@ -363,7 +361,7 @@ for statement_dep, dom_before, dom_after in deps_and_domains: print("================ constraint check failure =================") print("constraint map not subset of SIO") print("dependency:") - print(statement_dep) + print(statement_dep_set) print("concurrent inames:", conc_inames) print("sequential inames:", non_conc_inames) print("constraint map space (statment instances -> statement instances):") diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index 5f1af3a22..c1589ec12 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -150,10 +150,10 @@ print(SIO_symbolic_valid.space) # Introduce an all dep print("----------------------------------------------------------------------") -statement_deps = create_dependencies_from_legacy_knl(knl) +statement_dep_sets = create_dependencies_from_legacy_knl(knl) print("Statement Dependencies:") -for sd in statement_deps: - print(sd) +for dep_set in statement_dep_sets: + print(dep_set) print("") print("----------------------------------------------------------------------") print("dict{lp insn id : sched sid int}:") @@ -161,16 +161,16 @@ print(sched.lp_insnid_to_int_sid) print("----------------------------------------------------------------------") statement_var = 's' sched_is_valid = True -for statement_dep in statement_deps: +for statement_dep_set in statement_dep_sets: # TODO is using this union in creating schedule (not deps) okay? combined_doms = knl.get_inames_domain( - statement_dep.statement_before.active_inames | - statement_dep.statement_after.active_inames + statement_dep_set.statement_before.active_inames | + statement_dep_set.statement_after.active_inames ) constraint_map = create_dependency_constraint( - statement_dep, + statement_dep_set, all_inames_ordered, statement_var, combined_doms, -- GitLab From 634ee89b76986ce5f19d6a02ce809d79dca4d13e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 6 Jul 2019 23:18:16 -0500 Subject: [PATCH 062/183] now keeping domains for insn_before and insn_after separate; insn instance tuples must have same space, so they require inames not present in insns/domains, so setting those inames in those statement instances to dummy parameter --- dependency.py | 54 +++++--- example_dependency_checking.py | 21 +++- example_pairwise_schedule_validity.py | 169 +++++++++++++++----------- example_schedule_creation_old.py | 33 +++-- sched_check_utils.py | 138 ++++++++++++++------- schedule.py | 94 +++++--------- 6 files changed, 302 insertions(+), 207 deletions(-) diff --git a/dependency.py b/dependency.py index 0cab987f7..810f2d62a 100644 --- a/dependency.py +++ b/dependency.py @@ -52,15 +52,16 @@ def create_dependency_constraint( statement_dep_set, all_inames_ordered, statement_var, - domain_constraint_set, - #dom_before_constraint_set, - #dom_after_constraint_set, + dom_before_constraint_set, + dom_after_constraint_set, sid_to_int, + unused_param_name, ): from schedule_checker.sched_check_utils import ( make_islvars_with_var_primes, append_apostrophes, add_dims_to_isl_set, + add_missing_dims_to_isl_set, create_new_set_with_primes, ) # This function uses the dependency given to create the following constraint: @@ -68,11 +69,21 @@ def create_dependency_constraint( # assumes statements are numbered sequentially - # create some isl vars to use, e.g., {s, i, j, s', i', j'} - statement_var_prime = statement_var+"'" + # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} islvars = make_islvars_with_var_primes( [statement_var]+all_inames_ordered, - []) + [unused_param_name]) + statement_var_prime = statement_var+"'" + + # get (ordered) list of unused before/after inames + inames_before_unused = [] + for iname in all_inames_ordered: + if iname not in dom_before_constraint_set.get_var_names(isl.dim_type.out): + inames_before_unused.append(iname) + inames_after_unused = [] + for iname in all_inames_ordered: + if iname not in dom_after_constraint_set.get_var_names(isl.dim_type.out): + inames_after_unused.append(iname + "'") # initialize constraints to False # this will disappear as soon as we add a constraint that is not dt.NONE @@ -106,6 +117,11 @@ def create_dependency_constraint( islvars[0]) # True """ + # set unused vars == unused dummy param + for iname in inames_before_unused+inames_after_unused: + constraint_set = constraint_set & islvars[iname].eq_set( + islvars[unused_param_name]) + # set statement_var == statement # s_before_int = sid_to_int[statement_dep_set.statement_before.sid] s_after_int = sid_to_int[statement_dep_set.statement_after.sid] @@ -119,26 +135,30 @@ def create_dependency_constraint( # convert constraint set to map all_constraints_map = _convert_constraint_set_to_map( - all_constraints_set, len(all_inames_ordered)+1) + all_constraints_set, len(all_inames_ordered) + 1) # +1 for statement var - # now apply domain to constraint variables + # now apply domain sets to constraint variables - # TODO use separate domain for before and after insns? - range_constraint_set = create_new_set_with_primes(domain_constraint_set) + # add statement variable to doms to enable intersection new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' domain_to_intersect = add_dims_to_isl_set( - domain_constraint_set, isl.dim_type.out, ["s"], new_pose) + dom_before_constraint_set, isl.dim_type.out, ["s"], new_pose) + range_constraint_set = create_new_set_with_primes(dom_after_constraint_set) range_to_intersect = add_dims_to_isl_set( range_constraint_set, isl.dim_type.out, ["s'"], new_pose) - #new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' - #domain_to_intersect = add_dims_to_isl_set( - # dom_before_constraint_set, isl.dim_type.out, ["s"], new_pose) - #range_constraint_set = create_new_set_with_primes(dom_after_constraint_set) - #range_to_intersect = add_dims_to_isl_set( - # range_constraint_set, isl.dim_type.out, ["s'"], new_pose) + # insert inames missing from doms to enable intersection + domain_to_intersect = add_missing_dims_to_isl_set( + domain_to_intersect, isl.dim_type.out, ["s"] + all_inames_ordered) + range_to_intersect = add_missing_dims_to_isl_set( + range_to_intersect, + isl.dim_type.out, + append_apostrophes(["s"] + all_inames_ordered)) + + # intersect doms map_with_loop_domain_constraints = all_constraints_map.intersect_domain( domain_to_intersect).intersect_range(range_to_intersect) + return map_with_loop_domain_constraints diff --git a/example_dependency_checking.py b/example_dependency_checking.py index 739e01091..1168ddd46 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -30,8 +30,8 @@ knl = lp.tag_inames(knl, {"i": "l.0"}) print("Kernel:") print(knl) -all_inames_ordered = ['i', 'j'] -#all_inames_ordered = sorted(list(knl.all_inames())) +all_necessary_inames_ordered = ['i', 'j'] +#all_necessary_inames_ordered = sorted(list(knl.all_inames())) statement_var = 's' # example sched: @@ -41,7 +41,7 @@ print("------------------------------------------------------------------------- # for a given i, statement 0 happens before statement 1 params_sched = ['p0', 'p1'] -in_names_sched = [statement_var]+all_inames_ordered +in_names_sched = [statement_var]+all_necessary_inames_ordered out_names_sched = ['l0', 'l1'] sched_space = get_isl_space(params_sched, in_names_sched, out_names_sched) @@ -114,9 +114,10 @@ print("----------------------------------------------------------------------") # i dependency is none, j dependency is `prior` statement_var = 's' +unused_param_name = 'unused' domains = {} -for iname in all_inames_ordered: +for iname in all_necessary_inames_ordered: domains[iname] = knl.get_inames_domain(iname) domains_list = list(domains.values()) @@ -131,13 +132,21 @@ combined_doms = knl.get_inames_domain( statement_dep_set.statement_before.active_inames | # noqa statement_dep_set.statement_after.active_inames ) +dom_before = knl.get_inames_domain( + statement_dep_set.statement_before.active_inames + ) +dom_after = knl.get_inames_domain( + statement_dep_set.statement_after.active_inames + ) constraint_map = create_dependency_constraint( statement_dep_set, - all_inames_ordered, + all_necessary_inames_ordered, statement_var, - combined_doms, + dom_before, + dom_after, insnid_to_int_sid, + unused_param_name=unused_param_name, ) print("constraint map space:") print(constraint_map.space) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index cde2bfddb..ec17c93df 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -20,34 +20,43 @@ knl_choice = "example" #knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" -#knl_choice = "stroud" # TODO invalid sched? +#knl_choice = "stroud" # invalid sched? #knl_choice = "add_barrier" #knl_choice = "nop" #TODO nop not in sched... error -#knl_choice = "nest" +#knl_choice = "nest_multi_dom" if knl_choice == "example": knl = lp.make_kernel( - #"{[i,j]: 0<=i<2 and 1<=j<3}", - #"{[i,j]: pi_lo<=itemp = b[i,j] {id=insn_a}", - "a[i,j] = temp + 1 {id=insn_b,dep=insn_a}", - "c[i,j] = d[i,j] {id=insn_c}", - "out[t,tt] = in[t,tt] {id=insn_d}", + "{[i,ii]: 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_lo,pi_up,pj_lo,pj_up >= 1", - #assumptions="pi_up,pj_up >= 1", - #assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", - assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", + assumptions="pi,pj,pk,pt >= 1", lang_version=(2018, 2) ) knl = lp.add_and_infer_dtypes( knl, - {"b": np.float32, "d": np.float32, "in": np.float32}) - knl = lp.tag_inames(knl, {"i": "l.0"}) + {"b": np.float32, "d": np.float32, "f": np.float32}) + #knl = lp.tag_inames(knl, {"i": "l.0"}) knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) elif knl_choice == "matmul": @@ -195,34 +204,50 @@ if knl_choice == "nop": knl = lp.fix_parameters(knl, dim=3) knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) -if knl_choice == "nest": +if knl_choice == "nest_multi_dom": + #"{[i,j,k]: 0<=i,j,kfoo = 0 {id=insn0} for i - <>acc = 0 {id=insn1} + <>acc = 0 {id=insn0} for j for k - acc = acc + j + k {id=insn2,dep=insn1} + acc = acc + j + k {id=insn1,dep=insn0} end end - foo = foo + acc {id=insn3,dep=insn2} end - <>bar = foo {id=insn4,dep=insn3} """, - name="nest", - assumptions="n >= 1", + name="nest_multi_dom", + #assumptions="n >= 1", + assumptions="ni,nj,nk >= 1", lang_version=(2018, 2) ) + """ + <>foo = 0 {id=insn0} + for i + <>acc = 0 {id=insn1} + for j + for k + acc = acc + j + k {id=insn2,dep=insn1} + end + end + foo = foo + acc {id=insn3,dep=insn2} + end + <>bar = foo {id=insn4,dep=insn3} + """ knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) # Print kernel info ------------------------------------------------------ -print("Kernel:") -print(knl) +#print("Kernel:") +#print(knl) #print(lp.generate_code_v2(knl).device_code()) print("="*80) print("Iname tags: %s" % (knl.iname_to_tags)) @@ -245,17 +270,11 @@ for dep_set in statement_dep_sets: # get separate domains for before.active_inames and after.active_inames deps_and_domains = [] for dep_set in statement_dep_sets: - #deps_and_domains.append([ - # dep_set, knl.get_inames_domain( - # dep_set.statement_before.active_inames | - # dep_set.statement_after.active_inames)]) - # TODO need to have separate domains for separate instructions? - # ...domain for after distinct from before deps_and_domains.append([ - dep_set, - knl.get_inames_domain(dep_set.statement_before.active_inames), - knl.get_inames_domain(dep_set.statement_after.active_inames) - ]) + dep_set, + knl.get_inames_domain(dep_set.statement_before.active_inames), + knl.get_inames_domain(dep_set.statement_after.active_inames) + ]) print("-"*85) print("StatementDependencies w/domains:") @@ -270,19 +289,22 @@ sched_is_valid = True for statement_dep_set, dom_before, dom_after in deps_and_domains: s_before = statement_dep_set.statement_before s_after = statement_dep_set.statement_after - # TODO separate dom for before and after insns - # TODO is using this union in creating schedule (not deps) okay? + # The isl map representing the schedule maps + # statement instances -> lex time + # The 'in_' dim vars need to match for all sched items in the map, + # Instructions that use fewer inames will still need to + # have the unused inames in their 'in_' dim vars, so we'll + # include them and set them equal to a dummy variable. + + # Get all inames now in order to maintain list with consistent ordering + # This will help keep isl maps/sets compatible combined_doms = knl.get_inames_domain( s_before.active_inames | s_after.active_inames ) - - # Get all inames now in order to maintain list with consistent ordering - # This will help keep isl maps/sets compatible - # TODO is this still necessary? - all_inames_ordered = order_var_names_to_match_islset( - knl.all_inames(), combined_doms) # should separate doms? + all_necessary_inames_ordered = order_var_names_to_match_islset( + knl.all_inames(), combined_doms) # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency @@ -294,13 +316,22 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: print("LexSchedule before processing:") print(sched) - # get an isl map representing the LexSchedule - # this requires information about the iname domains + # Right now, statement tuples consist of single int. + # Add all inames from combined domains to statement tuples. + # This may include inames not used in every instruction, + # but all in-tuples need to match because they will become + # the in-dims for an isl map, so if an iname is needed in one + # statement tuple, then it is needed in all statement tuples. + sched.add_symbolic_inames_to_statement_instances( + all_necessary_inames_ordered) + print("LexSchedule with inames added:") + print(sched) + + # Get an isl map representing the LexSchedule; + # this requires the iname domains sched_map_symbolic = sched.create_symbolic_isl_map( - combined_doms, all_inames_ordered) # should separate doms? - #sched_map_symbolic = sched.create_symbolic_isl_map( - # dom_before, dom_after, all_inames_ordered) - print("LexSchedule after processing:") + [dom_before, dom_after], all_necessary_inames_ordered) + print("LexSchedule after creating symbolic isl map:") print(sched) print("LexSched:") print(prettier_map_string(sched_map_symbolic)) @@ -308,12 +339,9 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: print(sched_map_symbolic.space) print("-"*85) - # *Explicit* lexicographic mapping- map each tuple to all tuples occuring later - #lex_map_explicit = sched.get_explicit_sched_map() - # get map representing lexicographic ordering lex_order_map_symbolic = sched.get_lex_order_map_for_symbolic_sched() - print("lex map symbolic:") + print("lex order map symbolic:") print(prettier_map_string(lex_order_map_symbolic)) print("space (lex time -> lex time):") print(lex_order_map_symbolic.space) @@ -321,10 +349,6 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: # create statement instance ordering, # maps each statement instance to all statement instances occuring later - #SIO_explicit = get_statement_ordering_map( - # example_sched_explicit, lex_map_explicit) - #print("statement instance ordering explicit:") - #print(prettier_map_string(SIO_explicit)) SIO_symbolic = get_statement_ordering_map( sched_map_symbolic, lex_order_map_symbolic) print("statement instance ordering symbolic:") @@ -342,38 +366,44 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: statement_var = 's' constraint_map = create_dependency_constraint( statement_dep_set, - all_inames_ordered, # TODO separate lists for separate doms? + all_necessary_inames_ordered, statement_var, - combined_doms, # TODO separate domains for before/after - #dom_before, - #dom_after, + dom_before, + dom_after, sched.lp_insnid_to_int_sid, + sched.unused_param_name, ) print("constraint map:") print(prettier_map_string(constraint_map)) - #print("space (statment instances -> statement instances):") - #print(constraint_map.space) + aligned_constraint_map = constraint_map.align_params(SIO_symbolic.space) + print("aligned constraint map:") + print(prettier_map_string(aligned_constraint_map)) - assert constraint_map.space == SIO_symbolic.space - if not constraint_map.is_subset(SIO_symbolic): # TODO is this the right question? + assert aligned_constraint_map.space == SIO_symbolic.space + if not aligned_constraint_map.is_subset(SIO_symbolic): sched_is_valid = False conc_inames, non_conc_inames = get_concurrent_inames(knl) print("================ constraint check failure =================") print("constraint map not subset of SIO") print("dependency:") print(statement_dep_set) + """ print("concurrent inames:", conc_inames) print("sequential inames:", non_conc_inames) print("constraint map space (statment instances -> statement instances):") - print(constraint_map.space) + print(aligned_constraint_map.space) print("SIO space (statement instances -> statement instances):") print(SIO_symbolic.space) print("constraint map:") - print(prettier_map_string(constraint_map)) + print(prettier_map_string(aligned_constraint_map)) print("statement instance ordering:") print(prettier_map_string(SIO_symbolic)) print("{insn id -> sched sid int} dict:") print(sched.lp_insnid_to_int_sid) + print("gist") + print(aligned_constraint_map.gist(SIO_symbolic)) + print(SIO_symbolic.gist(aligned_constraint_map)) + """ print("===========================================================") print("is sched valid? constraint map subset of SIO?") @@ -463,4 +493,3 @@ schedule_explicit_map2 = isl.Map( assert schedule_explicit_map2 == schedule_explicit_map == sched.get_isl_map() ''' - diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index c1589ec12..5abda6748 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -102,14 +102,27 @@ if not all_iname_domains_equal(knl): "schedule checker does not yet handle kernels where " "get_inames_domain(iname) is not same for all inames") domain_union = _union_inames_domains(knl) -all_inames_ordered = order_var_names_to_match_islset(knl.all_inames(), domain_union) +all_necessary_inames_ordered = order_var_names_to_match_islset( + knl.all_inames(), domain_union) # get all inames in consistent ordering: sched = LexSchedule(knl) print("LexSchedule before processing:") print(sched) +# Right now, statement tuples consist of single int. +# Add all inames from combined domains to statement tuples. +# This may include inames not used in every instruction, +# but all in-tuples need to match because they will become +# the in-dims for an isl map, so if an iname is needed in one +# statement tuple, then it is needed in all statement tuples. +sched.add_symbolic_inames_to_statement_instances( + all_necessary_inames_ordered) +print("LexSchedule with inames added:") +print(sched) -sched_map_symbolic = sched.create_symbolic_isl_map(domain_union, all_inames_ordered) +sched_map_symbolic = sched.create_symbolic_isl_map( + [domain_union]*len(sched.lex_schedule), # due to changes, need one per insn + all_necessary_inames_ordered) print("LexSchedule after processing:") print(sched) # ------------------------------------------------------------------- @@ -163,18 +176,18 @@ statement_var = 's' sched_is_valid = True for statement_dep_set in statement_dep_sets: - # TODO is using this union in creating schedule (not deps) okay? - combined_doms = knl.get_inames_domain( - statement_dep_set.statement_before.active_inames | - statement_dep_set.statement_after.active_inames - ) - + dom_before = knl.get_inames_domain( + statement_dep_set.statement_before.active_inames) + dom_after = knl.get_inames_domain( + statement_dep_set.statement_after.active_inames) constraint_map = create_dependency_constraint( statement_dep_set, - all_inames_ordered, + all_necessary_inames_ordered, statement_var, - combined_doms, + dom_before, + dom_after, sched.lp_insnid_to_int_sid, + sched.unused_param_name, ) print("constraint map:") print(prettier_map_string(constraint_map)) diff --git a/sched_check_utils.py b/sched_check_utils.py index 9be7ca4dd..f436db247 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -18,13 +18,44 @@ def get_islvars_from_space(space): 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]) + 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 is_ordered_sublist(sub_list, full_list): + full_idx = 0 + sub_idx = 0 + while sub_idx < len(sub_list) and full_idx < len(full_list): + if sub_list[sub_idx] == full_list[full_idx]: + sub_idx += 1 + full_idx += 1 + return sub_idx == len(sub_list) + + +def add_missing_dims_to_isl_set(isl_set, dim_type, all_dim_names): + # assumes vars in set are ordered subset of all_dim_names + assert is_ordered_sublist( + isl_set.get_var_names(dim_type), + all_dim_names, + ) + + new_set = isl_set.copy() + for i, name in enumerate(all_dim_names): + if i >= new_set.n_dim() or \ + new_set.get_dim_name(dim_type, i) != name: + # insert missing dim + new_set = new_set.insert_dims( + dim_type, i, 1 + ).set_dim_name( + dim_type, i, name) + + return new_set + + def create_new_set_with_primes(old_set): new_set = old_set.copy() for i in range(old_set.n_dim()): @@ -68,7 +99,7 @@ def append_apostrophes(strings): return [s+"'" for s in strings] -def _union_of_sets(set_list): +def _union_of_isl_sets_or_maps(set_list): union = set_list[0] for s in set_list[1:]: union = union.union(s) @@ -131,70 +162,95 @@ def create_explicit_map_from_tuples(tuple_pairs, space): return union_map -def create_symbolic_isl_map_from_tuples(tuple_pairs, space, domain_to_intersect): +def create_symbolic_isl_map_from_tuples( + tuple_pairs, + space, + domains_to_intersect, + unused_param_name, + ): # given a list of pairs of ((input), (output)) tuples, create an isl map - # and intersect that map with domain_to_intersect + # and intersect each pair with corresponding domain_to_intersect + #TODO allow None for domains + assert len(tuple_pairs) == len(domains_to_intersect) dim_type = isl.dim_type - from schedule_checker.sched_check_utils import get_islvars_from_space #param_names = space.get_var_names(isl.dim_type.param) - out_names = space.get_var_names(dim_type.out) - in_names = space.get_var_names(isl.dim_type.in_) + 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 # initialize set with constraint that is always false - constraints_set = islvars[0].eq_set(islvars[0] + 1) - for tup_in, tup_out in tuple_pairs: + #constraints_set = islvars[0].eq_set(islvars[0] + 1) + all_maps = [] + for (tup_in, tup_out), dom in zip(tuple_pairs, domains_to_intersect): # initialize constraint with true constraint = islvars[0].eq_set(islvars[0]) # set values for 'in' dimension using tuple vals - for i, val_in in enumerate(tup_in): + 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[in_names[i]].eq_set(islvars[0]+val_in) + & islvars[dim_name].eq_set(islvars[0]+val_in) else: constraint = constraint \ - & islvars[in_names[i]].eq_set(islvars[val_in]) + & islvars[dim_name].eq_set(islvars[val_in]) + + # TODO we probably shouldn't rely on domains_to_intersect + # here for determing where to set inames equal to dummy vars, + # should instead determine before in LexSchedule and pass info in + dom_var_names = dom.get_var_names(dim_type.out) + assert set( + [var for var in tup_out if not isinstance(var, int)] + ).issubset(set(dom_var_names)) + unused_inames = set(space_in_names) - set(dom_var_names) - set(['s']) + for unused_iname in unused_inames: + constraint = constraint & islvars[unused_iname].eq_set( + islvars[unused_param_name]) + # set values for 'out' dimension using tuple vals - for i, val_out in enumerate(tup_out): + 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[out_names[i]].eq_set(islvars[0]+val_out) + & islvars[dim_name].eq_set(islvars[0]+val_out) else: constraint = constraint \ - & islvars[out_names[i]].eq_set(islvars[val_out]) - - # union this constraint with full set of constraints - constraints_set = constraints_set | constraint - - # convert set to map by moving dimensions around - result_map = isl.Map.from_domain(constraints_set) - result_map = result_map.move_dims( - dim_type.out, 0, dim_type.in_, - len(in_names), len(out_names)) - ''' - result_map_vars_in = result_map.space.get_var_names(isl.dim_type.in_) - domain_stripped = domain_to_intersect.project_out_except( - result_map_vars_in, [isl.dim_type.set]) - return result_map.intersect_domain(domain_stripped) - ''' - - # if there are any dimensions in domain_to_intersect that are missing from - # result_map, insert these dimensions so that we can intersect the domain - from schedule_checker.sched_check_utils import add_missing_set_dims_to_map_indims - # TODO make sure these always align properly - result_map = add_missing_set_dims_to_map_indims(result_map, domain_to_intersect) - return result_map.intersect_domain(domain_to_intersect) - - -def set_space_names(space, param_names=None, in_names=None, out_names=None): + & 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)) + + # TODO remove: + 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 = add_missing_dims_to_isl_set( + dom, isl.dim_type.out, + space_in_names, + ) + + # 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_space_names( + space, param_names=None, in_names=None, out_names=None): new_space = space.copy() dim_type = isl.dim_type if param_names: diff --git a/schedule.py b/schedule.py index 9a46f3338..66327db08 100644 --- a/schedule.py +++ b/schedule.py @@ -45,6 +45,9 @@ class StatementInstance(object): class LexSchedule(object): # contains a mapping of {statement instance: lex point} + unused_param_name = "unused" + #TODO use statement var + #statement_variable = "statement" def __init__( self, @@ -59,10 +62,6 @@ class LexSchedule(object): # into explicit statement instances self.inames_enumerated = [] - # symbolic inames added to statement instances in sched - # that have *not* been enumerated into explicit statement instances - self.inames_added_to_statement_instances = [] - # map from loopy insn_id strings to statement id ints self.lp_insnid_to_int_sid = {} @@ -70,6 +69,7 @@ class LexSchedule(object): # we don't have an iname named 's' # TODO change to var less common than 's' and/or generate something unique? assert not any(iname == 's' for iname in knl.all_inames()) + assert not any(iname == self.unused_param_name for iname in knl.all_inames()) from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) @@ -83,7 +83,7 @@ class LexSchedule(object): if isinstance(sched_item, EnterLoop): iname = sched_item.iname # if the schedule is empty, this is the first schedule item, so - # don't increment lex dim val enumerating items in current code block, + # don't increment lex dim val enumerating items in current block, # otherwise, this loop is next item in current code block, so # increment lex dim val enumerating items in current code block if self.lex_schedule: # if the schedule is not empty @@ -108,6 +108,9 @@ class LexSchedule(object): if isinstance(sched_item, RunInstruction): lp_insn_id = sched_item.insn_id else: # Barrier + # TODO make sure it's okay to ignore barriers without id + # matmul example has barrier that fails this assertion... + # assert sched_item.originating_insn_id is not None lp_insn_id = sched_item.originating_insn_id # if include_only_insn_ids list was passed, @@ -144,18 +147,11 @@ class LexSchedule(object): self.lex_schedule = new_sched def add_symbolic_inames_to_statement_instances(self, inames): - for iname in inames: - new_sched = OrderedDict() - iname_found = False - for insn, lex_pt in self.lex_schedule.items(): - if iname in lex_pt: - new_sched[tuple(list(insn)+[iname])] = lex_pt - iname_found = True - else: - new_sched[insn] = lex_pt - self.lex_schedule = new_sched - if iname_found: - self.inames_added_to_statement_instances.append(iname) + # append inames to lex tuples (matching specified order) + new_sched = OrderedDict() + for insn, lex_pt in self.lex_schedule.items(): + new_sched[tuple(list(insn)+inames[:])] = lex_pt + self.lex_schedule = new_sched def add_new_lp_insnid(self, lp_insnid): # create an int representing this instruction and @@ -166,74 +162,46 @@ class LexSchedule(object): else: self.lp_insnid_to_int_sid[lp_insnid] = 0 - def get_isl_space_for_symbolic_sched(self): - # create an isl space - # {('s', ) -> - # (lexicographic ordering dims)} - - params_sched = [] - # TODO make "s" a variable for consistency - in_names_sched = ["s"] + self.inames_added_to_statement_instances - # TODO make "l" a variable for consistency - out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] - from schedule_checker.sched_check_utils import get_isl_space - return get_isl_space(params_sched, in_names_sched, out_names_sched) - def get_last_schedule_item(self): return next(reversed(self.lex_schedule)) def get_last_lex_pt(self): return self.lex_schedule[self.get_last_schedule_item()] - #def create_symbolic_isl_map(self, dom_before, dom_after, inames): - def create_symbolic_isl_map(self, domain, inames): - + def create_symbolic_isl_map(self, domains, inames_ordered): # create isl map representing lex schedule - # TODO if inames will always match domain out vars, don't need to pass them from schedule_checker.sched_check_utils import ( create_symbolic_isl_map_from_tuples, add_dims_to_isl_set ) - # Get all inames now in order to maintain list with consistent ordering - # This will help keep isl maps/sets compatible - domain_iname_order = domain.get_var_names(isl.dim_type.out) - inames_ordered_to_match_domain = [] - for iname in domain_iname_order: - if iname in inames: - inames_ordered_to_match_domain.append(iname) - self.add_symbolic_inames_to_statement_instances( - inames_ordered_to_match_domain) + assert len(domains) == len(self.lex_schedule) # create an isl space - # {('s', ) -> + # {('s', used in >=1 statement domain>) -> # (lexicographic ordering dims)} - sched_space = self.get_isl_space_for_symbolic_sched() - """ - # TODO maybe don't project this out, constraints may involve any iname later? - domain_stripped = domain_intersection.project_out_except( - self.inames_added_to_statement_instances, - [isl.dim_type.set] - ) - """ - - # insert 's' dim into domain so that its space allows for + params_sched = [self.unused_param_name] + # TODO make "s" a variable for consistency + in_names_sched = ["s"] + inames_ordered + # TODO make "l" a variable for consistency + out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] + from schedule_checker.sched_check_utils import get_isl_space + sched_space = get_isl_space(params_sched, in_names_sched, out_names_sched) + + # Insert 's' dim into domain so that its space allows for # intersection with sched map later # TODO first need to make sure statement var name isn't already being used new_pose = 0 # insert 's' at beginning - domain_to_intersect = add_dims_to_isl_set( - domain, isl.dim_type.out, ['s'], new_pose) - #dom_before_to_intersect = add_dims_to_isl_set( - # dom_before, isl.dim_type.out, ['s'], new_pose) - #dom_after_to_intersect = add_dims_to_isl_set( - # dom_before, isl.dim_type.out, ['s'], new_pose) + doms_to_intersect = [] + for dom in domains: + doms_to_intersect.append(add_dims_to_isl_set( + dom, isl.dim_type.out, ['s'], new_pose)) # create isl map return create_symbolic_isl_map_from_tuples( - #list(self.items()), sched_space, - #dom_before_to_intersect, dom_after_to_intersect) - list(self.items()), sched_space, domain_to_intersect) + list(self.items()), sched_space, + doms_to_intersect, self.unused_param_name) def get_lex_order_map_for_symbolic_sched(self): from schedule_checker.lexicographic_order_map import ( -- GitLab From b7a0ca0d82bc23882a22187db5074420983adab3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 6 Jul 2019 23:52:44 -0500 Subject: [PATCH 063/183] changed hardcoded statement var (in multiple places) into lexsched class var --- dependency.py | 23 +++++++------- example_dependency_checking.py | 4 +-- example_pairwise_schedule_validity.py | 45 +++++++++++++-------------- example_schedule_creation_old.py | 3 +- sched_check_utils.py | 4 ++- schedule.py | 32 +++++++++---------- 6 files changed, 56 insertions(+), 55 deletions(-) diff --git a/dependency.py b/dependency.py index 810f2d62a..73161fb5d 100644 --- a/dependency.py +++ b/dependency.py @@ -51,11 +51,11 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): def create_dependency_constraint( statement_dep_set, all_inames_ordered, - statement_var, dom_before_constraint_set, dom_after_constraint_set, sid_to_int, unused_param_name, + statement_var_name, ): from schedule_checker.sched_check_utils import ( make_islvars_with_var_primes, @@ -71,9 +71,9 @@ def create_dependency_constraint( # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} islvars = make_islvars_with_var_primes( - [statement_var]+all_inames_ordered, + [statement_var_name]+all_inames_ordered, [unused_param_name]) - statement_var_prime = statement_var+"'" + statement_var_name_prime = statement_var_name+"'" # get (ordered) list of unused before/after inames inames_before_unused = [] @@ -122,12 +122,12 @@ def create_dependency_constraint( constraint_set = constraint_set & islvars[iname].eq_set( islvars[unused_param_name]) - # set statement_var == statement # + # set statement_var_name == statement # s_before_int = sid_to_int[statement_dep_set.statement_before.sid] s_after_int = sid_to_int[statement_dep_set.statement_after.sid] - constraint_set = constraint_set & islvars[statement_var].eq_set( + constraint_set = constraint_set & islvars[statement_var_name].eq_set( islvars[0]+s_before_int) - constraint_set = constraint_set & islvars[statement_var_prime].eq_set( + constraint_set = constraint_set & islvars[statement_var_name_prime].eq_set( islvars[0]+s_after_int) # union this constraint_set with all_constraints_set @@ -140,20 +140,21 @@ def create_dependency_constraint( # now apply domain sets to constraint variables # add statement variable to doms to enable intersection - new_pose = 0 # insert 's' at beginning # TODO don't hardcode 's' + new_pose = 0 # insert 'statement' at beginning # TODO don't hardcode position domain_to_intersect = add_dims_to_isl_set( - dom_before_constraint_set, isl.dim_type.out, ["s"], new_pose) + dom_before_constraint_set, isl.dim_type.out, [statement_var_name], new_pose) range_constraint_set = create_new_set_with_primes(dom_after_constraint_set) range_to_intersect = add_dims_to_isl_set( - range_constraint_set, isl.dim_type.out, ["s'"], new_pose) + range_constraint_set, isl.dim_type.out, [statement_var_name_prime], new_pose) # insert inames missing from doms to enable intersection domain_to_intersect = add_missing_dims_to_isl_set( - domain_to_intersect, isl.dim_type.out, ["s"] + all_inames_ordered) + domain_to_intersect, isl.dim_type.out, + [statement_var_name] + all_inames_ordered) range_to_intersect = add_missing_dims_to_isl_set( range_to_intersect, isl.dim_type.out, - append_apostrophes(["s"] + all_inames_ordered)) + append_apostrophes([statement_var_name] + all_inames_ordered)) # intersect doms map_with_loop_domain_constraints = all_constraints_map.intersect_domain( diff --git a/example_dependency_checking.py b/example_dependency_checking.py index 1168ddd46..84adc8fdc 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -142,11 +142,11 @@ dom_after = knl.get_inames_domain( constraint_map = create_dependency_constraint( statement_dep_set, all_necessary_inames_ordered, - statement_var, dom_before, dom_after, insnid_to_int_sid, - unused_param_name=unused_param_name, + unused_param_name, + statement_var, ) print("constraint map space:") print(constraint_map.space) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index ec17c93df..de3108e47 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -18,7 +18,7 @@ from schedule_checker.sched_check_utils import ( knl_choice = "example" #knl_choice = "matmul" -#knl_choice = "scan" +knl_choice = "scan" #knl_choice = "dependent_domain" #knl_choice = "stroud" # invalid sched? #knl_choice = "add_barrier" @@ -27,32 +27,32 @@ knl_choice = "example" if knl_choice == "example": knl = lp.make_kernel( - [ + [ "{[i,ii]: 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 + ], + [ + """ + for i + for k + <>temp = b[i,k] {id=insn_a} end - for t - e[t] = f[t] {id=insn_d} + for j + a[i,j] = temp + 1 {id=insn_b,dep=insn_a} + c[i,j] = d[i,j] {id=insn_c} end - """ - ], - name="example", - assumptions="pi,pj,pk,pt >= 1", - lang_version=(2018, 2) - ) + 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}) @@ -363,15 +363,14 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: # create a map representing constraints from the dependency, # maps each statement instance to all statement instances that must occur later - statement_var = 's' constraint_map = create_dependency_constraint( statement_dep_set, all_necessary_inames_ordered, - statement_var, dom_before, dom_after, sched.lp_insnid_to_int_sid, sched.unused_param_name, + sched.statement_var_name, ) print("constraint map:") print(prettier_map_string(constraint_map)) diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index 5abda6748..9e9599fe5 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -172,7 +172,6 @@ print("----------------------------------------------------------------------") print("dict{lp insn id : sched sid int}:") print(sched.lp_insnid_to_int_sid) print("----------------------------------------------------------------------") -statement_var = 's' sched_is_valid = True for statement_dep_set in statement_dep_sets: @@ -183,11 +182,11 @@ for statement_dep_set in statement_dep_sets: constraint_map = create_dependency_constraint( statement_dep_set, all_necessary_inames_ordered, - statement_var, dom_before, dom_after, sched.lp_insnid_to_int_sid, sched.unused_param_name, + sched.statement_var_name, ) print("constraint map:") print(prettier_map_string(constraint_map)) diff --git a/sched_check_utils.py b/sched_check_utils.py index f436db247..bf085048d 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -167,6 +167,7 @@ def create_symbolic_isl_map_from_tuples( space, domains_to_intersect, unused_param_name, + statement_var_name, # TODO can we not pass this? ): # given a list of pairs of ((input), (output)) tuples, create an isl map @@ -209,7 +210,8 @@ def create_symbolic_isl_map_from_tuples( assert set( [var for var in tup_out if not isinstance(var, int)] ).issubset(set(dom_var_names)) - unused_inames = set(space_in_names) - set(dom_var_names) - set(['s']) + unused_inames = set(space_in_names) \ + - set(dom_var_names) - set([statement_var_name]) for unused_iname in unused_inames: constraint = constraint & islvars[unused_iname].eq_set( islvars[unused_param_name]) diff --git a/schedule.py b/schedule.py index 66327db08..dde3c2ea5 100644 --- a/schedule.py +++ b/schedule.py @@ -45,9 +45,9 @@ class StatementInstance(object): class LexSchedule(object): # contains a mapping of {statement instance: lex point} + unused_param_name = "unused" - #TODO use statement var - #statement_variable = "statement" + statement_var_name = "statement" def __init__( self, @@ -65,11 +65,11 @@ class LexSchedule(object): # map from loopy insn_id strings to statement id ints self.lp_insnid_to_int_sid = {} - # since 's' will be used to represent statement numbering, make sure - # we don't have an iname named 's' - # TODO change to var less common than 's' and/or generate something unique? - assert not any(iname == 's' for iname in knl.all_inames()) - assert not any(iname == self.unused_param_name for iname in knl.all_inames()) + # make sure we don't have an iname name conflict + assert not any( + iname == self.statement_var_name for iname in knl.all_inames()) + assert not any( + iname == self.unused_param_name for iname in knl.all_inames()) from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) @@ -179,29 +179,29 @@ class LexSchedule(object): assert len(domains) == len(self.lex_schedule) # create an isl space - # {('s', used in >=1 statement domain>) -> + # {('statement', used in >=1 statement domain>) -> # (lexicographic ordering dims)} params_sched = [self.unused_param_name] - # TODO make "s" a variable for consistency - in_names_sched = ["s"] + inames_ordered + in_names_sched = [self.statement_var_name] + inames_ordered # TODO make "l" a variable for consistency out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] from schedule_checker.sched_check_utils import get_isl_space sched_space = get_isl_space(params_sched, in_names_sched, out_names_sched) - # Insert 's' dim into domain so that its space allows for + # Insert 'statement' dim into domain so that its space allows for # intersection with sched map later - # TODO first need to make sure statement var name isn't already being used - new_pose = 0 # insert 's' at beginning + new_pose = 0 # insert 'statement' dim at beginning + # TODO don't hardcode pose doms_to_intersect = [] for dom in domains: doms_to_intersect.append(add_dims_to_isl_set( - dom, isl.dim_type.out, ['s'], new_pose)) + dom, isl.dim_type.out, [self.statement_var_name], new_pose)) # create isl map return create_symbolic_isl_map_from_tuples( list(self.items()), sched_space, - doms_to_intersect, self.unused_param_name) + doms_to_intersect, + self.unused_param_name, self.statement_var_name) def get_lex_order_map_for_symbolic_sched(self): from schedule_checker.lexicographic_order_map import ( @@ -290,7 +290,7 @@ class LexSchedule(object): def get_isl_space_for_explicit_sched(self): params_sched = ["ps"] + ["p"+iname for iname in self.inames_enumerated] - in_names_sched = ["s"] + self.inames_enumerated + in_names_sched = [self.statement_var_name] + self.inames_enumerated out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] from schedule_checker.sched_check_utils import get_isl_space return get_isl_space(params_sched, in_names_sched, out_names_sched) -- GitLab From 03b418023ca24f164400dde862e95e6a346c41ca Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 7 Jul 2019 00:06:25 -0500 Subject: [PATCH 064/183] made lex time var names a lexsched class variable instead of hardcoding them in multiple places --- example_pairwise_schedule_validity.py | 2 +- schedule.py | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index de3108e47..7be1ea588 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -18,7 +18,7 @@ from schedule_checker.sched_check_utils import ( knl_choice = "example" #knl_choice = "matmul" -knl_choice = "scan" +#knl_choice = "scan" #knl_choice = "dependent_domain" #knl_choice = "stroud" # invalid sched? #knl_choice = "add_barrier" diff --git a/schedule.py b/schedule.py index dde3c2ea5..f52fb819a 100644 --- a/schedule.py +++ b/schedule.py @@ -48,6 +48,7 @@ class LexSchedule(object): unused_param_name = "unused" statement_var_name = "statement" + lex_var_prefix = "l" def __init__( self, @@ -184,7 +185,7 @@ class LexSchedule(object): params_sched = [self.unused_param_name] in_names_sched = [self.statement_var_name] + inames_ordered # TODO make "l" a variable for consistency - out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] + out_names_sched = self.get_lex_var_names() from schedule_checker.sched_check_utils import get_isl_space sched_space = get_isl_space(params_sched, in_names_sched, out_names_sched) @@ -203,13 +204,17 @@ class LexSchedule(object): doms_to_intersect, self.unused_param_name, 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_symbolic_sched(self): from schedule_checker.lexicographic_order_map import ( create_symbolic_lex_order_map, ) - n_dims = self.max_lex_dims() - return create_symbolic_lex_order_map(n_dims) + return create_symbolic_lex_order_map( + n_dims, in_names=self.get_lex_var_names()) def get_isl_map_str(self): map_str = "{" @@ -291,7 +296,7 @@ class LexSchedule(object): def get_isl_space_for_explicit_sched(self): params_sched = ["ps"] + ["p"+iname for iname in self.inames_enumerated] in_names_sched = [self.statement_var_name] + self.inames_enumerated - out_names_sched = ["l"+str(i) for i in range(self.max_lex_dims())] + out_names_sched = self.get_lex_var_names() from schedule_checker.sched_check_utils import get_isl_space return get_isl_space(params_sched, in_names_sched, out_names_sched) -- GitLab From 4eac76a933b823320ba01ca4e4fd770b8227694c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 14 Jul 2019 19:13:58 -0500 Subject: [PATCH 065/183] simplified no-op kernel --- example_pairwise_schedule_validity.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 7be1ea588..bb2cbf9dc 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -178,29 +178,19 @@ if knl_choice == "add_barrier": if knl_choice == "nop": knl = lp.make_kernel( [ - "{[a]: 0<=a<10}", "{[b]: b_start<=b b_start = 1 - <> b_end = 2 for b - <> c_start = 1 <> c_end = 2 - for c ... nop end - - <>t[idim] = 1 end - end """, "...", seq_dependencies=True) - knl = lp.fix_parameters(knl, dim=3) knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) -- GitLab From df77ff5aa4ee21647d02b8de5208f00aa9f79473 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 14 Jul 2019 20:47:10 -0500 Subject: [PATCH 066/183] ignore barrier insns when originating_insn_id is None --- schedule.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/schedule.py b/schedule.py index f52fb819a..3f76e8807 100644 --- a/schedule.py +++ b/schedule.py @@ -110,9 +110,12 @@ class LexSchedule(object): lp_insn_id = sched_item.insn_id else: # Barrier # 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 sched_item.originating_insn_id is not None lp_insn_id = sched_item.originating_insn_id + if lp_insn_id is None: + continue # if include_only_insn_ids list was passed, # only process insns found in list, -- GitLab From c85add94c5b9033cf7d86f88962cd36246c01fa7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 14 Jul 2019 20:48:07 -0500 Subject: [PATCH 067/183] added get_all_nonconcurrent_insn_iname_subsets(knl) and get_all_sched_items_within_inames(knl, inames) --- sched_check_utils.py | 61 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/sched_check_utils.py b/sched_check_utils.py index bf085048d..f15dcc99f 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -286,6 +286,10 @@ def get_isl_space(param_names, in_names, out_names): def get_concurrent_inames(knl): from loopy.kernel.data import LocalIndexTag, GroupIndexTag conc_inames = set() + + # TODO remove non-conc test + assertion + nonconc_inames = set() + all_inames = knl.all_inames() for iname in all_inames: iname_tags = knl.iname_to_tags.get(iname, None) @@ -293,4 +297,61 @@ def get_concurrent_inames(knl): isinstance(tag, (LocalIndexTag, GroupIndexTag)) for tag in iname_tags): conc_inames.add(iname) + else: + nonconc_inames.add(iname) + + # TODO remove non-conc test + assertion + assert all_inames-conc_inames == nonconc_inames + return conc_inames, all_inames-conc_inames + + +def get_all_nonconcurrent_insn_iname_subsets(knl, exclude_empty=False): + from loopy.schedule import Barrier, RunInstruction + + _, non_conc_inames = get_concurrent_inames(knl) + + iname_subsets = set() + #TODO do we need to check anything besides Barrer, RunInsn? + for sched_item in knl.schedule: + if isinstance(sched_item, (RunInstruction, Barrier)): + if isinstance(sched_item, RunInstruction): + insn_id = sched_item.insn_id + else: # Barrier + # TODO make sure it's okay to ignore barriers without id + # matmul example has barrier that fails this assertion... + # assert sched_item.originating_insn_id is not None + insn_id = sched_item.originating_insn_id + if insn_id is None: + continue + + insn = knl.id_to_insn[insn_id] + + iname_subsets.add(insn.within_inames & non_conc_inames) + + if exclude_empty: + iname_subsets.discard(frozenset()) + + return iname_subsets + + +def get_all_sched_items_within_inames(knl, inames): + from loopy.schedule import Barrier, RunInstruction + + sched_items = [] + for sched_item in knl.schedule: + if isinstance(sched_item, (RunInstruction, Barrier)): + if isinstance(sched_item, RunInstruction): + insn_id = sched_item.insn_id + else: # Barrier + # TODO make sure it's okay to ignore barriers without id + # matmul example has barrier that fails this assertion... + # assert sched_item.originating_insn_id is not None + insn_id = sched_item.originating_insn_id + if insn_id is None: + continue + + insn = knl.id_to_insn[insn_id] + if inames.issubset(insn.within_inames): + sched_items.append(sched_item) + return sched_items -- GitLab From 20bcbcee5304efb47c7295faf30306e5e1c7ff7f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 14 Jul 2019 20:48:51 -0500 Subject: [PATCH 068/183] adding example to test loop carried dep logic --- example_pairwise_schedule_validity.py | 31 +++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index bb2cbf9dc..cb9f45601 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -16,7 +16,7 @@ from schedule_checker.sched_check_utils import ( # Choose kernel ---------------------------------------------------------- -knl_choice = "example" +#knl_choice = "example" #knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" @@ -24,6 +24,7 @@ knl_choice = "example" #knl_choice = "add_barrier" #knl_choice = "nop" #TODO nop not in sched... error #knl_choice = "nest_multi_dom" +knl_choice = "loop_carried_deps" if knl_choice == "example": knl = lp.make_kernel( @@ -147,6 +148,9 @@ elif knl_choice == "stroud": assumptions="deg>=0 and nels>=1" ) + knl = lp.add_and_infer_dtypes( + knl, + dict(coeffs=np.float32, qpts=np.int32)) knl = lp.fix_parameters(knl, nqp1d=7, deg=4) knl = lp.split_iname(knl, "el", 16, inner_tag="l.0") knl = lp.split_iname(knl, "el_outer", 2, outer_tag="g.0", inner_tag="ilp", @@ -168,6 +172,7 @@ if knl_choice == "add_barrier": 'cnst', shape=('n'), initializer=cnst, scope=lp.AddressSpace.GLOBAL, read_only=True), '...']) + knl = lp.add_and_infer_dtypes(knl, dict(a=np.float32)) knl = lp.fix_parameters(knl, n=16) knl = lp.add_barrier(knl, "id:first", "id:second") @@ -233,12 +238,30 @@ if knl_choice == "nest_multi_dom": knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) +if knl_choice == "loop_carried_deps": + knl = lp.make_kernel( + "{[i]: 0<=iacc0 = 0 {id=insn0} + for i + acc0 = acc0 + i {id=insn1,dep=insn0} + <>acc2 = acc0 + i {id=insn2,dep=insn1} + <>acc3 = acc2 + i {id=insn3,dep=insn2} + <>acc4 = acc0 + i {id=insn4,dep=insn1} + end + """, + name="loop_carried_deps", + assumptions="n >= 1", + lang_version=(2018, 2) + ) + knl = lp.preprocess_kernel(knl) + knl = lp.get_one_scheduled_kernel(knl) # Print kernel info ------------------------------------------------------ -#print("Kernel:") -#print(knl) -#print(lp.generate_code_v2(knl).device_code()) +print("Kernel:") +print(knl) +print(lp.generate_code_v2(knl).device_code()) print("="*80) print("Iname tags: %s" % (knl.iname_to_tags)) print("="*80) -- GitLab From 14a62cbfc71d33072735d43d8cffca439f9f213f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 14 Jul 2019 22:44:19 -0500 Subject: [PATCH 069/183] created _get_insn_id_from_sched_item(); changed get_all_sched_items_within_inames() -> get_sched_item_ids_within_inames(), which returns ids instead of sched items --- sched_check_utils.py | 38 ++++++++++++++++++++------------------ schedule.py | 12 ++++++------ 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index f15dcc99f..04a9041cc 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -306,6 +306,16 @@ def get_concurrent_inames(knl): return conc_inames, all_inames-conc_inames +def _get_insn_id_from_sched_item(knl, sched_item): + from loopy.schedule import Barrier + if isinstance(sched_item, Barrier): + return sched_item.originating_insn_id + else: + return sched_item.insn_id + + +# TODO for better performance, could combine these funcs so we don't +# loop over schedule more than once def get_all_nonconcurrent_insn_iname_subsets(knl, exclude_empty=False): from loopy.schedule import Barrier, RunInstruction @@ -315,18 +325,13 @@ def get_all_nonconcurrent_insn_iname_subsets(knl, exclude_empty=False): #TODO do we need to check anything besides Barrer, RunInsn? for sched_item in knl.schedule: if isinstance(sched_item, (RunInstruction, Barrier)): - if isinstance(sched_item, RunInstruction): - insn_id = sched_item.insn_id - else: # Barrier + insn_id = _get_insn_id_from_sched_item(knl, sched_item) + if insn_id is None: # TODO make sure it's okay to ignore barriers without id # matmul example has barrier that fails this assertion... # assert sched_item.originating_insn_id is not None - insn_id = sched_item.originating_insn_id - if insn_id is None: - continue - + continue insn = knl.id_to_insn[insn_id] - iname_subsets.add(insn.within_inames & non_conc_inames) if exclude_empty: @@ -335,23 +340,20 @@ def get_all_nonconcurrent_insn_iname_subsets(knl, exclude_empty=False): return iname_subsets -def get_all_sched_items_within_inames(knl, inames): +def get_sched_item_ids_within_inames(knl, inames): from loopy.schedule import Barrier, RunInstruction - sched_items = [] + sched_item_ids = [] for sched_item in knl.schedule: if isinstance(sched_item, (RunInstruction, Barrier)): - if isinstance(sched_item, RunInstruction): - insn_id = sched_item.insn_id - else: # Barrier + insn_id = _get_insn_id_from_sched_item(knl, sched_item) + if insn_id is None: # TODO make sure it's okay to ignore barriers without id # matmul example has barrier that fails this assertion... # assert sched_item.originating_insn_id is not None - insn_id = sched_item.originating_insn_id - if insn_id is None: - continue + continue insn = knl.id_to_insn[insn_id] if inames.issubset(insn.within_inames): - sched_items.append(sched_item) - return sched_items + sched_item_ids.append(insn_id) + return sched_item_ids diff --git a/schedule.py b/schedule.py index 3f76e8807..be60ca533 100644 --- a/schedule.py +++ b/schedule.py @@ -106,16 +106,16 @@ class LexSchedule(object): next_insn_lex_pt.pop() next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 elif isinstance(sched_item, (RunInstruction, Barrier)): - if isinstance(sched_item, RunInstruction): - lp_insn_id = sched_item.insn_id - else: # Barrier + from schedule_checker.sched_check_utils import ( + _get_insn_id_from_sched_item, + ) + lp_insn_id = _get_insn_id_from_sched_item(knl, sched_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 sched_item.originating_insn_id is not None - lp_insn_id = sched_item.originating_insn_id - if lp_insn_id is None: - continue + continue # if include_only_insn_ids list was passed, # only process insns found in list, -- GitLab From cb57453d2ef70371e6355132527dcc27e0c1597e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 14 Jul 2019 22:52:45 -0500 Subject: [PATCH 070/183] returning set rather than list from get_sched_item_ids_within_inames() --- sched_check_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 04a9041cc..bbd4ae81f 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -343,7 +343,7 @@ def get_all_nonconcurrent_insn_iname_subsets(knl, exclude_empty=False): def get_sched_item_ids_within_inames(knl, inames): from loopy.schedule import Barrier, RunInstruction - sched_item_ids = [] + sched_item_ids = set() for sched_item in knl.schedule: if isinstance(sched_item, (RunInstruction, Barrier)): insn_id = _get_insn_id_from_sched_item(knl, sched_item) @@ -355,5 +355,5 @@ def get_sched_item_ids_within_inames(knl, inames): insn = knl.id_to_insn[insn_id] if inames.issubset(insn.within_inames): - sched_item_ids.append(insn_id) + sched_item_ids.add(insn_id) return sched_item_ids -- GitLab From 4bcd56d1ac25c234339c63fd5a94dcdd5180cee9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 14 Jul 2019 23:42:37 -0500 Subject: [PATCH 071/183] creating PRIOR deps (no corresponding constraint yet) for loop-carried dependencies --- dependency.py | 84 ++++++++++++++++++++++++++++++++++++++------ sched_check_utils.py | 12 ++++--- 2 files changed, 80 insertions(+), 16 deletions(-) diff --git a/dependency.py b/dependency.py index 73161fb5d..8a02de011 100644 --- a/dependency.py +++ b/dependency.py @@ -4,7 +4,7 @@ import islpy as isl class DependencyType: NONE = "none" SAME = "same" - #PRIOR = "prior" + PRIOR = "prior" #ALL = "all" @@ -107,15 +107,10 @@ def create_dependency_constraint( if dep_type == dt.SAME: constraint_set = create_elementwise_equality_conjunction_set( inames_list, inames_prime, islvars) - """ - # TODO define these if useful, otherwise remove - elif dep_type == dt.PRIOR: - constraint_set = constraint_set & islvars[iname].lt_set( - islvars[iname_prime]) - elif dep_type == dt.ALL: - constraint_set = constraint_set & islvars[0].eq_set( - islvars[0]) # True - """ + if dep_type == dt.PRIOR: + # TODO using false as placeholder + constraint_set = islvars[0].eq_set(islvars[0] + 1) + pass # set unused vars == unused dummy param for iname in inames_before_unused+inames_after_unused: @@ -166,7 +161,11 @@ def create_dependency_constraint( def create_dependencies_from_legacy_knl(knl): # Introduce SAME dep for set of shared, non-concurrent inames - from schedule_checker.sched_check_utils import get_concurrent_inames + from schedule_checker.sched_check_utils import ( + get_concurrent_inames, + get_all_nonconcurrent_insn_iname_subsets, + get_sched_item_ids_within_inames, + ) from schedule_checker.schedule import Statement dt = DependencyType conc_inames, non_conc_inames = get_concurrent_inames(knl) @@ -194,4 +193,67 @@ def create_dependencies_from_legacy_knl(knl): statement_dep_sets.append( StatementDependencySet(s_before, s_after, dep_dict)) + # loop-carried deps ------------------------------------------ + + # Go through insns and get all unique insn.depends_on iname sets + non_conc_iname_subsets = get_all_nonconcurrent_insn_iname_subsets( + knl, exclude_empty=True, non_conc_inames=non_conc_inames) + print("NONCONCURRENT INAME SUBSETS") + print(non_conc_iname_subsets) + + # For each set of insns within a given iname set, find sources and sinks. + # Then make PRIOR dep from all sinks to all sources at previous iterations + for iname_subset in non_conc_iname_subsets: + # find items within this iname set + sched_item_ids = get_sched_item_ids_within_inames(knl, iname_subset) + print("") + print("inames:", iname_subset) + print("matching sched items:", sched_item_ids) + + # find sources and sinks + sources, sinks = get_dependency_sources_and_sinks(knl, sched_item_ids) + # TODO this ignores deps connecting to items outside sched_item_ids, + # is that okay? + print("sources:", sources) + print("sinks:", sinks) + + # create prior deps + for source_id in sources: + for sink_id in sinks: + dep_dict = {} + sink_insn_inames = knl.id_to_insn[sink_id].within_inames + source_insn_inames = knl.id_to_insn[source_id].within_inames + shared_inames = sink_insn_inames & source_insn_inames + shared_non_conc_inames = shared_inames & non_conc_inames + + # TODO who tracks the iname nesting (needed for prior)? + dep_dict[dt.PRIOR] = shared_non_conc_inames + + s_before = Statement(sink_id, sink_insn_inames) + s_after = Statement(source_id, source_insn_inames) + statement_dep_sets.append( + StatementDependencySet(s_before, s_after, dep_dict)) + return statement_dep_sets + + +def get_dependency_sources_and_sinks(knl, sched_item_ids): + from schedule_checker.sched_check_utils import ( + _get_insn_id_from_sched_item, + ) + sources = set() + dep_heads = set() # all dependency heads (within sched_item_ids) + for item_id in sched_item_ids: + # find the deps within sched_item_ids + deps = knl.id_to_insn[item_id].depends_on & sched_item_ids + if deps: + # add deps to dep_heads + dep_heads.update(deps) + else: # has no deps (within sched_item_ids), this is a source + sources.add(item_id) + + # sinks don't point to anyone + sinks = sched_item_ids - dep_heads + + return sources, sinks + diff --git a/sched_check_utils.py b/sched_check_utils.py index bbd4ae81f..1d89df6d2 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -288,7 +288,7 @@ def get_concurrent_inames(knl): conc_inames = set() # TODO remove non-conc test + assertion - nonconc_inames = set() + non_conc_inames = set() all_inames = knl.all_inames() for iname in all_inames: @@ -298,10 +298,10 @@ def get_concurrent_inames(knl): for tag in iname_tags): conc_inames.add(iname) else: - nonconc_inames.add(iname) + non_conc_inames.add(iname) # TODO remove non-conc test + assertion - assert all_inames-conc_inames == nonconc_inames + assert all_inames-conc_inames == non_conc_inames return conc_inames, all_inames-conc_inames @@ -316,10 +316,12 @@ def _get_insn_id_from_sched_item(knl, sched_item): # TODO for better performance, could combine these funcs so we don't # loop over schedule more than once -def get_all_nonconcurrent_insn_iname_subsets(knl, exclude_empty=False): +def get_all_nonconcurrent_insn_iname_subsets( + knl, exclude_empty=False, non_conc_inames=None): from loopy.schedule import Barrier, RunInstruction - _, non_conc_inames = get_concurrent_inames(knl) + if non_conc_inames is None: + _, non_conc_inames = get_concurrent_inames(knl) iname_subsets = set() #TODO do we need to check anything besides Barrer, RunInsn? -- GitLab From 22bcccc6e53f5794684f35c189b2723681aaa179 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 15 Jul 2019 01:43:29 -0500 Subject: [PATCH 072/183] adding+testing PRIOR deps for loop carried dependencies; renamed statement.sid to statement.insn_id for clarity; fixed domain list order ambiguity in sched.create_symbolic_isl_map() --- dependency.py | 49 ++++++++++-------- example_pairwise_schedule_validity.py | 71 +++++++++++++++++---------- example_schedule_creation_old.py | 6 ++- sched_check_utils.py | 7 +-- schedule.py | 30 ++++++----- 5 files changed, 101 insertions(+), 62 deletions(-) diff --git a/dependency.py b/dependency.py index 8a02de011..e705a4ec8 100644 --- a/dependency.py +++ b/dependency.py @@ -27,14 +27,18 @@ class StatementDependencySet(object): for dep_type, inames in self.deps.items()]) -def create_elementwise_equality_conjunction_set(names0, names1, islvars): +def create_elementwise_comparison_conjunction_set( + names0, names1, islvars, op="eq"): # initialize set with constraint that is always true - eq_set = islvars[0].eq_set(islvars[0]) + conj_set = islvars[0].eq_set(islvars[0]) for n0, n1 in zip(names0, names1): - eq_set = eq_set & islvars[n0].eq_set(islvars[n1]) + 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 eq_set + return conj_set def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): @@ -53,7 +57,7 @@ def create_dependency_constraint( all_inames_ordered, dom_before_constraint_set, dom_after_constraint_set, - sid_to_int, + insn_id_to_int, unused_param_name, statement_var_name, ): @@ -97,7 +101,7 @@ def create_dependency_constraint( continue # need to put inames in a list so that order of inames and inames' - # matches when calling create_elementwise_equality_conj... + # matches when calling create_elementwise_comparison_conj... if not isinstance(inames, list): inames_list = list(inames) else: @@ -105,12 +109,13 @@ def create_dependency_constraint( inames_prime = append_apostrophes(inames_list) # e.g., [j', k'] if dep_type == dt.SAME: - constraint_set = create_elementwise_equality_conjunction_set( - inames_list, inames_prime, islvars) - if dep_type == dt.PRIOR: - # TODO using false as placeholder - constraint_set = islvars[0].eq_set(islvars[0] + 1) - pass + constraint_set = create_elementwise_comparison_conjunction_set( + inames_list, inames_prime, islvars, op="eq") + elif dep_type == dt.PRIOR: + # TODO for now, PRIOR requires upper left quadrant happen before, + # but next need to switch this to ordering based on loop nest + constraint_set = create_elementwise_comparison_conjunction_set( + inames_list, inames_prime, islvars, op="lt") # set unused vars == unused dummy param for iname in inames_before_unused+inames_after_unused: @@ -118,8 +123,8 @@ def create_dependency_constraint( islvars[unused_param_name]) # set statement_var_name == statement # - s_before_int = sid_to_int[statement_dep_set.statement_before.sid] - s_after_int = sid_to_int[statement_dep_set.statement_after.sid] + s_before_int = insn_id_to_int[statement_dep_set.statement_before.insn_id] + s_after_int = insn_id_to_int[statement_dep_set.statement_after.insn_id] constraint_set = constraint_set & islvars[statement_var_name].eq_set( islvars[0]+s_before_int) constraint_set = constraint_set & islvars[statement_var_name_prime].eq_set( @@ -198,24 +203,25 @@ def create_dependencies_from_legacy_knl(knl): # Go through insns and get all unique insn.depends_on iname sets non_conc_iname_subsets = get_all_nonconcurrent_insn_iname_subsets( knl, exclude_empty=True, non_conc_inames=non_conc_inames) - print("NONCONCURRENT INAME SUBSETS") - print(non_conc_iname_subsets) + #print("-"*85) + #print("NONCONCURRENT INAME SUBSETS") + #print(non_conc_iname_subsets) # For each set of insns within a given iname set, find sources and sinks. # Then make PRIOR dep from all sinks to all sources at previous iterations for iname_subset in non_conc_iname_subsets: # find items within this iname set sched_item_ids = get_sched_item_ids_within_inames(knl, iname_subset) - print("") - print("inames:", iname_subset) - print("matching sched items:", sched_item_ids) + #print("") + #print("inames:", iname_subset) + #print("matching sched items:", sched_item_ids) # find sources and sinks sources, sinks = get_dependency_sources_and_sinks(knl, sched_item_ids) # TODO this ignores deps connecting to items outside sched_item_ids, # is that okay? - print("sources:", sources) - print("sinks:", sinks) + #print("sources:", sources) + #print("sinks:", sinks) # create prior deps for source_id in sources: @@ -233,6 +239,7 @@ def create_dependencies_from_legacy_knl(knl): s_after = Statement(source_id, source_insn_inames) statement_dep_sets.append( StatementDependencySet(s_before, s_after, dep_dict)) + #print("-"*85) return statement_dep_sets diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index cb9f45601..8b79cb551 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -20,7 +20,7 @@ from schedule_checker.sched_check_utils import ( #knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" -#knl_choice = "stroud" # invalid sched? +#knl_choice = "stroud" # TODO invalid sched? #knl_choice = "add_barrier" #knl_choice = "nop" #TODO nop not in sched... error #knl_choice = "nest_multi_dom" @@ -298,8 +298,16 @@ for dep_set, dom_before, dom_after in deps_and_domains: # For each dependency, create+test schedule containing pair of insns------ +print("="*85) +print("Looping through dep pairs...") + sched_is_valid = True for statement_dep_set, dom_before, dom_after in deps_and_domains: + print("="*85) + print(statement_dep_set) + print("dom_before:", dom_before) + print("dom_after:", dom_after) + s_before = statement_dep_set.statement_before s_after = statement_dep_set.statement_after @@ -322,12 +330,12 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency sched = LexSchedule(knl, include_only_insn_ids=[ - s_before.sid, - s_after.sid + s_before.insn_id, + s_after.insn_id ]) - print("-"*85) - print("LexSchedule before processing:") - print(sched) + #print("-"*85) + #print("LexSchedule before processing:") + #print(sched) # Right now, statement tuples consist of single int. # Add all inames from combined domains to statement tuples. @@ -340,38 +348,51 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: print("LexSchedule with inames added:") print(sched) + print("dict{lp insn id : sched sid int}:") + print(sched.lp_insnid_to_int_sid) + print("-"*85) # Get an isl map representing the LexSchedule; # this requires the iname domains + + if len(sched) == 1: + assert dom_before == dom_after + sid_to_dom = { + sched.lp_insnid_to_int_sid[s_before.insn_id]: dom_before} + elif len(sched) == 2: + sid_to_dom = { + sched.lp_insnid_to_int_sid[s_before.insn_id]: dom_before, + sched.lp_insnid_to_int_sid[s_after.insn_id]: dom_after, + } + else: + assert False + print("sid_to_dom:\n",sid_to_dom) + sched_map_symbolic = sched.create_symbolic_isl_map( - [dom_before, dom_after], all_necessary_inames_ordered) + sid_to_dom, all_necessary_inames_ordered) print("LexSchedule after creating symbolic isl map:") print(sched) print("LexSched:") print(prettier_map_string(sched_map_symbolic)) - print("space (statement instances -> lex time):") - print(sched_map_symbolic.space) - print("-"*85) + #print("space (statement instances -> lex time):") + #print(sched_map_symbolic.space) + #print("-"*85) # get map representing lexicographic ordering lex_order_map_symbolic = sched.get_lex_order_map_for_symbolic_sched() - print("lex order map symbolic:") - print(prettier_map_string(lex_order_map_symbolic)) - print("space (lex time -> lex time):") - print(lex_order_map_symbolic.space) - print("-"*85) + #print("lex order map symbolic:") + #print(prettier_map_string(lex_order_map_symbolic)) + #print("space (lex time -> lex time):") + #print(lex_order_map_symbolic.space) + #print("-"*85) # create statement instance ordering, # maps each statement instance to all statement instances occuring later SIO_symbolic = get_statement_ordering_map( sched_map_symbolic, lex_order_map_symbolic) - print("statement instance ordering symbolic:") - print(prettier_map_string(SIO_symbolic)) - print("SIO space (statement instances -> statement instances):") - print(SIO_symbolic.space) - print("-"*85) - - print("dict{lp insn id : sched sid int}:") - print(sched.lp_insnid_to_int_sid) + #print("statement instance ordering symbolic:") + #print(prettier_map_string(SIO_symbolic)) + #print("SIO space (statement instances -> statement instances):") + #print(SIO_symbolic.space) print("-"*85) # create a map representing constraints from the dependency, @@ -385,8 +406,8 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: sched.unused_param_name, sched.statement_var_name, ) - print("constraint map:") - print(prettier_map_string(constraint_map)) + #print("constraint map:") + #print(prettier_map_string(constraint_map)) aligned_constraint_map = constraint_map.align_params(SIO_symbolic.space) print("aligned constraint map:") print(prettier_map_string(aligned_constraint_map)) diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index 9e9599fe5..ce157418d 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -120,8 +120,12 @@ sched.add_symbolic_inames_to_statement_instances( print("LexSchedule with inames added:") print(sched) +sid_to_dom = {} +for insn_id, sid in sched.lp_insnid_to_int_sid.items(): + sid_to_dom[sid] = domain_union + sched_map_symbolic = sched.create_symbolic_isl_map( - [domain_union]*len(sched.lex_schedule), # due to changes, need one per insn + sid_to_dom, all_necessary_inames_ordered) print("LexSchedule after processing:") print(sched) diff --git a/sched_check_utils.py b/sched_check_utils.py index 1d89df6d2..9804ec5d0 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -165,7 +165,7 @@ def create_explicit_map_from_tuples(tuple_pairs, space): def create_symbolic_isl_map_from_tuples( tuple_pairs, space, - domains_to_intersect, + domains_to_intersect, # TODO pass these zipped w/tuples? unused_param_name, statement_var_name, # TODO can we not pass this? ): @@ -207,9 +207,10 @@ def create_symbolic_isl_map_from_tuples( # here for determing where to set inames equal to dummy vars, # should instead determine before in LexSchedule and pass info in dom_var_names = dom.get_var_names(dim_type.out) - assert set( + if not set( [var for var in tup_out if not isinstance(var, int)] - ).issubset(set(dom_var_names)) + ).issubset(set(dom_var_names)): + assert False unused_inames = set(space_in_names) \ - set(dom_var_names) - set([statement_var_name]) for unused_iname in unused_inames: diff --git a/schedule.py b/schedule.py index be60ca533..ccda2e0af 100644 --- a/schedule.py +++ b/schedule.py @@ -5,15 +5,15 @@ from collections import OrderedDict class Statement(object): def __init__( self, - sid, + insn_id, active_inames, ): - self.sid = sid # string + self.insn_id = insn_id # string self.active_inames = active_inames # [string, ] def __str__(self): return "%s {%s}" % ( - self.sid, ",".join(self.active_inames)) + self.insn_id, ",".join(self.active_inames)) class StatementInstance(object): @@ -31,12 +31,12 @@ class StatementInstance(object): def __str__(self): import six return "[%s,%s]" % ( - self.statement.sid, ",".join( + self.statement.insn_id, ",".join( ["%d" % (v) for k, v in sorted(six.iteritems(self.iname_vals))])) def __eq__(self, other): return self.iname_vals == other.iname_vals and \ - self.statement.sid == other.statement.sid + self.statement.insn_id == other.statement.insn_id def __hash__(self): return hash(str(self)) @@ -172,7 +172,7 @@ class LexSchedule(object): def get_last_lex_pt(self): return self.lex_schedule[self.get_last_schedule_item()] - def create_symbolic_isl_map(self, domains, inames_ordered): + def create_symbolic_isl_map(self, sid_to_dom, inames_ordered): # create isl map representing lex schedule from schedule_checker.sched_check_utils import ( @@ -180,7 +180,7 @@ class LexSchedule(object): add_dims_to_isl_set ) - assert len(domains) == len(self.lex_schedule) + assert len(sid_to_dom) == len(self.lex_schedule) # create an isl space # {('statement', used in >=1 statement domain>) -> @@ -195,11 +195,14 @@ class LexSchedule(object): # Insert 'statement' dim into domain so that its space allows for # intersection with sched map later new_pose = 0 # insert 'statement' dim at beginning - # TODO don't hardcode pose + # TODO don't hardcode statement var pose doms_to_intersect = [] - for dom in domains: - doms_to_intersect.append(add_dims_to_isl_set( - dom, isl.dim_type.out, [self.statement_var_name], new_pose)) + for tup_in, tup_out in self.items(): + sid = tup_in[0] # TODO don't hardcode this + doms_to_intersect.append( + add_dims_to_isl_set( + sid_to_dom[sid], isl.dim_type.out, + [self.statement_var_name], new_pose)) # create isl map return create_symbolic_isl_map_from_tuples( @@ -223,7 +226,7 @@ class LexSchedule(object): map_str = "{" for state_inst, lex_pt in self.lex_schedule.items(): domain_elem = "[s=%s,%s]" % ( - state_inst.statement.sid, ",".join( + state_inst.statement.insn_id, ",".join( ["%s=%d" % (iname, val) for iname, val in state_inst.iname_vals.items()])) range_elem = "[%s]" % (",".join("%s" % (lx) for lx in lex_pt)) @@ -253,6 +256,9 @@ class LexSchedule(object): def values(self): return self.lex_schedule.values() + def __len__(self): + return len(self.lex_schedule) + #def __str__(self): # #return str(self.get_isl_map()) # return str(self.get_isl_map_str()) -- GitLab From e000ee0effe1febbec6275b3810481dcd7019b8b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 15 Jul 2019 21:03:35 -0500 Subject: [PATCH 073/183] removed some old TODOs --- example_pairwise_schedule_validity.py | 87 +-------------------------- sched_check_utils.py | 4 +- schedule.py | 2 - 3 files changed, 3 insertions(+), 90 deletions(-) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 8b79cb551..220ce389d 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -365,7 +365,7 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: } else: assert False - print("sid_to_dom:\n",sid_to_dom) + print("sid_to_dom:\n", sid_to_dom) sched_map_symbolic = sched.create_symbolic_isl_map( sid_to_dom, all_necessary_inames_ordered) @@ -441,88 +441,3 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: print("is sched valid? constraint map subset of SIO?") print(sched_is_valid) - - -# TODO create example with simple explicit sched -''' -all_inames = ['i', 'j'] -iname_params = ['p0', 'p1'] -iname_param_vals = [2, 2] -statement_var = 's' -statement_param = 'ps' -statement_bound = 2 - - - -s0 = Statement("0", ["i", "j"]) -s1 = Statement("1", ["i", "j"]) -print("Statements:") -print(s0) -print(s1) - -s0_00 = StatementInstance(s0, {"i": 0, "j": 0}) -s0_10 = StatementInstance(s0, {"i": 1, "j": 0}) -s0_01 = StatementInstance(s0, {"i": 0, "j": 1}) -s0_11 = StatementInstance(s0, {"i": 1, "j": 1}) -s1_00 = StatementInstance(s1, {"i": 0, "j": 0}) -s1_10 = StatementInstance(s1, {"i": 1, "j": 0}) -s1_01 = StatementInstance(s1, {"i": 0, "j": 1}) -s1_11 = StatementInstance(s1, {"i": 1, "j": 1}) -print("Statement instances:") -print(s0_00) -print(s0_10) -print(s0_01) -print(s0_11) -print(s1_00) -print(s1_10) -print(s1_01) -print(s1_11) - -state_inst_to_lex_time_dict = { - s0_00: (0,0), - s1_00: (0,1), - s0_10: (0,0), - s1_10: (0,1), - s0_01: (1,0), - s1_01: (1,1), - s0_11: (1,0), - s1_11: (1,1), - } - -sched = LexSchedule(state_inst_to_lex_time_dict) -print("LexSchedule:") -print(sched) - -# sched map should be this: -schedule_explicit_map = isl.Map( - """{ - [s,i,j] -> [0,0] : s = 0 and i = 0 and j = 0; - [s,i,j] -> [0,1] : s = 1 and i = 0 and j = 0; - [s,i,j] -> [0,0] : s = 0 and i = 1 and j = 0; - [s,i,j] -> [0,1] : s = 1 and i = 1 and j = 0; - [s,i,j] -> [1,0] : s = 0 and i = 0 and j = 1; - [s,i,j] -> [1,1] : s = 1 and i = 0 and j = 1; - [s,i,j] -> [1,0] : s = 0 and i = 1 and j = 1; - [s,i,j] -> [1,1] : s = 1 and i = 1 and j = 1; - }""") - -schedule_general_map = isl.Map("{[s,i,j] -> [j,s]}") - -print("Map representing schedule generally:") -print(schedule_general_map) - -# the following is equivalent to explicit map above: -schedule_explicit_map2 = isl.Map( - """{ - [s=0,i=0,j=0] -> [0,0]; - [s=1,i=0,j=0] -> [0,1]; - [s=0,i=1,j=0] -> [0,0]; - [s=1,i=1,j=0] -> [0,1]; - [s=0,i=0,j=1] -> [1,0]; - [s=1,i=0,j=1] -> [1,1]; - [s=0,i=1,j=1] -> [1,0]; - [s=1,i=1,j=1] -> [1,1]; - }""") -assert schedule_explicit_map2 == schedule_explicit_map == sched.get_isl_map() - -''' diff --git a/sched_check_utils.py b/sched_check_utils.py index 9804ec5d0..697e0b033 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -208,8 +208,8 @@ def create_symbolic_isl_map_from_tuples( # should instead determine before in LexSchedule and pass info in dom_var_names = dom.get_var_names(dim_type.out) if not set( - [var for var in tup_out if not isinstance(var, int)] - ).issubset(set(dom_var_names)): + [var for var in tup_out if not isinstance(var, int)] + ).issubset(set(dom_var_names)): assert False unused_inames = set(space_in_names) \ - set(dom_var_names) - set([statement_var_name]) diff --git a/schedule.py b/schedule.py index ccda2e0af..0a5645130 100644 --- a/schedule.py +++ b/schedule.py @@ -79,7 +79,6 @@ class LexSchedule(object): # 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] - # TODO originally assumed perfect loop nesting, still the case? for sched_item in knl.schedule: if isinstance(sched_item, EnterLoop): iname = sched_item.iname @@ -187,7 +186,6 @@ class LexSchedule(object): # (lexicographic ordering dims)} params_sched = [self.unused_param_name] in_names_sched = [self.statement_var_name] + inames_ordered - # TODO make "l" a variable for consistency out_names_sched = self.get_lex_var_names() from schedule_checker.sched_check_utils import get_isl_space sched_space = get_isl_space(params_sched, in_names_sched, out_names_sched) -- GitLab From 571aa4893edf6902bd8f9d467801ffbec5c46528 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 15 Jul 2019 21:24:09 -0500 Subject: [PATCH 074/183] statement variable position within statement instance tuples now less hard coded --- dependency.py | 8 +++++--- example_dependency_checking.py | 2 ++ example_pairwise_schedule_validity.py | 1 + example_schedule_creation_old.py | 1 + schedule.py | 12 ++++++++---- 5 files changed, 17 insertions(+), 7 deletions(-) diff --git a/dependency.py b/dependency.py index e705a4ec8..8298528b1 100644 --- a/dependency.py +++ b/dependency.py @@ -60,6 +60,7 @@ def create_dependency_constraint( insn_id_to_int, unused_param_name, statement_var_name, + statement_var_pose, ): from schedule_checker.sched_check_utils import ( make_islvars_with_var_primes, @@ -140,12 +141,13 @@ def create_dependency_constraint( # now apply domain sets to constraint variables # add statement variable to doms to enable intersection - new_pose = 0 # insert 'statement' at beginning # TODO don't hardcode position domain_to_intersect = add_dims_to_isl_set( - dom_before_constraint_set, isl.dim_type.out, [statement_var_name], new_pose) + dom_before_constraint_set, isl.dim_type.out, + [statement_var_name], statement_var_pose) range_constraint_set = create_new_set_with_primes(dom_after_constraint_set) range_to_intersect = add_dims_to_isl_set( - range_constraint_set, isl.dim_type.out, [statement_var_name_prime], new_pose) + range_constraint_set, isl.dim_type.out, + [statement_var_name_prime], statement_var_pose) # insert inames missing from doms to enable intersection domain_to_intersect = add_missing_dims_to_isl_set( diff --git a/example_dependency_checking.py b/example_dependency_checking.py index 84adc8fdc..5c3e3281b 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -114,6 +114,7 @@ print("----------------------------------------------------------------------") # i dependency is none, j dependency is `prior` statement_var = 's' +statement_var_pose = 0 unused_param_name = 'unused' domains = {} @@ -147,6 +148,7 @@ constraint_map = create_dependency_constraint( insnid_to_int_sid, unused_param_name, statement_var, + statement_var_pose, ) print("constraint map space:") print(constraint_map.space) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 220ce389d..d30097422 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -405,6 +405,7 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: sched.lp_insnid_to_int_sid, sched.unused_param_name, sched.statement_var_name, + sched.statement_var_pose(), ) #print("constraint map:") #print(prettier_map_string(constraint_map)) diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index ce157418d..87678df56 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -191,6 +191,7 @@ for statement_dep_set in statement_dep_sets: sched.lp_insnid_to_int_sid, sched.unused_param_name, sched.statement_var_name, + sched.statement_var_pose(), ) print("constraint map:") print(prettier_map_string(constraint_map)) diff --git a/schedule.py b/schedule.py index 0a5645130..605d66ec4 100644 --- a/schedule.py +++ b/schedule.py @@ -171,6 +171,11 @@ class LexSchedule(object): def get_last_lex_pt(self): return self.lex_schedule[self.get_last_schedule_item()] + def statement_var_pose(self): + # TODO what is the proper way to provide this information + # while keeping it immutable? + return 0 # 1st position in statement instance tuple + def create_symbolic_isl_map(self, sid_to_dom, inames_ordered): # create isl map representing lex schedule @@ -192,15 +197,13 @@ class LexSchedule(object): # Insert 'statement' dim into domain so that its space allows for # intersection with sched map later - new_pose = 0 # insert 'statement' dim at beginning - # TODO don't hardcode statement var pose doms_to_intersect = [] for tup_in, tup_out in self.items(): - sid = tup_in[0] # TODO don't hardcode this + sid = tup_in[self.statement_var_pose()] doms_to_intersect.append( add_dims_to_isl_set( sid_to_dom[sid], isl.dim_type.out, - [self.statement_var_name], new_pose)) + [self.statement_var_name], self.statement_var_pose())) # create isl map return create_symbolic_isl_map_from_tuples( @@ -221,6 +224,7 @@ class LexSchedule(object): n_dims, in_names=self.get_lex_var_names()) def get_isl_map_str(self): + # TODO remove this and other unused functions map_str = "{" for state_inst, lex_pt in self.lex_schedule.items(): domain_elem = "[s=%s,%s]" % ( -- GitLab From 18ea86b720eb37d8d9f338ac447e8108fff19f55 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 15 Jul 2019 21:59:55 -0500 Subject: [PATCH 075/183] moved/removed unused code --- dependency.py | 4 -- example_dependency_checking.py | 1 - example_pairwise_schedule_validity.py | 8 ++-- sched_check_utils.py | 57 ++++++++++++++------------- schedule.py | 57 +++++---------------------- 5 files changed, 44 insertions(+), 83 deletions(-) diff --git a/dependency.py b/dependency.py index 8298528b1..2c22d3b49 100644 --- a/dependency.py +++ b/dependency.py @@ -247,9 +247,6 @@ def create_dependencies_from_legacy_knl(knl): def get_dependency_sources_and_sinks(knl, sched_item_ids): - from schedule_checker.sched_check_utils import ( - _get_insn_id_from_sched_item, - ) sources = set() dep_heads = set() # all dependency heads (within sched_item_ids) for item_id in sched_item_ids: @@ -265,4 +262,3 @@ def get_dependency_sources_and_sinks(knl, sched_item_ids): sinks = sched_item_ids - dep_heads return sources, sinks - diff --git a/example_dependency_checking.py b/example_dependency_checking.py index 5c3e3281b..ede094231 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -120,7 +120,6 @@ unused_param_name = 'unused' domains = {} for iname in all_necessary_inames_ordered: domains[iname] = knl.get_inames_domain(iname) -domains_list = list(domains.values()) # make some dependencies manually for now: s0 = Statement("0", {"i", "j"}) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index d30097422..25afb3e7d 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -9,7 +9,6 @@ from schedule_checker.lexicographic_order_map import ( get_statement_ordering_map, ) from schedule_checker.sched_check_utils import ( - get_concurrent_inames, prettier_map_string, order_var_names_to_match_islset, ) @@ -160,7 +159,7 @@ elif knl_choice == "stroud": knl = lp.get_one_scheduled_kernel(knl) if knl_choice == "add_barrier": np.random.seed(17) - a = np.random.randn(16) + #a = np.random.randn(16) cnst = np.random.randn(16) knl = lp.make_kernel( "{[i, ii]: 0<=i, ii statement instances):") diff --git a/sched_check_utils.py b/sched_check_utils.py index 697e0b033..95fdf368f 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -6,10 +6,6 @@ def prettier_map_string(isl_map): ).replace("{ ", "{\n").replace(" }", "\n}").replace("; ", ";\n") -def flatten_2d_list(list2d): - return [item for inner_list in list2d for item in inner_list] - - 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_) @@ -64,29 +60,6 @@ def create_new_set_with_primes(old_set): return new_set -def add_missing_set_dims_to_map_indims(islmap, islset): - new_map = islmap.copy() - for i in range(islset.n_dim()): - new_dim_name = islset.get_dim_name(isl.dim_type.out, i) - # does new_dim_name already exist in map? - dim_idx = new_map.find_dim_by_name(isl.dim_type.in_, new_dim_name) - if dim_idx == -1: - # new map needs dim, insert it - new_map = new_map.insert_dims(isl.dim_type.in_, i, 1) - new_map = new_map.set_dim_name(isl.dim_type.in_, i, new_dim_name) - else: - # new_map already has new_dim_name - if dim_idx == i: - # and it's already in the right spot - continue - else: - # move it - # TODO how do we move these? move_dims doesn't work for same dim_type - print("%s not in right spot" % (new_dim_name)) - raise ValueError("(this should not happen)") - return new_map - - def make_islvars_with_var_primes(var_names, param_names): return isl.make_zero_and_vars( var_names+append_apostrophes(var_names), param_names) @@ -360,3 +333,33 @@ def get_sched_item_ids_within_inames(knl, inames): if inames.issubset(insn.within_inames): sched_item_ids.add(insn_id) return sched_item_ids + + +# currently unused: +""" +def flatten_2d_list(list2d): + return [item for inner_list in list2d for item in inner_list] + + +def add_missing_set_dims_to_map_indims(islmap, islset): + new_map = islmap.copy() + for i in range(islset.n_dim()): + new_dim_name = islset.get_dim_name(isl.dim_type.out, i) + # does new_dim_name already exist in map? + dim_idx = new_map.find_dim_by_name(isl.dim_type.in_, new_dim_name) + if dim_idx == -1: + # new map needs dim, insert it + new_map = new_map.insert_dims(isl.dim_type.in_, i, 1) + new_map = new_map.set_dim_name(isl.dim_type.in_, i, new_dim_name) + else: + # new_map already has new_dim_name + if dim_idx == i: + # and it's already in the right spot + continue + else: + # move it + # TODO how do we move these? move_dims doesn't work for same dim_type + print("%s not in right spot" % (new_dim_name)) + raise ValueError("(this should not happen)") + return new_map +""" diff --git a/schedule.py b/schedule.py index 605d66ec4..0e1ed7325 100644 --- a/schedule.py +++ b/schedule.py @@ -16,32 +16,6 @@ class Statement(object): self.insn_id, ",".join(self.active_inames)) -class StatementInstance(object): - def __init__( - self, - statement, - iname_vals, - ): - assert all( - [iname in statement.active_inames - for iname, val in iname_vals.items()]) - self.statement = statement # statement - self.iname_vals = iname_vals # dict{string:int} - - def __str__(self): - import six - return "[%s,%s]" % ( - self.statement.insn_id, ",".join( - ["%d" % (v) for k, v in sorted(six.iteritems(self.iname_vals))])) - - def __eq__(self, other): - return self.iname_vals == other.iname_vals and \ - self.statement.insn_id == other.statement.insn_id - - def __hash__(self): - return hash(str(self)) - - class LexSchedule(object): # contains a mapping of {statement instance: lex point} @@ -168,9 +142,6 @@ class LexSchedule(object): def get_last_schedule_item(self): return next(reversed(self.lex_schedule)) - def get_last_lex_pt(self): - return self.lex_schedule[self.get_last_schedule_item()] - def statement_var_pose(self): # TODO what is the proper way to provide this information # while keeping it immutable? @@ -223,20 +194,6 @@ class LexSchedule(object): return create_symbolic_lex_order_map( n_dims, in_names=self.get_lex_var_names()) - def get_isl_map_str(self): - # TODO remove this and other unused functions - map_str = "{" - for state_inst, lex_pt in self.lex_schedule.items(): - domain_elem = "[s=%s,%s]" % ( - state_inst.statement.insn_id, ",".join( - ["%s=%d" % (iname, val) - for iname, val in state_inst.iname_vals.items()])) - range_elem = "[%s]" % (",".join("%s" % (lx) for lx in lex_pt)) - map_str += "%s -> %s; " % (domain_elem, range_elem) - map_str += "}" - #TODO return map not string - return map_str - def __bool__(self): return bool(self.lex_schedule) @@ -261,12 +218,16 @@ class LexSchedule(object): def __len__(self): return len(self.lex_schedule) - #def __str__(self): - # #return str(self.get_isl_map()) - # return str(self.get_isl_map_str()) - def __str__(self): - return str(list(self.lex_schedule.items())) + sched_str = "{\n" + for state_tuple, lex_pt in self.lex_schedule.items(): + domain_elem = "[%s=%s,%s]" % ( + self.statement_var_name, + state_tuple[self.statement_var_pose()], + ",".join(state_tuple[1:])) + sched_str += "%s -> %s;\n" % (domain_elem, lex_pt) + sched_str += "}" + return sched_str # Methods related to *explicit* schedule/map creation ------------------ # TODO consider removing these -- GitLab From aec46dd2f7901ab4fa2e1676f2f65a6a64b6f8f9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 15 Jul 2019 22:11:48 -0500 Subject: [PATCH 076/183] added get_inames_in_sched_order(scheduled_knl) func --- example_pairwise_schedule_validity.py | 3 +++ sched_check_utils.py | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 25afb3e7d..7e363b802 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -11,6 +11,7 @@ from schedule_checker.lexicographic_order_map import ( from schedule_checker.sched_check_utils import ( prettier_map_string, order_var_names_to_match_islset, + get_inames_in_sched_order, ) # Choose kernel ---------------------------------------------------------- @@ -267,6 +268,8 @@ print("="*80) print("Loopy schedule:") for sched_item in knl.schedule: print(sched_item) +print("scheduled iname order:") +print(get_inames_in_sched_order(knl)) print("="*80) # Create StatementDependencySet(s) from kernel dependencies ----------------- diff --git a/sched_check_utils.py b/sched_check_utils.py index 95fdf368f..2fd4bb952 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -335,6 +335,12 @@ def get_sched_item_ids_within_inames(knl, inames): return sched_item_ids +def get_inames_in_sched_order(scheduled_knl): + # returns non-concurrent inames in order found in sched + from loopy.schedule import EnterLoop + return [sched_item.iname for sched_item in scheduled_knl.schedule + if isinstance(sched_item, EnterLoop)] + # currently unused: """ def flatten_2d_list(list2d): -- GitLab From fd91ef7b51fad4477d46d618e45989f3e68f5654 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 15 Jul 2019 23:06:21 -0500 Subject: [PATCH 077/183] now PRIOR requires statement_before complete previous *lexicographically ordered* iterations of nested loops before statement_after completes current iteration --- dependency.py | 66 ++++++++++++++++++++++----- example_pairwise_schedule_validity.py | 12 +++-- example_schedule_creation_old.py | 8 ++-- lexicographic_order_map.py | 24 ++++++---- schedule.py | 4 +- 5 files changed, 83 insertions(+), 31 deletions(-) diff --git a/dependency.py b/dependency.py index 2c22d3b49..0b15e7669 100644 --- a/dependency.py +++ b/dependency.py @@ -54,9 +54,10 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): def create_dependency_constraint( statement_dep_set, - all_inames_ordered, + all_dom_inames_ordered, dom_before_constraint_set, dom_after_constraint_set, + sched_iname_order, insn_id_to_int, unused_param_name, statement_var_name, @@ -76,17 +77,17 @@ def create_dependency_constraint( # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} islvars = make_islvars_with_var_primes( - [statement_var_name]+all_inames_ordered, + [statement_var_name]+all_dom_inames_ordered, [unused_param_name]) statement_var_name_prime = statement_var_name+"'" # get (ordered) list of unused before/after inames inames_before_unused = [] - for iname in all_inames_ordered: + for iname in all_dom_inames_ordered: if iname not in dom_before_constraint_set.get_var_names(isl.dim_type.out): inames_before_unused.append(iname) inames_after_unused = [] - for iname in all_inames_ordered: + for iname in all_dom_inames_ordered: if iname not in dom_after_constraint_set.get_var_names(isl.dim_type.out): inames_after_unused.append(iname + "'") @@ -113,10 +114,30 @@ def create_dependency_constraint( constraint_set = create_elementwise_comparison_conjunction_set( inames_list, inames_prime, islvars, op="eq") elif dep_type == dt.PRIOR: - # TODO for now, PRIOR requires upper left quadrant happen before, - # but next need to switch this to ordering based on loop nest - constraint_set = create_elementwise_comparison_conjunction_set( - inames_list, inames_prime, islvars, op="lt") + # (old) PRIOR requires upper left quadrant happen before: + #constraint_set = create_elementwise_comparison_conjunction_set( + # inames_list, inames_prime, islvars, op="lt") + + # PRIOR requires statement_before complete previous iterations + # of (nested) loops before statement_after completes current iteration + inames_list_nest_ordered = [ + iname for iname in sched_iname_order + if iname in inames_list] + inames_list_nest_ordered_prime = append_apostrophes( + inames_list_nest_ordered) + if set(inames_list_nest_ordered) != set(inames_list): + # TODO when does this happen? + # TODO what do we do here? + assert False + + from schedule_checker.lexicographic_order_map import ( + get_lex_order_constraint + ) + constraint_set = get_lex_order_constraint( + islvars, + inames_list_nest_ordered, + inames_list_nest_ordered_prime, + ) # set unused vars == unused dummy param for iname in inames_before_unused+inames_after_unused: @@ -136,8 +157,19 @@ def create_dependency_constraint( # convert constraint set to map all_constraints_map = _convert_constraint_set_to_map( - all_constraints_set, len(all_inames_ordered) + 1) # +1 for statement var - + all_constraints_set, len(all_dom_inames_ordered) + 1) # +1 for statement var + + """ + # for debugging + if dt.PRIOR in statement_dep_set.deps.keys(): + print("!"*90) + print(inames_list_nest_ordered) + from schedule_checker.sched_check_utils import ( + prettier_map_string, + ) + print(prettier_map_string(all_constraints_map)) + print("."*90) + """ # now apply domain sets to constraint variables # add statement variable to doms to enable intersection @@ -152,15 +184,25 @@ def create_dependency_constraint( # insert inames missing from doms to enable intersection domain_to_intersect = add_missing_dims_to_isl_set( domain_to_intersect, isl.dim_type.out, - [statement_var_name] + all_inames_ordered) + [statement_var_name] + all_dom_inames_ordered) range_to_intersect = add_missing_dims_to_isl_set( range_to_intersect, isl.dim_type.out, - append_apostrophes([statement_var_name] + all_inames_ordered)) + append_apostrophes([statement_var_name] + all_dom_inames_ordered)) # intersect doms map_with_loop_domain_constraints = all_constraints_map.intersect_domain( domain_to_intersect).intersect_range(range_to_intersect) + """ + # for debugging + if dt.PRIOR in statement_dep_set.deps.keys(): + print(inames_list_nest_ordered) + from schedule_checker.sched_check_utils import ( + prettier_map_string, + ) + print(prettier_map_string(map_with_loop_domain_constraints)) + print("!"*90) + """ return map_with_loop_domain_constraints diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 7e363b802..7a2c7dd52 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -268,8 +268,9 @@ print("="*80) print("Loopy schedule:") for sched_item in knl.schedule: print(sched_item) +sched_iname_order = get_inames_in_sched_order(knl) print("scheduled iname order:") -print(get_inames_in_sched_order(knl)) +print(sched_iname_order) print("="*80) # Create StatementDependencySet(s) from kernel dependencies ----------------- @@ -326,7 +327,7 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: s_before.active_inames | s_after.active_inames ) - all_necessary_inames_ordered = order_var_names_to_match_islset( + all_dom_inames_ordered = order_var_names_to_match_islset( knl.all_inames(), combined_doms) # Create a mapping of {statement instance: lex point} @@ -346,7 +347,7 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: # the in-dims for an isl map, so if an iname is needed in one # statement tuple, then it is needed in all statement tuples. sched.add_symbolic_inames_to_statement_instances( - all_necessary_inames_ordered) + all_dom_inames_ordered) print("LexSchedule with inames added:") print(sched) @@ -370,7 +371,7 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: print("sid_to_dom:\n", sid_to_dom) sched_map_symbolic = sched.create_symbolic_isl_map( - sid_to_dom, all_necessary_inames_ordered) + sid_to_dom, all_dom_inames_ordered) print("LexSchedule after creating symbolic isl map:") print(sched) print("LexSched:") @@ -401,9 +402,10 @@ for statement_dep_set, dom_before, dom_after in deps_and_domains: # maps each statement instance to all statement instances that must occur later constraint_map = create_dependency_constraint( statement_dep_set, - all_necessary_inames_ordered, + all_dom_inames_ordered, dom_before, dom_after, + sched_iname_order, sched.lp_insnid_to_int_sid, sched.unused_param_name, sched.statement_var_name, diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index 87678df56..e90609482 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -102,7 +102,7 @@ if not all_iname_domains_equal(knl): "schedule checker does not yet handle kernels where " "get_inames_domain(iname) is not same for all inames") domain_union = _union_inames_domains(knl) -all_necessary_inames_ordered = order_var_names_to_match_islset( +all_dom_inames_ordered = order_var_names_to_match_islset( knl.all_inames(), domain_union) # get all inames in consistent ordering: @@ -116,7 +116,7 @@ print(sched) # the in-dims for an isl map, so if an iname is needed in one # statement tuple, then it is needed in all statement tuples. sched.add_symbolic_inames_to_statement_instances( - all_necessary_inames_ordered) + all_dom_inames_ordered) print("LexSchedule with inames added:") print(sched) @@ -126,7 +126,7 @@ for insn_id, sid in sched.lp_insnid_to_int_sid.items(): sched_map_symbolic = sched.create_symbolic_isl_map( sid_to_dom, - all_necessary_inames_ordered) + all_dom_inames_ordered) print("LexSchedule after processing:") print(sched) # ------------------------------------------------------------------- @@ -185,7 +185,7 @@ for statement_dep_set in statement_dep_sets: statement_dep_set.statement_after.active_inames) constraint_map = create_dependency_constraint( statement_dep_set, - all_necessary_inames_ordered, + all_dom_inames_ordered, dom_before, dom_after, sched.lp_insnid_to_int_sid, diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 7b34d190b..994bbdad4 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -32,6 +32,21 @@ def get_statement_ordering_map(sched_map, lex_map): return sched_map.apply_range(lex_map).apply_range(sched_map.reverse()) +def get_lex_order_constraint(islvars, in_names, out_names): + # create constraint enforcing lex ordering, e.g., in the 3-dim case: + # i0 < o0 or ((i0 = o0) and (i1 < o1)) + # or ((i0 = o0) and (i1 = o1) and (i2 < o2)) + lex_order_constraint = islvars[in_names[0]].lt_set(islvars[out_names[0]]) + for i in range(1, len(in_names)): + lex_order_constraint_conj = islvars[in_names[i]].lt_set( + islvars[out_names[i]]) + for j in range(i): + lex_order_constraint_conj = lex_order_constraint_conj & \ + islvars[in_names[j]].eq_set(islvars[out_names[j]]) + lex_order_constraint = lex_order_constraint | lex_order_constraint_conj + return lex_order_constraint + + def create_symbolic_lex_order_map( n_dims, in_names=None, @@ -53,14 +68,7 @@ def create_symbolic_lex_order_map( # create constraint enforcing lex ordering, e.g., in the 3-dim case: # i0 < o0 or ((i0 = o0) and (i1 < o1)) # or ((i0 = o0) and (i1 = o1) and (i2 < o2)) - lex_order_constraint = islvars[in_names[0]].lt_set(islvars[out_names[0]]) - for i in range(1, len(in_names)): - lex_order_constraint_conj = islvars[in_names[i]].lt_set( - islvars[out_names[i]]) - for j in range(i): - lex_order_constraint_conj = lex_order_constraint_conj & \ - islvars[in_names[j]].eq_set(islvars[out_names[j]]) - lex_order_constraint = lex_order_constraint | lex_order_constraint_conj + lex_order_constraint = get_lex_order_constraint(islvars, in_names, out_names) #lex_set = lex_set_outer_bounds & lex_order_constraint #lex_map = isl.Map.from_domain(lex_set) diff --git a/schedule.py b/schedule.py index 0e1ed7325..f47eb2705 100644 --- a/schedule.py +++ b/schedule.py @@ -147,7 +147,7 @@ class LexSchedule(object): # while keeping it immutable? return 0 # 1st position in statement instance tuple - def create_symbolic_isl_map(self, sid_to_dom, inames_ordered): + def create_symbolic_isl_map(self, sid_to_dom, dom_inames_ordered): # create isl map representing lex schedule from schedule_checker.sched_check_utils import ( @@ -161,7 +161,7 @@ class LexSchedule(object): # {('statement', used in >=1 statement domain>) -> # (lexicographic ordering dims)} params_sched = [self.unused_param_name] - in_names_sched = [self.statement_var_name] + inames_ordered + in_names_sched = [self.statement_var_name] + dom_inames_ordered out_names_sched = self.get_lex_var_names() from schedule_checker.sched_check_utils import get_isl_space sched_space = get_isl_space(params_sched, in_names_sched, out_names_sched) -- GitLab From 7d945266cab83e2ac6d81274a60870eb14bf7e3d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 16 Jul 2019 01:47:42 -0500 Subject: [PATCH 078/183] encapsulated sched checking procedure into single function that takes kernel and returns bool --- __init__.py | 234 ++++++++++++++++++++++++++ example_pairwise_schedule_validity.py | 209 +---------------------- 2 files changed, 239 insertions(+), 204 deletions(-) diff --git a/__init__.py b/__init__.py index e69de29bb..fb3543494 100644 --- a/__init__.py +++ b/__init__.py @@ -0,0 +1,234 @@ +def check_schedule_validity(test_knl, verbose=False): + + from schedule_checker.dependency import ( + create_dependencies_from_legacy_knl, + create_dependency_constraint, + ) + from schedule_checker.schedule import LexSchedule + from schedule_checker.lexicographic_order_map import ( + get_statement_ordering_map, + ) + from schedule_checker.sched_check_utils import ( + prettier_map_string, + order_var_names_to_match_islset, + get_inames_in_sched_order, + ) + + if test_knl.schedule is None: + from loopy import preprocess_kernel, get_one_scheduled_kernel + knl = lp.preprocess_kernel(test_knl) + knl = lp.get_one_scheduled_kernel(knl) + else: + knl = test_knl + + sched_iname_order = get_inames_in_sched_order(knl) + + if verbose: + # Print kernel info ------------------------------------------------------ + print("="*80) + print("Kernel:") + print(knl) + from loopy import generate_code_v2 + print(generate_code_v2(knl).device_code()) + print("="*80) + print("Iname tags: %s" % (knl.iname_to_tags)) + print("="*80) + print("Loopy schedule:") + for sched_item in knl.schedule: + print(sched_item) + print("scheduled iname order:") + print(sched_iname_order) + + # Create StatementDependencySet(s) from kernel dependencies ----------------- + + # Introduce SAME dep for set of shared, non-concurrent inames. + # For each set of insns within a given iname subset, find sources and sinks, + # then make PRIOR dep from all sinks to all sources at previous iterations. + statement_dep_sets = create_dependencies_from_legacy_knl(knl) + + # get separate domains for before.active_inames and after.active_inames + deps_and_domains = [] + for dep_set in statement_dep_sets: + deps_and_domains.append([ + dep_set, + knl.get_inames_domain(dep_set.statement_before.active_inames), + knl.get_inames_domain(dep_set.statement_after.active_inames) + ]) + + if verbose: + print("="*80) + print("StatementDependencies w/domains:") + for dep_set, dom_before, dom_after in deps_and_domains: + print(dep_set) + print(dom_before) + print(dom_after) + + # For each dependency, create+test schedule containing pair of insns------ + + if verbose: + print("="*80) + print("Looping through dep pairs...") + + sched_is_valid = True + for statement_dep_set, dom_before, dom_after in deps_and_domains: + if verbose: + print("="*80) + print("statement dep set:") + print(statement_dep_set) + print("dom_before:", dom_before) + print("dom_after:", dom_after) + + s_before = statement_dep_set.statement_before + s_after = statement_dep_set.statement_after + + # The isl map representing the schedule maps + # statement instances -> lex time + # The 'in_' dim vars need to match for all sched items in the map, + # Instructions that use fewer inames will still need to + # have the unused inames in their 'in_' dim vars, so we'll + # include them and set them equal to a dummy variable. + + # Get all inames now in order to maintain list with consistent ordering + # This will help keep isl maps/sets compatible + combined_doms = knl.get_inames_domain( + s_before.active_inames | + s_after.active_inames + ) + all_dom_inames_ordered = order_var_names_to_match_islset( + knl.all_inames(), combined_doms) + + # Create a mapping of {statement instance: lex point} + # including only instructions involved in this dependency + sched = LexSchedule(knl, include_only_insn_ids=[ + s_before.insn_id, + s_after.insn_id + ]) + + #print("-"*80) + #print("LexSchedule before processing:") + #print(sched) + + # Right now, statement tuples consist of single int. + # Add all inames from combined domains to statement tuples. + # This may include inames not used in every instruction, + # but all in-tuples need to match because they will become + # the in-dims for an isl map, so if an iname is needed in one + # statement tuple, then it is needed in all statement tuples. + sched.add_symbolic_inames_to_statement_instances( + all_dom_inames_ordered) + if verbose: + print("-"*80) + print("LexSchedule with inames added:") + print(sched) + print("dict{lp insn id : sched sid int}:") + print(sched.lp_insnid_to_int_sid) + + # Get an isl map representing the LexSchedule; + # this requires the iname domains + + if len(sched) == 1: + assert dom_before == dom_after + sid_to_dom = { + sched.lp_insnid_to_int_sid[s_before.insn_id]: dom_before} + elif len(sched) == 2: + sid_to_dom = { + sched.lp_insnid_to_int_sid[s_before.insn_id]: dom_before, + sched.lp_insnid_to_int_sid[s_after.insn_id]: dom_after, + } + else: + assert False + + sched_map_symbolic = sched.create_symbolic_isl_map( + sid_to_dom, all_dom_inames_ordered) + + if verbose: + print("sid_to_dom:\n", sid_to_dom) + print("LexSchedule after creating symbolic isl map:") + print(sched) + print("LexSched:") + print(prettier_map_string(sched_map_symbolic)) + #print("space (statement instances -> lex time):") + #print(sched_map_symbolic.space) + #print("-"*80) + + # get map representing lexicographic ordering + lex_order_map_symbolic = sched.get_lex_order_map_for_symbolic_sched() + """ + if verbose: + print("lex order map symbolic:") + print(prettier_map_string(lex_order_map_symbolic)) + print("space (lex time -> lex time):") + print(lex_order_map_symbolic.space) + print("-"*80) + """ + + # create statement instance ordering, + # maps each statement instance to all statement instances occuring later + sio = get_statement_ordering_map( + sched_map_symbolic, lex_order_map_symbolic) + """ + if verbose: + print("statement instance ordering symbolic:") + print(prettier_map_string(sio)) + print("SIO space (statement instances -> statement instances):") + print(sio.space) + print("-"*80) + """ + + # create a map representing constraints from the dependency, + # maps each statement instance to all statement instances that must occur later + constraint_map = create_dependency_constraint( + statement_dep_set, + all_dom_inames_ordered, + dom_before, + dom_after, + sched_iname_order, + sched.lp_insnid_to_int_sid, + sched.unused_param_name, + sched.statement_var_name, + sched.statement_var_pose(), + ) + + aligned_constraint_map = constraint_map.align_params(sio.space) + if verbose: + print("constraint map:") + print(prettier_map_string(aligned_constraint_map)) + + assert aligned_constraint_map.space == sio.space + + if not aligned_constraint_map.is_subset(sio): + + sched_is_valid = False + + if verbose: + print("================ constraint check failure =================") + print("constraint map not subset of SIO") + print("dependency:") + print(statement_dep_set) + print("statement instance ordering:") + print(prettier_map_string(sio)) + print("constraint_map.gist(sio):") + print(aligned_constraint_map.gist(sio)) + print("sio.gist(constraint_map)") + print(sio.gist(aligned_constraint_map)) + """ + from schedule_checker.sched_check_utils import ( + get_concurrent_inames, + ) + conc_inames, non_conc_inames = get_concurrent_inames(knl) + print("concurrent inames:", conc_inames) + print("sequential inames:", non_conc_inames) + print("constraint map space (statment instances -> statement instances):") + print(aligned_constraint_map.space) + print("SIO space (statement instances -> statement instances):") + print(sio.space) + print("constraint map:") + print(prettier_map_string(aligned_constraint_map)) + print("statement instance ordering:") + print(prettier_map_string(sio)) + print("{insn id -> sched sid int} dict:") + print(sched.lp_insnid_to_int_sid) + """ + print("===========================================================") + + return sched_is_valid diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 7a2c7dd52..2c4a01256 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -1,18 +1,6 @@ import loopy as lp import numpy as np -from schedule_checker.dependency import ( - create_dependencies_from_legacy_knl, - create_dependency_constraint, -) -from schedule_checker.schedule import LexSchedule -from schedule_checker.lexicographic_order_map import ( - get_statement_ordering_map, -) -from schedule_checker.sched_check_utils import ( - prettier_map_string, - order_var_names_to_match_islset, - get_inames_in_sched_order, -) +from schedule_checker import check_schedule_validity # Choose kernel ---------------------------------------------------------- @@ -20,7 +8,7 @@ from schedule_checker.sched_check_utils import ( #knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" -#knl_choice = "stroud" # TODO invalid sched? +#knl_choice = "stroud_bernstein" # TODO invalid sched? #knl_choice = "add_barrier" #knl_choice = "nop" #TODO nop not in sched... error #knl_choice = "nest_multi_dom" @@ -110,7 +98,7 @@ elif knl_choice == "dependent_domain": knl = lp.realize_reduction(knl, force_scan=True) knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) -elif knl_choice == "stroud": +elif knl_choice == "stroud_bernstein": knl = lp.make_kernel( "{[el, i2, alpha1,alpha2]: \ 0 <= el < nels and \ @@ -144,7 +132,7 @@ elif knl_choice == "stroud": lp.GlobalArg("coeffs", None, shape=None), "..." ], - name="stroud", + name="stroud_bernstein", assumptions="deg>=0 and nels>=1" ) @@ -257,195 +245,8 @@ if knl_choice == "loop_carried_deps": knl = lp.preprocess_kernel(knl) knl = lp.get_one_scheduled_kernel(knl) -# Print kernel info ------------------------------------------------------ -print("Kernel:") -print(knl) -print(lp.generate_code_v2(knl).device_code()) -print("="*80) -print("Iname tags: %s" % (knl.iname_to_tags)) -print("="*80) -print("Loopy schedule:") -for sched_item in knl.schedule: - print(sched_item) -sched_iname_order = get_inames_in_sched_order(knl) -print("scheduled iname order:") -print(sched_iname_order) -print("="*80) - -# Create StatementDependencySet(s) from kernel dependencies ----------------- - -# Introduce SAME dep for set of shared, non-concurrent inames -print("-"*85) -statement_dep_sets = create_dependencies_from_legacy_knl(knl) -print("Statement Dependencies:") -for dep_set in statement_dep_sets: - print(dep_set) - print("") - -# get separate domains for before.active_inames and after.active_inames -deps_and_domains = [] -for dep_set in statement_dep_sets: - deps_and_domains.append([ - dep_set, - knl.get_inames_domain(dep_set.statement_before.active_inames), - knl.get_inames_domain(dep_set.statement_after.active_inames) - ]) - -print("-"*85) -print("StatementDependencies w/domains:") -for dep_set, dom_before, dom_after in deps_and_domains: - print(dep_set) - print(dom_before) - print(dom_after) - -# For each dependency, create+test schedule containing pair of insns------ - -print("="*85) -print("Looping through dep pairs...") - -sched_is_valid = True -for statement_dep_set, dom_before, dom_after in deps_and_domains: - print("="*85) - print(statement_dep_set) - print("dom_before:", dom_before) - print("dom_after:", dom_after) - - s_before = statement_dep_set.statement_before - s_after = statement_dep_set.statement_after - - # The isl map representing the schedule maps - # statement instances -> lex time - # The 'in_' dim vars need to match for all sched items in the map, - # Instructions that use fewer inames will still need to - # have the unused inames in their 'in_' dim vars, so we'll - # include them and set them equal to a dummy variable. - - # Get all inames now in order to maintain list with consistent ordering - # This will help keep isl maps/sets compatible - combined_doms = knl.get_inames_domain( - s_before.active_inames | - s_after.active_inames - ) - all_dom_inames_ordered = order_var_names_to_match_islset( - knl.all_inames(), combined_doms) - - # Create a mapping of {statement instance: lex point} - # including only instructions involved in this dependency - sched = LexSchedule(knl, include_only_insn_ids=[ - s_before.insn_id, - s_after.insn_id - ]) - #print("-"*85) - #print("LexSchedule before processing:") - #print(sched) - - # Right now, statement tuples consist of single int. - # Add all inames from combined domains to statement tuples. - # This may include inames not used in every instruction, - # but all in-tuples need to match because they will become - # the in-dims for an isl map, so if an iname is needed in one - # statement tuple, then it is needed in all statement tuples. - sched.add_symbolic_inames_to_statement_instances( - all_dom_inames_ordered) - print("LexSchedule with inames added:") - print(sched) - - print("dict{lp insn id : sched sid int}:") - print(sched.lp_insnid_to_int_sid) - print("-"*85) - # Get an isl map representing the LexSchedule; - # this requires the iname domains - - if len(sched) == 1: - assert dom_before == dom_after - sid_to_dom = { - sched.lp_insnid_to_int_sid[s_before.insn_id]: dom_before} - elif len(sched) == 2: - sid_to_dom = { - sched.lp_insnid_to_int_sid[s_before.insn_id]: dom_before, - sched.lp_insnid_to_int_sid[s_after.insn_id]: dom_after, - } - else: - assert False - print("sid_to_dom:\n", sid_to_dom) - - sched_map_symbolic = sched.create_symbolic_isl_map( - sid_to_dom, all_dom_inames_ordered) - print("LexSchedule after creating symbolic isl map:") - print(sched) - print("LexSched:") - print(prettier_map_string(sched_map_symbolic)) - #print("space (statement instances -> lex time):") - #print(sched_map_symbolic.space) - #print("-"*85) - - # get map representing lexicographic ordering - lex_order_map_symbolic = sched.get_lex_order_map_for_symbolic_sched() - #print("lex order map symbolic:") - #print(prettier_map_string(lex_order_map_symbolic)) - #print("space (lex time -> lex time):") - #print(lex_order_map_symbolic.space) - #print("-"*85) - - # create statement instance ordering, - # maps each statement instance to all statement instances occuring later - SIO_symbolic = get_statement_ordering_map( - sched_map_symbolic, lex_order_map_symbolic) - #print("statement instance ordering symbolic:") - #print(prettier_map_string(SIO_symbolic)) - #print("SIO space (statement instances -> statement instances):") - #print(SIO_symbolic.space) - print("-"*85) - - # create a map representing constraints from the dependency, - # maps each statement instance to all statement instances that must occur later - constraint_map = create_dependency_constraint( - statement_dep_set, - all_dom_inames_ordered, - dom_before, - dom_after, - sched_iname_order, - sched.lp_insnid_to_int_sid, - sched.unused_param_name, - sched.statement_var_name, - sched.statement_var_pose(), - ) - #print("constraint map:") - #print(prettier_map_string(constraint_map)) - aligned_constraint_map = constraint_map.align_params(SIO_symbolic.space) - print("aligned constraint map:") - print(prettier_map_string(aligned_constraint_map)) - - assert aligned_constraint_map.space == SIO_symbolic.space - if not aligned_constraint_map.is_subset(SIO_symbolic): - sched_is_valid = False - print("================ constraint check failure =================") - print("constraint map not subset of SIO") - print("dependency:") - print(statement_dep_set) - """ - from schedule_checker.sched_check_utils import ( - get_concurrent_inames, - ) - conc_inames, non_conc_inames = get_concurrent_inames(knl) - print("concurrent inames:", conc_inames) - print("sequential inames:", non_conc_inames) - print("constraint map space (statment instances -> statement instances):") - print(aligned_constraint_map.space) - print("SIO space (statement instances -> statement instances):") - print(SIO_symbolic.space) - print("constraint map:") - print(prettier_map_string(aligned_constraint_map)) - print("statement instance ordering:") - print(prettier_map_string(SIO_symbolic)) - print("{insn id -> sched sid int} dict:") - print(sched.lp_insnid_to_int_sid) - print("gist") - print(aligned_constraint_map.gist(SIO_symbolic)) - print(SIO_symbolic.gist(aligned_constraint_map)) - """ - print("===========================================================") +sched_is_valid = check_schedule_validity(knl, verbose=True) print("is sched valid? constraint map subset of SIO?") print(sched_is_valid) -- GitLab From ab0c1b16b6e0df4b71a2e0531fecc9086ececa03 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 20 Jul 2019 12:11:54 -0500 Subject: [PATCH 079/183] added comment about unnecessary (but not problematic) lex point incrementation --- schedule.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/schedule.py b/schedule.py index f47eb2705..f4e42e9fb 100644 --- a/schedule.py +++ b/schedule.py @@ -78,6 +78,8 @@ class LexSchedule(object): next_insn_lex_pt.pop() next_insn_lex_pt.pop() next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 + # if we didn't add any statements while in this loop, we might + # sometimes be able to skip this increment, but it's not hurting anything elif isinstance(sched_item, (RunInstruction, Barrier)): from schedule_checker.sched_check_utils import ( _get_insn_id_from_sched_item, -- GitLab From 25f2d436bdeb4958bb54d58c74560bc381685ebf Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 20 Jul 2019 12:13:06 -0500 Subject: [PATCH 080/183] looping through instructions in unscheduled kernel, rather than sched items in sched kernel, in get_all_nonconcurrent_insn_iname_subsets() and get_sched_item_ids_within_inames() --- sched_check_utils.py | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 2fd4bb952..f7b15827c 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -292,23 +292,13 @@ def _get_insn_id_from_sched_item(knl, sched_item): # loop over schedule more than once def get_all_nonconcurrent_insn_iname_subsets( knl, exclude_empty=False, non_conc_inames=None): - from loopy.schedule import Barrier, RunInstruction if non_conc_inames is None: _, non_conc_inames = get_concurrent_inames(knl) iname_subsets = set() - #TODO do we need to check anything besides Barrer, RunInsn? - for sched_item in knl.schedule: - if isinstance(sched_item, (RunInstruction, Barrier)): - insn_id = _get_insn_id_from_sched_item(knl, sched_item) - if insn_id is None: - # TODO make sure it's okay to ignore barriers without id - # matmul example has barrier that fails this assertion... - # assert sched_item.originating_insn_id is not None - continue - insn = knl.id_to_insn[insn_id] - iname_subsets.add(insn.within_inames & non_conc_inames) + for insn in knl.instructions: + iname_subsets.add(insn.within_inames & non_conc_inames) if exclude_empty: iname_subsets.discard(frozenset()) @@ -317,21 +307,11 @@ def get_all_nonconcurrent_insn_iname_subsets( def get_sched_item_ids_within_inames(knl, inames): - from loopy.schedule import Barrier, RunInstruction sched_item_ids = set() - for sched_item in knl.schedule: - if isinstance(sched_item, (RunInstruction, Barrier)): - insn_id = _get_insn_id_from_sched_item(knl, sched_item) - if insn_id is None: - # TODO make sure it's okay to ignore barriers without id - # matmul example has barrier that fails this assertion... - # assert sched_item.originating_insn_id is not None - continue - - insn = knl.id_to_insn[insn_id] - if inames.issubset(insn.within_inames): - sched_item_ids.add(insn_id) + for insn in knl.instructions: + if inames.issubset(insn.within_inames): + sched_item_ids.add(insn.id) return sched_item_ids @@ -341,6 +321,7 @@ def get_inames_in_sched_order(scheduled_knl): return [sched_item.iname for sched_item in scheduled_knl.schedule if isinstance(sched_item, EnterLoop)] + # currently unused: """ def flatten_2d_list(list2d): -- GitLab From 66eb8d9984ed341e03b1b7cee0b0fecba98053d8 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 20 Jul 2019 12:16:08 -0500 Subject: [PATCH 081/183] creating dependencies from *unscheduled* kernel; getting loop priority from knl.loop_priority for PRIOR deps; when priority is unknown, PRIOR requires that quadrant happen first --- __init__.py | 74 ++++++++++++++------------- dependency.py | 67 +++++++++++++++--------- example_dependency_checking.py | 3 +- example_pairwise_schedule_validity.py | 29 +++-------- example_schedule_creation_old.py | 2 + 5 files changed, 94 insertions(+), 81 deletions(-) diff --git a/__init__.py b/__init__.py index fb3543494..bf682da87 100644 --- a/__init__.py +++ b/__init__.py @@ -1,4 +1,4 @@ -def check_schedule_validity(test_knl, verbose=False): +def check_schedule_validity(unscheduled_knl, verbose=False): from schedule_checker.dependency import ( create_dependencies_from_legacy_knl, @@ -14,45 +14,24 @@ def check_schedule_validity(test_knl, verbose=False): get_inames_in_sched_order, ) - if test_knl.schedule is None: - from loopy import preprocess_kernel, get_one_scheduled_kernel - knl = lp.preprocess_kernel(test_knl) - knl = lp.get_one_scheduled_kernel(knl) - else: - knl = test_knl - - sched_iname_order = get_inames_in_sched_order(knl) - - if verbose: - # Print kernel info ------------------------------------------------------ - print("="*80) - print("Kernel:") - print(knl) - from loopy import generate_code_v2 - print(generate_code_v2(knl).device_code()) - print("="*80) - print("Iname tags: %s" % (knl.iname_to_tags)) - print("="*80) - print("Loopy schedule:") - for sched_item in knl.schedule: - print(sched_item) - print("scheduled iname order:") - print(sched_iname_order) + from loopy import preprocess_kernel + # TODO check to see if preprocessed already? + preprocessed_knl = preprocess_kernel(unscheduled_knl) # Create StatementDependencySet(s) from kernel dependencies ----------------- # Introduce SAME dep for set of shared, non-concurrent inames. # For each set of insns within a given iname subset, find sources and sinks, # then make PRIOR dep from all sinks to all sources at previous iterations. - statement_dep_sets = create_dependencies_from_legacy_knl(knl) + statement_dep_sets = create_dependencies_from_legacy_knl(preprocessed_knl) # get separate domains for before.active_inames and after.active_inames deps_and_domains = [] for dep_set in statement_dep_sets: deps_and_domains.append([ dep_set, - knl.get_inames_domain(dep_set.statement_before.active_inames), - knl.get_inames_domain(dep_set.statement_after.active_inames) + preprocessed_knl.get_inames_domain(dep_set.statement_before.active_inames), + preprocessed_knl.get_inames_domain(dep_set.statement_after.active_inames) ]) if verbose: @@ -63,6 +42,31 @@ def check_schedule_validity(test_knl, verbose=False): print(dom_before) print(dom_after) + # get a schedule to check + if preprocessed_knl.schedule is None: + from loopy import get_one_scheduled_kernel + scheduled_knl = get_one_scheduled_kernel(preprocessed_knl) + else: + scheduled_knl = preprocessed_knl + + sched_iname_order = get_inames_in_sched_order(scheduled_knl) + + if verbose: + # Print kernel info ------------------------------------------------------ + print("="*80) + print("Kernel:") + print(scheduled_knl) + from loopy import generate_code_v2 + print(generate_code_v2(scheduled_knl).device_code()) + print("="*80) + print("Iname tags: %s" % (scheduled_knl.iname_to_tags)) + print("="*80) + print("Loopy schedule:") + for sched_item in scheduled_knl.schedule: + print(sched_item) + print("scheduled iname order:") + print(sched_iname_order) + # For each dependency, create+test schedule containing pair of insns------ if verbose: @@ -90,16 +94,16 @@ def check_schedule_validity(test_knl, verbose=False): # Get all inames now in order to maintain list with consistent ordering # This will help keep isl maps/sets compatible - combined_doms = knl.get_inames_domain( + combined_doms = preprocessed_knl.get_inames_domain( s_before.active_inames | s_after.active_inames ) all_dom_inames_ordered = order_var_names_to_match_islset( - knl.all_inames(), combined_doms) + preprocessed_knl.all_inames(), combined_doms) # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency - sched = LexSchedule(knl, include_only_insn_ids=[ + sched = LexSchedule(scheduled_knl, include_only_insn_ids=[ s_before.insn_id, s_after.insn_id ]) @@ -176,13 +180,13 @@ def check_schedule_validity(test_knl, verbose=False): """ # create a map representing constraints from the dependency, - # maps each statement instance to all statement instances that must occur later + # maps statement instance to all statement instances that must occur later constraint_map = create_dependency_constraint( statement_dep_set, all_dom_inames_ordered, dom_before, dom_after, - sched_iname_order, + unscheduled_knl.loop_priority, sched.lp_insnid_to_int_sid, sched.unused_param_name, sched.statement_var_name, @@ -215,10 +219,10 @@ def check_schedule_validity(test_knl, verbose=False): from schedule_checker.sched_check_utils import ( get_concurrent_inames, ) - conc_inames, non_conc_inames = get_concurrent_inames(knl) + conc_inames, non_conc_inames = get_concurrent_inames(scheduled_knl) print("concurrent inames:", conc_inames) print("sequential inames:", non_conc_inames) - print("constraint map space (statment instances -> statement instances):") + print("constraint map space (stmt instances -> stmt instances):") print(aligned_constraint_map.space) print("SIO space (statement instances -> statement instances):") print(sio.space) diff --git a/dependency.py b/dependency.py index 0b15e7669..788854fb1 100644 --- a/dependency.py +++ b/dependency.py @@ -57,7 +57,7 @@ def create_dependency_constraint( all_dom_inames_ordered, dom_before_constraint_set, dom_after_constraint_set, - sched_iname_order, + loop_priorities, insn_id_to_int, unused_param_name, statement_var_name, @@ -114,30 +114,49 @@ def create_dependency_constraint( constraint_set = create_elementwise_comparison_conjunction_set( inames_list, inames_prime, islvars, op="eq") elif dep_type == dt.PRIOR: - # (old) PRIOR requires upper left quadrant happen before: - #constraint_set = create_elementwise_comparison_conjunction_set( - # inames_list, inames_prime, islvars, op="lt") - - # PRIOR requires statement_before complete previous iterations - # of (nested) loops before statement_after completes current iteration - inames_list_nest_ordered = [ - iname for iname in sched_iname_order - if iname in inames_list] - inames_list_nest_ordered_prime = append_apostrophes( - inames_list_nest_ordered) - if set(inames_list_nest_ordered) != set(inames_list): - # TODO when does this happen? - # TODO what do we do here? - assert False - - from schedule_checker.lexicographic_order_map import ( - get_lex_order_constraint - ) - constraint_set = get_lex_order_constraint( - islvars, - inames_list_nest_ordered, - inames_list_nest_ordered_prime, + + # if nesting is known: + # TODO there might be situations where we know the priority even + # though loop_priorities is None + priority_known = False + if loop_priorities: + for priority_tuple in loop_priorities: + # TODO might be able to deduce priority from multiple tuples + # even if all inames are not present in any single tuple + if set(inames_list).issubset(set(priority_tuple)): + priority_known = True + break + + # if only one loop, we know the priority + if not priority_known and len(inames_list) == 1: + priority_tuple = tuple(inames_list) + priority_known = True + + if priority_known: + # PRIOR requires statement_before complete previous iterations + # of loops before statement_after completes current iteration + # according to loop nest order + inames_list_nest_ordered = [ + iname for iname in priority_tuple + if iname in inames_list] + inames_list_nest_ordered_prime = append_apostrophes( + inames_list_nest_ordered) + if set(inames_list_nest_ordered) != set(inames_list): + # TODO could this happen? + assert False + + from schedule_checker.lexicographic_order_map import ( + get_lex_order_constraint ) + constraint_set = get_lex_order_constraint( + islvars, + inames_list_nest_ordered, + inames_list_nest_ordered_prime, + ) + else: # priority not known + # PRIOR requires upper left quadrant happen before: + constraint_set = create_elementwise_comparison_conjunction_set( + inames_list, inames_prime, islvars, op="lt") # set unused vars == unused dummy param for iname in inames_before_unused+inames_after_unused: diff --git a/example_dependency_checking.py b/example_dependency_checking.py index ede094231..b037a02fa 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -138,12 +138,13 @@ dom_before = knl.get_inames_domain( dom_after = knl.get_inames_domain( statement_dep_set.statement_after.active_inames ) - +loop_priority = None # TODO constraint_map = create_dependency_constraint( statement_dep_set, all_necessary_inames_ordered, dom_before, dom_after, + loop_priority, insnid_to_int_sid, unused_param_name, statement_var, diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 2c4a01256..64edcea44 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -4,15 +4,15 @@ from schedule_checker import check_schedule_validity # Choose kernel ---------------------------------------------------------- -#knl_choice = "example" -#knl_choice = "matmul" +knl_choice = "example" +knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" #knl_choice = "stroud_bernstein" # TODO invalid sched? #knl_choice = "add_barrier" #knl_choice = "nop" #TODO nop not in sched... error #knl_choice = "nest_multi_dom" -knl_choice = "loop_carried_deps" +#knl_choice = "loop_carried_deps" if knl_choice == "example": knl = lp.make_kernel( @@ -46,8 +46,9 @@ if knl_choice == "example": knl, {"b": np.float32, "d": np.float32, "f": np.float32}) #knl = lp.tag_inames(knl, {"i": "l.0"}) - knl = lp.preprocess_kernel(knl) - knl = lp.get_one_scheduled_kernel(knl) + #knl = lp.prioritize_loops(knl, "i,k,j") + knl = lp.prioritize_loops(knl, "i,k") + knl = lp.prioritize_loops(knl, "i,j") elif knl_choice == "matmul": bsize = 16 knl = lp.make_kernel( @@ -65,8 +66,7 @@ elif knl_choice == "matmul": knl = lp.split_iname(knl, "k", bsize) knl = lp.add_prefetch(knl, "a", ["k_inner", "i_inner"], default_tag="l.auto") knl = lp.add_prefetch(knl, "b", ["j_inner", "k_inner"], default_tag="l.auto") - knl = lp.preprocess_kernel(knl) - knl = lp.get_one_scheduled_kernel(knl) + knl = lp.prioritize_loops(knl, "k_outer,k_inner") elif knl_choice == "scan": stride = 1 n_scan = 16 @@ -81,8 +81,6 @@ elif knl_choice == "scan": knl = lp.fix_parameters(knl, n=n_scan) knl = lp.realize_reduction(knl, force_scan=True) - knl = lp.preprocess_kernel(knl) - knl = lp.get_one_scheduled_kernel(knl) elif knl_choice == "dependent_domain": knl = lp.make_kernel( [ @@ -96,8 +94,6 @@ elif knl_choice == "dependent_domain": lang_version=(2018, 2), ) knl = lp.realize_reduction(knl, force_scan=True) - knl = lp.preprocess_kernel(knl) - knl = lp.get_one_scheduled_kernel(knl) elif knl_choice == "stroud_bernstein": knl = lp.make_kernel( "{[el, i2, alpha1,alpha2]: \ @@ -144,8 +140,6 @@ elif knl_choice == "stroud_bernstein": knl = lp.split_iname(knl, "el_outer", 2, outer_tag="g.0", inner_tag="ilp", slabs=(0, 1)) knl = lp.tag_inames(knl, dict(i2="l.1", alpha1="unr", alpha2="unr")) - knl = lp.preprocess_kernel(knl) - knl = lp.get_one_scheduled_kernel(knl) if knl_choice == "add_barrier": np.random.seed(17) #a = np.random.randn(16) @@ -166,8 +160,6 @@ if knl_choice == "add_barrier": knl = lp.split_iname(knl, "i", 2, outer_tag="g.0", inner_tag="l.0") knl = lp.split_iname(knl, "ii", 2, outer_tag="g.0", inner_tag="l.0") - knl = lp.preprocess_kernel(knl) - knl = lp.get_one_scheduled_kernel(knl) if knl_choice == "nop": knl = lp.make_kernel( [ @@ -185,8 +177,6 @@ if knl_choice == "nop": "...", seq_dependencies=True) knl = lp.fix_parameters(knl, dim=3) - knl = lp.preprocess_kernel(knl) - knl = lp.get_one_scheduled_kernel(knl) if knl_choice == "nest_multi_dom": #"{[i,j,k]: 0<=i,j,kbar = foo {id=insn4,dep=insn3} """ + knl = lp.prioritize_loops(knl, "i,j,k") - knl = lp.preprocess_kernel(knl) - knl = lp.get_one_scheduled_kernel(knl) if knl_choice == "loop_carried_deps": knl = lp.make_kernel( "{[i]: 0<=i Date: Mon, 22 Jul 2019 06:12:17 -0500 Subject: [PATCH 082/183] when checking to see if loop priority is known, instead of requiring all relevant inames be present in single tuple within the knl.loop_priority set, determine whether the sets taken together fully specify the loop prority, e.g., if we ahve (a,b) and (b,c) then we know a->b->c --- __init__.py | 16 +++++--- dependency.py | 49 ++++++++++++++++++++++- example_pairwise_schedule_validity.py | 24 +++++++----- sched_check_utils.py | 56 +++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 16 deletions(-) diff --git a/__init__.py b/__init__.py index bf682da87..4019453ee 100644 --- a/__init__.py +++ b/__init__.py @@ -1,4 +1,7 @@ -def check_schedule_validity(unscheduled_knl, verbose=False): +def check_schedule_validity( + unscheduled_knl, + verbose=False, + _use_scheduled_kernel_to_obtain_loop_priority=False): from schedule_checker.dependency import ( create_dependencies_from_legacy_knl, @@ -94,12 +97,13 @@ def check_schedule_validity(unscheduled_knl, verbose=False): # Get all inames now in order to maintain list with consistent ordering # This will help keep isl maps/sets compatible - combined_doms = preprocessed_knl.get_inames_domain( - s_before.active_inames | - s_after.active_inames - ) all_dom_inames_ordered = order_var_names_to_match_islset( - preprocessed_knl.all_inames(), combined_doms) + preprocessed_knl.all_inames(), + preprocessed_knl.get_inames_domain( + s_before.active_inames | + s_after.active_inames + ) + ) # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency diff --git a/dependency.py b/dependency.py index 788854fb1..5a5e06189 100644 --- a/dependency.py +++ b/dependency.py @@ -120,12 +120,59 @@ def create_dependency_constraint( # though loop_priorities is None priority_known = False if loop_priorities: + # assumes all loop_priority tuples are consistent + + # with multiple priority tuples, determine whether the combined + # info they contain can give us a single, full proiritization, + # e.g., if prios={(a, b), (b, c), (c, d, e)}, then we know + # a -> b -> c -> d -> e + + # remove irrelevant inames from priority tuples (because we're + # about to perform a costly operation on remaining tuples) + relevant_priorities = set() + for p_tuple in loop_priorities: + new_tuple = [iname for iname in p_tuple if iname in inames_list] + # empty tuples and single tuples don't help us define + # a nesting, so ignore them (if we're dealing with a single + # iname, priorities will be ignored later anyway) + if len(new_tuple) > 1: + relevant_priorities.add(tuple(new_tuple)) + + nested_after = {} + for iname in inames_list: + comes_after_iname = set() + for p_tuple in relevant_priorities: + if iname in p_tuple: + comes_after_iname.update([ + iname for iname in + p_tuple[p_tuple.index(iname)+1:]]) + nested_after[iname] = comes_after_iname + + from schedule_checker.sched_check_utils import ( + get_orderings_of_length_n + ) + orders = get_orderings_of_length_n( + nested_after, + required_length=len(inames_list), + #return_first_found=True, # TODO might be faster + return_first_found=False, + ) + if orders: + assert len(orders) == 1 + # TODO can remove assert if return_first_found above + # (or if we trust that all iname priorities are consistent) + priority_known = True + priority_tuple = orders.pop() + + # old way + """ for priority_tuple in loop_priorities: - # TODO might be able to deduce priority from multiple tuples + # might be able to deduce priority from multiple tuples # even if all inames are not present in any single tuple if set(inames_list).issubset(set(priority_tuple)): priority_known = True break + """ # if only one loop, we know the priority if not priority_known and len(inames_list) == 1: diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 64edcea44..4bdf9b3d2 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -4,13 +4,14 @@ from schedule_checker import check_schedule_validity # Choose kernel ---------------------------------------------------------- + knl_choice = "example" -knl_choice = "matmul" +#knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" #knl_choice = "stroud_bernstein" # TODO invalid sched? #knl_choice = "add_barrier" -#knl_choice = "nop" #TODO nop not in sched... error +#knl_choice = "nop" #knl_choice = "nest_multi_dom" #knl_choice = "loop_carried_deps" @@ -184,20 +185,23 @@ if knl_choice == "nest_multi_dom": "{[i]: 0<=iacc = 0 {id=insn0} - for j - for k - acc = acc + j + k {id=insn1,dep=insn0} + for x,xx + for i + <>acc = 0 {id=insn0} + for j + for k + acc = acc + j + k {id=insn1,dep=insn0} + end end end end """, name="nest_multi_dom", #assumptions="n >= 1", - assumptions="ni,nj,nk >= 1", + assumptions="ni,nj,nk,nx >= 1", lang_version=(2018, 2) ) """ @@ -213,7 +217,9 @@ if knl_choice == "nest_multi_dom": end <>bar = foo {id=insn4,dep=insn3} """ - knl = lp.prioritize_loops(knl, "i,j,k") + knl = lp.prioritize_loops(knl, "x,xx,i") + knl = lp.prioritize_loops(knl, "i,j") + knl = lp.prioritize_loops(knl, "j,k") if knl_choice == "loop_carried_deps": knl = lp.make_kernel( diff --git a/sched_check_utils.py b/sched_check_utils.py index f7b15827c..4e72f3c5d 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -322,6 +322,62 @@ def get_inames_in_sched_order(scheduled_knl): if isinstance(sched_item, EnterLoop)] +# TODO made a mess trying to make this as fast as possible, +# probably a better way +def _generate_orderings_starting_w_prefix( + allowed_after_dict, orderings, required_length=None, + start_prefix=(), return_first_found=False): + # comes after dict = {str: set(str)} + # start prefix = tuple(str) + # orderings = set + if start_prefix: + next_items = allowed_after_dict[start_prefix[-1]]-set(start_prefix) + else: + next_items = allowed_after_dict.keys() + + if required_length: + if len(start_prefix) == required_length: + orderings.add(start_prefix) + if return_first_found: + return + else: + orderings.add(start_prefix) + if return_first_found: + return + + # return if no more items left + if not next_items: + return + + for next_item in next_items: + new_prefix = start_prefix + (next_item,) + _generate_orderings_starting_w_prefix( + allowed_after_dict, + orderings, + required_length=required_length, + start_prefix=new_prefix, + return_first_found=return_first_found, + ) + if return_first_found and orderings: + return + return + + +def get_orderings_of_length_n( + allowed_after_dict, required_length, return_first_found=False): + # comes after dict = {str: set(str)} + # note: if the set for a dict key is empty, nothing allowed to come after + orderings = set() + _generate_orderings_starting_w_prefix( + allowed_after_dict, + orderings, + required_length=required_length, + start_prefix=(), + return_first_found=return_first_found, + ) + return orderings + + # currently unused: """ def flatten_2d_list(list2d): -- GitLab From 1bb00d4300365941bcdc8f28814c7afefb9ea156 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 23 Jul 2019 07:03:42 -0500 Subject: [PATCH 083/183] in get_concurrent_inames, check for ConcurrentTag rather than list of specific tags --- sched_check_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 4e72f3c5d..e116bc91c 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -258,7 +258,7 @@ def get_isl_space(param_names, in_names, out_names): def get_concurrent_inames(knl): - from loopy.kernel.data import LocalIndexTag, GroupIndexTag + from loopy.kernel.data import ConcurrentTag conc_inames = set() # TODO remove non-conc test + assertion @@ -268,7 +268,7 @@ def get_concurrent_inames(knl): for iname in all_inames: iname_tags = knl.iname_to_tags.get(iname, None) if iname_tags and any( - isinstance(tag, (LocalIndexTag, GroupIndexTag)) + isinstance(tag, ConcurrentTag) for tag in iname_tags): conc_inames.add(iname) else: -- GitLab From 9865c52224a572d2cb907015c3c3c5cd197c5162 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 23 Jul 2019 07:04:23 -0500 Subject: [PATCH 084/183] made simpler stroud_bernstein kernel for debugging --- __init__.py | 22 +++++++++++++-------- example_pairwise_schedule_validity.py | 28 ++++++++++++++++++++++++--- schedule.py | 2 +- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/__init__.py b/__init__.py index 4019453ee..a9da6f457 100644 --- a/__init__.py +++ b/__init__.py @@ -1,3 +1,5 @@ + + def check_schedule_validity( unscheduled_knl, verbose=False, @@ -33,8 +35,10 @@ def check_schedule_validity( for dep_set in statement_dep_sets: deps_and_domains.append([ dep_set, - preprocessed_knl.get_inames_domain(dep_set.statement_before.active_inames), - preprocessed_knl.get_inames_domain(dep_set.statement_after.active_inames) + preprocessed_knl.get_inames_domain( + dep_set.statement_before.active_inames), + preprocessed_knl.get_inames_domain( + dep_set.statement_after.active_inames) ]) if verbose: @@ -95,15 +99,15 @@ def check_schedule_validity( # have the unused inames in their 'in_' dim vars, so we'll # include them and set them equal to a dummy variable. + # combined_doms is only used for printing (map.gist(dom)) + # and for getting a consistent iname ordering to use in our maps + combined_doms = preprocessed_knl.get_inames_domain( + s_before.active_inames | s_after.active_inames) + # Get all inames now in order to maintain list with consistent ordering # This will help keep isl maps/sets compatible all_dom_inames_ordered = order_var_names_to_match_islset( - preprocessed_knl.all_inames(), - preprocessed_knl.get_inames_domain( - s_before.active_inames | - s_after.active_inames - ) - ) + preprocessed_knl.all_inames(), combined_doms) # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency @@ -219,6 +223,8 @@ def check_schedule_validity( print(aligned_constraint_map.gist(sio)) print("sio.gist(constraint_map)") print(sio.gist(aligned_constraint_map)) + print("loop priority known:") + print(preprocessed_knl.loop_priority) """ from schedule_checker.sched_check_utils import ( get_concurrent_inames, diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 4bdf9b3d2..0addf8209 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -5,11 +5,12 @@ from schedule_checker import check_schedule_validity # Choose kernel ---------------------------------------------------------- -knl_choice = "example" +#knl_choice = "example" #knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" -#knl_choice = "stroud_bernstein" # TODO invalid sched? +#knl_choice = "stroud_bernstein_orig" # TODO invalid sched? +knl_choice = "stroud_bernstein" # TODO invalid sched? #knl_choice = "add_barrier" #knl_choice = "nop" #knl_choice = "nest_multi_dom" @@ -95,7 +96,7 @@ elif knl_choice == "dependent_domain": lang_version=(2018, 2), ) knl = lp.realize_reduction(knl, force_scan=True) -elif knl_choice == "stroud_bernstein": +elif knl_choice == "stroud_bernstein_orig": knl = lp.make_kernel( "{[el, i2, alpha1,alpha2]: \ 0 <= el < nels and \ @@ -141,6 +142,27 @@ elif knl_choice == "stroud_bernstein": knl = lp.split_iname(knl, "el_outer", 2, outer_tag="g.0", inner_tag="ilp", slabs=(0, 1)) knl = lp.tag_inames(knl, dict(i2="l.1", alpha1="unr", alpha2="unr")) +elif knl_choice == "stroud_bernstein": + knl = lp.make_kernel( + "{[el]: 0 <= el < nels}", + """ + for el + tmp[el] = 3.14 {id=write_tmp} + aind = 1 {id=aind_incr,dep=write_tmp} + end + """, + name="stroud_bernstein", + assumptions="nels>=1 and nels mod 32 = 0", + ) + + knl = lp.split_iname(knl, "el", 16, + inner_tag="l.0", + ) + knl = lp.split_iname(knl, "el_outer", 2, + outer_tag="g.0", + inner_tag="ilp", + ) + #knl = lp.prioritize_loops(knl, "el_outer_outer,el_outer_inner,el_inner,a") if knl_choice == "add_barrier": np.random.seed(17) #a = np.random.randn(16) diff --git a/schedule.py b/schedule.py index f4e42e9fb..8d7626be0 100644 --- a/schedule.py +++ b/schedule.py @@ -79,7 +79,7 @@ class LexSchedule(object): next_insn_lex_pt.pop() next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 # if we didn't add any statements while in this loop, we might - # sometimes be able to skip this increment, but it's not hurting anything + # sometimes be able to skip increment, but it's not hurting anything elif isinstance(sched_item, (RunInstruction, Barrier)): from schedule_checker.sched_check_utils import ( _get_insn_id_from_sched_item, -- GitLab From 3208f05c54e363a81e7a9c3655480418b7bfc56a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 23 Jul 2019 07:10:12 -0500 Subject: [PATCH 085/183] added (commented out) unr tag to replace ilp tag in stroud kernel --- example_pairwise_schedule_validity.py | 1 + 1 file changed, 1 insertion(+) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 0addf8209..460f1ad14 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -161,6 +161,7 @@ elif knl_choice == "stroud_bernstein": knl = lp.split_iname(knl, "el_outer", 2, outer_tag="g.0", inner_tag="ilp", + #inner_tag="unr", ) #knl = lp.prioritize_loops(knl, "el_outer_outer,el_outer_inner,el_inner,a") if knl_choice == "add_barrier": -- GitLab From 55172e335b51cebfedb205d78f2bb1eef5db4362 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 27 Jul 2019 15:21:11 -0500 Subject: [PATCH 086/183] for checking for concurrent tags, using existing loopy function rather than recreating it --- sched_check_utils.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index e116bc91c..687b43e3c 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -259,23 +259,34 @@ def get_isl_space(param_names, in_names, out_names): def get_concurrent_inames(knl): from loopy.kernel.data import ConcurrentTag + conc_inames_old = set() conc_inames = set() # TODO remove non-conc test + assertion + non_conc_inames_old = set() non_conc_inames = set() all_inames = knl.all_inames() for iname in all_inames: + # TODO remove old version: iname_tags = knl.iname_to_tags.get(iname, None) if iname_tags and any( isinstance(tag, ConcurrentTag) for tag in iname_tags): + conc_inames_old.add(iname) + else: + non_conc_inames_old.add(iname) + + if knl.iname_tags_of_type(iname, ConcurrentTag): conc_inames.add(iname) else: non_conc_inames.add(iname) # TODO remove non-conc test + assertion - assert all_inames-conc_inames == non_conc_inames + assert all_inames-conc_inames_old == non_conc_inames_old + + assert conc_inames == conc_inames_old + assert non_conc_inames == non_conc_inames_old return conc_inames, all_inames-conc_inames -- GitLab From 9e325b33f1baa52ad4755540c2263e58bee9d7f3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 27 Jul 2019 15:21:43 -0500 Subject: [PATCH 087/183] ignoring loops with concurent tags when creating sched --- schedule.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/schedule.py b/schedule.py index 8d7626be0..b7c47bb31 100644 --- a/schedule.py +++ b/schedule.py @@ -47,6 +47,7 @@ class LexSchedule(object): iname == self.unused_param_name for iname in knl.all_inames()) from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) + from loopy.kernel.data import ConcurrentTag # go through knl.schedule and generate self.lex_schedule @@ -56,6 +57,10 @@ class LexSchedule(object): for sched_item in knl.schedule: if isinstance(sched_item, EnterLoop): iname = sched_item.iname + if knl.iname_tags_of_type(iname, ConcurrentTag): + # TODO in the future, this should be unnecessary because there + # won't be any inames with ConcurrentTags in the loopy sched + continue # if the schedule is empty, this is the first schedule item, so # don't increment lex dim val enumerating items in current block, # otherwise, this loop is next item in current code block, so @@ -71,6 +76,10 @@ class LexSchedule(object): next_insn_lex_pt.append(iname) next_insn_lex_pt.append(0) elif isinstance(sched_item, LeaveLoop): + if knl.iname_tags_of_type(sched_item.iname, ConcurrentTag): + # TODO in the future, this should be unnecessary because there + # won't be any inames with ConcurrentTags in the loopy sched + continue # upon leaving a loop, # pop lex dimension for enumerating code blocks within this loop, and # pop lex dimension for the loop variable, and -- GitLab From 8782ae7304d0e6383423df8aa0b806dacec7f30d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 29 Jul 2019 18:02:21 -0500 Subject: [PATCH 088/183] comnew TODOs from code review with Matt --- __init__.py | 33 +++++++++++++------------ dependency.py | 23 +++++++++--------- example_dependency_checking.py | 16 ++++++------ example_pairwise_schedule_validity.py | 35 +++++++++++---------------- sched_check_utils.py | 7 ++++++ schedule.py | 2 ++ 6 files changed, 61 insertions(+), 55 deletions(-) diff --git a/__init__.py b/__init__.py index a9da6f457..b56957c5d 100644 --- a/__init__.py +++ b/__init__.py @@ -1,5 +1,9 @@ +# TODO create a set of broken and valid kernels to test against +# (small kernels to test a specific case) +# TODO work on granularity of encapsulation, encapsulate some of this in +# separate functions def check_schedule_validity( unscheduled_knl, verbose=False, @@ -16,23 +20,22 @@ def check_schedule_validity( from schedule_checker.sched_check_utils import ( prettier_map_string, order_var_names_to_match_islset, - get_inames_in_sched_order, ) from loopy import preprocess_kernel - # TODO check to see if preprocessed already? + # TODO check to see if preprocessed already? kernel.kernel_status attr? preprocessed_knl = preprocess_kernel(unscheduled_knl) - # Create StatementDependencySet(s) from kernel dependencies ----------------- + # Create StatementPairDependencySet(s) from kernel dependencies ----------------- # Introduce SAME dep for set of shared, non-concurrent inames. # For each set of insns within a given iname subset, find sources and sinks, # then make PRIOR dep from all sinks to all sources at previous iterations. - statement_dep_sets = create_dependencies_from_legacy_knl(preprocessed_knl) + statement_pair_dep_sets = create_dependencies_from_legacy_knl(preprocessed_knl) # get separate domains for before.active_inames and after.active_inames deps_and_domains = [] - for dep_set in statement_dep_sets: + for dep_set in statement_pair_dep_sets: deps_and_domains.append([ dep_set, preprocessed_knl.get_inames_domain( @@ -56,8 +59,6 @@ def check_schedule_validity( else: scheduled_knl = preprocessed_knl - sched_iname_order = get_inames_in_sched_order(scheduled_knl) - if verbose: # Print kernel info ------------------------------------------------------ print("="*80) @@ -71,8 +72,8 @@ def check_schedule_validity( print("Loopy schedule:") for sched_item in scheduled_knl.schedule: print(sched_item) - print("scheduled iname order:") - print(sched_iname_order) + #print("scheduled iname order:") + #print(sched_iname_order) # For each dependency, create+test schedule containing pair of insns------ @@ -81,16 +82,16 @@ def check_schedule_validity( print("Looping through dep pairs...") sched_is_valid = True - for statement_dep_set, dom_before, dom_after in deps_and_domains: + for statement_pair_dep_set, dom_before, dom_after in deps_and_domains: if verbose: print("="*80) print("statement dep set:") - print(statement_dep_set) + print(statement_pair_dep_set) print("dom_before:", dom_before) print("dom_after:", dom_after) - s_before = statement_dep_set.statement_before - s_after = statement_dep_set.statement_after + s_before = statement_pair_dep_set.statement_before + s_after = statement_pair_dep_set.statement_after # The isl map representing the schedule maps # statement instances -> lex time @@ -103,6 +104,7 @@ def check_schedule_validity( # and for getting a consistent iname ordering to use in our maps combined_doms = preprocessed_knl.get_inames_domain( s_before.active_inames | s_after.active_inames) + # TODO not guaranteed to work # Get all inames now in order to maintain list with consistent ordering # This will help keep isl maps/sets compatible @@ -149,6 +151,7 @@ def check_schedule_validity( } else: assert False + # TODO maybe can just do len 2 case sched_map_symbolic = sched.create_symbolic_isl_map( sid_to_dom, all_dom_inames_ordered) @@ -190,7 +193,7 @@ def check_schedule_validity( # create a map representing constraints from the dependency, # maps statement instance to all statement instances that must occur later constraint_map = create_dependency_constraint( - statement_dep_set, + statement_pair_dep_set, all_dom_inames_ordered, dom_before, dom_after, @@ -216,7 +219,7 @@ def check_schedule_validity( print("================ constraint check failure =================") print("constraint map not subset of SIO") print("dependency:") - print(statement_dep_set) + print(statement_pair_dep_set) print("statement instance ordering:") print(prettier_map_string(sio)) print("constraint_map.gist(sio):") diff --git a/dependency.py b/dependency.py index 5a5e06189..a26d219c9 100644 --- a/dependency.py +++ b/dependency.py @@ -8,12 +8,12 @@ class DependencyType: #ALL = "all" -class StatementDependencySet(object): +class StatementPairDependencySet(object): def __init__( self, statement_before, statement_after, - deps, # {dep_type: iname} + deps, # {dep_type: iname_set} ): self.statement_before = statement_before self.statement_after = statement_after @@ -99,7 +99,7 @@ def create_dependency_constraint( # all_constraints_set will be the union of all these constraints dt = DependencyType for dep_type, inames in statement_dep_set.deps.items(): - if dep_type == dt.NONE: + if dep_type == dt.NONE: # TODO remove, not used continue # need to put inames in a list so that order of inames and inames' @@ -151,12 +151,14 @@ def create_dependency_constraint( from schedule_checker.sched_check_utils import ( get_orderings_of_length_n ) + # TODO explain how it only creates explicitly described orderings orders = get_orderings_of_length_n( nested_after, required_length=len(inames_list), #return_first_found=True, # TODO might be faster return_first_found=False, ) + # TODO make sure this handles a cycle (error) if orders: assert len(orders) == 1 # TODO can remove assert if return_first_found above @@ -306,7 +308,7 @@ def create_dependencies_from_legacy_knl(knl): s_before = Statement(insn_before.id, insn_before_inames) s_after = Statement(insn_after.id, insn_after_inames) statement_dep_sets.append( - StatementDependencySet(s_before, s_after, dep_dict)) + StatementPairDependencySet(s_before, s_after, dep_dict)) # loop-carried deps ------------------------------------------ @@ -328,11 +330,10 @@ def create_dependencies_from_legacy_knl(knl): # find sources and sinks sources, sinks = get_dependency_sources_and_sinks(knl, sched_item_ids) - # TODO this ignores deps connecting to items outside sched_item_ids, - # is that okay? #print("sources:", sources) #print("sinks:", sinks) + # TODO in future, consider putting in a single no-op source and sink # create prior deps for source_id in sources: for sink_id in sinks: @@ -348,7 +349,7 @@ def create_dependencies_from_legacy_knl(knl): s_before = Statement(sink_id, sink_insn_inames) s_after = Statement(source_id, source_insn_inames) statement_dep_sets.append( - StatementDependencySet(s_before, s_after, dep_dict)) + StatementPairDependencySet(s_before, s_after, dep_dict)) #print("-"*85) return statement_dep_sets @@ -356,17 +357,17 @@ def create_dependencies_from_legacy_knl(knl): def get_dependency_sources_and_sinks(knl, sched_item_ids): sources = set() - dep_heads = set() # all dependency heads (within sched_item_ids) + dependees = set() # all dependees (within sched_item_ids) for item_id in sched_item_ids: # find the deps within sched_item_ids deps = knl.id_to_insn[item_id].depends_on & sched_item_ids if deps: - # add deps to dep_heads - dep_heads.update(deps) + # add deps to dependees + dependees.update(deps) else: # has no deps (within sched_item_ids), this is a source sources.add(item_id) # sinks don't point to anyone - sinks = sched_item_ids - dep_heads + sinks = sched_item_ids - dependees return sources, sinks diff --git a/example_dependency_checking.py b/example_dependency_checking.py index b037a02fa..f7a4d51bd 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -1,6 +1,6 @@ import loopy as lp from schedule_checker.dependency import ( # noqa - StatementDependencySet, + StatementPairDependencySet, DependencyType as dt, create_dependency_constraint, ) @@ -126,21 +126,21 @@ s0 = Statement("0", {"i", "j"}) s1 = Statement("1", {"i", "j"}) insnid_to_int_sid = {"0": 0, "1": 1} -statement_dep_set = StatementDependencySet(s0, s1, {dt.SAME: ["i", "j"]}) -print(statement_dep_set) +statement_pair_dep_set = StatementPairDependencySet(s0, s1, {dt.SAME: ["i", "j"]}) +print(statement_pair_dep_set) combined_doms = knl.get_inames_domain( - statement_dep_set.statement_before.active_inames | # noqa - statement_dep_set.statement_after.active_inames + statement_pair_dep_set.statement_before.active_inames | # noqa + statement_pair_dep_set.statement_after.active_inames ) dom_before = knl.get_inames_domain( - statement_dep_set.statement_before.active_inames + statement_pair_dep_set.statement_before.active_inames ) dom_after = knl.get_inames_domain( - statement_dep_set.statement_after.active_inames + statement_pair_dep_set.statement_after.active_inames ) loop_priority = None # TODO constraint_map = create_dependency_constraint( - statement_dep_set, + statement_pair_dep_set, all_necessary_inames_ordered, dom_before, dom_after, diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 460f1ad14..00fb969f8 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -5,12 +5,12 @@ from schedule_checker import check_schedule_validity # Choose kernel ---------------------------------------------------------- -#knl_choice = "example" +knl_choice = "example" #knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" #knl_choice = "stroud_bernstein_orig" # TODO invalid sched? -knl_choice = "stroud_bernstein" # TODO invalid sched? +#knl_choice = "stroud_bernstein" # TODO invalid sched? #knl_choice = "add_barrier" #knl_choice = "nop" #knl_choice = "nest_multi_dom" @@ -108,10 +108,8 @@ elif knl_choice == "stroud_bernstein_orig": <> s = 1-xi <> r = xi/s <> aind = 0 {id=aind_init} - for alpha1 <> w = s**(deg-alpha1) {id=init_w} - for alpha2 tmp[el,alpha1,i2] = tmp[el,alpha1,i2] + w * coeffs[aind] \ {id=write_tmp,dep=init_w:aind_init} @@ -123,25 +121,17 @@ elif knl_choice == "stroud_bernstein_orig": end end """, - [ - # Must declare coeffs to have "no" shape, to keep loopy - # from trying to figure it out the shape automatically. - - lp.GlobalArg("coeffs", None, shape=None), - "..." - ], - name="stroud_bernstein", - assumptions="deg>=0 and nels>=1" - ) - - knl = lp.add_and_infer_dtypes( - knl, + [lp.GlobalArg("coeffs", None, shape=None), "..."], + name="stroud_bernstein", assumptions="deg>=0 and nels>=1") + knl = lp.add_and_infer_dtypes(knl, dict(coeffs=np.float32, qpts=np.int32)) knl = lp.fix_parameters(knl, nqp1d=7, deg=4) knl = lp.split_iname(knl, "el", 16, inner_tag="l.0") - knl = lp.split_iname(knl, "el_outer", 2, outer_tag="g.0", inner_tag="ilp", - slabs=(0, 1)) + knl = lp.split_iname(knl, "el_outer", 2, outer_tag="g.0", + inner_tag="ilp", slabs=(0, 1)) knl = lp.tag_inames(knl, dict(i2="l.1", alpha1="unr", alpha2="unr")) + # Must declare coeffs to have "no" shape, to keep loopy + # from trying to figure it out the shape automatically. elif knl_choice == "stroud_bernstein": knl = lp.make_kernel( "{[el]: 0 <= el < nels}", @@ -155,13 +145,16 @@ elif knl_choice == "stroud_bernstein": assumptions="nels>=1 and nels mod 32 = 0", ) - knl = lp.split_iname(knl, "el", 16, + knl = lp.split_iname( + knl, "el", 16, inner_tag="l.0", ) - knl = lp.split_iname(knl, "el_outer", 2, + knl = lp.split_iname( + knl, "el_outer", 2, outer_tag="g.0", inner_tag="ilp", #inner_tag="unr", + #inner_tag="g.1", ) #knl = lp.prioritize_loops(knl, "el_outer_outer,el_outer_inner,el_inner,a") if knl_choice == "add_barrier": diff --git a/sched_check_utils.py b/sched_check_utils.py index 687b43e3c..8aeca4cbf 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -98,6 +98,7 @@ def all_iname_domains_equal(knl): def order_var_names_to_match_islset(var_names, islset): + # TODO specifiy isl dim # returns subset of var_names found in islset in # order matching the islset variables name_order = islset.get_var_names(isl.dim_type.out) @@ -143,6 +144,8 @@ def create_symbolic_isl_map_from_tuples( statement_var_name, # TODO can we not pass this? ): + # TODO clarify this with comments + # given a list of pairs of ((input), (output)) tuples, create an isl map # and intersect each pair with corresponding domain_to_intersect #TODO allow None for domains @@ -186,6 +189,8 @@ def create_symbolic_isl_map_from_tuples( assert False unused_inames = set(space_in_names) \ - set(dom_var_names) - set([statement_var_name]) + # TODO find another way to determine which inames should be unused and + # make an assertion to double check this for unused_iname in unused_inames: constraint = constraint & islvars[unused_iname].eq_set( islvars[unused_param_name]) @@ -334,7 +339,9 @@ def get_inames_in_sched_order(scheduled_knl): # TODO made a mess trying to make this as fast as possible, +# TODO use yield to clean this up # probably a better way +# TODO find topological sort in loopy, then find longest path in dag def _generate_orderings_starting_w_prefix( allowed_after_dict, orderings, required_length=None, start_prefix=(), return_first_found=False): diff --git a/schedule.py b/schedule.py index b7c47bb31..eab68891d 100644 --- a/schedule.py +++ b/schedule.py @@ -31,6 +31,7 @@ class LexSchedule(object): ): # mapping of {statement instance: lex point} + # TODO make the key a data type that knows the var names self.lex_schedule = OrderedDict() # symbolic inames in sched that have been enumerated @@ -60,6 +61,7 @@ class LexSchedule(object): if knl.iname_tags_of_type(iname, ConcurrentTag): # TODO in the future, this should be unnecessary because there # won't be any inames with ConcurrentTags in the loopy sched + # TODO warn continue # if the schedule is empty, this is the first schedule item, so # don't increment lex dim val enumerating items in current block, -- GitLab From 087ea62538a815f33dfcf8a5368fa161c7d3801a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 30 Jul 2019 10:41:04 -0500 Subject: [PATCH 089/183] updated example ilp kernel; added isl set dim as parameter to order_var_names_to_match_islset() --- __init__.py | 3 ++- example_pairwise_schedule_validity.py | 36 +++++++++++++++++---------- example_schedule_creation_old.py | 3 ++- sched_check_utils.py | 4 +-- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/__init__.py b/__init__.py index b56957c5d..923c137ec 100644 --- a/__init__.py +++ b/__init__.py @@ -108,8 +108,9 @@ def check_schedule_validity( # Get all inames now in order to maintain list with consistent ordering # This will help keep isl maps/sets compatible + import islpy as isl all_dom_inames_ordered = order_var_names_to_match_islset( - preprocessed_knl.all_inames(), combined_doms) + preprocessed_knl.all_inames(), combined_doms, isl.dim_type.out) # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 00fb969f8..3d5917c0d 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -10,7 +10,7 @@ knl_choice = "example" #knl_choice = "scan" #knl_choice = "dependent_domain" #knl_choice = "stroud_bernstein_orig" # TODO invalid sched? -#knl_choice = "stroud_bernstein" # TODO invalid sched? +#knl_choice = "ilp_kernel" #knl_choice = "add_barrier" #knl_choice = "nop" #knl_choice = "nest_multi_dom" @@ -122,7 +122,7 @@ elif knl_choice == "stroud_bernstein_orig": end """, [lp.GlobalArg("coeffs", None, shape=None), "..."], - name="stroud_bernstein", assumptions="deg>=0 and nels>=1") + name="stroud_bernstein_orig", assumptions="deg>=0 and nels>=1") knl = lp.add_and_infer_dtypes(knl, dict(coeffs=np.float32, qpts=np.int32)) knl = lp.fix_parameters(knl, nqp1d=7, deg=4) @@ -132,31 +132,41 @@ elif knl_choice == "stroud_bernstein_orig": knl = lp.tag_inames(knl, dict(i2="l.1", alpha1="unr", alpha2="unr")) # Must declare coeffs to have "no" shape, to keep loopy # from trying to figure it out the shape automatically. -elif knl_choice == "stroud_bernstein": +elif knl_choice == "ilp_kernel": knl = lp.make_kernel( - "{[el]: 0 <= el < nels}", + "{[i,j,ilp_iname]: 0 <= i,j < n and 0 <= ilp_iname < 4}", """ - for el - tmp[el] = 3.14 {id=write_tmp} - aind = 1 {id=aind_incr,dep=write_tmp} + for i + for j + for ilp_iname + tmp[i,j,ilp_iname] = 3.14 + end + end end """, - name="stroud_bernstein", - assumptions="nels>=1 and nels mod 32 = 0", + name="ilp_kernel", + assumptions="n>=1 and n mod 4 = 0", ) - + # TODO why is conditional on ilp_name? + knl = lp.tag_inames(knl, {"j": "l.0","ilp_iname": "ilp"}) + """ + for i + tmp[i] = 3.14 {id=write_tmp} + aind = 1 {id=aind_incr,dep=write_tmp} + end knl = lp.split_iname( - knl, "el", 16, + knl, "i", 16, inner_tag="l.0", ) knl = lp.split_iname( - knl, "el_outer", 2, + knl, "i_outer", 2, outer_tag="g.0", inner_tag="ilp", #inner_tag="unr", #inner_tag="g.1", ) - #knl = lp.prioritize_loops(knl, "el_outer_outer,el_outer_inner,el_inner,a") + """ + #knl = lp.prioritize_loops(knl, "i_outer_outer,i_outer_inner,i_inner,a") if knl_choice == "add_barrier": np.random.seed(17) #a = np.random.randn(16) diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py index 3dfa8edac..0a9f9abaf 100644 --- a/example_schedule_creation_old.py +++ b/example_schedule_creation_old.py @@ -1,5 +1,6 @@ import loopy as lp import numpy as np +import islpy as isl from schedule_checker.dependency import ( create_dependencies_from_legacy_knl, create_dependency_constraint, @@ -103,7 +104,7 @@ if not all_iname_domains_equal(knl): "get_inames_domain(iname) is not same for all inames") domain_union = _union_inames_domains(knl) all_dom_inames_ordered = order_var_names_to_match_islset( - knl.all_inames(), domain_union) + knl.all_inames(), domain_union, isl.dim_type.out) # get all inames in consistent ordering: sched = LexSchedule(knl) diff --git a/sched_check_utils.py b/sched_check_utils.py index 8aeca4cbf..b48c55a8d 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -97,11 +97,11 @@ def all_iname_domains_equal(knl): return True -def order_var_names_to_match_islset(var_names, islset): +def order_var_names_to_match_islset(var_names, islset, set_dim=isl.dim_type.out): # TODO specifiy isl dim # returns subset of var_names found in islset in # order matching the islset variables - name_order = islset.get_var_names(isl.dim_type.out) + name_order = islset.get_var_names(set_dim) names_ordered_to_match_islset = [] for v in name_order: if v in var_names: -- GitLab From f59dfcf0f5086f66ba7417b8408dcce37cbf08be Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 30 Jul 2019 10:42:38 -0500 Subject: [PATCH 090/183] removed test assertions from get_concurrent_inames() --- sched_check_utils.py | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index b48c55a8d..1954b63b1 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -98,7 +98,6 @@ def all_iname_domains_equal(knl): def order_var_names_to_match_islset(var_names, islset, set_dim=isl.dim_type.out): - # TODO specifiy isl dim # returns subset of var_names found in islset in # order matching the islset variables name_order = islset.get_var_names(set_dim) @@ -264,35 +263,16 @@ def get_isl_space(param_names, in_names, out_names): def get_concurrent_inames(knl): from loopy.kernel.data import ConcurrentTag - conc_inames_old = set() conc_inames = set() - - # TODO remove non-conc test + assertion - non_conc_inames_old = set() non_conc_inames = set() all_inames = knl.all_inames() for iname in all_inames: - # TODO remove old version: - iname_tags = knl.iname_to_tags.get(iname, None) - if iname_tags and any( - isinstance(tag, ConcurrentTag) - for tag in iname_tags): - conc_inames_old.add(iname) - else: - non_conc_inames_old.add(iname) - if knl.iname_tags_of_type(iname, ConcurrentTag): conc_inames.add(iname) else: non_conc_inames.add(iname) - # TODO remove non-conc test + assertion - assert all_inames-conc_inames_old == non_conc_inames_old - - assert conc_inames == conc_inames_old - assert non_conc_inames == non_conc_inames_old - return conc_inames, all_inames-conc_inames -- GitLab From 8e0fb8184414ac00c85989629e220d57728b7387 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 31 Jul 2019 18:09:03 -0500 Subject: [PATCH 091/183] added valid sched tests --- test/test_valid_scheds.py | 276 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 test/test_valid_scheds.py diff --git a/test/test_valid_scheds.py b/test/test_valid_scheds.py new file mode 100644 index 000000000..24855c455 --- /dev/null +++ b/test/test_valid_scheds.py @@ -0,0 +1,276 @@ +from __future__ import division, print_function + +__copyright__ = "Copyright (C) 2018 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 sys +from pyopencl.tools import ( # noqa + pytest_generate_tests_for_pyopencl + as pytest_generate_tests) +import loopy as lp +import numpy as np +from schedule_checker import check_schedule_validity + + +def test_loop_prioritization(): + knl = lp.make_kernel( + [ + "{[i,ii]: 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") + assert check_schedule_validity(knl) + + +def test_matmul(): + bsize = 16 + knl = lp.make_kernel( + "{[i,k,j]: 0<=i {[i,j]: 0<=i {[i]: 0<=i xi = qpts[1, i2] + <> s = 1-xi + <> r = xi/s + <> aind = 0 {id=aind_init} + for alpha1 + <> w = s**(deg-alpha1) {id=init_w} + for alpha2 + tmp[el,alpha1,i2] = tmp[el,alpha1,i2] + w * coeffs[aind] \ + {id=write_tmp,dep=init_w:aind_init} + w = w * r * ( deg - alpha1 - alpha2 ) / (1 + alpha2) \ + {id=update_w,dep=init_w:write_tmp} + aind = aind + 1 \ + {id=aind_incr,dep=aind_init:write_tmp:update_w} + end + end + end + """, + [lp.GlobalArg("coeffs", None, shape=None), "..."], + name="stroud_bernstein_orig", assumptions="deg>=0 and nels>=1") + knl = lp.add_and_infer_dtypes(knl, + dict(coeffs=np.float32, qpts=np.int32)) + knl = lp.fix_parameters(knl, nqp1d=7, deg=4) + knl = lp.split_iname(knl, "el", 16, inner_tag="l.0") + knl = lp.split_iname(knl, "el_outer", 2, outer_tag="g.0", + inner_tag="ilp", slabs=(0, 1)) + knl = lp.tag_inames(knl, dict(i2="l.1", alpha1="unr", alpha2="unr")) + assert check_schedule_validity(knl) + + +def test_ilp(): + knl = lp.make_kernel( + "{[i,j,ilp_iname]: 0 <= i,j < n and 0 <= ilp_iname < 4}", + """ + for i + for j + for ilp_iname + tmp[i,j,ilp_iname] = 3.14 + end + end + end + """, + name="ilp_kernel", + assumptions="n>=1 and n mod 4 = 0", + ) + knl = lp.tag_inames(knl, {"j": "l.0", "ilp_iname": "ilp"}) + #knl = lp.prioritize_loops(knl, "i_outer_outer,i_outer_inner,i_inner,a") + assert check_schedule_validity(knl) + + +def test_barrier(): + np.random.seed(17) + cnst = np.random.randn(16) + knl = lp.make_kernel( + "{[i, ii]: 0<=i, ii c_end = 2 + for c + ... nop + end + end + """, + "...", + seq_dependencies=True) + knl = lp.fix_parameters(knl, dim=3) + assert check_schedule_validity(knl) + + +def test_multi_domain(): + knl = lp.make_kernel( + [ + "{[i]: 0<=iacc = 0 {id=insn0} + for j + for k + acc = acc + j + k {id=insn1,dep=insn0} + end + end + end + end + """, + name="nest_multi_dom", + assumptions="ni,nj,nk,nx >= 1", + lang_version=(2018, 2) + ) + knl = lp.prioritize_loops(knl, "x,xx,i") + knl = lp.prioritize_loops(knl, "i,j") + knl = lp.prioritize_loops(knl, "j,k") + assert check_schedule_validity(knl) + + +def test_loop_carried_deps(): + knl = lp.make_kernel( + "{[i]: 0<=iacc0 = 0 {id=insn0} + for i + acc0 = acc0 + i {id=insn1,dep=insn0} + <>acc2 = acc0 + i {id=insn2,dep=insn1} + <>acc3 = acc2 + i {id=insn3,dep=insn2} + <>acc4 = acc0 + i {id=insn4,dep=insn1} + end + """, + name="loop_carried_deps", + assumptions="n >= 1", + lang_version=(2018, 2) + ) + assert check_schedule_validity(knl) + + +if __name__ == "__main__": + if len(sys.argv) > 1: + exec(sys.argv[1]) + else: + from pytest import main + main([__file__]) -- GitLab From c95b3be4761e0257d525238c27792dde57c63f8b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 8 Aug 2019 06:55:39 -0500 Subject: [PATCH 092/183] removed unused functions+example related to explicit schedule creation --- example_schedule_creation_old.py | 209 ------------------------------- schedule.py | 80 ------------ 2 files changed, 289 deletions(-) delete mode 100644 example_schedule_creation_old.py diff --git a/example_schedule_creation_old.py b/example_schedule_creation_old.py deleted file mode 100644 index 0a9f9abaf..000000000 --- a/example_schedule_creation_old.py +++ /dev/null @@ -1,209 +0,0 @@ -import loopy as lp -import numpy as np -import islpy as isl -from schedule_checker.dependency import ( - create_dependencies_from_legacy_knl, - create_dependency_constraint, -) -from schedule_checker.schedule import LexSchedule -from schedule_checker.lexicographic_order_map import ( - get_statement_ordering_map, -) -from schedule_checker.sched_check_utils import ( - prettier_map_string, - _union_inames_domains, - all_iname_domains_equal, - order_var_names_to_match_islset, -) - -# TODO either remove this file or update as an example of full sched creation -# (rather than the usual pairwise schedule creation) - -knl_choice = "example" -#knl_choice = "matmul" -#knl_choice = "scan" - -if knl_choice == "example": - # make example kernel - knl = lp.make_kernel( - #"{[i,j]: 0<=i<2 and 1<=j<3}", - #"{[i,j]: pi_lo<=itemp = b[i,j] {id=insn_a}", - "a[i,j] = temp + 1 {id=insn_b,dep=insn_a}", - "c[i,j] = d[i,j] {id=insn_c}", - "out[t,tt] = in[t,tt] {id=insn_d}", - ], - name="example", - #assumptions="pi_lo,pi_up,pj_lo,pj_up >= 1", - #assumptions="pi_up,pj_up >= 1", - #assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", - assumptions="pi_up,pj_up,pt_up,pt_lo >= 1 and pt_lo < pt_up", - lang_version=(2018, 2) - ) - #knl = lp.add_and_infer_dtypes(knl, {"b": np.float32, "d": np.float32}) - knl = lp.add_and_infer_dtypes(knl, - {"b": np.float32, "d": np.float32, "in": np.float32}) - knl = lp.tag_inames(knl, {"i": "l.0"}) - knl = lp.preprocess_kernel(knl) - knl = lp.get_one_scheduled_kernel(knl) -elif knl_choice == "matmul": - bsize = 16 - knl = lp.make_kernel( - "{[i,k,j]: 0<=i {[i,j]: 0<=i lex time):") -print(sched_map_symbolic.space) - -# *Explicit* lexicographic mapping- map each tuple to all tuples occuring later -print("---------------------------------------------------------------------------") -#lex_map_explicit = sched.get_explicit_sched_map() - -lex_map_symbolic = sched.get_lex_order_map_for_symbolic_sched() - -print("lex map symbolic:") -print(prettier_map_string(lex_map_symbolic)) -print("space (lex time -> lex time):") -print(lex_map_symbolic.space) - -# Statement instance ordering -print("----------------------------------------------------------------------") -#SIO_explicit_valid = get_statement_ordering_map( -# example_sched_explicit, lex_map_explicit) -#print("statement instance ordering explicit (valid_sched):") -#print(prettier_map_string(SIO_explicit_valid)) -SIO_symbolic_valid = get_statement_ordering_map( - sched_map_symbolic, lex_map_symbolic) -print("statement instance ordering symbolic (valid_sched):") -print(prettier_map_string(SIO_symbolic_valid)) -print("space (statement instances -> statement instances):") -print(SIO_symbolic_valid.space) - -# For every shared (between depender and dependee) non-concurrent iname, -# Introduce a same dep -# (Perform voodoo guesswork to determine whether a ‘prior’ dep is needed) -# For every shared (between depender and dependee) concurrent iname, -# Introduce an all dep - -print("----------------------------------------------------------------------") -statement_dep_sets = create_dependencies_from_legacy_knl(knl) -print("Statement Dependencies:") -for dep_set in statement_dep_sets: - print(dep_set) - print("") -print("----------------------------------------------------------------------") -print("dict{lp insn id : sched sid int}:") -print(sched.lp_insnid_to_int_sid) -print("----------------------------------------------------------------------") -sched_is_valid = True -for statement_dep_set in statement_dep_sets: - - loop_priority = None # TODO - dom_before = knl.get_inames_domain( - statement_dep_set.statement_before.active_inames) - dom_after = knl.get_inames_domain( - statement_dep_set.statement_after.active_inames) - constraint_map = create_dependency_constraint( - statement_dep_set, - all_dom_inames_ordered, - dom_before, - dom_after, - loop_priority, - sched.lp_insnid_to_int_sid, - sched.unused_param_name, - sched.statement_var_name, - sched.statement_var_pose(), - ) - print("constraint map:") - print(prettier_map_string(constraint_map)) - #print("space (statment instances -> statement instances):") - #print(constraint_map.space) - - assert constraint_map.space == SIO_symbolic_valid.space - if not constraint_map.is_subset(SIO_symbolic_valid): - sched_is_valid = False - -print("is valid sched valid? constraint map subset of SIO?") -print(sched_is_valid) diff --git a/schedule.py b/schedule.py index eab68891d..0c551ca1a 100644 --- a/schedule.py +++ b/schedule.py @@ -241,83 +241,3 @@ class LexSchedule(object): sched_str += "%s -> %s;\n" % (domain_elem, lex_pt) sched_str += "}" return sched_str - - # Methods related to *explicit* schedule/map creation ------------------ - # TODO consider removing these - - def get_min_lex_dim_vals(self, var_bounds_dict): - - # this only works for integer lex pts (no symbolic vars): - #return [min(dim_pts) for dim_pts in zip(*self.lex_schedule.values())] - result = [] - for dim_pts in zip(*self.lex_schedule.values()): - if all(isinstance(pt, int) for pt in dim_pts): - result.append(min(dim_pts)) - else: - assert all(pt == dim_pts[0] for pt in dim_pts) - # append lower bound for this variable - result.append(var_bounds_dict[dim_pts[0]][0]) - return result - - def enumerate_iname(self, iname, bound): - new_sched = OrderedDict() - iname_found = False - for insn, lex_pt in self.lex_schedule.items(): - if iname in lex_pt: - for v in range(bound[0], bound[1]): - new_sched[tuple(list(insn)+[v])] = [ - lx if lx != iname else v for lx in lex_pt] - iname_found = True - else: - new_sched[insn] = lex_pt - self.lex_schedule = new_sched - if iname_found: - self.inames_enumerated.append(iname) - - def enumerate_inames(self, iname_bounds): - for iname, bound in iname_bounds.items(): - self.enumerate_iname(iname, bound) - - def get_isl_space_for_explicit_sched(self): - params_sched = ["ps"] + ["p"+iname for iname in self.inames_enumerated] - in_names_sched = [self.statement_var_name] + self.inames_enumerated - out_names_sched = self.get_lex_var_names() - from schedule_checker.sched_check_utils import get_isl_space - return get_isl_space(params_sched, in_names_sched, out_names_sched) - - def create_explicit_isl_map(self, sched_space): - from schedule_checker.sched_check_utils import ( - create_explicit_map_from_tuples - ) - return create_explicit_map_from_tuples(list(self.items()), sched_space) - - def enumerate_symbolic_inames_and_create_explicit_isl_map(self, iname_bounds): - self.enumerate_inames(iname_bounds) - sched_space = self.get_isl_space_for_explicit_sched() - return self.create_explicit_isl_map(sched_space) - - def get_explicit_sched_map(self): - - from schedule_checker.lexicographic_order_map import ( - make_lex_order_map_tuple_pairs, - ) - from schedule_checker.sched_check_utils import ( - create_explicit_map_from_tuples, - get_isl_space, - append_apostrophes - ) - - # TODO lower bound may not be zero - lex_dim_bounds = list(zip(self.get_min_lex_dim_vals(), - self.get_max_lex_dim_vals())) - sched_space = self.get_isl_space_for_explicit_sched() - - lex_in_names = sched_space.get_var_names(isl.dim_type.out) - lex_out_names = append_apostrophes(lex_in_names) - lex_params = [] - - explicit_lex_map_pairs = make_lex_order_map_tuple_pairs(lex_dim_bounds) - lex_space_explicit = get_isl_space(lex_params, lex_in_names, lex_out_names) - - return create_explicit_map_from_tuples(explicit_lex_map_pairs, - lex_space_explicit) -- GitLab From 4a2deff0a9260f4d0ea713f46678932665916d82 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 8 Aug 2019 07:02:37 -0500 Subject: [PATCH 093/183] warning when encountering+ignoring EnterLoop with ConcurrentTag in sched creation --- schedule.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/schedule.py b/schedule.py index 0c551ca1a..3c73036c5 100644 --- a/schedule.py +++ b/schedule.py @@ -59,9 +59,13 @@ class LexSchedule(object): if isinstance(sched_item, EnterLoop): iname = sched_item.iname if knl.iname_tags_of_type(iname, ConcurrentTag): - # TODO in the future, this should be unnecessary because there + # In the future, this should be unnecessary because there # won't be any inames with ConcurrentTags in the loopy sched - # TODO warn + from warnings import warn + warn( + "LexSchedule.__init__: Encountered EnterLoop for iname %s " + "with ConcurrentTag(s) in schedule for kernel %s. " + "Ignoring this loop." % (iname, kernel.name)) continue # if the schedule is empty, this is the first schedule item, so # don't increment lex dim val enumerating items in current block, @@ -79,7 +83,7 @@ class LexSchedule(object): next_insn_lex_pt.append(0) elif isinstance(sched_item, LeaveLoop): if knl.iname_tags_of_type(sched_item.iname, ConcurrentTag): - # TODO in the future, this should be unnecessary because there + # In the future, this should be unnecessary because there # won't be any inames with ConcurrentTags in the loopy sched continue # upon leaving a loop, -- GitLab From ac95ce64867fa79948efaffb954b6c4650b71f59 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 8 Aug 2019 07:11:12 -0500 Subject: [PATCH 094/183] removed a TODO --- sched_check_utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 1954b63b1..e4b9bcbf1 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -1,6 +1,9 @@ import islpy as isl +# TODO remove assertions once satisified they are unnecessary + + def prettier_map_string(isl_map): return str(isl_map ).replace("{ ", "{\n").replace(" }", "\n}").replace("; ", ";\n") @@ -140,7 +143,7 @@ def create_symbolic_isl_map_from_tuples( space, domains_to_intersect, # TODO pass these zipped w/tuples? unused_param_name, - statement_var_name, # TODO can we not pass this? + statement_var_name, ): # TODO clarify this with comments @@ -210,7 +213,6 @@ def create_symbolic_isl_map_from_tuples( dim_type.out, 0, dim_type.in_, len(space_in_names), len(space_out_names)) - # TODO remove: assert space_in_names == map_from_set.get_var_names( isl.dim_type.in_) -- GitLab From 1b13ca39b7144e92d9b098a2aa1b6c9d86183fc0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 8 Aug 2019 07:18:43 -0500 Subject: [PATCH 095/183] zipping tuple pairs with corresponding domains before passing them to create_symbolic_isl_map_from_tuples() --- sched_check_utils.py | 8 +++----- schedule.py | 3 +-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index e4b9bcbf1..ad7bbc351 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -139,9 +139,8 @@ def create_explicit_map_from_tuples(tuple_pairs, space): def create_symbolic_isl_map_from_tuples( - tuple_pairs, + tuple_pairs_with_domains, # list of ((tup_in, tup_out), dom_to_intersect) space, - domains_to_intersect, # TODO pass these zipped w/tuples? unused_param_name, statement_var_name, ): @@ -151,7 +150,6 @@ def create_symbolic_isl_map_from_tuples( # given a list of pairs of ((input), (output)) tuples, create an isl map # and intersect each pair with corresponding domain_to_intersect #TODO allow None for domains - assert len(tuple_pairs) == len(domains_to_intersect) dim_type = isl.dim_type @@ -166,7 +164,7 @@ def create_symbolic_isl_map_from_tuples( # initialize set with constraint that is always false #constraints_set = islvars[0].eq_set(islvars[0] + 1) all_maps = [] - for (tup_in, tup_out), dom in zip(tuple_pairs, domains_to_intersect): + for (tup_in, tup_out), dom in tuple_pairs_with_domains: # initialize constraint with true constraint = islvars[0].eq_set(islvars[0]) @@ -181,7 +179,7 @@ def create_symbolic_isl_map_from_tuples( constraint = constraint \ & islvars[dim_name].eq_set(islvars[val_in]) - # TODO we probably shouldn't rely on domains_to_intersect + # TODO we probably shouldn't rely on dom # here for determing where to set inames equal to dummy vars, # should instead determine before in LexSchedule and pass info in dom_var_names = dom.get_var_names(dim_type.out) diff --git a/schedule.py b/schedule.py index 3c73036c5..6e5cd3bbb 100644 --- a/schedule.py +++ b/schedule.py @@ -195,8 +195,7 @@ class LexSchedule(object): # create isl map return create_symbolic_isl_map_from_tuples( - list(self.items()), sched_space, - doms_to_intersect, + zip(list(self.items()), doms_to_intersect), sched_space, self.unused_param_name, self.statement_var_name) def get_lex_var_names(self): -- GitLab From fad96a45c2872061091ebbc74932b5ff0e6fee55 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 8 Aug 2019 07:31:19 -0500 Subject: [PATCH 096/183] renamed make_lex_order_map_tuple_pairs()->def lex_order_map_tuple_pairs_from_explicit_bounds() --- example_dependency_checking.py | 5 +++-- example_lex_map_creation.py | 4 ++-- lexicographic_order_map.py | 3 +-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example_dependency_checking.py b/example_dependency_checking.py index f7a4d51bd..dee185a92 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -5,7 +5,7 @@ from schedule_checker.dependency import ( # noqa create_dependency_constraint, ) from schedule_checker.lexicographic_order_map import ( - make_lex_order_map_tuple_pairs, + lex_order_map_tuple_pairs_from_explicit_bounds, get_statement_ordering_map, ) from schedule_checker.schedule import Statement @@ -84,7 +84,8 @@ lex_params = [] lex_in_names = out_names_sched lex_out_names = append_apostrophes(out_names_sched) -explicit_lex_map_pairs = make_lex_order_map_tuple_pairs(lex_dim_bounds) +explicit_lex_map_pairs = lex_order_map_tuple_pairs_from_explicit_bounds( + lex_dim_bounds) # for pair in explicit_lex_map_pairs: # print(pair[0], pair[1]) lex_space_explicit = get_isl_space(lex_params, lex_in_names, lex_out_names) diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py index 527d97869..79730d036 100644 --- a/example_lex_map_creation.py +++ b/example_lex_map_creation.py @@ -2,7 +2,7 @@ from schedule_checker.lexicographic_order_map import ( get_statement_ordering_map, create_symbolic_lex_order_map, ) -from schedule_checker.sched_check_utils import( +from schedule_checker.sched_check_utils import ( create_explicit_map_from_tuples, get_isl_space, ) @@ -22,7 +22,7 @@ print(lex_map_symbolic) """ dim_bounds = [(0,2), (0,2)] # max vals for each dim (e.g., 0 <= i0 < max0 ...) -explicit_lex_map_pairs = make_lex_order_map_tuple_pairs(dim_bounds) +explicit_lex_map_pairs = lex_order_map_tuple_pairs_from_explicit_bounds(dim_bounds) # for pair in explicit_lex_map_pairs: # print(pair[0], pair[1]) lex_map_explicit = create_explicit_map_from_tuples(explicit_lex_map_pairs, diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 994bbdad4..05d5111c0 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -1,7 +1,7 @@ import islpy as isl -def make_lex_order_map_tuple_pairs(dim_bounds): +def lex_order_map_tuple_pairs_from_explicit_bounds(dim_bounds): # Given list of integer dimension bound pairs # [(lower0, upper0), (lower1, upper1) ... ], @@ -16,7 +16,6 @@ def make_lex_order_map_tuple_pairs(dim_bounds): lex_tuples = list( itertools.product(*[range(l, u) for l, u in dim_bounds])) # goes up to u-1 because u is a non-inclusive upper bound - # TODO: is itertools.product ordering guaranteed? map_pairs = [] for i, l_before in enumerate(lex_tuples): -- GitLab From 3ab809fe85595538e95f39dd12f5100aad66c2f7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 8 Aug 2019 13:05:37 -0500 Subject: [PATCH 097/183] refactored LexSchedule to contain list of LexScheduleItems instead of dictionary mapping statement instance tuples to lex time tuples; LexScheduleItems contain statement instance + lex order info --- __init__.py | 1 - dependency.py | 19 +++++-- example_dependency_checking.py | 4 +- schedule.py | 96 ++++++++++++++++------------------ 4 files changed, 62 insertions(+), 58 deletions(-) diff --git a/__init__.py b/__init__.py index 923c137ec..8e17898de 100644 --- a/__init__.py +++ b/__init__.py @@ -202,7 +202,6 @@ def check_schedule_validity( sched.lp_insnid_to_int_sid, sched.unused_param_name, sched.statement_var_name, - sched.statement_var_pose(), ) aligned_constraint_map = constraint_map.align_params(sio.space) diff --git a/dependency.py b/dependency.py index a26d219c9..d035134d3 100644 --- a/dependency.py +++ b/dependency.py @@ -8,6 +8,20 @@ class DependencyType: #ALL = "all" +class Statement(object): + def __init__( + self, + insn_id, # loopy insn id + active_inames, + ): + self.insn_id = insn_id # string + self.active_inames = active_inames # [string, ] + + def __str__(self): + return "%s {%s}" % ( + self.insn_id, ",".join(self.active_inames)) + + class StatementPairDependencySet(object): def __init__( self, @@ -61,7 +75,7 @@ def create_dependency_constraint( insn_id_to_int, unused_param_name, statement_var_name, - statement_var_pose, + statement_var_pose=0, ): from schedule_checker.sched_check_utils import ( make_islvars_with_var_primes, @@ -73,8 +87,6 @@ def create_dependency_constraint( # This function uses the dependency given to create the following constraint: # Statement [s,i,j] comes before statement [s',i',j'] iff - # assumes statements are numbered sequentially - # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} islvars = make_islvars_with_var_primes( [statement_var_name]+all_dom_inames_ordered, @@ -283,7 +295,6 @@ def create_dependencies_from_legacy_knl(knl): get_all_nonconcurrent_insn_iname_subsets, get_sched_item_ids_within_inames, ) - from schedule_checker.schedule import Statement dt = DependencyType conc_inames, non_conc_inames = get_concurrent_inames(knl) #all_inames = list(knl.all_inames()) diff --git a/example_dependency_checking.py b/example_dependency_checking.py index dee185a92..0ebb8244a 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -3,12 +3,12 @@ from schedule_checker.dependency import ( # noqa StatementPairDependencySet, DependencyType as dt, create_dependency_constraint, + Statement, ) from schedule_checker.lexicographic_order_map import ( lex_order_map_tuple_pairs_from_explicit_bounds, get_statement_ordering_map, ) -from schedule_checker.schedule import Statement from schedule_checker.sched_check_utils import ( prettier_map_string, append_apostrophes, @@ -115,7 +115,6 @@ print("----------------------------------------------------------------------") # i dependency is none, j dependency is `prior` statement_var = 's' -statement_var_pose = 0 unused_param_name = 'unused' domains = {} @@ -149,7 +148,6 @@ constraint_map = create_dependency_constraint( insnid_to_int_sid, unused_param_name, statement_var, - statement_var_pose, ) print("constraint map space:") print(constraint_map.space) diff --git a/schedule.py b/schedule.py index 6e5cd3bbb..74ff5c94b 100644 --- a/schedule.py +++ b/schedule.py @@ -2,23 +2,29 @@ import islpy as isl from collections import OrderedDict -class Statement(object): +class LexScheduleItem(object): def __init__( self, - insn_id, - active_inames, + insn_id, # loopy insn id + int_id, # sid int (statement id within LexSchedule) + inames, + lex_pt, # point in lexicographic ordering ): self.insn_id = insn_id # string - self.active_inames = active_inames # [string, ] + self.int_id = int_id + self.inames = inames # [string, ] + self.lex_pt = lex_pt def __str__(self): - return "%s {%s}" % ( - self.insn_id, ",".join(self.active_inames)) + return "%s:%d {%s} -> %s" % ( + self.insn_id, self.statment_id, ",".join(self.inames), + self.lex_pt) class LexSchedule(object): - # contains a mapping of {statement instance: lex point} + # contains list of LexScheduleItems + # representing a mapping of {statement instance: lex point} unused_param_name = "unused" statement_var_name = "statement" @@ -30,13 +36,8 @@ class LexSchedule(object): include_only_insn_ids=None, ): - # mapping of {statement instance: lex point} - # TODO make the key a data type that knows the var names - self.lex_schedule = OrderedDict() - - # symbolic inames in sched that have been enumerated - # into explicit statement instances - self.inames_enumerated = [] + # list of LexScheduleItems + self.lex_schedule = [] # map from loopy insn_id strings to statement id ints self.lp_insnid_to_int_sid = {} @@ -118,7 +119,12 @@ class LexSchedule(object): insn_id_int = self.lp_insnid_to_int_sid[lp_insn_id] # add ((sid,), lex_pt) pair to lex schedule - self.lex_schedule[(insn_id_int,)] = next_insn_lex_pt[:] + self.lex_schedule.append( + LexScheduleItem( + insn_id=lp_insn_id, + int_id=insn_id_int, + inames=None, + lex_pt=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 @@ -130,21 +136,25 @@ class LexSchedule(object): self.pad_lex_pts_with_zeros() def max_lex_dims(self): - return max(len(lex_pt) for insn, lex_pt in self.items()) + return max(len(stmt.lex_pt) for stmt in self.lex_schedule) def pad_lex_pts_with_zeros(self): # pad lex points with zeros so that all points have same number of dims max_lex_dim = self.max_lex_dims() - new_sched = OrderedDict() - for insn, lex_pt in self.items(): - new_sched[insn] = lex_pt + [0]*(max_lex_dim-len(lex_pt)) + new_sched = [] + for stmt in self.lex_schedule: + new_sched.append( + LexScheduleItem(stmt.insn_id, stmt.int_id, stmt.inames, + stmt.lex_pt + [0]*(max_lex_dim-len(stmt.lex_pt)))) self.lex_schedule = new_sched def add_symbolic_inames_to_statement_instances(self, inames): # append inames to lex tuples (matching specified order) - new_sched = OrderedDict() - for insn, lex_pt in self.lex_schedule.items(): - new_sched[tuple(list(insn)+inames[:])] = lex_pt + new_sched = [] + for stmt in self.lex_schedule: + new_sched.append( + LexScheduleItem( + stmt.insn_id, stmt.int_id, tuple(inames[:]), stmt.lex_pt)) self.lex_schedule = new_sched def add_new_lp_insnid(self, lp_insnid): @@ -156,14 +166,6 @@ class LexSchedule(object): else: self.lp_insnid_to_int_sid[lp_insnid] = 0 - def get_last_schedule_item(self): - return next(reversed(self.lex_schedule)) - - def statement_var_pose(self): - # TODO what is the proper way to provide this information - # while keeping it immutable? - return 0 # 1st position in statement instance tuple - def create_symbolic_isl_map(self, sid_to_dom, dom_inames_ordered): # create isl map representing lex schedule @@ -178,7 +180,7 @@ class LexSchedule(object): # {('statement', used in >=1 statement domain>) -> # (lexicographic ordering dims)} params_sched = [self.unused_param_name] - in_names_sched = [self.statement_var_name] + dom_inames_ordered + in_names_sched = [self.statement_var_name] + dom_inames_ordered[:] out_names_sched = self.get_lex_var_names() from schedule_checker.sched_check_utils import get_isl_space sched_space = get_isl_space(params_sched, in_names_sched, out_names_sched) @@ -186,17 +188,20 @@ class LexSchedule(object): # Insert 'statement' dim into domain so that its space allows for # intersection with sched map later doms_to_intersect = [] - for tup_in, tup_out in self.items(): - sid = tup_in[self.statement_var_pose()] + for stmt in self.lex_schedule: doms_to_intersect.append( add_dims_to_isl_set( - sid_to_dom[sid], isl.dim_type.out, - [self.statement_var_name], self.statement_var_pose())) + sid_to_dom[stmt.int_id], isl.dim_type.out, + [self.statement_var_name], 0)) # create isl map return create_symbolic_isl_map_from_tuples( - zip(list(self.items()), doms_to_intersect), sched_space, - self.unused_param_name, self.statement_var_name) + zip( + [((stmt.int_id,) + tuple(stmt.inames), stmt.lex_pt) + for stmt in self.lex_schedule], + doms_to_intersect + ), + sched_space, self.unused_param_name, self.statement_var_name) def get_lex_var_names(self): return [self.lex_var_prefix+str(i) @@ -222,25 +227,16 @@ class LexSchedule(object): def __iter__(self): return iter(self.lex_schedule) - def keys(self): - return self.lex_schedule.keys() - - def items(self): - return self.lex_schedule.items() - - def values(self): - return self.lex_schedule.values() - def __len__(self): return len(self.lex_schedule) def __str__(self): sched_str = "{\n" - for state_tuple, lex_pt in self.lex_schedule.items(): + for stmt in self.lex_schedule: domain_elem = "[%s=%s,%s]" % ( self.statement_var_name, - state_tuple[self.statement_var_pose()], - ",".join(state_tuple[1:])) - sched_str += "%s -> %s;\n" % (domain_elem, lex_pt) + stmt.int_id, + ",".join(stmt.inames)) + sched_str += "%s -> %s;\n" % (domain_elem, stmt.lex_pt) sched_str += "}" return sched_str -- GitLab From 4067a9c995394e750750392e3bca3739e6e6a904 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 11 Aug 2019 09:48:27 -0500 Subject: [PATCH 098/183] fixed typo kernel->knl --- schedule.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/schedule.py b/schedule.py index 74ff5c94b..91d63a316 100644 --- a/schedule.py +++ b/schedule.py @@ -1,5 +1,4 @@ import islpy as isl -from collections import OrderedDict class LexScheduleItem(object): @@ -66,7 +65,7 @@ class LexSchedule(object): warn( "LexSchedule.__init__: Encountered EnterLoop for iname %s " "with ConcurrentTag(s) in schedule for kernel %s. " - "Ignoring this loop." % (iname, kernel.name)) + "Ignoring this loop." % (iname, knl.name)) continue # if the schedule is empty, this is the first schedule item, so # don't increment lex dim val enumerating items in current block, -- GitLab From 2cf845bd4dedc69cde847dc8a5e4257e96f7c962 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 11 Aug 2019 09:49:35 -0500 Subject: [PATCH 099/183] fixed typo statment_id->int_id --- schedule.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schedule.py b/schedule.py index 91d63a316..57feacc95 100644 --- a/schedule.py +++ b/schedule.py @@ -16,7 +16,7 @@ class LexScheduleItem(object): def __str__(self): return "%s:%d {%s} -> %s" % ( - self.insn_id, self.statment_id, ",".join(self.inames), + self.insn_id, self.int_id, ",".join(self.inames), self.lex_pt) -- GitLab From c5a27eec8c0ac724631e029baeeae406b6d8763d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 11 Aug 2019 10:10:36 -0500 Subject: [PATCH 100/183] instead of holding map of {loopy insn id : lex sched int id}, create it from sched items if necessary using new member function --- __init__.py | 13 +++++++------ schedule.py | 25 ++++++------------------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/__init__.py b/__init__.py index 8e17898de..efc23a62d 100644 --- a/__init__.py +++ b/__init__.py @@ -131,12 +131,13 @@ def check_schedule_validity( # statement tuple, then it is needed in all statement tuples. sched.add_symbolic_inames_to_statement_instances( all_dom_inames_ordered) + lp_insn_id_to_lex_sched_id = sched.loopy_insn_id_to_lex_sched_id() if verbose: print("-"*80) print("LexSchedule with inames added:") print(sched) print("dict{lp insn id : sched sid int}:") - print(sched.lp_insnid_to_int_sid) + print(lp_insn_id_to_lex_sched_id) # Get an isl map representing the LexSchedule; # this requires the iname domains @@ -144,11 +145,11 @@ def check_schedule_validity( if len(sched) == 1: assert dom_before == dom_after sid_to_dom = { - sched.lp_insnid_to_int_sid[s_before.insn_id]: dom_before} + lp_insn_id_to_lex_sched_id[s_before.insn_id]: dom_before} elif len(sched) == 2: sid_to_dom = { - sched.lp_insnid_to_int_sid[s_before.insn_id]: dom_before, - sched.lp_insnid_to_int_sid[s_after.insn_id]: dom_after, + lp_insn_id_to_lex_sched_id[s_before.insn_id]: dom_before, + lp_insn_id_to_lex_sched_id[s_after.insn_id]: dom_after, } else: assert False @@ -199,7 +200,7 @@ def check_schedule_validity( dom_before, dom_after, unscheduled_knl.loop_priority, - sched.lp_insnid_to_int_sid, + lp_insn_id_to_lex_sched_id, sched.unused_param_name, sched.statement_var_name, ) @@ -244,7 +245,7 @@ def check_schedule_validity( print("statement instance ordering:") print(prettier_map_string(sio)) print("{insn id -> sched sid int} dict:") - print(sched.lp_insnid_to_int_sid) + print(lp_insn_id_to_lex_sched_id) """ print("===========================================================") diff --git a/schedule.py b/schedule.py index 57feacc95..bf28ba566 100644 --- a/schedule.py +++ b/schedule.py @@ -12,7 +12,7 @@ class LexScheduleItem(object): self.insn_id = insn_id # string self.int_id = int_id self.inames = inames # [string, ] - self.lex_pt = lex_pt + self.lex_pt = lex_pt # [int, ] def __str__(self): return "%s:%d {%s} -> %s" % ( @@ -38,9 +38,6 @@ class LexSchedule(object): # list of LexScheduleItems self.lex_schedule = [] - # map from loopy insn_id strings to statement id ints - self.lp_insnid_to_int_sid = {} - # make sure we don't have an iname name conflict assert not any( iname == self.statement_var_name for iname in knl.all_inames()) @@ -112,16 +109,12 @@ class LexSchedule(object): # otherwise process all instructions if (include_only_insn_ids is None or lp_insn_id in include_only_insn_ids): - # create an int representing this instruction and - # update the map from loopy insn_ids to statement ids - self.add_new_lp_insnid(lp_insn_id) - insn_id_int = self.lp_insnid_to_int_sid[lp_insn_id] - # add ((sid,), lex_pt) pair to lex schedule + # add sched item self.lex_schedule.append( LexScheduleItem( insn_id=lp_insn_id, - int_id=insn_id_int, + int_id=len(self.lex_schedule), # int representing insn inames=None, lex_pt=next_insn_lex_pt[:])) @@ -134,6 +127,9 @@ class LexSchedule(object): # 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 dict([(lsi.insn_id, lsi.int_id) for lsi in self.lex_schedule]) + def max_lex_dims(self): return max(len(stmt.lex_pt) for stmt in self.lex_schedule) @@ -156,15 +152,6 @@ class LexSchedule(object): stmt.insn_id, stmt.int_id, tuple(inames[:]), stmt.lex_pt)) self.lex_schedule = new_sched - def add_new_lp_insnid(self, lp_insnid): - # create an int representing this instruction and - # update the map from loopy insn_ids to statement ids - if self.lp_insnid_to_int_sid: - self.lp_insnid_to_int_sid[lp_insnid] = max( - self.lp_insnid_to_int_sid.values()) + 1 - else: - self.lp_insnid_to_int_sid[lp_insnid] = 0 - def create_symbolic_isl_map(self, sid_to_dom, dom_inames_ordered): # create isl map representing lex schedule -- GitLab From 843f58e7f1979f0915ca96cdaa63b136282355fa Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 11 Aug 2019 10:54:10 -0500 Subject: [PATCH 101/183] combined unnecessary separate cases for len-1 and len-2 schedules --- __init__.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/__init__.py b/__init__.py index efc23a62d..35e11f964 100644 --- a/__init__.py +++ b/__init__.py @@ -142,18 +142,15 @@ def check_schedule_validity( # Get an isl map representing the LexSchedule; # this requires the iname domains + assert len(sched) in [1, 2] if len(sched) == 1: assert dom_before == dom_after - sid_to_dom = { - lp_insn_id_to_lex_sched_id[s_before.insn_id]: dom_before} - elif len(sched) == 2: - sid_to_dom = { - lp_insn_id_to_lex_sched_id[s_before.insn_id]: dom_before, - lp_insn_id_to_lex_sched_id[s_after.insn_id]: dom_after, - } - else: - assert False - # TODO maybe can just do len 2 case + + # get a mapping from lex schedule id to relevant inames domain + sid_to_dom = { + lp_insn_id_to_lex_sched_id[s_before.insn_id]: dom_before, + lp_insn_id_to_lex_sched_id[s_after.insn_id]: dom_after, + } sched_map_symbolic = sched.create_symbolic_isl_map( sid_to_dom, all_dom_inames_ordered) -- GitLab From 6b531c40af1bb7ee84d312457bc5909cc60d519b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 11 Aug 2019 11:06:29 -0500 Subject: [PATCH 102/183] commenting out printing of code because calling generate_code_v2 at end of loopy sched generation causes problem with save_reload tests --- __init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index 35e11f964..c12cb2214 100644 --- a/__init__.py +++ b/__init__.py @@ -65,7 +65,7 @@ def check_schedule_validity( print("Kernel:") print(scheduled_knl) from loopy import generate_code_v2 - print(generate_code_v2(scheduled_knl).device_code()) + #print(generate_code_v2(scheduled_knl).device_code()) print("="*80) print("Iname tags: %s" % (scheduled_knl.iname_to_tags)) print("="*80) -- GitLab From 927838fc4c553decf19a89933089e6e39d6f3a7f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 11 Aug 2019 11:14:37 -0500 Subject: [PATCH 103/183] only preprocess if not already preprocessed --- __init__.py | 16 ++++++++++------ schedule.py | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/__init__.py b/__init__.py index c12cb2214..0e15bd85a 100644 --- a/__init__.py +++ b/__init__.py @@ -1,11 +1,11 @@ -# TODO create a set of broken and valid kernels to test against +# TODO create a set of broken kernels to test against # (small kernels to test a specific case) # TODO work on granularity of encapsulation, encapsulate some of this in # separate functions def check_schedule_validity( - unscheduled_knl, + knl, verbose=False, _use_scheduled_kernel_to_obtain_loop_priority=False): @@ -22,9 +22,13 @@ def check_schedule_validity( order_var_names_to_match_islset, ) - from loopy import preprocess_kernel - # TODO check to see if preprocessed already? kernel.kernel_status attr? - preprocessed_knl = preprocess_kernel(unscheduled_knl) + # Preprocess if not already preprocessed + from loopy.kernel import KernelState + if knl.state < KernelState.PREPROCESSED: + from loopy import preprocess_kernel + preprocessed_knl = preprocess_kernel(knl) + else: + preprocessed_knl = knl # Create StatementPairDependencySet(s) from kernel dependencies ----------------- @@ -196,7 +200,7 @@ def check_schedule_validity( all_dom_inames_ordered, dom_before, dom_after, - unscheduled_knl.loop_priority, + knl.loop_priority, lp_insn_id_to_lex_sched_id, sched.unused_param_name, sched.statement_var_name, diff --git a/schedule.py b/schedule.py index bf28ba566..7c4b832ca 100644 --- a/schedule.py +++ b/schedule.py @@ -114,7 +114,7 @@ class LexSchedule(object): self.lex_schedule.append( LexScheduleItem( insn_id=lp_insn_id, - int_id=len(self.lex_schedule), # int representing insn + int_id=len(self.lex_schedule), # int representing insn inames=None, lex_pt=next_insn_lex_pt[:])) -- GitLab From 6b9638bd99267c57e50bb853afc69538a0eb2120 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 11 Aug 2019 11:24:25 -0500 Subject: [PATCH 104/183] removing unused dependency types --- dependency.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/dependency.py b/dependency.py index d035134d3..be1077731 100644 --- a/dependency.py +++ b/dependency.py @@ -2,10 +2,8 @@ import islpy as isl class DependencyType: - NONE = "none" SAME = "same" PRIOR = "prior" - #ALL = "all" class Statement(object): @@ -104,16 +102,13 @@ def create_dependency_constraint( inames_after_unused.append(iname + "'") # initialize constraints to False - # this will disappear as soon as we add a constraint that is not dt.NONE + # this will disappear as soon as we add a constraint all_constraints_set = islvars[0].eq_set(islvars[0] + 1) # for each (dep_type, inames) pair, create 'happens before' constraint, # all_constraints_set will be the union of all these constraints dt = DependencyType for dep_type, inames in statement_dep_set.deps.items(): - if dep_type == dt.NONE: # TODO remove, not used - continue - # need to put inames in a list so that order of inames and inames' # matches when calling create_elementwise_comparison_conj... if not isinstance(inames, list): @@ -309,12 +304,6 @@ def create_dependencies_from_legacy_knl(knl): shared_non_conc_inames = shared_inames & non_conc_inames dep_dict[dt.SAME] = shared_non_conc_inames - """ - for conc_iname in shared_conc_inames: - dep_dict[conc_iname] = dt.ALL - for non_shared_iname in non_shared_inames: - dep_dict[non_shared_iname] = dt.ALL - """ s_before = Statement(insn_before.id, insn_before_inames) s_after = Statement(insn_after.id, insn_after_inames) -- GitLab From 39074d08c593c2d1d3cd4a9dd31db88405164a42 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 11 Aug 2019 11:27:45 -0500 Subject: [PATCH 105/183] removed TODO that has been handled --- dependency.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/dependency.py b/dependency.py index be1077731..9945aeafd 100644 --- a/dependency.py +++ b/dependency.py @@ -122,10 +122,8 @@ def create_dependency_constraint( inames_list, inames_prime, islvars, op="eq") elif dep_type == dt.PRIOR: - # if nesting is known: - # TODO there might be situations where we know the priority even - # though loop_priorities is None priority_known = False + # if nesting info is provided: if loop_priorities: # assumes all loop_priority tuples are consistent -- GitLab From b88cc89bc5bb2982d0f2ce4ac8cc5ec8e3d8c058 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sun, 11 Aug 2019 11:38:03 -0500 Subject: [PATCH 106/183] removed commented-out code --- __init__.py | 2 +- dependency.py | 41 ------------------------ example_pairwise_schedule_validity.py | 45 ++++++++------------------- sched_check_utils.py | 4 --- test/test_valid_scheds.py | 26 +++++++--------- 5 files changed, 26 insertions(+), 92 deletions(-) diff --git a/__init__.py b/__init__.py index 0e15bd85a..c5bc0ca19 100644 --- a/__init__.py +++ b/__init__.py @@ -68,7 +68,7 @@ def check_schedule_validity( print("="*80) print("Kernel:") print(scheduled_knl) - from loopy import generate_code_v2 + #from loopy import generate_code_v2 #print(generate_code_v2(scheduled_knl).device_code()) print("="*80) print("Iname tags: %s" % (scheduled_knl.iname_to_tags)) diff --git a/dependency.py b/dependency.py index 9945aeafd..a3ae6067e 100644 --- a/dependency.py +++ b/dependency.py @@ -171,16 +171,6 @@ def create_dependency_constraint( priority_known = True priority_tuple = orders.pop() - # old way - """ - for priority_tuple in loop_priorities: - # might be able to deduce priority from multiple tuples - # even if all inames are not present in any single tuple - if set(inames_list).issubset(set(priority_tuple)): - priority_known = True - break - """ - # if only one loop, we know the priority if not priority_known and len(inames_list) == 1: priority_tuple = tuple(inames_list) @@ -232,17 +222,6 @@ def create_dependency_constraint( all_constraints_map = _convert_constraint_set_to_map( all_constraints_set, len(all_dom_inames_ordered) + 1) # +1 for statement var - """ - # for debugging - if dt.PRIOR in statement_dep_set.deps.keys(): - print("!"*90) - print(inames_list_nest_ordered) - from schedule_checker.sched_check_utils import ( - prettier_map_string, - ) - print(prettier_map_string(all_constraints_map)) - print("."*90) - """ # now apply domain sets to constraint variables # add statement variable to doms to enable intersection @@ -266,16 +245,6 @@ def create_dependency_constraint( # intersect doms map_with_loop_domain_constraints = all_constraints_map.intersect_domain( domain_to_intersect).intersect_range(range_to_intersect) - """ - # for debugging - if dt.PRIOR in statement_dep_set.deps.keys(): - print(inames_list_nest_ordered) - from schedule_checker.sched_check_utils import ( - prettier_map_string, - ) - print(prettier_map_string(map_with_loop_domain_constraints)) - print("!"*90) - """ return map_with_loop_domain_constraints @@ -290,7 +259,6 @@ def create_dependencies_from_legacy_knl(knl): ) dt = DependencyType conc_inames, non_conc_inames = get_concurrent_inames(knl) - #all_inames = list(knl.all_inames()) statement_dep_sets = [] for insn_after in knl.instructions: for insn_before_id in insn_after.depends_on: @@ -313,23 +281,15 @@ def create_dependencies_from_legacy_knl(knl): # Go through insns and get all unique insn.depends_on iname sets non_conc_iname_subsets = get_all_nonconcurrent_insn_iname_subsets( knl, exclude_empty=True, non_conc_inames=non_conc_inames) - #print("-"*85) - #print("NONCONCURRENT INAME SUBSETS") - #print(non_conc_iname_subsets) # For each set of insns within a given iname set, find sources and sinks. # Then make PRIOR dep from all sinks to all sources at previous iterations for iname_subset in non_conc_iname_subsets: # find items within this iname set sched_item_ids = get_sched_item_ids_within_inames(knl, iname_subset) - #print("") - #print("inames:", iname_subset) - #print("matching sched items:", sched_item_ids) # find sources and sinks sources, sinks = get_dependency_sources_and_sinks(knl, sched_item_ids) - #print("sources:", sources) - #print("sinks:", sinks) # TODO in future, consider putting in a single no-op source and sink # create prior deps @@ -348,7 +308,6 @@ def create_dependencies_from_legacy_knl(knl): s_after = Statement(source_id, source_insn_inames) statement_dep_sets.append( StatementPairDependencySet(s_before, s_after, dep_dict)) - #print("-"*85) return statement_dep_sets diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 3d5917c0d..0cca2d18a 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -24,22 +24,20 @@ if knl_choice == "example": "{[j,jj]: 0<=jtemp = 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 + """ + for i + for k + <>temp = b[i,k] {id=insn_a} end - for t - e[t] = f[t] {id=insn_d} + 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) @@ -148,24 +146,7 @@ elif knl_choice == "ilp_kernel": assumptions="n>=1 and n mod 4 = 0", ) # TODO why is conditional on ilp_name? - knl = lp.tag_inames(knl, {"j": "l.0","ilp_iname": "ilp"}) - """ - for i - tmp[i] = 3.14 {id=write_tmp} - aind = 1 {id=aind_incr,dep=write_tmp} - end - knl = lp.split_iname( - knl, "i", 16, - inner_tag="l.0", - ) - knl = lp.split_iname( - knl, "i_outer", 2, - outer_tag="g.0", - inner_tag="ilp", - #inner_tag="unr", - #inner_tag="g.1", - ) - """ + knl = lp.tag_inames(knl, {"j": "l.0", "ilp_iname": "ilp"}) #knl = lp.prioritize_loops(knl, "i_outer_outer,i_outer_inner,i_inner,a") if knl_choice == "add_barrier": np.random.seed(17) diff --git a/sched_check_utils.py b/sched_check_utils.py index ad7bbc351..c93b49782 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -378,10 +378,6 @@ def get_orderings_of_length_n( # currently unused: """ -def flatten_2d_list(list2d): - return [item for inner_list in list2d for item in inner_list] - - def add_missing_set_dims_to_map_indims(islmap, islset): new_map = islmap.copy() for i in range(islset.n_dim()): diff --git a/test/test_valid_scheds.py b/test/test_valid_scheds.py index 24855c455..6603c7a93 100644 --- a/test/test_valid_scheds.py +++ b/test/test_valid_scheds.py @@ -39,22 +39,20 @@ def test_loop_prioritization(): "{[j,jj]: 0<=jtemp = 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 + """ + for i + for k + <>temp = b[i,k] {id=insn_a} end - for t - e[t] = f[t] {id=insn_d} + 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) -- GitLab From d7b4b42d8c499e4f3b0b70976f452e10960a8cf4 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 12 Aug 2019 12:09:17 -0500 Subject: [PATCH 107/183] slightly better comments to explain what get_orderings_of_length_n() does --- dependency.py | 12 +++++++----- sched_check_utils.py | 13 ++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/dependency.py b/dependency.py index a3ae6067e..e5c71ef09 100644 --- a/dependency.py +++ b/dependency.py @@ -143,7 +143,9 @@ def create_dependency_constraint( if len(new_tuple) > 1: relevant_priorities.add(tuple(new_tuple)) - nested_after = {} + # create a mapping from each iname to inames that must be + # nested inside that iname + nested_inside = {} for iname in inames_list: comes_after_iname = set() for p_tuple in relevant_priorities: @@ -151,16 +153,16 @@ def create_dependency_constraint( comes_after_iname.update([ iname for iname in p_tuple[p_tuple.index(iname)+1:]]) - nested_after[iname] = comes_after_iname + nested_inside[iname] = comes_after_iname from schedule_checker.sched_check_utils import ( get_orderings_of_length_n ) - # TODO explain how it only creates explicitly described orderings + # get all orderings that are explicitly allowed by priorities orders = get_orderings_of_length_n( - nested_after, + nested_inside, required_length=len(inames_list), - #return_first_found=True, # TODO might be faster + #return_first_found=True, # faster; obviates assert test below return_first_found=False, ) # TODO make sure this handles a cycle (error) diff --git a/sched_check_utils.py b/sched_check_utils.py index c93b49782..f99c0b508 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -318,14 +318,12 @@ def get_inames_in_sched_order(scheduled_knl): if isinstance(sched_item, EnterLoop)] -# TODO made a mess trying to make this as fast as possible, # TODO use yield to clean this up -# probably a better way -# TODO find topological sort in loopy, then find longest path in dag +# TODO use topological sort from loopy, then find longest path in dag def _generate_orderings_starting_w_prefix( allowed_after_dict, orderings, required_length=None, start_prefix=(), return_first_found=False): - # comes after dict = {str: set(str)} + # alowed_after_dict = {str: set(str)} # start prefix = tuple(str) # orderings = set if start_prefix: @@ -363,8 +361,13 @@ def _generate_orderings_starting_w_prefix( def get_orderings_of_length_n( allowed_after_dict, required_length, return_first_found=False): - # comes after dict = {str: set(str)} + # get all orderings that are *explicitly* allowed by allowed_after_dict + # i.e., if we know a->b and c->b, we don't know enough to return a->c->b + # note: if the set for a dict key is empty, nothing allowed to come after + + # alowed_after_dict = {str: set(str)} + orderings = set() _generate_orderings_starting_w_prefix( allowed_after_dict, -- GitLab From 02ce094a52b88d13096a777ef6a006589862146a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 12 Aug 2019 12:38:13 -0500 Subject: [PATCH 108/183] check+error for inconsistent priorities; also relevant test case --- dependency.py | 18 ++++---- test/test_invalid_scheds.py | 91 +++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 test/test_invalid_scheds.py diff --git a/dependency.py b/dependency.py index e5c71ef09..f94423a02 100644 --- a/dependency.py +++ b/dependency.py @@ -156,20 +156,22 @@ def create_dependency_constraint( nested_inside[iname] = comes_after_iname from schedule_checker.sched_check_utils import ( - get_orderings_of_length_n - ) + get_orderings_of_length_n) # get all orderings that are explicitly allowed by priorities orders = get_orderings_of_length_n( nested_inside, required_length=len(inames_list), - #return_first_found=True, # faster; obviates assert test below - return_first_found=False, + #return_first_found=True, + return_first_found=False, # slower; allows priorities test below ) - # TODO make sure this handles a cycle (error) + if orders: - assert len(orders) == 1 - # TODO can remove assert if return_first_found above - # (or if we trust that all iname priorities are consistent) + # test for invalid priorities (includes cycles) + if len(orders) != 1: + raise ValueError( + "create_dependency_constriant encountered invalid " + "priorities %s" + % (loop_priorities)) priority_known = True priority_tuple = orders.pop() diff --git a/test/test_invalid_scheds.py b/test/test_invalid_scheds.py new file mode 100644 index 000000000..db85e10c4 --- /dev/null +++ b/test/test_invalid_scheds.py @@ -0,0 +1,91 @@ +from __future__ import division, print_function + +__copyright__ = "Copyright (C) 2018 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 sys +from pyopencl.tools import ( # noqa + pytest_generate_tests_for_pyopencl + as pytest_generate_tests) +import loopy as lp +import numpy as np +from schedule_checker import check_schedule_validity + + +def test_invalid_prioritiy_detection(): + ref_knl = lp.make_kernel( + [ + "{[h]: 0<=h acc = 0 + for h,i,j,k + acc = acc + h + i + j + k + end + """, + name="priorities", + assumptions="ni,nj,nk,nh >= 1", + lang_version=(2018, 2) + ) + + # no error: + knl0 = lp.prioritize_loops(ref_knl, "h,i") + knl0 = lp.prioritize_loops(ref_knl, "i,j") + knl0 = lp.prioritize_loops(knl0, "j,k") + assert check_schedule_validity(knl0) + + # no error: + knl1 = lp.prioritize_loops(ref_knl, "h,i,k") + knl1 = lp.prioritize_loops(knl1, "h,j,k") + assert check_schedule_validity(knl1) + + # error (cycle): + knl2 = lp.prioritize_loops(ref_knl, "h,i,j") + knl2 = lp.prioritize_loops(knl2, "j,k") + knl2 = lp.prioritize_loops(knl2, "k,i") + try: + check_schedule_validity(knl2) + # should raise error + assert False + except ValueError as e: + assert "invalid priorities" in str(e) + + # error (inconsistent priorities): + knl3 = lp.prioritize_loops(ref_knl, "h,i,j,k") + knl3 = lp.prioritize_loops(knl3, "h,j,i,k") + try: + check_schedule_validity(knl3) + # should raise error + assert False + except ValueError as e: + assert "invalid priorities" in str(e) + + +if __name__ == "__main__": + if len(sys.argv) > 1: + exec(sys.argv[1]) + else: + from pytest import main + main([__file__]) -- GitLab From 5d969b19d49364606426c30b4bd1aa96c52081a8 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 12 Aug 2019 12:43:30 -0500 Subject: [PATCH 109/183] removed two TODOs --- dependency.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependency.py b/dependency.py index f94423a02..aa6d63eee 100644 --- a/dependency.py +++ b/dependency.py @@ -295,8 +295,9 @@ def create_dependencies_from_legacy_knl(knl): # find sources and sinks sources, sinks = get_dependency_sources_and_sinks(knl, sched_item_ids) - # TODO in future, consider putting in a single no-op source and sink # create prior deps + + # in future, consider inserting single no-op source and sink for source_id in sources: for sink_id in sinks: dep_dict = {} @@ -305,7 +306,6 @@ def create_dependencies_from_legacy_knl(knl): shared_inames = sink_insn_inames & source_insn_inames shared_non_conc_inames = shared_inames & non_conc_inames - # TODO who tracks the iname nesting (needed for prior)? dep_dict[dt.PRIOR] = shared_non_conc_inames s_before = Statement(sink_id, sink_insn_inames) -- GitLab From f7afb2828cb3ce9f373508300b143b70285771f0 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 12 Aug 2019 13:17:22 -0500 Subject: [PATCH 110/183] WIP-removing combined domain creation (was used for getting consistent iname order that matches domains) --- __init__.py | 30 +++++++++++++++++++++--------- sched_check_utils.py | 15 +++++++++++++++ 2 files changed, 36 insertions(+), 9 deletions(-) diff --git a/__init__.py b/__init__.py index c5bc0ca19..32b86c590 100644 --- a/__init__.py +++ b/__init__.py @@ -19,7 +19,7 @@ def check_schedule_validity( ) from schedule_checker.sched_check_utils import ( prettier_map_string, - order_var_names_to_match_islset, + order_var_names_to_match_islsets, ) # Preprocess if not already preprocessed @@ -33,8 +33,10 @@ def check_schedule_validity( # Create StatementPairDependencySet(s) from kernel dependencies ----------------- # Introduce SAME dep for set of shared, non-concurrent inames. + # For each set of insns within a given iname subset, find sources and sinks, # then make PRIOR dep from all sinks to all sources at previous iterations. + statement_pair_dep_sets = create_dependencies_from_legacy_knl(preprocessed_knl) # get separate domains for before.active_inames and after.active_inames @@ -104,17 +106,27 @@ def check_schedule_validity( # have the unused inames in their 'in_' dim vars, so we'll # include them and set them equal to a dummy variable. - # combined_doms is only used for printing (map.gist(dom)) - # and for getting a consistent iname ordering to use in our maps - combined_doms = preprocessed_knl.get_inames_domain( - s_before.active_inames | s_after.active_inames) - # TODO not guaranteed to work - - # Get all inames now in order to maintain list with consistent ordering + # Get a consistent iname ordering to use in our maps # This will help keep isl maps/sets compatible + + # TODO We're starting with an order matching the domains + # so that we don't have to worry about reordering isl sets/maps later + # and if we don't, assertions will fail. Later, improve this so we can + # start with arbitrary ordering of inames, or find some other way to + # make this more intuitive+robust. import islpy as isl - all_dom_inames_ordered = order_var_names_to_match_islset( + all_dom_inames_ordered = order_var_names_to_match_islsets( + preprocessed_knl.all_inames(), [dom_after, dom_before], isl.dim_type.out) + + combined_doms = preprocessed_knl.get_inames_domain( + s_before.active_inames | s_after.active_inames) + from schedule_checker.sched_check_utils import ( + order_var_names_to_match_islset) + _all_dom_inames_ordered = order_var_names_to_match_islset( preprocessed_knl.all_inames(), combined_doms, isl.dim_type.out) + print(all_dom_inames_ordered) + print(_all_dom_inames_ordered) + #assert all_dom_inames_ordered == _all_dom_inames_ordered # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency diff --git a/sched_check_utils.py b/sched_check_utils.py index f99c0b508..482762864 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -111,6 +111,21 @@ def order_var_names_to_match_islset(var_names, islset, set_dim=isl.dim_type.out) return names_ordered_to_match_islset +def order_var_names_to_match_islsets(var_names, islset_list, set_dim=isl.dim_type.out): + # returns subset of var_names found in islset in + # order matching the islset variables + name_order = [] + for islset in islset_list: + name_order.extend( + [v for v in islset.get_var_names(set_dim) + if v not in name_order]) + names_ordered_to_match_islsets = [] + for v in name_order: + if v in var_names: + names_ordered_to_match_islsets.append(v) + return names_ordered_to_match_islsets + + def create_explicit_map_from_tuples(tuple_pairs, space): dim_type = isl.dim_type -- GitLab From 4a33f708f788636926eb088abf636b4ed5c7f2cd Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 12 Aug 2019 16:09:11 -0500 Subject: [PATCH 111/183] refactored (again) so that LexSchedule now contains a list of (LexScheduleStatement, [lex point]) tuples --- dependency.py | 12 ++++---- example_dependency_checking.py | 6 ++-- schedule.py | 51 +++++++++++++++------------------- 3 files changed, 32 insertions(+), 37 deletions(-) diff --git a/dependency.py b/dependency.py index aa6d63eee..fefdc11da 100644 --- a/dependency.py +++ b/dependency.py @@ -6,7 +6,7 @@ class DependencyType: PRIOR = "prior" -class Statement(object): +class LoopyStatement(object): def __init__( self, insn_id, # loopy insn id @@ -162,7 +162,7 @@ def create_dependency_constraint( nested_inside, required_length=len(inames_list), #return_first_found=True, - return_first_found=False, # slower; allows priorities test below + return_first_found=False, # slower; allows priorities test below ) if orders: @@ -275,8 +275,8 @@ def create_dependencies_from_legacy_knl(knl): dep_dict[dt.SAME] = shared_non_conc_inames - s_before = Statement(insn_before.id, insn_before_inames) - s_after = Statement(insn_after.id, insn_after_inames) + s_before = LoopyStatement(insn_before.id, insn_before_inames) + s_after = LoopyStatement(insn_after.id, insn_after_inames) statement_dep_sets.append( StatementPairDependencySet(s_before, s_after, dep_dict)) @@ -308,8 +308,8 @@ def create_dependencies_from_legacy_knl(knl): dep_dict[dt.PRIOR] = shared_non_conc_inames - s_before = Statement(sink_id, sink_insn_inames) - s_after = Statement(source_id, source_insn_inames) + s_before = LoopyStatement(sink_id, sink_insn_inames) + s_after = LoopyStatement(source_id, source_insn_inames) statement_dep_sets.append( StatementPairDependencySet(s_before, s_after, dep_dict)) diff --git a/example_dependency_checking.py b/example_dependency_checking.py index 0ebb8244a..f55540c44 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -3,7 +3,7 @@ from schedule_checker.dependency import ( # noqa StatementPairDependencySet, DependencyType as dt, create_dependency_constraint, - Statement, + LoopyStatement, ) from schedule_checker.lexicographic_order_map import ( lex_order_map_tuple_pairs_from_explicit_bounds, @@ -122,8 +122,8 @@ for iname in all_necessary_inames_ordered: domains[iname] = knl.get_inames_domain(iname) # make some dependencies manually for now: -s0 = Statement("0", {"i", "j"}) -s1 = Statement("1", {"i", "j"}) +s0 = LoopyStatement("0", {"i", "j"}) +s1 = LoopyStatement("1", {"i", "j"}) insnid_to_int_sid = {"0": 0, "1": 1} statement_pair_dep_set = StatementPairDependencySet(s0, s1, {dt.SAME: ["i", "j"]}) diff --git a/schedule.py b/schedule.py index 7c4b832ca..a5d90b010 100644 --- a/schedule.py +++ b/schedule.py @@ -1,30 +1,24 @@ import islpy as isl -class LexScheduleItem(object): +class LexScheduleStatement(object): def __init__( self, insn_id, # loopy insn id int_id, # sid int (statement id within LexSchedule) inames, - lex_pt, # point in lexicographic ordering ): self.insn_id = insn_id # string self.int_id = int_id self.inames = inames # [string, ] - self.lex_pt = lex_pt # [int, ] def __str__(self): - return "%s:%d {%s} -> %s" % ( - self.insn_id, self.int_id, ",".join(self.inames), - self.lex_pt) + return "%s:%d {%s}" % ( + self.insn_id, self.int_id, ",".join(self.inames)) class LexSchedule(object): - # contains list of LexScheduleItems - # representing a mapping of {statement instance: lex point} - unused_param_name = "unused" statement_var_name = "statement" lex_var_prefix = "l" @@ -35,7 +29,7 @@ class LexSchedule(object): include_only_insn_ids=None, ): - # list of LexScheduleItems + # list of LexScheduleStatements self.lex_schedule = [] # make sure we don't have an iname name conflict @@ -112,11 +106,13 @@ class LexSchedule(object): # add sched item self.lex_schedule.append( - LexScheduleItem( + ( + LexScheduleStatement( insn_id=lp_insn_id, int_id=len(self.lex_schedule), # int representing insn - inames=None, - lex_pt=next_insn_lex_pt[:])) + inames=None), + 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 @@ -128,28 +124,27 @@ class LexSchedule(object): self.pad_lex_pts_with_zeros() def loopy_insn_id_to_lex_sched_id(self): - return dict([(lsi.insn_id, lsi.int_id) for lsi in self.lex_schedule]) + return dict([(stmt.insn_id, stmt.int_id) for stmt, _ in self.lex_schedule]) def max_lex_dims(self): - return max(len(stmt.lex_pt) for stmt in self.lex_schedule) + return max(len(lex_pt) for _, lex_pt in self.lex_schedule) def pad_lex_pts_with_zeros(self): # pad lex points with zeros so that all points have same number of dims max_lex_dim = self.max_lex_dims() new_sched = [] - for stmt in self.lex_schedule: - new_sched.append( - LexScheduleItem(stmt.insn_id, stmt.int_id, stmt.inames, - stmt.lex_pt + [0]*(max_lex_dim-len(stmt.lex_pt)))) + for stmt, lex_pt in self.lex_schedule: + new_sched.append((stmt, lex_pt + [0]*(max_lex_dim-len(lex_pt)))) self.lex_schedule = new_sched def add_symbolic_inames_to_statement_instances(self, inames): # append inames to lex tuples (matching specified order) new_sched = [] - for stmt in self.lex_schedule: - new_sched.append( - LexScheduleItem( - stmt.insn_id, stmt.int_id, tuple(inames[:]), stmt.lex_pt)) + for stmt, lex_pt in self.lex_schedule: + new_sched.append(( + LexScheduleStatement(stmt.insn_id, stmt.int_id, tuple(inames[:])), + lex_pt + )) self.lex_schedule = new_sched def create_symbolic_isl_map(self, sid_to_dom, dom_inames_ordered): @@ -174,7 +169,7 @@ class LexSchedule(object): # Insert 'statement' dim into domain so that its space allows for # intersection with sched map later doms_to_intersect = [] - for stmt in self.lex_schedule: + for stmt, _ in self.lex_schedule: doms_to_intersect.append( add_dims_to_isl_set( sid_to_dom[stmt.int_id], isl.dim_type.out, @@ -183,8 +178,8 @@ class LexSchedule(object): # create isl map return create_symbolic_isl_map_from_tuples( zip( - [((stmt.int_id,) + tuple(stmt.inames), stmt.lex_pt) - for stmt in self.lex_schedule], + [((stmt.int_id,) + tuple(stmt.inames), lex_pt) + for stmt, lex_pt in self.lex_schedule], doms_to_intersect ), sched_space, self.unused_param_name, self.statement_var_name) @@ -218,11 +213,11 @@ class LexSchedule(object): def __str__(self): sched_str = "{\n" - for stmt in self.lex_schedule: + for stmt, lex_pt in self.lex_schedule: domain_elem = "[%s=%s,%s]" % ( self.statement_var_name, stmt.int_id, ",".join(stmt.inames)) - sched_str += "%s -> %s;\n" % (domain_elem, stmt.lex_pt) + sched_str += "%s -> %s;\n" % (domain_elem, lex_pt) sched_str += "}" return sched_str -- GitLab From a80c31abf4d571616099f059e753f95070bc116a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 12 Aug 2019 16:35:05 -0500 Subject: [PATCH 112/183] added initial docstrings for LexSchedule and LexScheduleStatement --- schedule.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/schedule.py b/schedule.py index a5d90b010..b29cdd6e8 100644 --- a/schedule.py +++ b/schedule.py @@ -2,6 +2,26 @@ import islpy as isl class LexScheduleStatement(object): + """A representation of a Loopy statement instance or set of + instances used in a :class:`LexSchedule`. + + .. attribute:: insn_id + + A :class:`str` specifying the instruction id. + + .. attribute:: int_id + + A :class:`int` uniquely identifying the instruction. + + .. attribute:: inames + + A list of :class:`str` representing the inames applying to + this instruction, and possibly additional inames that do not + apply to this instruction but must be included because they + are used in another instruction in the program ordering. + + """ + def __init__( self, insn_id, # loopy insn id @@ -18,6 +38,41 @@ class LexScheduleStatement(object): class LexSchedule(object): + """A program ordering represented as a mapping from statement + instances to points in a lexicographic ordering. + + .. attribute:: lex_schedule + + A :class:`list` of (:class:`LexScheduleStatement`, :class:`list`) + tuples, representing the program ordering as a map from + statement instances to points in a lexicographic ordering. Points + in lexicographic ordering represented as list of :class:`int`. + + .. attribute:: unused_param_name + + A :class:`str` that specifies the name of a dummy isl parameter + assigned to variables in domain elements of the isl map that + represent inames unused in a particular statement instance. + The domain space of the generated isl map will have a dimension + for every iname used in any statement instance found in the + program ordering. An element in the domain of this map may + represent a statement instance that does not lie within + iname x, but will still need to assign a value to the x domain + variable. In this case, the parameter unused_param_name is + is assigned to x. + + .. 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". + + """ unused_param_name = "unused" statement_var_name = "statement" @@ -138,6 +193,8 @@ class LexSchedule(object): self.lex_schedule = new_sched def add_symbolic_inames_to_statement_instances(self, inames): + # TODO if inames is same for all stmt instances, just keep single copy somewhere + # append inames to lex tuples (matching specified order) new_sched = [] for stmt, lex_pt in self.lex_schedule: -- GitLab From a16d516a04a67024816b0c93c08e8838986c2e67 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 12 Aug 2019 16:37:25 -0500 Subject: [PATCH 113/183] added todo --- schedule.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/schedule.py b/schedule.py index b29cdd6e8..0b24d5f85 100644 --- a/schedule.py +++ b/schedule.py @@ -1,6 +1,10 @@ import islpy as isl +# TODO if inames must be same for all stmt instances in lex sched, +# just keep single copy somewhere. After fixing this, combine +# LexScheduleStatement and LoopyStatement into single class + class LexScheduleStatement(object): """A representation of a Loopy statement instance or set of instances used in a :class:`LexSchedule`. -- GitLab From 32f4cf80e5c2433fc12caaa47fbccff3dd71bb5a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 20 Aug 2019 02:28:10 -0500 Subject: [PATCH 114/183] keeping single copy of map_domain_inames in schedule rather than storing redundant copies in all statement instances; combined LoopyStatement with LexScheduleStatement --- __init__.py | 10 +++--- dependency.py | 31 +++++++--------- example_dependency_checking.py | 14 ++++---- schedule.py | 66 +++++++++++++++++----------------- 4 files changed, 59 insertions(+), 62 deletions(-) diff --git a/__init__.py b/__init__.py index c5bc0ca19..1a103a8a7 100644 --- a/__init__.py +++ b/__init__.py @@ -37,15 +37,15 @@ def check_schedule_validity( # then make PRIOR dep from all sinks to all sources at previous iterations. statement_pair_dep_sets = create_dependencies_from_legacy_knl(preprocessed_knl) - # get separate domains for before.active_inames and after.active_inames + # get separate domains for before.within_inames and after.within_inames deps_and_domains = [] for dep_set in statement_pair_dep_sets: deps_and_domains.append([ dep_set, preprocessed_knl.get_inames_domain( - dep_set.statement_before.active_inames), + dep_set.statement_before.within_inames), preprocessed_knl.get_inames_domain( - dep_set.statement_after.active_inames) + dep_set.statement_after.within_inames) ]) if verbose: @@ -107,7 +107,7 @@ def check_schedule_validity( # combined_doms is only used for printing (map.gist(dom)) # and for getting a consistent iname ordering to use in our maps combined_doms = preprocessed_knl.get_inames_domain( - s_before.active_inames | s_after.active_inames) + s_before.within_inames | s_after.within_inames) # TODO not guaranteed to work # Get all inames now in order to maintain list with consistent ordering @@ -133,7 +133,7 @@ def check_schedule_validity( # but all in-tuples need to match because they will become # the in-dims for an isl map, so if an iname is needed in one # statement tuple, then it is needed in all statement tuples. - sched.add_symbolic_inames_to_statement_instances( + sched.set_symbolic_inames_for_statement_instance_space( all_dom_inames_ordered) lp_insn_id_to_lex_sched_id = sched.loopy_insn_id_to_lex_sched_id() if verbose: diff --git a/dependency.py b/dependency.py index fefdc11da..e71e77b31 100644 --- a/dependency.py +++ b/dependency.py @@ -6,20 +6,6 @@ class DependencyType: PRIOR = "prior" -class LoopyStatement(object): - def __init__( - self, - insn_id, # loopy insn id - active_inames, - ): - self.insn_id = insn_id # string - self.active_inames = active_inames # [string, ] - - def __str__(self): - return "%s {%s}" % ( - self.insn_id, ",".join(self.active_inames)) - - class StatementPairDependencySet(object): def __init__( self, @@ -261,6 +247,7 @@ def create_dependencies_from_legacy_knl(knl): get_all_nonconcurrent_insn_iname_subsets, get_sched_item_ids_within_inames, ) + from schedule_checker.schedule import LexScheduleStatement dt = DependencyType conc_inames, non_conc_inames = get_concurrent_inames(knl) statement_dep_sets = [] @@ -275,8 +262,12 @@ def create_dependencies_from_legacy_knl(knl): dep_dict[dt.SAME] = shared_non_conc_inames - s_before = LoopyStatement(insn_before.id, insn_before_inames) - s_after = LoopyStatement(insn_after.id, insn_after_inames) + s_before = LexScheduleStatement( + insn_id=insn_before.id, + within_inames=insn_before_inames) + s_after = LexScheduleStatement( + insn_id=insn_after.id, + within_inames=insn_after_inames) statement_dep_sets.append( StatementPairDependencySet(s_before, s_after, dep_dict)) @@ -308,8 +299,12 @@ def create_dependencies_from_legacy_knl(knl): dep_dict[dt.PRIOR] = shared_non_conc_inames - s_before = LoopyStatement(sink_id, sink_insn_inames) - s_after = LoopyStatement(source_id, source_insn_inames) + s_before = LexScheduleStatement( + insn_id=sink_id, + within_inames=sink_insn_inames) + s_after = LexScheduleStatement( + insn_id=source_id, + within_inames=source_insn_inames) statement_dep_sets.append( StatementPairDependencySet(s_before, s_after, dep_dict)) diff --git a/example_dependency_checking.py b/example_dependency_checking.py index f55540c44..b81c52de7 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -3,7 +3,6 @@ from schedule_checker.dependency import ( # noqa StatementPairDependencySet, DependencyType as dt, create_dependency_constraint, - LoopyStatement, ) from schedule_checker.lexicographic_order_map import ( lex_order_map_tuple_pairs_from_explicit_bounds, @@ -15,6 +14,7 @@ from schedule_checker.sched_check_utils import ( create_explicit_map_from_tuples, get_isl_space, ) +from schedule_checker.schedule import LexScheduleStatement # make example kernel @@ -122,21 +122,21 @@ for iname in all_necessary_inames_ordered: domains[iname] = knl.get_inames_domain(iname) # make some dependencies manually for now: -s0 = LoopyStatement("0", {"i", "j"}) -s1 = LoopyStatement("1", {"i", "j"}) +s0 = LexScheduleStatement(insn_id="0", within_inames={"i", "j"}) +s1 = LexScheduleStatement(insn_id="1", within_inames={"i", "j"}) insnid_to_int_sid = {"0": 0, "1": 1} statement_pair_dep_set = StatementPairDependencySet(s0, s1, {dt.SAME: ["i", "j"]}) print(statement_pair_dep_set) combined_doms = knl.get_inames_domain( - statement_pair_dep_set.statement_before.active_inames | # noqa - statement_pair_dep_set.statement_after.active_inames + statement_pair_dep_set.statement_before.within_inames | # noqa + statement_pair_dep_set.statement_after.within_inames ) dom_before = knl.get_inames_domain( - statement_pair_dep_set.statement_before.active_inames + statement_pair_dep_set.statement_before.within_inames ) dom_after = knl.get_inames_domain( - statement_pair_dep_set.statement_after.active_inames + statement_pair_dep_set.statement_after.within_inames ) loop_priority = None # TODO constraint_map = create_dependency_constraint( diff --git a/schedule.py b/schedule.py index 0b24d5f85..0d068f98d 100644 --- a/schedule.py +++ b/schedule.py @@ -1,13 +1,8 @@ import islpy as isl -# TODO if inames must be same for all stmt instances in lex sched, -# just keep single copy somewhere. After fixing this, combine -# LexScheduleStatement and LoopyStatement into single class - class LexScheduleStatement(object): - """A representation of a Loopy statement instance or set of - instances used in a :class:`LexSchedule`. + """A representation of a Loopy statement instance. .. attribute:: insn_id @@ -17,28 +12,34 @@ class LexScheduleStatement(object): A :class:`int` uniquely identifying the instruction. - .. attribute:: inames + .. attribute:: within_inames - A list of :class:`str` representing the inames applying to - this instruction, and possibly additional inames that do not - apply to this instruction but must be included because they - are used in another instruction in the program ordering. + 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, # sid int (statement id within LexSchedule) - inames, + 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.inames = inames # [string, ] + self.within_inames = within_inames def __str__(self): - return "%s:%d {%s}" % ( - self.insn_id, self.int_id, ",".join(self.inames)) + if self.int_id: + 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 LexSchedule(object): @@ -52,6 +53,13 @@ class LexSchedule(object): statement instances to points in a lexicographic ordering. Points in lexicographic ordering represented as list of :class:`int`. + .. attribute:: map_domain_inames + + A list of :class:`str` representing the union of inames used + in all statement instances. `statement_var_name` and + `map_domain_inames` are the names of the dims of the space of the + ISL map domain. + .. attribute:: unused_param_name A :class:`str` that specifies the name of a dummy isl parameter @@ -91,6 +99,9 @@ class LexSchedule(object): # list of LexScheduleStatements self.lex_schedule = [] + # inames for statement instance space + self.map_domain_inames = [] + # make sure we don't have an iname name conflict assert not any( iname == self.statement_var_name for iname in knl.all_inames()) @@ -164,12 +175,11 @@ class LexSchedule(object): or lp_insn_id in include_only_insn_ids): # add sched item - self.lex_schedule.append( - ( + self.lex_schedule.append(( LexScheduleStatement( insn_id=lp_insn_id, int_id=len(self.lex_schedule), # int representing insn - inames=None), + ), next_insn_lex_pt[:] )) @@ -196,17 +206,9 @@ class LexSchedule(object): new_sched.append((stmt, lex_pt + [0]*(max_lex_dim-len(lex_pt)))) self.lex_schedule = new_sched - def add_symbolic_inames_to_statement_instances(self, inames): - # TODO if inames is same for all stmt instances, just keep single copy somewhere - - # append inames to lex tuples (matching specified order) - new_sched = [] - for stmt, lex_pt in self.lex_schedule: - new_sched.append(( - LexScheduleStatement(stmt.insn_id, stmt.int_id, tuple(inames[:])), - lex_pt - )) - self.lex_schedule = new_sched + def set_symbolic_inames_for_statement_instance_space(self, inames): + # set map_domain_inames + self.map_domain_inames = inames[:] def create_symbolic_isl_map(self, sid_to_dom, dom_inames_ordered): # create isl map representing lex schedule @@ -239,7 +241,7 @@ class LexSchedule(object): # create isl map return create_symbolic_isl_map_from_tuples( zip( - [((stmt.int_id,) + tuple(stmt.inames), lex_pt) + [((stmt.int_id,) + tuple(self.map_domain_inames), lex_pt) for stmt, lex_pt in self.lex_schedule], doms_to_intersect ), @@ -278,7 +280,7 @@ class LexSchedule(object): domain_elem = "[%s=%s,%s]" % ( self.statement_var_name, stmt.int_id, - ",".join(stmt.inames)) + ",".join(self.map_domain_inames)) sched_str += "%s -> %s;\n" % (domain_elem, lex_pt) sched_str += "}" return sched_str -- GitLab From 2d653ea7346b9cbe8920e6065bec447ee5a9c9c5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 26 Aug 2019 20:44:03 -0500 Subject: [PATCH 115/183] active_inames->within_inames --- __init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/__init__.py b/__init__.py index 5b71a0171..28153982a 100644 --- a/__init__.py +++ b/__init__.py @@ -127,7 +127,7 @@ def check_schedule_validity( preprocessed_knl.all_inames(), [dom_after, dom_before], isl.dim_type.out) combined_doms = preprocessed_knl.get_inames_domain( - s_before.active_inames | s_after.active_inames) + s_before.within_inames | s_after.within_inames) from schedule_checker.sched_check_utils import ( order_var_names_to_match_islset) _all_dom_inames_ordered = order_var_names_to_match_islset( @@ -154,7 +154,7 @@ def check_schedule_validity( # the in-dims for an isl map, so if an iname is needed in one # statement tuple, then it is needed in all statement tuples. sched.set_symbolic_inames_for_statement_instance_space( - all_dom_inames_ordered) + _all_dom_inames_ordered) lp_insn_id_to_lex_sched_id = sched.loopy_insn_id_to_lex_sched_id() if verbose: print("-"*80) @@ -177,7 +177,7 @@ def check_schedule_validity( } sched_map_symbolic = sched.create_symbolic_isl_map( - sid_to_dom, all_dom_inames_ordered) + sid_to_dom, _all_dom_inames_ordered) if verbose: print("sid_to_dom:\n", sid_to_dom) @@ -217,7 +217,7 @@ def check_schedule_validity( # maps statement instance to all statement instances that must occur later constraint_map = create_dependency_constraint( statement_pair_dep_set, - all_dom_inames_ordered, + _all_dom_inames_ordered, dom_before, dom_after, knl.loop_priority, -- GitLab From 6f0512ef00f2fe050e1b0c98afcede2cd62ae12d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 26 Aug 2019 23:22:07 -0500 Subject: [PATCH 116/183] changed add_missing_dims_to_isl_set()->align_and_add_missing_dims_to_isl_set(); now any arbitrary initial iname ordering can be used; removed now unused order_var_names_to_match_islset(s) --- __init__.py | 40 ++++---------- dependency.py | 6 +-- example_pairwise_schedule_validity.py | 31 ++++++++++- sched_check_utils.py | 78 +++++++++++---------------- 4 files changed, 74 insertions(+), 81 deletions(-) diff --git a/__init__.py b/__init__.py index 28153982a..958d3ff67 100644 --- a/__init__.py +++ b/__init__.py @@ -19,7 +19,6 @@ def check_schedule_validity( ) from schedule_checker.sched_check_utils import ( prettier_map_string, - order_var_names_to_match_islsets, ) # Preprocess if not already preprocessed @@ -107,34 +106,15 @@ def check_schedule_validity( # include them and set them equal to a dummy variable. # Get a consistent iname ordering to use in our maps - # combined_doms is only used for printing (map.gist(dom)) - # and for getting a consistent iname ordering to use in our maps - combined_doms = preprocessed_knl.get_inames_domain( - s_before.within_inames | s_after.within_inames) - # TODO not guaranteed to work - # TODO remove this and make domain processing more robust - - # Get all inames now in order to maintain list with consistent ordering # This will help keep isl maps/sets compatible - - # TODO We're starting with an order matching the domains - # so that we don't have to worry about reordering isl sets/maps later - # and if we don't, assertions will fail. Later, improve this so we can - # start with arbitrary ordering of inames, or find some other way to - # make this more intuitive+robust. - import islpy as isl - all_dom_inames_ordered = order_var_names_to_match_islsets( - preprocessed_knl.all_inames(), [dom_after, dom_before], isl.dim_type.out) - - combined_doms = preprocessed_knl.get_inames_domain( - s_before.within_inames | s_after.within_inames) + # TODO make it unnecessary to track this ordering from schedule_checker.sched_check_utils import ( - order_var_names_to_match_islset) - _all_dom_inames_ordered = order_var_names_to_match_islset( - preprocessed_knl.all_inames(), combined_doms, isl.dim_type.out) - print(all_dom_inames_ordered) - print(_all_dom_inames_ordered) - #assert all_dom_inames_ordered == _all_dom_inames_ordered + list_var_names_in_isl_sets, + ) + consistent_iname_ordering = list_var_names_in_isl_sets( + [dom_before, dom_after]) + print("iname ordering:", consistent_iname_ordering) + assert set(consistent_iname_ordering).issubset(knl.all_inames()) # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency @@ -154,7 +134,7 @@ def check_schedule_validity( # the in-dims for an isl map, so if an iname is needed in one # statement tuple, then it is needed in all statement tuples. sched.set_symbolic_inames_for_statement_instance_space( - _all_dom_inames_ordered) + consistent_iname_ordering) lp_insn_id_to_lex_sched_id = sched.loopy_insn_id_to_lex_sched_id() if verbose: print("-"*80) @@ -177,7 +157,7 @@ def check_schedule_validity( } sched_map_symbolic = sched.create_symbolic_isl_map( - sid_to_dom, _all_dom_inames_ordered) + sid_to_dom, consistent_iname_ordering) if verbose: print("sid_to_dom:\n", sid_to_dom) @@ -217,7 +197,7 @@ def check_schedule_validity( # maps statement instance to all statement instances that must occur later constraint_map = create_dependency_constraint( statement_pair_dep_set, - _all_dom_inames_ordered, + consistent_iname_ordering, dom_before, dom_after, knl.loop_priority, diff --git a/dependency.py b/dependency.py index e71e77b31..47dc32f86 100644 --- a/dependency.py +++ b/dependency.py @@ -65,7 +65,7 @@ def create_dependency_constraint( make_islvars_with_var_primes, append_apostrophes, add_dims_to_isl_set, - add_missing_dims_to_isl_set, + align_and_add_missing_dims_to_isl_set, create_new_set_with_primes, ) # This function uses the dependency given to create the following constraint: @@ -224,10 +224,10 @@ def create_dependency_constraint( [statement_var_name_prime], statement_var_pose) # insert inames missing from doms to enable intersection - domain_to_intersect = add_missing_dims_to_isl_set( + domain_to_intersect = align_and_add_missing_dims_to_isl_set( domain_to_intersect, isl.dim_type.out, [statement_var_name] + all_dom_inames_ordered) - range_to_intersect = add_missing_dims_to_isl_set( + range_to_intersect = align_and_add_missing_dims_to_isl_set( range_to_intersect, isl.dim_type.out, append_apostrophes([statement_var_name] + all_dom_inames_ordered)) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 0cca2d18a..4a62c791d 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -5,7 +5,8 @@ from schedule_checker import check_schedule_validity # Choose kernel ---------------------------------------------------------- -knl_choice = "example" +#knl_choice = "example" +knl_choice = "unused_inames" #knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" @@ -49,6 +50,34 @@ if knl_choice == "example": #knl = lp.prioritize_loops(knl, "i,k,j") knl = lp.prioritize_loops(knl, "i,k") knl = lp.prioritize_loops(knl, "i,j") +if knl_choice == "unused_inames": + knl = lp.make_kernel( + [ + "{[i,ii]: 0<=itemp = b[i,k] {id=insn_a} + end + for j + a[i,j] = temp + 1 {id=insn_b,dep=insn_a} + end + end + """, + name="unused_inames", + assumptions="pi,pj,pk >= 1", + lang_version=(2018, 2) + ) + knl = lp.add_and_infer_dtypes( + knl, + {"b": np.float32}) + #knl = lp.tag_inames(knl, {"i": "l.0"}) + #knl = lp.prioritize_loops(knl, "i,k,j") + knl = lp.prioritize_loops(knl, "i,k") + knl = lp.prioritize_loops(knl, "i,j") elif knl_choice == "matmul": bsize = 16 knl = lp.make_kernel( diff --git a/sched_check_utils.py b/sched_check_utils.py index 482762864..b081d9917 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -25,32 +25,33 @@ def add_dims_to_isl_set(isl_set, dim_type, names, new_pose_start): return new_set -def is_ordered_sublist(sub_list, full_list): - full_idx = 0 - sub_idx = 0 - while sub_idx < len(sub_list) and full_idx < len(full_list): - if sub_list[sub_idx] == full_list[full_idx]: - sub_idx += 1 - full_idx += 1 - return sub_idx == len(sub_list) - - -def add_missing_dims_to_isl_set(isl_set, dim_type, all_dim_names): - # assumes vars in set are ordered subset of all_dim_names - assert is_ordered_sublist( - isl_set.get_var_names(dim_type), - all_dim_names, - ) +def align_and_add_missing_dims_to_isl_set(isl_set, dim_type, desired_dims_ordered): + assert set(isl_set.get_var_names(dim_type)).issubset(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 i, name in enumerate(all_dim_names): - if i >= new_set.n_dim() or \ - new_set.get_dim_name(dim_type, i) != name: - # insert missing dim + for desired_pose, name in enumerate(desired_dims_ordered): + # if iname doesn't exist in set, add dim: + if not name in new_set.get_var_names(dim_type): + # insert missing dim in correct location new_set = new_set.insert_dims( - dim_type, i, 1 + dim_type, desired_pose, 1 ).set_dim_name( - dim_type, i, 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) + # TODO is this safe? + # 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 @@ -100,30 +101,13 @@ def all_iname_domains_equal(knl): return True -def order_var_names_to_match_islset(var_names, islset, set_dim=isl.dim_type.out): - # returns subset of var_names found in islset in - # order matching the islset variables - name_order = islset.get_var_names(set_dim) - names_ordered_to_match_islset = [] - for v in name_order: - if v in var_names: - names_ordered_to_match_islset.append(v) - return names_ordered_to_match_islset - - -def order_var_names_to_match_islsets(var_names, islset_list, set_dim=isl.dim_type.out): - # returns subset of var_names found in islset in - # order matching the islset variables - name_order = [] - for islset in islset_list: - name_order.extend( - [v for v in islset.get_var_names(set_dim) - if v not in name_order]) - names_ordered_to_match_islsets = [] - for v in name_order: - if v in var_names: - names_ordered_to_match_islsets.append(v) - return names_ordered_to_match_islsets +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_explicit_map_from_tuples(tuple_pairs, space): @@ -232,7 +216,7 @@ def create_symbolic_isl_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 = add_missing_dims_to_isl_set( + dom_with_all_inames = align_and_add_missing_dims_to_isl_set( dom, isl.dim_type.out, space_in_names, ) -- GitLab From 0e87b45b5a3c1238d65c2d2712f0f10b2af2529a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 27 Aug 2019 01:48:19 -0500 Subject: [PATCH 117/183] removed unnecessary state (instance variable) from LexSchedule; now domain inames are passed directly to the isl map creation method rather than storing them as part of the LexSchedule --- __init__.py | 11 ++--------- schedule.py | 43 ++++++++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/__init__.py b/__init__.py index 958d3ff67..7b201f0fb 100644 --- a/__init__.py +++ b/__init__.py @@ -114,7 +114,8 @@ def check_schedule_validity( consistent_iname_ordering = list_var_names_in_isl_sets( [dom_before, dom_after]) print("iname ordering:", consistent_iname_ordering) - assert set(consistent_iname_ordering).issubset(knl.all_inames()) + print("all inames:", knl.all_inames()) + assert set(consistent_iname_ordering).issubset(knl.all_inames()) # TODO remove assert # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency @@ -127,14 +128,6 @@ def check_schedule_validity( #print("LexSchedule before processing:") #print(sched) - # Right now, statement tuples consist of single int. - # Add all inames from combined domains to statement tuples. - # This may include inames not used in every instruction, - # but all in-tuples need to match because they will become - # the in-dims for an isl map, so if an iname is needed in one - # statement tuple, then it is needed in all statement tuples. - sched.set_symbolic_inames_for_statement_instance_space( - consistent_iname_ordering) lp_insn_id_to_lex_sched_id = sched.loopy_insn_id_to_lex_sched_id() if verbose: print("-"*80) diff --git a/schedule.py b/schedule.py index 0d068f98d..9439227b5 100644 --- a/schedule.py +++ b/schedule.py @@ -53,13 +53,6 @@ class LexSchedule(object): statement instances to points in a lexicographic ordering. Points in lexicographic ordering represented as list of :class:`int`. - .. attribute:: map_domain_inames - - A list of :class:`str` representing the union of inames used - in all statement instances. `statement_var_name` and - `map_domain_inames` are the names of the dims of the space of the - ISL map domain. - .. attribute:: unused_param_name A :class:`str` that specifies the name of a dummy isl parameter @@ -99,9 +92,6 @@ class LexSchedule(object): # list of LexScheduleStatements self.lex_schedule = [] - # inames for statement instance space - self.map_domain_inames = [] - # make sure we don't have an iname name conflict assert not any( iname == self.statement_var_name for iname in knl.all_inames()) @@ -206,12 +196,21 @@ class LexSchedule(object): new_sched.append((stmt, lex_pt + [0]*(max_lex_dim-len(lex_pt)))) self.lex_schedule = new_sched - def set_symbolic_inames_for_statement_instance_space(self, inames): - # set map_domain_inames - self.map_domain_inames = inames[:] + def create_symbolic_isl_map( + self, + sid_to_dom, + dom_inames_ordered): + + """Create isl map representing lex schedule + + .. arg:: dom_inames_ordered - def create_symbolic_isl_map(self, sid_to_dom, dom_inames_ordered): - # create isl map representing lex schedule + A list of :class:`str` representing the union of inames used + in all statement instances. `statement_var_name` and + `dom_inames_ordered` are the names of the dims of the space of the + ISL map domain. + + """ from schedule_checker.sched_check_utils import ( create_symbolic_isl_map_from_tuples, @@ -238,10 +237,17 @@ class LexSchedule(object): sid_to_dom[stmt.int_id], isl.dim_type.out, [self.statement_var_name], 0)) + # Right now, statement tuples consist of single int. + # Add all inames from combined domains to domain tuples. + # This may include inames not used in every instruction, + # but all in-tuples need to match because they will become + # the in-dims for an isl map, so if an iname is needed in one + # statement tuple, then it is needed in all statement tuples. + # create isl map return create_symbolic_isl_map_from_tuples( zip( - [((stmt.int_id,) + tuple(self.map_domain_inames), lex_pt) + [((stmt.int_id,) + tuple(dom_inames_ordered), lex_pt) for stmt, lex_pt in self.lex_schedule], doms_to_intersect ), @@ -277,10 +283,9 @@ class LexSchedule(object): def __str__(self): sched_str = "{\n" for stmt, lex_pt in self.lex_schedule: - domain_elem = "[%s=%s,%s]" % ( + domain_elem = "[%s=%s,]" % ( self.statement_var_name, - stmt.int_id, - ",".join(self.map_domain_inames)) + stmt.int_id) sched_str += "%s -> %s;\n" % (domain_elem, lex_pt) sched_str += "}" return sched_str -- GitLab From 6a41be2db6035d2857b26b9f351fef9b18faf892 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 27 Aug 2019 03:46:40 -0500 Subject: [PATCH 118/183] eliminated need to keep consistently ordered list of inames for isl set/map compatibility; instead reordering dims by name when necessary; renamed align_and_add_missing_dims_to_isl_set()->reorder_dims_by_name() and added options to *not* add missing inames while reordering --- __init__.py | 52 ++++++++++++++++++++++++++---- dependency.py | 21 ++++++++---- example_dependency_checking.py | 2 +- lexicographic_order_map.py | 1 + sched_check_utils.py | 59 ++++++++++++++-------------------- schedule.py | 10 ++++-- 6 files changed, 95 insertions(+), 50 deletions(-) diff --git a/__init__.py b/__init__.py index 7b201f0fb..81c8a7e05 100644 --- a/__init__.py +++ b/__init__.py @@ -149,8 +149,7 @@ def check_schedule_validity( lp_insn_id_to_lex_sched_id[s_after.insn_id]: dom_after, } - sched_map_symbolic = sched.create_symbolic_isl_map( - sid_to_dom, consistent_iname_ordering) + sched_map_symbolic = sched.create_symbolic_isl_map(sid_to_dom) if verbose: print("sid_to_dom:\n", sid_to_dom) @@ -177,20 +176,18 @@ def check_schedule_validity( # maps each statement instance to all statement instances occuring later sio = get_statement_ordering_map( sched_map_symbolic, lex_order_map_symbolic) - """ + if verbose: - print("statement instance ordering symbolic:") + print("statement instance ordering:") print(prettier_map_string(sio)) print("SIO space (statement instances -> statement instances):") print(sio.space) print("-"*80) - """ # create a map representing constraints from the dependency, # maps statement instance to all statement instances that must occur later constraint_map = create_dependency_constraint( statement_pair_dep_set, - consistent_iname_ordering, dom_before, dom_after, knl.loop_priority, @@ -199,12 +196,55 @@ def check_schedule_validity( sched.statement_var_name, ) + # align constraint map spaces to match sio so we can compare them + if verbose: + print("constraint map space (before aligning):") + print(constraint_map.space) + + # align params aligned_constraint_map = constraint_map.align_params(sio.space) + + # align in_ dims + import islpy as isl + from schedule_checker.sched_check_utils import ( + reorder_dims_by_name, + append_apostrophes, + ) + sio_in_names = sio.space.get_var_names(isl.dim_type.in_) + aligned_constraint_map = reorder_dims_by_name( + aligned_constraint_map, + isl.dim_type.in_, + sio_in_names, + add_missing=False, + new_names_are_permutation_only=True, + ) + + # align out dims + aligned_constraint_map = reorder_dims_by_name( + aligned_constraint_map, + isl.dim_type.out, + append_apostrophes(sio_in_names), + # TODO sio out names are only pretending to have apostrophes; confusing + add_missing=False, + new_names_are_permutation_only=True, + ) + if verbose: + print("constraint map space (after aligning):") + print(aligned_constraint_map.space) print("constraint map:") print(prettier_map_string(aligned_constraint_map)) assert aligned_constraint_map.space == sio.space + assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.in_) + == sio.space.get_var_names(isl.dim_type.in_)) + assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.out) + == append_apostrophes(sio.space.get_var_names(isl.dim_type.out))) + assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.param) + == sio.space.get_var_names(isl.dim_type.param)) if not aligned_constraint_map.is_subset(sio): diff --git a/dependency.py b/dependency.py index 47dc32f86..1c9ee5720 100644 --- a/dependency.py +++ b/dependency.py @@ -52,7 +52,6 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): def create_dependency_constraint( statement_dep_set, - all_dom_inames_ordered, dom_before_constraint_set, dom_after_constraint_set, loop_priorities, @@ -60,17 +59,25 @@ def create_dependency_constraint( unused_param_name, statement_var_name, statement_var_pose=0, + all_dom_inames_ordered=None, ): from schedule_checker.sched_check_utils import ( make_islvars_with_var_primes, append_apostrophes, add_dims_to_isl_set, - align_and_add_missing_dims_to_isl_set, + reorder_dims_by_name, create_new_set_with_primes, ) # This function uses the dependency given to create the following constraint: # Statement [s,i,j] comes before statement [s',i',j'] iff + from schedule_checker.sched_check_utils import ( + list_var_names_in_isl_sets, + ) + if all_dom_inames_ordered is None: + all_dom_inames_ordered = list_var_names_in_isl_sets( + [dom_before_constraint_set, dom_after_constraint_set]) + # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} islvars = make_islvars_with_var_primes( [statement_var_name]+all_dom_inames_ordered, @@ -224,13 +231,15 @@ def create_dependency_constraint( [statement_var_name_prime], statement_var_pose) # insert inames missing from doms to enable intersection - domain_to_intersect = align_and_add_missing_dims_to_isl_set( + domain_to_intersect = reorder_dims_by_name( domain_to_intersect, isl.dim_type.out, - [statement_var_name] + all_dom_inames_ordered) - range_to_intersect = align_and_add_missing_dims_to_isl_set( + [statement_var_name] + all_dom_inames_ordered, + add_missing=True) + range_to_intersect = reorder_dims_by_name( range_to_intersect, isl.dim_type.out, - append_apostrophes([statement_var_name] + all_dom_inames_ordered)) + append_apostrophes([statement_var_name] + all_dom_inames_ordered), + add_missing=True) # intersect doms map_with_loop_domain_constraints = all_constraints_map.intersect_domain( diff --git a/example_dependency_checking.py b/example_dependency_checking.py index b81c52de7..dec2d5abb 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -141,13 +141,13 @@ dom_after = knl.get_inames_domain( loop_priority = None # TODO constraint_map = create_dependency_constraint( statement_pair_dep_set, - all_necessary_inames_ordered, dom_before, dom_after, loop_priority, insnid_to_int_sid, unused_param_name, statement_var, + all_dom_inames_ordered=all_necessary_inames_ordered, ) print("constraint map space:") print(constraint_map.space) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 05d5111c0..730ffc081 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -28,6 +28,7 @@ def get_statement_ordering_map(sched_map, lex_map): # statement ordering: # map each statement instance to all statement instances that occur later # S -> L -> S^-1 + # TODO apostrophes aren't really there for range, this is confusing return sched_map.apply_range(lex_map).apply_range(sched_map.reverse()) diff --git a/sched_check_utils.py b/sched_check_utils.py index b081d9917..7f105ff38 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -25,8 +25,20 @@ def add_dims_to_isl_set(isl_set, dim_type, names, new_pose_start): return new_set -def align_and_add_missing_dims_to_isl_set(isl_set, dim_type, desired_dims_ordered): +def reorder_dims_by_name( + isl_set, dim_type, desired_dims_ordered, + add_missing=False, new_names_are_permutation_only=False): + 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)) @@ -34,13 +46,14 @@ def align_and_add_missing_dims_to_isl_set(isl_set, dim_type, desired_dims_ordere new_set = isl_set.copy() for desired_pose, name in enumerate(desired_dims_ordered): # if iname doesn't exist in set, add dim: - if not name in new_set.get_var_names(dim_type): - # 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 + 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) @@ -216,9 +229,11 @@ def create_symbolic_isl_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 = align_and_add_missing_dims_to_isl_set( + dom_with_all_inames = reorder_dims_by_name( dom, isl.dim_type.out, space_in_names, + add_missing=True, + new_names_are_permutation_only=False, ) # intersect domain with this map @@ -376,29 +391,3 @@ def get_orderings_of_length_n( return_first_found=return_first_found, ) return orderings - - -# currently unused: -""" -def add_missing_set_dims_to_map_indims(islmap, islset): - new_map = islmap.copy() - for i in range(islset.n_dim()): - new_dim_name = islset.get_dim_name(isl.dim_type.out, i) - # does new_dim_name already exist in map? - dim_idx = new_map.find_dim_by_name(isl.dim_type.in_, new_dim_name) - if dim_idx == -1: - # new map needs dim, insert it - new_map = new_map.insert_dims(isl.dim_type.in_, i, 1) - new_map = new_map.set_dim_name(isl.dim_type.in_, i, new_dim_name) - else: - # new_map already has new_dim_name - if dim_idx == i: - # and it's already in the right spot - continue - else: - # move it - # TODO how do we move these? move_dims doesn't work for same dim_type - print("%s not in right spot" % (new_dim_name)) - raise ValueError("(this should not happen)") - return new_map -""" diff --git a/schedule.py b/schedule.py index 9439227b5..5c8e4ac29 100644 --- a/schedule.py +++ b/schedule.py @@ -199,7 +199,7 @@ class LexSchedule(object): def create_symbolic_isl_map( self, sid_to_dom, - dom_inames_ordered): + dom_inames_ordered=None): """Create isl map representing lex schedule @@ -219,6 +219,12 @@ class LexSchedule(object): assert len(sid_to_dom) == len(self.lex_schedule) + from schedule_checker.sched_check_utils import ( + list_var_names_in_isl_sets, + ) + if dom_inames_ordered is None: + dom_inames_ordered = list_var_names_in_isl_sets(sid_to_dom.values()) + # create an isl space # {('statement', used in >=1 statement domain>) -> # (lexicographic ordering dims)} @@ -234,7 +240,7 @@ class LexSchedule(object): for stmt, _ in self.lex_schedule: doms_to_intersect.append( add_dims_to_isl_set( - sid_to_dom[stmt.int_id], isl.dim_type.out, + sid_to_dom[stmt.int_id], isl.dim_type.set, [self.statement_var_name], 0)) # Right now, statement tuples consist of single int. -- GitLab From d264a288789fc0163156ee8556cba4435a732a6e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 27 Aug 2019 04:05:34 -0500 Subject: [PATCH 119/183] removing unnecessary creation of iname list --- __init__.py | 19 ------------------- schedule.py | 13 ++++++++----- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/__init__.py b/__init__.py index 81c8a7e05..f0e953548 100644 --- a/__init__.py +++ b/__init__.py @@ -98,25 +98,6 @@ def check_schedule_validity( s_before = statement_pair_dep_set.statement_before s_after = statement_pair_dep_set.statement_after - # The isl map representing the schedule maps - # statement instances -> lex time - # The 'in_' dim vars need to match for all sched items in the map, - # Instructions that use fewer inames will still need to - # have the unused inames in their 'in_' dim vars, so we'll - # include them and set them equal to a dummy variable. - - # Get a consistent iname ordering to use in our maps - # This will help keep isl maps/sets compatible - # TODO make it unnecessary to track this ordering - from schedule_checker.sched_check_utils import ( - list_var_names_in_isl_sets, - ) - consistent_iname_ordering = list_var_names_in_isl_sets( - [dom_before, dom_after]) - print("iname ordering:", consistent_iname_ordering) - print("all inames:", knl.all_inames()) - assert set(consistent_iname_ordering).issubset(knl.all_inames()) # TODO remove assert - # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency sched = LexSchedule(scheduled_knl, include_only_insn_ids=[ diff --git a/schedule.py b/schedule.py index 5c8e4ac29..23ec14f0f 100644 --- a/schedule.py +++ b/schedule.py @@ -243,12 +243,15 @@ class LexSchedule(object): sid_to_dom[stmt.int_id], isl.dim_type.set, [self.statement_var_name], 0)) + # The isl map representing the schedule maps + # statement instances -> lex time + # The 'in_' dim vars need to match for all sched items in the map, + # Instructions that use fewer inames will still need to + # have the unused inames in their 'in_' dim vars, so we'll + # include them and set them equal to a dummy variable. + # Right now, statement tuples consist of single int. - # Add all inames from combined domains to domain tuples. - # This may include inames not used in every instruction, - # but all in-tuples need to match because they will become - # the in-dims for an isl map, so if an iname is needed in one - # statement tuple, then it is needed in all statement tuples. + # Add all inames from combined domains to map domain tuples. # create isl map return create_symbolic_isl_map_from_tuples( -- GitLab From 2c54b29016b7f414fc651cc8b3bbeefad22daa8c Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 27 Aug 2019 11:05:46 -0500 Subject: [PATCH 120/183] added docstrings for LexSchedule and its methods --- sched_check_utils.py | 1 + schedule.py | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 7f105ff38..6c6e87332 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -291,6 +291,7 @@ def get_concurrent_inames(knl): def _get_insn_id_from_sched_item(knl, sched_item): + # TODO could use loopy's sched_item_to_insn_id() from loopy.schedule import Barrier if isinstance(sched_item, Barrier): return sched_item.originating_insn_id diff --git a/schedule.py b/schedule.py index 23ec14f0f..92f92e6b4 100644 --- a/schedule.py +++ b/schedule.py @@ -88,6 +88,15 @@ class LexSchedule(object): knl, include_only_insn_ids=None, ): + """ + :arg kernel: A :class:`LoopKernel` whose instructions will be + described by this :class:`LexSchedule`. + + :arg include_only_insn_ids: A list of :class:`str` instruction ids + specifying which instructions to include in the mapping. If set + to None, all insructions will be included. + + """ # list of LexScheduleStatements self.lex_schedule = [] @@ -183,13 +192,23 @@ class LexSchedule(object): 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 dict([(stmt.insn_id, stmt.int_id) for stmt, _ in self.lex_schedule]) def max_lex_dims(self): return max(len(lex_pt) for _, lex_pt in self.lex_schedule) def pad_lex_pts_with_zeros(self): - # pad lex points with zeros so that all points have same number of dims + """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() new_sched = [] for stmt, lex_pt in self.lex_schedule: @@ -200,15 +219,18 @@ class LexSchedule(object): self, sid_to_dom, dom_inames_ordered=None): - """Create isl map representing lex schedule - .. arg:: dom_inames_ordered + .. arg:: sid_to_dom: A :class:`dict` mapping integer ids to domains, + where integer ids are instances of the `int_id` attribute of + :class:`LexScheduleStatement`, and domains are the + :class:`islpy.BasicSet` representing the domain for this + statement. - A list of :class:`str` representing the union of inames used - in all statement instances. `statement_var_name` and - `dom_inames_ordered` are the names of the dims of the space of the - ISL map domain. + .. arg:: dom_inames_ordered: A list of :class:`str` representing + the union of inames used in all statement instances. + `statement_var_name` and `dom_inames_ordered` are the names + of the dims of the space of the ISL map domain. """ @@ -267,6 +289,11 @@ class LexSchedule(object): for i in range(self.max_lex_dims())] def get_lex_order_map_for_symbolic_sched(self): + """Return an :class:`islpy.BasicMap` that maps each point in a + lexicographic ordering to every point that is + lexocigraphically greater. + """ + from schedule_checker.lexicographic_order_map import ( create_symbolic_lex_order_map, ) -- GitLab From 470654ad97a34845437f0ee6371bc0e2f80cb7c6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 27 Aug 2019 11:15:08 -0500 Subject: [PATCH 121/183] added docstring for StatementPairDependencySet --- dependency.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/dependency.py b/dependency.py index 1c9ee5720..1813fd80b 100644 --- a/dependency.py +++ b/dependency.py @@ -7,6 +7,24 @@ class DependencyType: class StatementPairDependencySet(object): + """A set of dependencies between two statements. + + .. attribute:: statement_before + + A :class:`LexScheduleStatement` depended on by statement_after. + + .. attribute:: statement_after + + A :class:`LexScheduleStatement` which depends on statement_before. + + .. attribute:: deps + + A :class:`dict` mapping instances of :class:`DependencyType` to + the Loopy kernel inames involved in that particular + dependency relationship. + + """ + def __init__( self, statement_before, -- GitLab From 1e1204451bf618f1beec80298724efbd915df198 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Sep 2019 18:08:35 -0500 Subject: [PATCH 122/183] minor changes to schedule docstrings --- schedule.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/schedule.py b/schedule.py index 92f92e6b4..bfbd789b6 100644 --- a/schedule.py +++ b/schedule.py @@ -51,7 +51,7 @@ class LexSchedule(object): A :class:`list` of (:class:`LexScheduleStatement`, :class:`list`) tuples, representing the program ordering as a map from statement instances to points in a lexicographic ordering. Points - in lexicographic ordering represented as list of :class:`int`. + in lexicographic ordering are represented as list of :class:`int`. .. attribute:: unused_param_name @@ -89,7 +89,7 @@ class LexSchedule(object): include_only_insn_ids=None, ): """ - :arg kernel: A :class:`LoopKernel` whose instructions will be + :arg knl: A :class:`LoopKernel` whose instructions will be described by this :class:`LexSchedule`. :arg include_only_insn_ids: A list of :class:`str` instruction ids -- GitLab From 5274862bafbc2430b2ce1b19129617ccc27a4d20 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Sep 2019 18:13:50 -0500 Subject: [PATCH 123/183] raise error if someone attempts to build a schedule of length greater than 2 --- schedule.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/schedule.py b/schedule.py index bfbd789b6..0237fe829 100644 --- a/schedule.py +++ b/schedule.py @@ -107,6 +107,12 @@ class LexSchedule(object): assert not any( iname == self.unused_param_name for iname in knl.all_inames()) + if (include_only_insn_ids is None and len(knl.schedule) > 2 + ) or len(include_only_insn_ids) > 2: + raise NotImplementedError( + "LexSchedule currently does not produce program orderings " + "with greater than 2 statements.") + from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.kernel.data import ConcurrentTag -- GitLab From b2a258f34d4b8f86ac5bbc74064f5a0d89df7c58 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Sep 2019 19:00:43 -0500 Subject: [PATCH 124/183] docstring for dependency type --- dependency.py | 33 +++++++++++++++++++++++++++++++++ schedule.py | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/dependency.py b/dependency.py index 1813fd80b..88bb17ef2 100644 --- a/dependency.py +++ b/dependency.py @@ -2,6 +2,38 @@ import islpy as isl class DependencyType: + """Strings specifying a particular type of dependency relationship. + + .. attribute:: SAME + + A :class:`str` specifying the following dependency relationship: + + If ``S = {i, j, ...}`` is a set of inames used in both statements + ``insn0`` and ``insn1``, and ``{i, j, ...}`` represent the values + of the inames in ``insn0``, and ``{i', j', ...}`` represent the + values of the inames in ``insn1``, then the dependency + ``insn0 happens before insn1 iff SAME({i, j})`` specifies that + ``insn0 happens before insn1 iff {i = i' and j = j' and ...}``. + Note that ``SAME({}) = True``. + + .. attribute:: PRIOR + + A :class:`str` specifying the following dependency relationship: + + If ``S = {i, j, k, ...}`` is a set of inames used in both statements + ``insn0`` and ``insn1``, and ``{i, j, k, ...}`` represent the values + of the inames in ``insn0``, and ``{i', j', k', ...}`` represent the + values of the inames in ``insn1``, then the dependency + ``insn0 happens before insn1 iff PRIOR({i, j, k})`` specifies one of + two possibilities, depending on whether the loop nest ordering is + known. If the loop nest ordering is unknown, then + ``insn0 happens before insn1 iff {i < i' and j < j' and k < k' ...}``. + If the loop nest ordering is known, the condition becomes + ``{i, j, k, ...}`` is lexicographically less than ``{i', j', k', ...}``, + i.e., ``i < i' or (i = i' and j < j') or (i = i' and j = j' and k < k') ...``. + + """ + SAME = "same" PRIOR = "prior" @@ -207,6 +239,7 @@ def create_dependency_constraint( from schedule_checker.lexicographic_order_map import ( get_lex_order_constraint ) + # TODO handle case where inames list is empty constraint_set = get_lex_order_constraint( islvars, inames_list_nest_ordered, diff --git a/schedule.py b/schedule.py index 0237fe829..d71fdc603 100644 --- a/schedule.py +++ b/schedule.py @@ -225,7 +225,7 @@ class LexSchedule(object): self, sid_to_dom, dom_inames_ordered=None): - """Create isl map representing lex schedule + """Create an isl map representing lex schedule .. arg:: sid_to_dom: A :class:`dict` mapping integer ids to domains, where integer ids are instances of the `int_id` attribute of -- GitLab From f133e25e5da23620d922d6d2ae37e8312a4117aa Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Sep 2019 19:19:55 -0500 Subject: [PATCH 125/183] docstring for create_elementwise_comparison_conjunction_set --- dependency.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dependency.py b/dependency.py index 88bb17ef2..8b7e6e92a 100644 --- a/dependency.py +++ b/dependency.py @@ -77,6 +77,26 @@ class StatementPairDependencySet(object): 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:`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:`PwAff` zero constant. + + .. arg op: A :class:`str` describing the operator to use when creating + the set constraints. Options: `eq` for `=`, `lt` for `<` + + .. return: 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]) -- GitLab From a804ff8bcc2417627c1ccb9717b36461c93825fe Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Sep 2019 19:24:24 -0500 Subject: [PATCH 126/183] adding 'return' description to docstring for create_symbolic_isl_map --- schedule.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/schedule.py b/schedule.py index d71fdc603..5e1c10f1b 100644 --- a/schedule.py +++ b/schedule.py @@ -225,19 +225,25 @@ class LexSchedule(object): self, sid_to_dom, dom_inames_ordered=None): - """Create an isl map representing lex schedule + """Create an isl map representing lex schedule as a mapping + from each statement instance to all statement instances + occuring later. - .. arg:: sid_to_dom: A :class:`dict` mapping integer ids to domains, + .. arg sid_to_dom: A :class:`dict` mapping integer ids to domains, where integer ids are instances of the `int_id` attribute of :class:`LexScheduleStatement`, and domains are the :class:`islpy.BasicSet` representing the domain for this statement. - .. arg:: dom_inames_ordered: A list of :class:`str` representing + .. arg dom_inames_ordered: A list of :class:`str` representing the union of inames used in all statement instances. `statement_var_name` and `dom_inames_ordered` are the names of the dims of the space of the ISL map domain. + .. return: An :class:`islpy.Map` representing the lex schedule as + a mapping from each statement instance to all statement instances + occuring later. + """ from schedule_checker.sched_check_utils import ( -- GitLab From feb1cf6924a3eb92bf1ca323bd6c68c4c9367063 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Sep 2019 19:57:41 -0500 Subject: [PATCH 127/183] added docstring for create_dependency_constraint --- dependency.py | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- schedule.py | 4 ++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/dependency.py b/dependency.py index 8b7e6e92a..f15cdd8d0 100644 --- a/dependency.py +++ b/dependency.py @@ -97,7 +97,6 @@ def create_elementwise_comparison_conjunction_set( """ - # initialize set with constraint that is always true conj_set = islvars[0].eq_set(islvars[0]) for n0, n1 in zip(names0, names1): @@ -131,6 +130,55 @@ def create_dependency_constraint( statement_var_pose=0, all_dom_inames_ordered=None, ): + """Create a statement dependency constraint represented as a map from + each statement instance to statement instances that must occur later, + i.e., ``{[s=0, i, j] -> [s'=1, i', j'] : condition on {i, j, i', j'}}`` + indicates that statement ``0`` comes before statment ``1`` when the + specified condition on inames ``i,j,i',j'`` is met. ``i'`` and ``j'`` + are the values of inames ``i`` and ``j`` in second statement instance. + + .. arg statement_dep_set: A :class:`StatementPairDependencySet` describing + the dependency relationship between the two statements. + + .. arg dom_before_constraint_set: A :class:`islpy.BasicSet` specifying the + domain for the 'before' statement in the relationship. + + .. arg dom_after_constraint_set: A :class:`islpy.BasicSet` specifying the + domain for the 'after' statement in the relationship. + + .. arg loop_priorities: A list of tuples from the ``loop_priority`` + attribute of :class:`loopy.LoopKernel` specifying the loop nest + ordering rules. + + .. arg insn_id_to_int: A :class:`dict` mapping insn_id to int_id, where + 'insn_id' and 'int_id' refer to the 'insn_id' and 'int_id' attributes + of :class:`LexScheduleStatement`. + + .. arg unused_param_name: A :class:`str` that specifies the name of a + dummy isl parameter assigned to variables in domain elements of the + isl map that represent inames unused in a particular statement + instance. The domain space of the generated isl map will have a + dimension for every iname used in any statement instance found in + the program ordering. An element in the domain of this map may + represent a statement instance that does not lie within iname x, but + will still need to assign a value to the x domain variable. In this + case, the parameter unused_param_name is is assigned to x. + + .. arg statement_var_name: A :class:`str` specifying the name of the + isl variable used to represent the unique :class:`int` statement id. + + .. arg statement_var_pose: A :class:`int` specifying which position in the + statement instance tuples holds the dimension representing the + statement id. Defaults to ``0``. + + .. arg all_dom_inames_ordered: A :class:`list` of :class:`str` specifying + an order for the dimensions representing inames. + + .. return: An :class:`islpy.Map` mapping each statement instance to all + statement instances that must occur later according to the constraints. + + """ + from schedule_checker.sched_check_utils import ( make_islvars_with_var_primes, append_apostrophes, diff --git a/schedule.py b/schedule.py index 5e1c10f1b..c182550ee 100644 --- a/schedule.py +++ b/schedule.py @@ -107,8 +107,8 @@ class LexSchedule(object): assert not any( iname == self.unused_param_name for iname in knl.all_inames()) - if (include_only_insn_ids is None and len(knl.schedule) > 2 - ) or len(include_only_insn_ids) > 2: + if ((include_only_insn_ids is None and len(knl.schedule) > 2) + or len(include_only_insn_ids) > 2): raise NotImplementedError( "LexSchedule currently does not produce program orderings " "with greater than 2 statements.") -- GitLab From 1015927ddcee0bf52584e90ae8885772333dabea Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Sep 2019 19:59:03 -0500 Subject: [PATCH 128/183] fixing docstring formatting --- schedule.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/schedule.py b/schedule.py index c182550ee..a2df9acb3 100644 --- a/schedule.py +++ b/schedule.py @@ -198,8 +198,8 @@ class LexSchedule(object): 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 + """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 dict([(stmt.insn_id, stmt.int_id) for stmt, _ in self.lex_schedule]) @@ -230,14 +230,14 @@ class LexSchedule(object): occuring later. .. arg sid_to_dom: A :class:`dict` mapping integer ids to domains, - where integer ids are instances of the `int_id` attribute of + where integer ids are instances of the ``int_id`` attribute of :class:`LexScheduleStatement`, and domains are the :class:`islpy.BasicSet` representing the domain for this statement. .. arg dom_inames_ordered: A list of :class:`str` representing the union of inames used in all statement instances. - `statement_var_name` and `dom_inames_ordered` are the names + ``statement_var_name`` and ``dom_inames_ordered`` are the names of the dims of the space of the ISL map domain. .. return: An :class:`islpy.Map` representing the lex schedule as -- GitLab From 7bedbbb4179d5452f16840c1c078501c0ebe6dd1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Sep 2019 20:21:52 -0500 Subject: [PATCH 129/183] added docstring to create_dependencies_from_legacy_kernel --- dependency.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/dependency.py b/dependency.py index f15cdd8d0..74b8a0978 100644 --- a/dependency.py +++ b/dependency.py @@ -368,6 +368,23 @@ def create_dependency_constraint( def create_dependencies_from_legacy_knl(knl): + """Return a list of :class:`StatementPairDependySet` instances created + for a :class:`loopy.LoopKernel` containing legacy depencencies. Create + the new dependencies according to the following rules. (1) If + a dependency exists between ``insn0`` and ``insn1``, create the dependnecy + ``SAME(SNC)`` where ``SNC`` is the set of non-concurrent inames used + by both ``insn0 and ``insn1``, and ``SAME`` is the relationship specified + by the ``SAME`` attribute of :class:`DependencyType`. (2) For each subset + of non-concurrent inames used by any instruction, find the set of all + instructions using those inames, create a directed graph with these + instructions as nodes and edges representing a 'happens before' + relationship specfied by each dependency, find the sources and sinks within + this graph, and connect each sink to each source (sink happens before + source) with a ``PRIOR(SNC)`` dependency, where ``PRIOR`` is the + relationship specified by the ``PRIOR`` attribute of + :class:`DependencyType`. + + """ # Introduce SAME dep for set of shared, non-concurrent inames from schedule_checker.sched_check_utils import ( -- GitLab From 547e2cace6f0b82ee317725587e5eb4bf34ad396 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Sep 2019 20:29:09 -0500 Subject: [PATCH 130/183] created docstring for get_dependency_sources_and_sinks --- dependency.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dependency.py b/dependency.py index 74b8a0978..8a118bdc5 100644 --- a/dependency.py +++ b/dependency.py @@ -457,6 +457,18 @@ def create_dependencies_from_legacy_knl(knl): def get_dependency_sources_and_sinks(knl, sched_item_ids): + """Implicitly create a directed graph with the schedule items specified + by ``sched_item_ids`` as nodes, and with edges representing a + 'happens before' relationship specfied by each legacy dependency between + two instructions. Return the sources and sinks within this graph. + + .. arg sched_item_ids: A :class:`list` of :class:`str` representing + loopy instruction ids. + + .. return: Two instances of :class:`set` of :class:`str` instruction ids + representing the sources and sinks in the dependency graph. + + """ sources = set() dependees = set() # all dependees (within sched_item_ids) for item_id in sched_item_ids: -- GitLab From 9acd446bcc412d9b2cad58841c1f6f99cb7fe78d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 3 Sep 2019 00:00:47 -0500 Subject: [PATCH 131/183] simplified and cleaned up lex map creation example --- example_lex_map_creation.py | 116 +++++------------------------------- 1 file changed, 14 insertions(+), 102 deletions(-) diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py index 79730d036..dde4e001e 100644 --- a/example_lex_map_creation.py +++ b/example_lex_map_creation.py @@ -5,32 +5,15 @@ from schedule_checker.lexicographic_order_map import ( from schedule_checker.sched_check_utils import ( create_explicit_map_from_tuples, get_isl_space, + prettier_map_string as pmap, ) -# *Symbolic* lexicographic mapping- map each tuple to all tuples occuring later - -#in_names = ["i", "j"] -#out_names = append_apostrophes(in_names) -n_dims = 2 # len(in_names) -lex_map_symbolic = create_symbolic_lex_order_map( - n_dims) -print("lex_map (symbolic):") -print(lex_map_symbolic) - - -# *Explicit* lexicographic mapping- map each tuple to all tuples occuring later - -""" -dim_bounds = [(0,2), (0,2)] # max vals for each dim (e.g., 0 <= i0 < max0 ...) -explicit_lex_map_pairs = lex_order_map_tuple_pairs_from_explicit_bounds(dim_bounds) -# for pair in explicit_lex_map_pairs: -# print(pair[0], pair[1]) -lex_map_explicit = create_explicit_map_from_tuples(explicit_lex_map_pairs, - lex_map_symbolic.space) -print("lex_map (explicit):") -print(lex_map_explicit) -""" +# Lexicographic order map- map each tuple to all tuples occuring later +n_dims = 2 +lex_order_map = create_symbolic_lex_order_map(n_dims) +print("lexicographic order map:") +print(pmap(lex_order_map)) # Example *explicit* schedule (map statement instances to lex time) @@ -38,12 +21,8 @@ param_names_sched = [] in_names_sched = ["s"] out_names_sched = ["i", "j"] sched_space = get_isl_space(param_names_sched, in_names_sched, out_names_sched) -example_sched = create_explicit_map_from_tuples( +sched_explicit = create_explicit_map_from_tuples( [ - #((0,), (2, 0, 0)), - #((1,), (2, 0, 1)), - #((2,), (2, 1, 0)), - #((3,), (2, 1, 1)), ((0,), (0, 0)), ((1,), (0, 1)), ((2,), (1, 0)), @@ -51,81 +30,14 @@ example_sched = create_explicit_map_from_tuples( ], sched_space, ) -print("example sched:") -print(example_sched) +print("example explicit sched:") +print(pmap(sched_explicit)) -# statement ordering: +# Statement instance ordering: # map each statement instance to all statement instances that occur later # S -> L -> S^-1 -""" -statement_instance_ordering_explicit = get_statement_ordering_map( - example_sched, lex_map_explicit) -print("statement instance ordering explicit:") -print(statement_instance_ordering_explicit) -""" - -statement_instance_ordering_symbolic = get_statement_ordering_map( - example_sched, lex_map_symbolic) -print("statement instance ordering symbolic:") -print(statement_instance_ordering_symbolic) - - -# example constraint test: -print("---------------------------------------------------------------------------") -""" -param_names_sched = ["ps", "p0", "p1"] -in_names_sched = ["s"] -out_names_sched = ["i", "j"] -sched_space = isl.Space.alloc(isl.DEFAULT_CONTEXT, 3, 1, 2) -sched_space = set_space_names( - sched_space, - param_names=param_names_sched, - in_names=in_names_sched, - out_names=out_names_sched) -example_sched = create_explicit_map_from_tuples( - [ - #((0,0), (0, 0)), - #((1,0), (0, 1)), - #((2,1), (1, 0)), - #((3,1), (1, 1)), - ((0,), (0, 0)), - ((1,), (0, 1)), - ((2,), (1, 0)), - ((3,), (1, 1)), - ], - sched_space, - ) -print("example sched:") -print(example_sched) -""" - -""" -param_names_sched = ["ps", "p0", "p1"] -in_names_sched = ["s","i","j"] -out_names_sched = ["l0","l1"] -sched_space = get_isl_space(param_names_sched, in_names_sched, out_names_sched) -example_sched = create_explicit_map_from_tuples( - [ - ((0,0,0), (0, 0)), - ((0,1,0), (0, 0)), - ((1,0,0), (0, 1)), - ((1,1,0), (0, 1)), - ((0,0,1), (1, 0)), - ((0,1,1), (1, 0)), - ((1,0,1), (1, 1)), - ((1,1,1), (1, 1)), - ], - sched_space, - ) -print("example sched:") -print(example_sched) - -print("lex map explicit:") -print(lex_map_explicit) - -statement_instance_ordering_explicit = get_statement_ordering_map( - example_sched, lex_map_explicit) -print("statement instance ordering explicit:") -print(statement_instance_ordering_explicit) -""" +sio = get_statement_ordering_map( + sched_explicit, lex_order_map) +print("Statement instance ordering:") +print(pmap(sio)) -- GitLab From 2edc3893d6651e9beb4febd7f1189590e703b8f4 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 3 Sep 2019 00:53:48 -0500 Subject: [PATCH 132/183] removed old/unused code/approach from dependency checking example and added code for ensuring spaces are aligned without enforcing iname order at map construcction --- example_dependency_checking.py | 157 +++++++++++++++++++-------------- 1 file changed, 93 insertions(+), 64 deletions(-) diff --git a/example_dependency_checking.py b/example_dependency_checking.py index dec2d5abb..0f04aee95 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -5,11 +5,11 @@ from schedule_checker.dependency import ( # noqa create_dependency_constraint, ) from schedule_checker.lexicographic_order_map import ( - lex_order_map_tuple_pairs_from_explicit_bounds, + create_symbolic_lex_order_map, get_statement_ordering_map, ) from schedule_checker.sched_check_utils import ( - prettier_map_string, + prettier_map_string as pmap, append_apostrophes, create_explicit_map_from_tuples, get_isl_space, @@ -30,18 +30,18 @@ knl = lp.tag_inames(knl, {"i": "l.0"}) print("Kernel:") print(knl) -all_necessary_inames_ordered = ['i', 'j'] -#all_necessary_inames_ordered = sorted(list(knl.all_inames())) +inames = ['i', 'j'] statement_var = 's' +unused_param_name = 'unused' # example sched: -print("---------------------------------------------------------------------------") +print("-"*80) # i is parallel, suppose we want to enforce the following: # for a given i, statement 0 happens before statement 1 -params_sched = ['p0', 'p1'] -in_names_sched = [statement_var]+all_necessary_inames_ordered +params_sched = ['p0', 'p1', unused_param_name] +in_names_sched = [statement_var]+inames out_names_sched = ['l0', 'l1'] sched_space = get_isl_space(params_sched, in_names_sched, out_names_sched) @@ -59,7 +59,7 @@ example_sched_valid = create_explicit_map_from_tuples( sched_space, ) print("example sched (valid):") -print(prettier_map_string(example_sched_valid)) +print(pmap(example_sched_valid)) example_sched_invalid = create_explicit_map_from_tuples( [ @@ -75,70 +75,54 @@ example_sched_invalid = create_explicit_map_from_tuples( sched_space, ) print("example sched (invalid):") -print(prettier_map_string(example_sched_invalid)) - -# *Explicit* lexicographic mapping- map each tuple to all tuples occuring later -print("---------------------------------------------------------------------------") -lex_dim_bounds = [(0, 2), (0, 2)] # max vals for each dim (e.g., 0 <= i0 < max0 ...) -lex_params = [] -lex_in_names = out_names_sched -lex_out_names = append_apostrophes(out_names_sched) - -explicit_lex_map_pairs = lex_order_map_tuple_pairs_from_explicit_bounds( - lex_dim_bounds) -# for pair in explicit_lex_map_pairs: -# print(pair[0], pair[1]) -lex_space_explicit = get_isl_space(lex_params, lex_in_names, lex_out_names) -lex_map_explicit = create_explicit_map_from_tuples(explicit_lex_map_pairs, - lex_space_explicit) -print("lex_map (explicit):") -print(prettier_map_string(lex_map_explicit)) +print(pmap(example_sched_invalid)) + +# Lexicographic order map- map each tuple to all tuples occuring later +print("-"*80) +n_dims = 2 +lex_order_map = create_symbolic_lex_order_map(n_dims) +print("lexicographic order map:") +print(pmap(lex_order_map)) # Statement instance ordering (valid sched) -print("----------------------------------------------------------------------") -SIO_explicit_valid = get_statement_ordering_map( - example_sched_valid, lex_map_explicit) -print("statement instance ordering explicit (valid_sched):") -print(prettier_map_string(SIO_explicit_valid)) +print("-"*80) +SIO_valid = get_statement_ordering_map( + example_sched_valid, lex_order_map) +print("statement instance ordering (valid_sched):") +print(pmap(SIO_valid)) + # Statement instance ordering (invalid sched) -print("----------------------------------------------------------------------") -SIO_explicit_invalid = get_statement_ordering_map( - example_sched_invalid, lex_map_explicit) -print("statement instance ordering explicit (invalid_sched):") -print(prettier_map_string(SIO_explicit_invalid)) +print("-"*80) +SIO_invalid = get_statement_ordering_map( + example_sched_invalid, lex_order_map) +print("statement instance ordering (invalid_sched):") +print(pmap(SIO_invalid)) # Dependencies and constraints: -print("----------------------------------------------------------------------") +print("-"*80) -# i is parallel, suppose we want to enforce the following: -# for a given i, statement 0 happens before statement 1 -# i dependency is none, j dependency is `prior` +# make some dependencies manually: -statement_var = 's' -unused_param_name = 'unused' - -domains = {} -for iname in all_necessary_inames_ordered: - domains[iname] = knl.get_inames_domain(iname) - -# make some dependencies manually for now: s0 = LexScheduleStatement(insn_id="0", within_inames={"i", "j"}) s1 = LexScheduleStatement(insn_id="1", within_inames={"i", "j"}) insnid_to_int_sid = {"0": 0, "1": 1} -statement_pair_dep_set = StatementPairDependencySet(s0, s1, {dt.SAME: ["i", "j"]}) +statement_pair_dep_set = StatementPairDependencySet( + s0, s1, {dt.SAME: ["i", "j"]}) +# SAME({i,j}) means: +# insn0{i,j} happens before insn1{i',j'} iff i = i' and j = j' + +print("Statement pair dependency set:") print(statement_pair_dep_set) -combined_doms = knl.get_inames_domain( - statement_pair_dep_set.statement_before.within_inames | # noqa - statement_pair_dep_set.statement_after.within_inames - ) + dom_before = knl.get_inames_domain( statement_pair_dep_set.statement_before.within_inames ) dom_after = knl.get_inames_domain( statement_pair_dep_set.statement_after.within_inames ) -loop_priority = None # TODO + +loop_priority = None constraint_map = create_dependency_constraint( statement_pair_dep_set, dom_before, @@ -147,20 +131,65 @@ constraint_map = create_dependency_constraint( insnid_to_int_sid, unused_param_name, statement_var, - all_dom_inames_ordered=all_necessary_inames_ordered, + #all_dom_inames_ordered=inames, # not necessary since algin spaces below ) -print("constraint map space:") +print("constraint map (before aligning space):") +print(pmap(constraint_map)) + +assert SIO_valid.space == SIO_invalid.space + +# align constraint map spaces to match sio so we can compare them + +print("constraint map space (before aligning):") print(constraint_map.space) + +# align params +aligned_constraint_map = constraint_map.align_params(SIO_valid.space) + +# align in_ dims +import islpy as isl +from schedule_checker.sched_check_utils import ( + reorder_dims_by_name, +) +SIO_valid_in_names = SIO_valid.space.get_var_names(isl.dim_type.in_) +aligned_constraint_map = reorder_dims_by_name( + aligned_constraint_map, + isl.dim_type.in_, + SIO_valid_in_names, + add_missing=False, + new_names_are_permutation_only=True, + ) + +# align out dims +aligned_constraint_map = reorder_dims_by_name( + aligned_constraint_map, + isl.dim_type.out, + append_apostrophes(SIO_valid_in_names), + # TODO SIO out names are only pretending to have apostrophes; confusing + add_missing=False, + new_names_are_permutation_only=True, + ) + +assert aligned_constraint_map.space == SIO_valid.space +assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.in_) + == SIO_valid.space.get_var_names(isl.dim_type.in_)) +assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.out) + == append_apostrophes(SIO_valid.space.get_var_names(isl.dim_type.out))) +assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.param) + == SIO_valid.space.get_var_names(isl.dim_type.param)) + +print("constraint map space (after aligning):") +print(aligned_constraint_map.space) +print("constraint map (after aligning space):") +print(pmap(aligned_constraint_map)) print("SIO space:") -print(SIO_explicit_valid.space) -#assert constraint_map.space == SIO_explicit_valid.space -print("constraint map:") -print(prettier_map_string(constraint_map)) +print(SIO_valid.space) print("is valid sched valid?") -print(constraint_map.is_subset(SIO_explicit_valid)) -#print(SIO_explicit_valid.is_subset(constraint_map)) +print(aligned_constraint_map.is_subset(SIO_valid)) print("is invalid sched valid?") -print(constraint_map.is_subset(SIO_explicit_invalid)) -#print(SIO_explicit_invalid.is_subset(constraint_map)) +print(aligned_constraint_map.is_subset(SIO_invalid)) -- GitLab From f99c1783bc1fa2bf46b5a9aa03dcb0fe5da9d39f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 3 Sep 2019 00:55:00 -0500 Subject: [PATCH 133/183] removed now-unused function lex_order_map_tuple_pairs_from_explicit_bounds() --- lexicographic_order_map.py | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 730ffc081..36345539b 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -1,29 +1,6 @@ import islpy as isl -def lex_order_map_tuple_pairs_from_explicit_bounds(dim_bounds): - - # Given list of integer dimension bound pairs - # [(lower0, upper0), (lower1, upper1) ... ], - # create a list of tuple pairs [(x0, x1, ...), (y0, y1, ...)] - # representing a relation that maps from each point - # to every point that comes after that point in a lexicographic ordering - - # lower bounds are inclusive, upper bounds are exclusive - - import itertools - # all lex tuples in order: - lex_tuples = list( - itertools.product(*[range(l, u) for l, u in dim_bounds])) - # goes up to u-1 because u is a non-inclusive upper bound - - map_pairs = [] - for i, l_before in enumerate(lex_tuples): - for l_after in lex_tuples[i+1:]: - map_pairs.append((l_before, l_after)) - return map_pairs - - def get_statement_ordering_map(sched_map, lex_map): # statement ordering: # map each statement instance to all statement instances that occur later -- GitLab From a21c8c3d265b3b2007c41160855c7910a3f33016 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 3 Sep 2019 01:03:24 -0500 Subject: [PATCH 134/183] fixed typo in schedule.create_symbolic_isl_map() docstring --- schedule.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/schedule.py b/schedule.py index a2df9acb3..30b09d8e3 100644 --- a/schedule.py +++ b/schedule.py @@ -240,9 +240,9 @@ class LexSchedule(object): ``statement_var_name`` and ``dom_inames_ordered`` are the names of the dims of the space of the ISL map domain. - .. return: An :class:`islpy.Map` representing the lex schedule as - a mapping from each statement instance to all statement instances - occuring later. + .. return: An :class:`islpy.Map` representing a schedule + as a mapping from each statement instance to a point in + a lexicographic ordering. """ -- GitLab From 99ccd567ff9c507d68caa809bcd1c2b012036fca Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 3 Sep 2019 01:41:00 -0500 Subject: [PATCH 135/183] added docstrings for get_statement_ordering_map() and get_lex_order_constraint() --- lexicographic_order_map.py | 69 +++++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 12 deletions(-) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 36345539b..20cb7c723 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -2,24 +2,68 @@ import islpy as isl def get_statement_ordering_map(sched_map, lex_map): - # statement ordering: - # map each statement instance to all statement instances that occur later - # S -> L -> S^-1 + """Return a mapping that maps each statement instance to + all statement instances occuring later. + + .. arg sched_map: An :class:`islpy.Map` representing a schedule + as a mapping from each statement instance to a point in + a 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') ...} + + .. return: 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 S -> L -> S^-1, where S + is the schedule map and L is the lexicographic ordering map. + + """ + # TODO apostrophes aren't really there for range, this is confusing return sched_map.apply_range(lex_map).apply_range(sched_map.reverse()) -def get_lex_order_constraint(islvars, in_names, out_names): - # create constraint enforcing lex ordering, e.g., in the 3-dim case: - # i0 < o0 or ((i0 = o0) and (i1 < o1)) - # or ((i0 = o0) and (i1 = o1) and (i2 < o2)) - lex_order_constraint = islvars[in_names[0]].lt_set(islvars[out_names[0]]) - for i in range(1, len(in_names)): - lex_order_constraint_conj = islvars[in_names[i]].lt_set( - islvars[out_names[i]]) +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:`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:`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 the 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 the point in lexicographic + time that occurs after. (see example below) + + .. return: An :class:`islpy.Set` representing a constraint that enforces a + lexicographic ordering. E.g., if ``before_names = [i, j, k]`` and + ``after_names = [i', j', k']``, 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[in_names[j]].eq_set(islvars[out_names[j]]) + islvars[before_names[j]].eq_set(islvars[after_names[j]]) lex_order_constraint = lex_order_constraint | lex_order_constraint_conj return lex_order_constraint @@ -29,6 +73,7 @@ def create_symbolic_lex_order_map( in_names=None, out_names=None, ): + if in_names is None: in_names = ["i%s" % (i) for i in range(n_dims)] if out_names is None: -- GitLab From 1a7d0f5372b266bc1283c1e47f2c2170f9ea8ddd Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 3 Sep 2019 01:52:29 -0500 Subject: [PATCH 136/183] added docstring for create_symbolic_lex_order_map(), fixed a few typos --- lexicographic_order_map.py | 59 ++++++++++++++++++++++++++------------ schedule.py | 2 +- 2 files changed, 41 insertions(+), 20 deletions(-) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 20cb7c723..687f18e84 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -40,16 +40,16 @@ def get_lex_order_constraint(islvars, before_names, after_names): 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 the point in lexicographic + 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 the point in lexicographic + the lexicographic space dimensions for a point in lexicographic time that occurs after. (see example below) .. return: An :class:`islpy.Set` representing a constraint that enforces a - lexicographic ordering. E.g., if ``before_names = [i, j, k]`` and - ``after_names = [i', j', k']``, return the set + 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') @@ -70,33 +70,54 @@ def get_lex_order_constraint(islvars, before_names, after_names): def create_symbolic_lex_order_map( n_dims, - in_names=None, - out_names=None, + 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. - if in_names is None: - in_names = ["i%s" % (i) for i in range(n_dims)] - if out_names is None: + .. 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) + + .. return: 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 schedule_checker.sched_check_utils import append_apostrophes - out_names = append_apostrophes(in_names) + after_names = append_apostrophes(before_names) - assert len(in_names) == len(out_names) == n_dims + assert len(before_names) == len(after_names) == n_dims dim_type = isl.dim_type islvars = isl.make_zero_and_vars( - in_names+out_names, + before_names+after_names, []) - # create constraint enforcing lex ordering, e.g., in the 3-dim case: - # i0 < o0 or ((i0 = o0) and (i1 < o1)) - # or ((i0 = o0) and (i1 = o1) and (i2 < o2)) - lex_order_constraint = get_lex_order_constraint(islvars, in_names, out_names) + lex_order_constraint = get_lex_order_constraint(islvars, before_names, after_names) - #lex_set = lex_set_outer_bounds & lex_order_constraint - #lex_map = isl.Map.from_domain(lex_set) lex_map = isl.Map.from_domain(lex_order_constraint) lex_map = lex_map.move_dims( dim_type.out, 0, dim_type.in_, - len(in_names), len(out_names)) + len(before_names), len(after_names)) return lex_map diff --git a/schedule.py b/schedule.py index 30b09d8e3..7595261fd 100644 --- a/schedule.py +++ b/schedule.py @@ -311,7 +311,7 @@ class LexSchedule(object): ) n_dims = self.max_lex_dims() return create_symbolic_lex_order_map( - n_dims, in_names=self.get_lex_var_names()) + n_dims, before_names=self.get_lex_var_names()) def __bool__(self): return bool(self.lex_schedule) -- GitLab From 529f7c8a51deeae6d0430babf9a09d73d328fb94 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 3 Sep 2019 01:55:49 -0500 Subject: [PATCH 137/183] renamed create_symbolic_lex_order_map()->create_lex_order_map() --- example_dependency_checking.py | 4 ++-- example_lex_map_creation.py | 4 ++-- lexicographic_order_map.py | 2 +- schedule.py | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/example_dependency_checking.py b/example_dependency_checking.py index 0f04aee95..52c554607 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -5,7 +5,7 @@ from schedule_checker.dependency import ( # noqa create_dependency_constraint, ) from schedule_checker.lexicographic_order_map import ( - create_symbolic_lex_order_map, + create_lex_order_map, get_statement_ordering_map, ) from schedule_checker.sched_check_utils import ( @@ -80,7 +80,7 @@ print(pmap(example_sched_invalid)) # Lexicographic order map- map each tuple to all tuples occuring later print("-"*80) n_dims = 2 -lex_order_map = create_symbolic_lex_order_map(n_dims) +lex_order_map = create_lex_order_map(n_dims) print("lexicographic order map:") print(pmap(lex_order_map)) diff --git a/example_lex_map_creation.py b/example_lex_map_creation.py index dde4e001e..83ff538d3 100644 --- a/example_lex_map_creation.py +++ b/example_lex_map_creation.py @@ -1,6 +1,6 @@ from schedule_checker.lexicographic_order_map import ( get_statement_ordering_map, - create_symbolic_lex_order_map, + create_lex_order_map, ) from schedule_checker.sched_check_utils import ( create_explicit_map_from_tuples, @@ -11,7 +11,7 @@ from schedule_checker.sched_check_utils import ( # Lexicographic order map- map each tuple to all tuples occuring later n_dims = 2 -lex_order_map = create_symbolic_lex_order_map(n_dims) +lex_order_map = create_lex_order_map(n_dims) print("lexicographic order map:") print(pmap(lex_order_map)) diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 687f18e84..356fb8731 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -68,7 +68,7 @@ def get_lex_order_constraint(islvars, before_names, after_names): return lex_order_constraint -def create_symbolic_lex_order_map( +def create_lex_order_map( n_dims, before_names=None, after_names=None, diff --git a/schedule.py b/schedule.py index 7595261fd..34af2cfbb 100644 --- a/schedule.py +++ b/schedule.py @@ -307,10 +307,10 @@ class LexSchedule(object): """ from schedule_checker.lexicographic_order_map import ( - create_symbolic_lex_order_map, + create_lex_order_map, ) n_dims = self.max_lex_dims() - return create_symbolic_lex_order_map( + return create_lex_order_map( n_dims, before_names=self.get_lex_var_names()) def __bool__(self): -- GitLab From cb639d9accd0d3ba12cb297ee4ed20e9a38b8594 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 3 Sep 2019 02:06:06 -0500 Subject: [PATCH 138/183] removed more unused functions; added TODOs for remaining docstrings --- sched_check_utils.py | 96 +++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 55 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 6c6e87332..a0a9ccc9f 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -28,6 +28,7 @@ def add_dims_to_isl_set(isl_set, dim_type, names, new_pose_start): def reorder_dims_by_name( isl_set, dim_type, desired_dims_ordered, add_missing=False, new_names_are_permutation_only=False): + # TODO add docstring assert set(isl_set.get_var_names(dim_type)).issubset(desired_dims_ordered) assert dim_type != isl.dim_type.param @@ -70,6 +71,7 @@ def reorder_dims_by_name( def create_new_set_with_primes(old_set): + # TODO add docstring new_set = old_set.copy() for i in range(old_set.n_dim()): new_set = new_set.set_dim_name(isl.dim_type.out, i, old_set.get_dim_name( @@ -78,6 +80,7 @@ def create_new_set_with_primes(old_set): def make_islvars_with_var_primes(var_names, param_names): + # TODO add docstring return isl.make_zero_and_vars( var_names+append_apostrophes(var_names), param_names) @@ -96,24 +99,6 @@ def _union_of_isl_sets_or_maps(set_list): return union -def _union_inames_domains(knl): - all_inames = list(knl.all_inames()) - domain_union = knl.get_inames_domain(all_inames[0]) - for iname in all_inames[1:]: - domain_union = domain_union.union(knl.get_inames_domain(iname)) - return domain_union - - -def all_iname_domains_equal(knl): - all_inames = list(knl.all_inames()) - - first = knl.get_inames_domain(all_inames[0]) - for iname in all_inames[1:]: - if knl.get_inames_domain(iname) != first: - return False - return True - - def list_var_names_in_isl_sets( isl_sets, set_dim=isl.dim_type.set): @@ -123,39 +108,13 @@ def list_var_names_in_isl_sets( return list(inames) -def create_explicit_map_from_tuples(tuple_pairs, space): - - dim_type = isl.dim_type - individual_maps = [] - - for tup_in, tup_out in tuple_pairs: - constraints = [] - for i, val_in in enumerate(tup_in): - constraints.append( - isl.Constraint.equality_alloc(space) - .set_coefficient_val(dim_type.in_, i, 1) - .set_constant_val(-1*val_in)) - for i, val_out in enumerate(tup_out): - constraints.append( - isl.Constraint.equality_alloc(space) - .set_coefficient_val(dim_type.out, i, 1) - .set_constant_val(-1*val_out)) - individual_maps.append( - isl.Map.universe(space).add_constraints(constraints)) - - union_map = individual_maps[0] - for m in individual_maps[1:]: - union_map = union_map.union(m) - - return union_map - - def create_symbolic_isl_map_from_tuples( tuple_pairs_with_domains, # list of ((tup_in, tup_out), dom_to_intersect) space, unused_param_name, statement_var_name, ): + # TODO add docstring # TODO clarify this with comments @@ -243,8 +202,9 @@ def create_symbolic_isl_map_from_tuples( return _union_of_isl_sets_or_maps(all_maps) -def set_space_names( +def set_all_space_names( space, param_names=None, in_names=None, out_names=None): + # TODO add docstring new_space = space.copy() dim_type = isl.dim_type if param_names: @@ -269,9 +229,10 @@ def set_space_names( def get_isl_space(param_names, in_names, out_names): + # TODO add docstring space = isl.Space.alloc( isl.DEFAULT_CONTEXT, len(param_names), len(in_names), len(out_names)) - return set_space_names( + return set_all_space_names( space, param_names=param_names, in_names=in_names, out_names=out_names) @@ -303,6 +264,7 @@ def _get_insn_id_from_sched_item(knl, sched_item): # loop over schedule more than once def get_all_nonconcurrent_insn_iname_subsets( knl, exclude_empty=False, non_conc_inames=None): + # TODO add docstring if non_conc_inames is None: _, non_conc_inames = get_concurrent_inames(knl) @@ -318,7 +280,6 @@ def get_all_nonconcurrent_insn_iname_subsets( def get_sched_item_ids_within_inames(knl, inames): - sched_item_ids = set() for insn in knl.instructions: if inames.issubset(insn.within_inames): @@ -326,13 +287,6 @@ def get_sched_item_ids_within_inames(knl, inames): return sched_item_ids -def get_inames_in_sched_order(scheduled_knl): - # returns non-concurrent inames in order found in sched - from loopy.schedule import EnterLoop - return [sched_item.iname for sched_item in scheduled_knl.schedule - if isinstance(sched_item, EnterLoop)] - - # TODO use yield to clean this up # TODO use topological sort from loopy, then find longest path in dag def _generate_orderings_starting_w_prefix( @@ -376,6 +330,7 @@ def _generate_orderings_starting_w_prefix( def get_orderings_of_length_n( allowed_after_dict, required_length, return_first_found=False): + # TODO add docstring # get all orderings that are *explicitly* allowed by allowed_after_dict # i.e., if we know a->b and c->b, we don't know enough to return a->c->b @@ -392,3 +347,34 @@ def get_orderings_of_length_n( return_first_found=return_first_found, ) return orderings + + +# only used for example purposes: + + +def create_explicit_map_from_tuples(tuple_pairs, space): + # TODO add docstring + + dim_type = isl.dim_type + individual_maps = [] + + for tup_in, tup_out in tuple_pairs: + constraints = [] + for i, val_in in enumerate(tup_in): + constraints.append( + isl.Constraint.equality_alloc(space) + .set_coefficient_val(dim_type.in_, i, 1) + .set_constant_val(-1*val_in)) + for i, val_out in enumerate(tup_out): + constraints.append( + isl.Constraint.equality_alloc(space) + .set_coefficient_val(dim_type.out, i, 1) + .set_constant_val(-1*val_out)) + individual_maps.append( + isl.Map.universe(space).add_constraints(constraints)) + + union_map = individual_maps[0] + for m in individual_maps[1:]: + union_map = union_map.union(m) + + return union_map -- GitLab From a566ba4f2f046919e175643e39cdf65438843a89 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Sep 2019 21:24:59 -0500 Subject: [PATCH 139/183] docstring for add_dims_to_isl_set() --- sched_check_utils.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index a0a9ccc9f..1604d7f0a 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -28,7 +28,33 @@ def add_dims_to_isl_set(isl_set, dim_type, names, new_pose_start): def reorder_dims_by_name( isl_set, dim_type, desired_dims_ordered, add_missing=False, new_names_are_permutation_only=False): - # TODO add docstring + """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` specifying the + dimension to be reordered. + + .. arg desired_dims_ordered: A :class:`list` of :class:`string` 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. + + .. return: 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 -- GitLab From 15e6e86b0e150ea3faab070611293685fe20111a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Sep 2019 21:29:01 -0500 Subject: [PATCH 140/183] renamed create_new_set_with_primes()->create_new_isl_set_with_primes() and added docstring --- dependency.py | 4 ++-- sched_check_utils.py | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/dependency.py b/dependency.py index 8a118bdc5..50fefa1cb 100644 --- a/dependency.py +++ b/dependency.py @@ -184,7 +184,7 @@ def create_dependency_constraint( append_apostrophes, add_dims_to_isl_set, reorder_dims_by_name, - create_new_set_with_primes, + create_new_isl_set_with_primes, ) # This function uses the dependency given to create the following constraint: # Statement [s,i,j] comes before statement [s',i',j'] iff @@ -344,7 +344,7 @@ def create_dependency_constraint( domain_to_intersect = add_dims_to_isl_set( dom_before_constraint_set, isl.dim_type.out, [statement_var_name], statement_var_pose) - range_constraint_set = create_new_set_with_primes(dom_after_constraint_set) + range_constraint_set = create_new_isl_set_with_primes(dom_after_constraint_set) range_to_intersect = add_dims_to_isl_set( range_constraint_set, isl.dim_type.out, [statement_var_name_prime], statement_var_pose) diff --git a/sched_check_utils.py b/sched_check_utils.py index 1604d7f0a..b0a35e9de 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -96,12 +96,18 @@ def reorder_dims_by_name( return new_set -def create_new_set_with_primes(old_set): - # TODO add docstring - new_set = old_set.copy() - for i in range(old_set.n_dim()): - new_set = new_set.set_dim_name(isl.dim_type.out, i, old_set.get_dim_name( - isl.dim_type.out, i)+"'") +def create_new_isl_set_with_primes(old_isl_set): + """Return an isl_set with apostrophes appended to + dim_type.set dimension names. + + .. arg old_isl_set: A :class:`islpy.Set`. + + """ + + new_set = old_isl_set.copy() + for i in range(old_isl_set.n_dim()): + new_set = new_set.set_dim_name(isl.dim_type.set, i, old_isl_set.get_dim_name( + isl.dim_type.set, i)+"'") return new_set -- GitLab From 16de2a29dd8305782b86c9aa33473514834d4ca7 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Sep 2019 21:36:27 -0500 Subject: [PATCH 141/183] docstring for make_islvars_with_var_primes() --- sched_check_utils.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index b0a35e9de..2300f4a45 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -36,7 +36,7 @@ def reorder_dims_by_name( .. arg dim_type: A :class:`islpy.dim_type` specifying the dimension to be reordered. - .. arg desired_dims_ordered: A :class:`list` of :class:`string` elements + .. 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 @@ -102,6 +102,9 @@ def create_new_isl_set_with_primes(old_isl_set): .. arg old_isl_set: A :class:`islpy.Set`. + .. return: A :class:`islpy.Set` matching `old_isl_set` with + apostrophes appended to dim_type.set dimension names. + """ new_set = old_isl_set.copy() @@ -112,7 +115,25 @@ def create_new_isl_set_with_primes(old_isl_set): def make_islvars_with_var_primes(var_names, param_names): - # TODO add docstring + """Return a dictionary from variable and parameter names + to :class:`PwAff` instances that represent each of + the variables and parameters, including + both the variables in `var_names` and a copy of each + variable with an apostrophe appended. + + .. arg var_names: A :class:`list` of :class:`str` elements + representing variable names. + + .. arg param_names: A :class:`list` of :class:`str` elements + representing parameter names. + + .. return: A dictionary from variable names to :class:`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:`PwAff` zero constant. + + """ + return isl.make_zero_and_vars( var_names+append_apostrophes(var_names), param_names) -- GitLab From b28a0093bc1fa050b9af23a214c74469c94084cd Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Sep 2019 22:21:27 -0500 Subject: [PATCH 142/183] docstring for create_symbolic_isl_map_from_tuples(); other minor improvements to documentation --- sched_check_utils.py | 52 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 2300f4a45..3d7a20281 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -33,8 +33,8 @@ def reorder_dims_by_name( .. arg isl_set: A :class:`islpy.Set` whose dimensions are to be reordered. - .. arg dim_type: A :class:`islpy.dim_type` specifying the - dimension to be reordered. + .. arg dim_type: A :class:`islpy.dim_type`, i.e., a :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. @@ -162,18 +162,50 @@ def list_var_names_in_isl_sets( def create_symbolic_isl_map_from_tuples( - tuple_pairs_with_domains, # list of ((tup_in, tup_out), dom_to_intersect) + tuple_pairs_with_domains, space, unused_param_name, statement_var_name, ): - # TODO add docstring + """Return a :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 unused_param_name: A :class:`str` that specifies the name of a + dummy isl parameter assigned to variables in domain elements of the + isl map that represent inames unused in a particular statement + instance. An element in the domain of this map may + represent a statement instance that does not lie within iname x, but + will still need to assign a value to the x domain variable. In this + case, the parameter unused_param_name is is assigned to x. This + situation is detected when a name present in `in_` dimension of + the space is not present in a particular domain. + + .. arg statement_var_name: A :class:`str` specifying the name of the + isl variable used to represent the unique :class:`int` statement id. + + .. return: 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. Any space `in_` dimension variable not + constrained by `domain` is assigned `unused_param_name`. - # TODO clarify this with comments + """ - # given a list of pairs of ((input), (output)) tuples, create an isl map - # and intersect each pair with corresponding domain_to_intersect - #TODO allow None for domains + # TODO clarify this with more comments + # TODO allow None for domains dim_type = isl.dim_type @@ -206,7 +238,7 @@ def create_symbolic_isl_map_from_tuples( # TODO we probably shouldn't rely on dom # here for determing where to set inames equal to dummy vars, # should instead determine before in LexSchedule and pass info in - dom_var_names = dom.get_var_names(dim_type.out) + dom_var_names = dom.get_var_names(dim_type.set) if not set( [var for var in tup_out if not isinstance(var, int)] ).issubset(set(dom_var_names)): @@ -242,7 +274,7 @@ def create_symbolic_isl_map_from_tuples( # 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.out, + dom, isl.dim_type.set, space_in_names, add_missing=True, new_names_are_permutation_only=False, -- GitLab From c832fe83937ef1e8c5bdce24078619a26bf35be3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Sep 2019 22:28:14 -0500 Subject: [PATCH 143/183] renamed set_all_space_names()->set_all_isl_space_names() and added docstring --- sched_check_utils.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 3d7a20281..33f3c7725 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -287,28 +287,34 @@ def create_symbolic_isl_map_from_tuples( return _union_of_isl_sets_or_maps(all_maps) -def set_all_space_names( - space, param_names=None, in_names=None, out_names=None): - # TODO add docstring - new_space = space.copy() +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(space.get_var_names(dim_type.param))): + 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(space.get_var_names(dim_type.in_))): + 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(space.get_var_names(dim_type.out))): + 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 @@ -317,7 +323,7 @@ def get_isl_space(param_names, in_names, out_names): # TODO add docstring space = isl.Space.alloc( isl.DEFAULT_CONTEXT, len(param_names), len(in_names), len(out_names)) - return set_all_space_names( + return set_all_isl_space_names( space, param_names=param_names, in_names=in_names, out_names=out_names) -- GitLab From 87e6ea4dd84725a3629bd63ae092b0b921769372 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Sep 2019 22:30:21 -0500 Subject: [PATCH 144/183] docstring for get_isl_space() --- sched_check_utils.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 33f3c7725..3d1583a67 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -33,7 +33,7 @@ def reorder_dims_by_name( .. arg isl_set: A :class:`islpy.Set` whose dimensions are to be reordered. - .. arg dim_type: A :class:`islpy.dim_type`, i.e., a :class:`int`, + .. 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 @@ -167,7 +167,7 @@ def create_symbolic_isl_map_from_tuples( unused_param_name, statement_var_name, ): - """Return a :class:`islpy.Map` constructed using the provided 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. @@ -320,7 +320,9 @@ def set_all_isl_space_names( def get_isl_space(param_names, in_names, out_names): - # TODO add docstring + """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( -- GitLab From 2961533a8c4b4d2c279ff8d2cf55aa2101c49608 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Sep 2019 22:40:30 -0500 Subject: [PATCH 145/183] docstring for get_all_nonconcurrent_insn_iname_subsets() --- sched_check_utils.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 3d1583a67..15cd89380 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -357,7 +357,21 @@ def _get_insn_id_from_sched_item(knl, sched_item): # loop over schedule more than once def get_all_nonconcurrent_insn_iname_subsets( knl, exclude_empty=False, non_conc_inames=None): - # TODO add docstring + """Return a :class:`set` of every unique subset of non-concurrent + inames used in an instruction in a :class:`loopy.LoopKernel`. + + .. arg knl: A :class:`loopy.LoopKernel`. + + .. arg exclude_empty: A :class:`bool` specifying whether to + exclude the empty set. + + .. arg non_conc_inames: A :class:`set` of non-concurrent inames + which may be provided if already known. + + .. return: A :class:`set` of every unique subset of non-concurrent + inames used in every instruction in a :class:`loopy.LoopKernel`. + + """ if non_conc_inames is None: _, non_conc_inames = get_concurrent_inames(knl) -- GitLab From 1727e2093ff2ebdaa4d45539405e59862b1b2aec Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Sep 2019 22:50:31 -0500 Subject: [PATCH 146/183] docstring for get_orderings_of_length_n() --- sched_check_utils.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 15cd89380..4f59d4a56 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -369,7 +369,7 @@ def get_all_nonconcurrent_insn_iname_subsets( which may be provided if already known. .. return: A :class:`set` of every unique subset of non-concurrent - inames used in every instruction in a :class:`loopy.LoopKernel`. + inames used in any instruction in a :class:`loopy.LoopKernel`. """ @@ -437,13 +437,25 @@ def _generate_orderings_starting_w_prefix( def get_orderings_of_length_n( allowed_after_dict, required_length, return_first_found=False): - # TODO add docstring - # get all orderings that are *explicitly* allowed by allowed_after_dict - # i.e., if we know a->b and c->b, we don't know enough to return a->c->b + """Return all orderings found in tree represented by `allowed_after_dict`. - # note: if the set for a dict key is empty, nothing allowed to come after + .. arg allowed_after_dict: A :class:`dict` mapping each :class:`string` + names to a :class:`set` of names that are allowed to come after + that name. - # alowed_after_dict = {str: set(str)} + .. arg required_length: A :class:`int` representing the length required + for all orderings. Orderings not matching the required length will + not be returned. + + .. arg return_first_found: A :class:`bool` specifying whether to return + the first valid ordering found. + + .. return: A :class:`set` of all orderings that are *explicitly* allowed + by the tree represented by `allowed_after_dict`. I.e., if we know + a->b and c->b, we don't know enough to return a->c->b. Note that + if the set for a dict key is empty, nothing is allowed to come after. + + """ orderings = set() _generate_orderings_starting_w_prefix( -- GitLab From 711e20fa220e5750286fc2b15218dba0dfb156fb Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Sep 2019 22:55:42 -0500 Subject: [PATCH 147/183] docstring for create_explicit_map_from_tuples() --- sched_check_utils.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/sched_check_utils.py b/sched_check_utils.py index 4f59d4a56..575923753 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -472,7 +472,13 @@ def get_orderings_of_length_n( def create_explicit_map_from_tuples(tuple_pairs, space): - # TODO add docstring + """Return a :class:`islpy.Map` in :class:`islpy.Space` space + mapping tup_in->tup_out for each `(tup_in, tup_out)` pair + in `tuple_pairs`, where `tup_in` and `tup_out` are + tuples of :class:`int` values to be assigned to the + corresponding dimension variables in `space`. + + """ dim_type = isl.dim_type individual_maps = [] -- GitLab From f8c3cfd13dd47f4ba616b091b16682825cde9fd9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 17 Sep 2019 12:15:00 -0500 Subject: [PATCH 148/183] switching example kernel --- example_pairwise_schedule_validity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 4a62c791d..0c5b1f61f 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -5,8 +5,8 @@ from schedule_checker import check_schedule_validity # Choose kernel ---------------------------------------------------------- -#knl_choice = "example" -knl_choice = "unused_inames" +knl_choice = "example" +#knl_choice = "unused_inames" #knl_choice = "matmul" #knl_choice = "scan" #knl_choice = "dependent_domain" -- GitLab From c8224a278da80ddbb18b1b2dfbf770373d1acd12 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 12 Nov 2019 16:46:31 -0600 Subject: [PATCH 149/183] WIP: adding wave equation example --- dependency.py | 124 ++++++++++++++ example_wave_equation.py | 338 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 462 insertions(+) create mode 100644 example_wave_equation.py diff --git a/dependency.py b/dependency.py index 50fefa1cb..d30f1a80e 100644 --- a/dependency.py +++ b/dependency.py @@ -367,6 +367,130 @@ def create_dependency_constraint( return map_with_loop_domain_constraints +def _create_5pt_stencil_dependency_constraint( + dom_before_constraint_set, + dom_after_constraint_set, + sid_before, + sid_after, + space_iname, + time_iname, + unused_param_name, + statement_var_name, + statement_var_pose=0, + all_dom_inames_ordered=None, + ): + + from schedule_checker.sched_check_utils import ( + make_islvars_with_var_primes, + append_apostrophes, + add_dims_to_isl_set, + reorder_dims_by_name, + create_new_isl_set_with_primes, + ) + # This function uses the dependency given to create the following constraint: + # Statement [s,i,j] comes before statement [s',i',j'] iff + + from schedule_checker.sched_check_utils import ( + list_var_names_in_isl_sets, + ) + if all_dom_inames_ordered is None: + all_dom_inames_ordered = list_var_names_in_isl_sets( + [dom_before_constraint_set, dom_after_constraint_set]) + + # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} + islvars = make_islvars_with_var_primes( + [statement_var_name]+all_dom_inames_ordered, + [unused_param_name]) + statement_var_name_prime = statement_var_name+"'" + + # get (ordered) list of unused before/after inames + inames_before_unused = [] + for iname in all_dom_inames_ordered: + if iname not in dom_before_constraint_set.get_var_names(isl.dim_type.out): + inames_before_unused.append(iname) + inames_after_unused = [] + for iname in all_dom_inames_ordered: + if iname not in dom_after_constraint_set.get_var_names(isl.dim_type.out): + inames_after_unused.append(iname + "'") + + # initialize constraints to False + # this will disappear as soon as we add a constraint + #all_constraints_set = islvars[0].eq_set(islvars[0] + 1) + + space_iname_prime = space_iname + "'" + time_iname_prime = time_iname + "'" + one = islvars[0] + 1 + two = islvars[0] + 2 + # global: + """ + constraint_set = ( + islvars[time_iname_prime].gt_set(islvars[time_iname]) & + ( + (islvars[space_iname_prime]-two).lt_set(islvars[space_iname]) & + islvars[space_iname].lt_set(islvars[space_iname_prime]+two) + ) + | + islvars[time_iname_prime].gt_set(islvars[time_iname] + one) & + islvars[space_iname].eq_set(islvars[space_iname_prime]) + ) + """ + # local dep: + constraint_set = ( + islvars[time_iname_prime].eq_set(islvars[time_iname] + one) & + ( + (islvars[space_iname_prime]-two).lt_set(islvars[space_iname]) & + islvars[space_iname].lt_set(islvars[space_iname_prime]+two) + ) + | + islvars[time_iname_prime].eq_set(islvars[time_iname] + two) & + islvars[space_iname].eq_set(islvars[space_iname_prime]) + ) + + + # set unused vars == unused dummy param + for iname in inames_before_unused+inames_after_unused: + constraint_set = constraint_set & islvars[iname].eq_set( + islvars[unused_param_name]) + + # set statement_var_name == statement # + constraint_set = constraint_set & islvars[statement_var_name].eq_set( + islvars[0]+sid_before) + constraint_set = constraint_set & islvars[statement_var_name_prime].eq_set( + islvars[0]+sid_after) + + # convert constraint set to map + all_constraints_map = _convert_constraint_set_to_map( + constraint_set, len(all_dom_inames_ordered) + 1) # +1 for statement var + + # now apply domain sets to constraint variables + + # add statement variable to doms to enable intersection + domain_to_intersect = add_dims_to_isl_set( + dom_before_constraint_set, isl.dim_type.out, + [statement_var_name], statement_var_pose) + range_constraint_set = create_new_isl_set_with_primes(dom_after_constraint_set) + range_to_intersect = add_dims_to_isl_set( + range_constraint_set, isl.dim_type.out, + [statement_var_name_prime], statement_var_pose) + + # insert inames missing from doms to enable intersection + domain_to_intersect = reorder_dims_by_name( + domain_to_intersect, isl.dim_type.out, + [statement_var_name] + all_dom_inames_ordered, + add_missing=True) + range_to_intersect = reorder_dims_by_name( + range_to_intersect, + isl.dim_type.out, + append_apostrophes([statement_var_name] + all_dom_inames_ordered), + add_missing=True) + + # intersect doms + map_with_loop_domain_constraints = all_constraints_map.intersect_domain( + domain_to_intersect).intersect_range(range_to_intersect) + + return map_with_loop_domain_constraints + + def create_dependencies_from_legacy_knl(knl): """Return a list of :class:`StatementPairDependySet` instances created for a :class:`loopy.LoopKernel` containing legacy depencencies. Create diff --git a/example_wave_equation.py b/example_wave_equation.py new file mode 100644 index 000000000..1fe656544 --- /dev/null +++ b/example_wave_equation.py @@ -0,0 +1,338 @@ +import loopy as lp +import numpy as np +from loopy.kernel_stat_collector import KernelStatCollector +from loopy.kernel_stat_collector import KernelStatOptions as kso # noqa +from schedule_checker import check_schedule_validity +from schedule_checker.sched_check_utils import ( + prettier_map_string, +) + +# Make kernel ---------------------------------------------------------- + +# u[x,t+1] = 2*u[x,t] - u[x,t-1] + c*(dt/dx)**2*(u[x+1,t] - 2*u[x,t] + u[x-1,t]) +knl = lp.make_kernel( + "{[x,t]: 0<=x lex time):") + #print(sched_map_symbolic.space) + #print("-"*80) + +# get map representing lexicographic ordering +lex_order_map_symbolic = sched.get_lex_order_map_for_symbolic_sched() +""" +if verbose: + print("lex order map symbolic:") + print(prettier_map_string(lex_order_map_symbolic)) + print("space (lex time -> lex time):") + print(lex_order_map_symbolic.space) + print("-"*80) +""" + +# create statement instance ordering, +# maps each statement instance to all statement instances occuring later +sio = get_statement_ordering_map( + sched_map_symbolic, lex_order_map_symbolic) + +if verbose: + print("statement instance ordering:") + print(prettier_map_string(sio)) + print("SIO space (statement instances -> statement instances):") + print(sio.space) + print("-"*80) + +# create a map representing constraints from the dependency, +# maps statement instance to all statement instances that must occur later +""" +constraint_map = create_dependency_constraint( + statement_pair_dep_set, + inames_domain_before, + inames_domain_after, + knl.loop_priority, + lp_insn_id_to_lex_sched_id, + sched.unused_param_name, + sched.statement_var_name, + ) +""" + +# align constraint map spaces to match sio so we can compare them +if verbose: + print("constraint map space (before aligning):") + print(constraint_map.space) + +# align params +aligned_constraint_map = constraint_map.align_params(sio.space) + +# align in_ dims +import islpy as isl +from schedule_checker.sched_check_utils import ( + reorder_dims_by_name, + append_apostrophes, +) +sio_in_names = sio.space.get_var_names(isl.dim_type.in_) +aligned_constraint_map = reorder_dims_by_name( + aligned_constraint_map, + isl.dim_type.in_, + sio_in_names, + add_missing=False, + new_names_are_permutation_only=True, + ) + +# align out dims +aligned_constraint_map = reorder_dims_by_name( + aligned_constraint_map, + isl.dim_type.out, + append_apostrophes(sio_in_names), + # TODO sio out names are only pretending to have apostrophes; confusing + add_missing=False, + new_names_are_permutation_only=True, + ) + +if verbose: + print("constraint map space (after aligning):") + print(aligned_constraint_map.space) + print("constraint map:") + print(prettier_map_string(aligned_constraint_map)) + +assert aligned_constraint_map.space == sio.space +assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.in_) + == sio.space.get_var_names(isl.dim_type.in_)) +assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.out) + == append_apostrophes(sio.space.get_var_names(isl.dim_type.out))) +assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.param) + == sio.space.get_var_names(isl.dim_type.param)) + +if not aligned_constraint_map.is_subset(sio): + + sched_is_valid = False + + if verbose: + print("================ constraint check failure =================") + print("constraint map not subset of SIO") + print("dependency:") + print(statement_pair_dep_set) + print("statement instance ordering:") + print(prettier_map_string(sio)) + print("constraint_map.gist(sio):") + print(aligned_constraint_map.gist(sio)) + print("sio.gist(constraint_map)") + print(sio.gist(aligned_constraint_map)) + print("loop priority known:") + print(preprocessed_knl.loop_priority) + """ + from schedule_checker.sched_check_utils import ( + get_concurrent_inames, + ) + conc_inames, non_conc_inames = get_concurrent_inames(scheduled_knl) + print("concurrent inames:", conc_inames) + print("sequential inames:", non_conc_inames) + print("constraint map space (stmt instances -> stmt instances):") + print(aligned_constraint_map.space) + print("SIO space (statement instances -> statement instances):") + print(sio.space) + print("constraint map:") + print(prettier_map_string(aligned_constraint_map)) + print("statement instance ordering:") + print(prettier_map_string(sio)) + print("{insn id -> sched sid int} dict:") + print(lp_insn_id_to_lex_sched_id) + """ + print("===========================================================") + + +print("is sched valid? constraint map subset of SIO?") +print(sched_is_valid) + + + + +""" +knl = lp.split_iname(knl, "i", bsize, outer_tag="g.0", inner_tag="l.1") +knl = lp.split_iname(knl, "j", bsize, outer_tag="g.1", inner_tag="l.0") +knl = lp.split_iname(knl, "k", bsize) +knl = lp.add_prefetch(knl, "a", ["k_inner", "i_inner"], default_tag="l.auto") +knl = lp.add_prefetch(knl, "b", ["j_inner", "k_inner"], default_tag="l.auto") +knl = lp.prioritize_loops(knl, "k_outer,k_inner") +""" + +''' +# (U_n^{k+1}-U_n^k)/dt = C*(U_{n+1}^k-U_n^k)/dx +# U_n^{k+1} = U_n^k + dt/dx*C*(U_{n+1}^k-U_n^k) +knl = lp.make_kernel( + "{[i,k]: 0<=i Date: Wed, 13 Nov 2019 14:28:00 -0600 Subject: [PATCH 150/183] hacked together some schedule checking for map_domain wave equation example --- example_wave_equation.py | 433 ++++++++++++++++++++++++++++++--------- 1 file changed, 338 insertions(+), 95 deletions(-) diff --git a/example_wave_equation.py b/example_wave_equation.py index 1fe656544..b401e52fa 100644 --- a/example_wave_equation.py +++ b/example_wave_equation.py @@ -1,91 +1,100 @@ import loopy as lp +from loopy import generate_code_v2 +from loopy import get_one_scheduled_kernel +from loopy.kernel import KernelState +from loopy import preprocess_kernel import numpy as np -from loopy.kernel_stat_collector import KernelStatCollector -from loopy.kernel_stat_collector import KernelStatOptions as kso # noqa +import islpy as isl +#from loopy.kernel_stat_collector import KernelStatCollector +#from loopy.kernel_stat_collector import KernelStatOptions as kso # noqa from schedule_checker import check_schedule_validity from schedule_checker.sched_check_utils import ( prettier_map_string, + reorder_dims_by_name, + append_apostrophes, +) +from schedule_checker.dependency import ( + create_dependencies_from_legacy_knl, + create_dependency_constraint, +) +from dependency import _create_5pt_stencil_dependency_constraint +from schedule_checker.schedule import LexSchedule +from schedule_checker.lexicographic_order_map import ( + get_statement_ordering_map, ) # Make kernel ---------------------------------------------------------- # u[x,t+1] = 2*u[x,t] - u[x,t-1] + c*(dt/dx)**2*(u[x+1,t] - 2*u[x,t] + u[x-1,t]) +# mine, works: +# "{[x,t]: 1<=x {[ix, it]: 1<=ix {[ix, it] -> [tx, tt, tparity, itt, itx]: " + "16*(tx - tt + tparity) + itx - itt = ix - it and " + "16*(tx + tt) + itt + itx = ix + it and " + "0<=tparity<2 and 0 <= itx - itt < 16 and 0 <= itt+itx < 16}") +m2 = isl.BasicMap( + "[nx,nt,unused] -> {[statement, ix, it] -> [statement'=statement, tx, tt, tparity, itt, itx]: " + "16*(tx - tt + tparity) + itx - itt = ix - it and " + "16*(tx + tt) + itt + itx = ix + it and " + "0<=tparity<2 and 0 <= itx - itt < 16 and 0 <= itt+itx < 16}") +m2_prime = isl.BasicMap( + "[nx,nt,unused] -> {[statement, ix, it] -> [statement'=statement, tx', tt', tparity', itt', itx']: " + "16*(tx' - tt' + tparity') + itx' - itt' = ix - it and " + "16*(tx' + tt') + itt' + itx' = ix + it and " + "0<=tparity'<2 and 0 <= itx' - itt' < 16 and 0 <= itt'+itx' < 16}") + +print("maping:") +print(prettier_map_string(m2)) + +# new kernel +knl = lp.map_domain(ref_knl, m) +knl = lp.prioritize_loops(knl, "tt,tparity,tx,itt,itx") +print("code after mapping:") +print(generate_code_v2(knl).device_code()) + +#print("constraint_map before apply_range:") +#print(prettier_map_string(constraint_map)) +mapped_constraint_map = constraint_map.apply_range(m2_prime) +#print("constraint_map after apply_range:") +#print(prettier_map_string(mapped_constraint_map)) +mapped_constraint_map = mapped_constraint_map.apply_domain(m2) +#print("constraint_map after apply_domain:") +#print(prettier_map_string(mapped_constraint_map)) +#1/0 + +statement_inames_mapped = set(["itx","itt","tt","tparity","tx"]) +sid_before = 0 +sid_after = 0 + +if knl.state < KernelState.PREPROCESSED: + preprocessed_knl = preprocess_kernel(knl) +else: + preprocessed_knl = knl +inames_domain_before_mapped = preprocessed_knl.get_inames_domain(statement_inames_mapped) +inames_domain_after_mapped = preprocessed_knl.get_inames_domain(statement_inames_mapped) +print("(mapped) inames_domain_before:", inames_domain_before_mapped) +print("(mapped) inames_domain_after:", inames_domain_after_mapped) + +# ============================================= + +verbose = False +verbose = True + +# get a schedule to check +if preprocessed_knl.schedule is None: + scheduled_knl = get_one_scheduled_kernel(preprocessed_knl) +else: + scheduled_knl = preprocessed_knl + +# {{{ verbose + +if verbose: + # Print kernel info ------------------------------------------------------ + print("="*80) + print("Kernel:") + print(scheduled_knl) + #print(generate_code_v2(scheduled_knl).device_code()) + print("="*80) + print("Iname tags: %s" % (scheduled_knl.iname_to_tags)) + print("="*80) + print("Loopy schedule:") + for sched_item in scheduled_knl.schedule: + print(sched_item) + #print("scheduled iname order:") + #print(sched_iname_order) + + print("="*80) + print("inames_domain_before_mapped:", inames_domain_before_mapped) + print("inames_domain_after_mapped:", inames_domain_after_mapped) + +# }}} + +# Create a mapping of {statement instance: lex point} +# including only instructions involved in this dependency +sched = LexSchedule(scheduled_knl, include_only_insn_ids=[ + str(sid_before), + str(sid_after) + ]) +# Get an isl map representing the LexSchedule; +# this requires the iname domains + +assert len(sched) in [1, 2] +if len(sched) == 1: + assert inames_domain_before_mapped == inames_domain_after_mapped + +# get a mapping from lex schedule id to relevant inames domain +sid_to_dom = { + sid_before: inames_domain_before_mapped, + sid_after: inames_domain_after_mapped, + } + +sched_map_symbolic = sched.create_symbolic_isl_map(sid_to_dom) + +# {{{ verbose + +if verbose: + print("sid_to_dom:\n", sid_to_dom) + print("LexSchedule after creating symbolic isl map:") + print(sched) + print("LexSched:") + print(prettier_map_string(sched_map_symbolic)) + #print("space (statement instances -> lex time):") + #print(sched_map_symbolic.space) + #print("-"*80) + +# }}} + +# get map representing lexicographic ordering +lex_order_map_symbolic = sched.get_lex_order_map_for_symbolic_sched() + +# {{{ verbose """ -knl = lp.split_iname(knl, "i", bsize, outer_tag="g.0", inner_tag="l.1") -knl = lp.split_iname(knl, "j", bsize, outer_tag="g.1", inner_tag="l.0") -knl = lp.split_iname(knl, "k", bsize) -knl = lp.add_prefetch(knl, "a", ["k_inner", "i_inner"], default_tag="l.auto") -knl = lp.add_prefetch(knl, "b", ["j_inner", "k_inner"], default_tag="l.auto") -knl = lp.prioritize_loops(knl, "k_outer,k_inner") +if verbose: + print("lex order map symbolic:") + print(prettier_map_string(lex_order_map_symbolic)) + print("space (lex time -> lex time):") + print(lex_order_map_symbolic.space) + print("-"*80) """ +# }}} + +# create statement instance ordering, +# maps each statement instance to all statement instances occuring later +sio = get_statement_ordering_map( + sched_map_symbolic, lex_order_map_symbolic) + +# {{{ verbose + +if verbose: + print("statement instance ordering:") + print(prettier_map_string(sio)) + print("SIO space (statement instances -> statement instances):") + print(sio.space) + print("-"*80) + +if verbose: + print("constraint map space (before aligning):") + print(constraint_map.space) + +# }}} + +# align constraint map spaces to match sio so we can compare them +# align params +aligned_constraint_map = mapped_constraint_map.align_params(sio.space) +#print(prettier_map_string(aligned_constraint_map)) + +# align in_ dims +sio_in_names = sio.space.get_var_names(isl.dim_type.in_) +aligned_constraint_map = reorder_dims_by_name( + aligned_constraint_map, + isl.dim_type.in_, + sio_in_names, + add_missing=False, + new_names_are_permutation_only=True, + ) + +#print(".....") +#print(aligned_constraint_map.space) +#print("...") +#print(set(aligned_constraint_map.get_var_names(isl.dim_type.out))) +#ppp = append_apostrophes(sio_in_names) +#print(ppp) +#print(set(aligned_constraint_map.get_var_names(isl.dim_type.out)).issubset(ppp)) +# align out dims +aligned_constraint_map = reorder_dims_by_name( + aligned_constraint_map, + isl.dim_type.out, + #append_apostrophes(sio_in_names), + sio_in_names, # TODO WHY no apostrophes? + # TODO sio out names are only pretending to have apostrophes; confusing + add_missing=False, + new_names_are_permutation_only=True, +) + +# {{{ verbose + +if verbose: + print("constraint map space (after aligning):") + print(aligned_constraint_map.space) + print("constraint map:") + print(prettier_map_string(aligned_constraint_map)) + +# }}} + +assert aligned_constraint_map.space == sio.space +assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.in_) + == sio.space.get_var_names(isl.dim_type.in_)) +assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.out) + == append_apostrophes(sio.space.get_var_names(isl.dim_type.out)) + ) or ( # TODO why no appostrophes? + aligned_constraint_map.space.get_var_names(isl.dim_type.out) + == sio.space.get_var_names(isl.dim_type.out) + ) +assert ( + aligned_constraint_map.space.get_var_names(isl.dim_type.param) + == sio.space.get_var_names(isl.dim_type.param)) + +sched_is_valid = aligned_constraint_map.is_subset(sio) + +if not sched_is_valid: + + # {{{ verbose + + if verbose: + print("================ constraint check failure =================") + print("constraint map not subset of SIO") + print("dependency:") + print(prettier_map_string(constraint_map)) + print("statement instance ordering:") + print(prettier_map_string(sio)) + print("constraint_map.gist(sio):") + print(aligned_constraint_map.gist(sio)) + print("sio.gist(constraint_map)") + print(sio.gist(aligned_constraint_map)) + print("loop priority known:") + print(preprocessed_knl.loop_priority) + """ + from schedule_checker.sched_check_utils import ( + get_concurrent_inames, + ) + conc_inames, non_conc_inames = get_concurrent_inames(scheduled_knl) + print("concurrent inames:", conc_inames) + print("sequential inames:", non_conc_inames) + print("constraint map space (stmt instances -> stmt instances):") + print(aligned_constraint_map.space) + print("SIO space (statement instances -> statement instances):") + print(sio.space) + print("constraint map:") + print(prettier_map_string(aligned_constraint_map)) + print("statement instance ordering:") + print(prettier_map_string(sio)) + print("{insn id -> sched sid int} dict:") + print(lp_insn_id_to_lex_sched_id) + """ + print("===========================================================") + + # }}} + +print("is sched valid? constraint map subset of SIO?") +print(sched_is_valid) + + + + + ''' # (U_n^{k+1}-U_n^k)/dt = C*(U_{n+1}^k-U_n^k)/dx # U_n^{k+1} = U_n^k + dt/dx*C*(U_{n+1}^k-U_n^k) -knl = lp.make_kernel( - "{[i,k]: 0<=i Date: Wed, 13 Nov 2019 19:36:24 -0600 Subject: [PATCH 151/183] update fixed mapping, enforce consistent domain/range variable ordering --- example_wave_equation.py | 58 +++++++++++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/example_wave_equation.py b/example_wave_equation.py index b401e52fa..f167cd865 100644 --- a/example_wave_equation.py +++ b/example_wave_equation.py @@ -43,6 +43,16 @@ knl = lp.make_kernel( assumptions="nx,nt >= 3", lang_version=(2018, 2), ) +''' +ref = lp.make_kernel( + "[nx,nt] -> {[ix, it]: 1<=ix {[ix, it] -> [tx, tt, tparity, itt, itx]: " "16*(tx - tt + tparity) + itx - itt = ix - it and " @@ -294,6 +308,26 @@ m2_prime = isl.BasicMap( "16*(tx' - tt' + tparity') + itx' - itt' = ix - it and " "16*(tx' + tt') + itt' + itx' = ix + it and " "0<=tparity'<2 and 0 <= itx' - itt' < 16 and 0 <= itt'+itx' < 16}") +""" + +# new +m = isl.BasicMap( + "[nx,nt] -> {[ix, it] -> [tx, tt, tparity, itt, itx]: " + "16*(tx - tt) + itx - itt = ix - it and " + "16*(tx + tt + tparity) + itt + itx = ix + it and " + "0<=tparity<2 and 0 <= itx - itt < 16 and 0 <= itt+itx < 16}") +m2 = isl.BasicMap( + "[nx,nt,unused] -> {[statement, ix, it] -> [statement'=statement, tx, tt, tparity, itt, itx]: " + "16*(tx - tt) + itx - itt = ix - it and " + "16*(tx + tt + tparity) + itt + itx = ix + it and " + "0<=tparity<2 and 0 <= itx - itt < 16 and 0 <= itt+itx < 16}") +m2_prime = isl.BasicMap( + "[nx,nt,unused] -> {[statement, ix, it] -> [statement'=statement, tx', tt', tparity', itt', itx']: " + "16*(tx' - tt') + itx' - itt' = ix - it and " + "16*(tx' + tt' + tparity') + itt' + itx' = ix + it and " + "0<=tparity'<2 and 0 <= itx' - itt' < 16 and 0 <= itt'+itx' < 16}") + +# TODO note order must match statement_iname_premap_order print("maping:") print(prettier_map_string(m2)) @@ -301,18 +335,18 @@ print(prettier_map_string(m2)) # new kernel knl = lp.map_domain(ref_knl, m) knl = lp.prioritize_loops(knl, "tt,tparity,tx,itt,itx") -print("code after mapping:") -print(generate_code_v2(knl).device_code()) - -#print("constraint_map before apply_range:") -#print(prettier_map_string(constraint_map)) -mapped_constraint_map = constraint_map.apply_range(m2_prime) -#print("constraint_map after apply_range:") -#print(prettier_map_string(mapped_constraint_map)) +#print("code after mapping:") +#print(generate_code_v2(knl).device_code()) + +print("constraint_map before apply_range:") +print(prettier_map_string(constraint_map)) +#mapped_constraint_map = constraint_map.apply_range(m2_prime) +mapped_constraint_map = constraint_map.apply_range(m2) +print("constraint_map after apply_range:") +print(prettier_map_string(mapped_constraint_map)) mapped_constraint_map = mapped_constraint_map.apply_domain(m2) -#print("constraint_map after apply_domain:") -#print(prettier_map_string(mapped_constraint_map)) -#1/0 +print("constraint_map after apply_domain:") +print(prettier_map_string(mapped_constraint_map)) statement_inames_mapped = set(["itx","itt","tt","tparity","tx"]) sid_before = 0 -- GitLab From ed4f308be528a56e44e31ed5c89dc6dc9d9a0e4b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 25 Nov 2019 10:37:35 -0600 Subject: [PATCH 152/183] initial stab at arbitrary dependency constraint construction --- dependency.py | 173 +++++++++++++++++++++++++++++++++++++++ example_wave_equation.py | 38 ++++++++- sched_check_utils.py | 24 ++++-- 3 files changed, 226 insertions(+), 9 deletions(-) diff --git a/dependency.py b/dependency.py index d30f1a80e..197815951 100644 --- a/dependency.py +++ b/dependency.py @@ -441,6 +441,10 @@ def _create_5pt_stencil_dependency_constraint( (islvars[space_iname_prime]-two).lt_set(islvars[space_iname]) & islvars[space_iname].lt_set(islvars[space_iname_prime]+two) ) + #( + #(islvars[space_iname]-two).lt_set(islvars[space_iname_prime]) & + # islvars[space_iname_prime].lt_set(islvars[space_iname]+two) + #) | islvars[time_iname_prime].eq_set(islvars[time_iname] + two) & islvars[space_iname].eq_set(islvars[space_iname_prime]) @@ -491,6 +495,175 @@ def _create_5pt_stencil_dependency_constraint( return map_with_loop_domain_constraints +def create_arbitrary_dependency_constraint( + constraint_str, + dom_before_constraint_set, + dom_after_constraint_set, + sid_before, + sid_after, + unused_param_name, + statement_var_name, + statement_var_pose=0, + all_dom_inames_ordered=None, + ): + + from schedule_checker.sched_check_utils import ( + make_islvars_with_var_primes, + #append_apostrophes, + append_marker_to_strings, + add_dims_to_isl_set, + reorder_dims_by_name, + create_new_isl_set_with_primes, + ) + # This function uses the constraint given to create the following map: + # Statement [s,i,j] comes before statement [s',i',j'] iff + + from schedule_checker.sched_check_utils import ( + list_var_names_in_isl_sets, + ) + if all_dom_inames_ordered is None: + all_dom_inames_ordered = list_var_names_in_isl_sets( + [dom_before_constraint_set, dom_after_constraint_set]) + + # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} + islvars = make_islvars_with_var_primes( + [statement_var_name]+all_dom_inames_ordered, + [unused_param_name], + marker="p") # TODO figure out before/after notation + #statement_var_name_prime = statement_var_name+"'" + statement_var_name_prime = statement_var_name+"p" # TODO figure out before/after notation + + # get (ordered) list of unused before/after inames + inames_before_unused = [] + for iname in all_dom_inames_ordered: + if iname not in dom_before_constraint_set.get_var_names(isl.dim_type.out): + inames_before_unused.append(iname) + inames_after_unused = [] + for iname in all_dom_inames_ordered: + if iname not in dom_after_constraint_set.get_var_names(isl.dim_type.out): + #inames_after_unused.append(iname + "'") + inames_after_unused.append(iname + "p") # TODO figure out before/after notation + + # initialize constraints to False + # this will disappear as soon as we add a constraint + all_constraints_set = islvars[0].eq_set(islvars[0] + 1) + space = all_constraints_set.space + from pymbolic import parse + from loopy.symbolic import aff_from_expr + + or_constraint_strs = constraint_str.split("or") + def _quant(s): + return "(" + s + ")" + def _diff(s0, s1): + return _quant(s0) + "-" + _quant(s1) + + for or_constraint_str in or_constraint_strs: + and_constraint_strs = or_constraint_str.split("and") + #conj_constraint = islvars[0].eq_set(islvars[0]) # init to true + conj_constraint = isl.BasicSet.universe(space) + for cons_str in and_constraint_strs: + if "<=" in cons_str: + lhs, rhs = cons_str.split("<=") + conj_constraint = conj_constraint.add_constraint( + isl.Constraint.inequality_from_aff( + aff_from_expr(space, parse(_diff(rhs,lhs))))) + # TODO something more robust than this string meddling^ + elif ">=" in cons_str: + lhs, rhs = cons_str.split(">=") + conj_constraint = conj_constraint.add_constraint( + isl.Constraint.inequality_from_aff( + aff_from_expr(space, parse(_diff(lhs,rhs))))) + elif "<" in cons_str: + lhs, rhs = cons_str.split("<") + conj_constraint = conj_constraint.add_constraint( + isl.Constraint.inequality_from_aff( + aff_from_expr(space, parse(_diff(rhs, lhs) + "- 1")))) + elif ">" in cons_str: + lhs, rhs = cons_str.split(">") + conj_constraint = conj_constraint.add_constraint( + isl.Constraint.inequality_from_aff( + aff_from_expr(space, parse(_diff(lhs, rhs) + "- 1")))) + elif "=" in cons_str: + lhs, rhs = cons_str.split("=") + conj_constraint = conj_constraint.add_constraint( + isl.Constraint.equality_from_aff( + aff_from_expr(space, parse(_diff(lhs, rhs))))) + else: + 1/0 + all_constraints_set = all_constraints_set | conj_constraint + + #TODO deleteme + """ + space_iname = "ix" + time_iname = "it" + + space_iname_prime = space_iname + "'" + time_iname_prime = time_iname + "'" + one = islvars[0] + 1 + two = islvars[0] + 2 + # local dep: + constraint_set = ( + islvars[time_iname_prime].eq_set(islvars[time_iname] + one) & + ( + (islvars[space_iname_prime]-two).lt_set(islvars[space_iname]) & + islvars[space_iname].lt_set(islvars[space_iname_prime]+two) + ) + #( + #(islvars[space_iname]-two).lt_set(islvars[space_iname_prime]) & + # islvars[space_iname_prime].lt_set(islvars[space_iname]+two) + #) + | + islvars[time_iname_prime].eq_set(islvars[time_iname] + two) & + islvars[space_iname].eq_set(islvars[space_iname_prime]) + ) + """ + + # set unused vars == unused dummy param + for iname in inames_before_unused+inames_after_unused: + all_constraints_set = all_constraints_set & islvars[iname].eq_set( + islvars[unused_param_name]) + + # set statement_var_name == statement # + all_constraints_set = all_constraints_set & islvars[statement_var_name].eq_set( + islvars[0]+sid_before) + all_constraints_set = all_constraints_set & islvars[statement_var_name_prime].eq_set( + islvars[0]+sid_after) + + # convert constraint set to map + all_constraints_map = _convert_constraint_set_to_map( + all_constraints_set, len(all_dom_inames_ordered) + 1) # +1 for statement var + + # now apply domain sets to constraint variables + + # add statement variable to doms to enable intersection + domain_to_intersect = add_dims_to_isl_set( + dom_before_constraint_set, isl.dim_type.out, + [statement_var_name], statement_var_pose) + range_constraint_set = create_new_isl_set_with_primes( + dom_after_constraint_set, + marker="p") # TODO figure out before/after notation + range_to_intersect = add_dims_to_isl_set( + range_constraint_set, isl.dim_type.out, + [statement_var_name_prime], statement_var_pose) + + # insert inames missing from doms to enable intersection + domain_to_intersect = reorder_dims_by_name( + domain_to_intersect, isl.dim_type.out, + [statement_var_name] + all_dom_inames_ordered, + add_missing=True) + range_to_intersect = reorder_dims_by_name( + range_to_intersect, + isl.dim_type.out, + append_marker_to_strings([statement_var_name] + all_dom_inames_ordered, "p"), # TODO figure out before/after notation + add_missing=True) + + # intersect doms + map_with_loop_domain_constraints = all_constraints_map.intersect_domain( + domain_to_intersect).intersect_range(range_to_intersect) + + return map_with_loop_domain_constraints + + def create_dependencies_from_legacy_knl(knl): """Return a list of :class:`StatementPairDependySet` instances created for a :class:`loopy.LoopKernel` containing legacy depencencies. Create diff --git a/example_wave_equation.py b/example_wave_equation.py index f167cd865..2be546a78 100644 --- a/example_wave_equation.py +++ b/example_wave_equation.py @@ -16,6 +16,7 @@ from schedule_checker.sched_check_utils import ( from schedule_checker.dependency import ( create_dependencies_from_legacy_knl, create_dependency_constraint, + create_arbitrary_dependency_constraint, ) from dependency import _create_5pt_stencil_dependency_constraint from schedule_checker.schedule import LexSchedule @@ -75,6 +76,7 @@ inames_domain_after = preprocessed_knl.get_inames_domain(statement_inames_premap print("(unmapped) inames_domain_before:", inames_domain_before) print("(unmapped) inames_domain_after:", inames_domain_after) +""" constraint_map = _create_5pt_stencil_dependency_constraint( inames_domain_before, inames_domain_after, @@ -90,6 +92,37 @@ constraint_map = _create_5pt_stencil_dependency_constraint( ) print("constraint_map before mapping:") print(prettier_map_string(constraint_map)) +1/0 +""" +""" + islvars[time_iname_prime].eq_set(islvars[time_iname] + one) & + ( + (islvars[space_iname_prime]-two).lt_set(islvars[space_iname]) & + islvars[space_iname].lt_set(islvars[space_iname_prime]+two) + ) + | + islvars[time_iname_prime].eq_set(islvars[time_iname] + two) & + islvars[space_iname].eq_set(islvars[space_iname_prime]) + ) +""" +# TODO testing new dep map +constraint_map = create_arbitrary_dependency_constraint( + "itp = it + 1 and ixp - 2 < ix and ix < ixp + 2 or itp = it + 2 and ix = ixp", + inames_domain_before, + inames_domain_after, + sid_before = sid_before, + sid_after = sid_after, + unused_param_name = "unused", + statement_var_name = "statement", + statement_var_pose=0, + #all_dom_inames_ordered=None, + all_dom_inames_ordered=statement_inames_premap_order, + ) +print("constraint_map before mapping:") +print(prettier_map_string(constraint_map)) +# TODO (left off here) +# TODO decide on before/after notation and make consistent +1/0 verbose = False verbose = True @@ -335,8 +368,9 @@ print(prettier_map_string(m2)) # new kernel knl = lp.map_domain(ref_knl, m) knl = lp.prioritize_loops(knl, "tt,tparity,tx,itt,itx") -#print("code after mapping:") -#print(generate_code_v2(knl).device_code()) +print("code after mapping:") +print(generate_code_v2(knl).device_code()) +1/0 print("constraint_map before apply_range:") print(prettier_map_string(constraint_map)) diff --git a/sched_check_utils.py b/sched_check_utils.py index 575923753..a91aef3a3 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -96,7 +96,7 @@ def reorder_dims_by_name( return new_set -def create_new_isl_set_with_primes(old_isl_set): +def create_new_isl_set_with_primes(old_isl_set, marker="'"): """Return an isl_set with apostrophes appended to dim_type.set dimension names. @@ -110,11 +110,11 @@ def create_new_isl_set_with_primes(old_isl_set): new_set = old_isl_set.copy() for i in range(old_isl_set.n_dim()): new_set = new_set.set_dim_name(isl.dim_type.set, i, old_isl_set.get_dim_name( - isl.dim_type.set, i)+"'") + isl.dim_type.set, i)+marker) return new_set -def make_islvars_with_var_primes(var_names, param_names): +def make_islvars_with_var_primes(var_names, param_names, marker="'"): """Return a dictionary from variable and parameter names to :class:`PwAff` instances that represent each of the variables and parameters, including @@ -134,15 +134,25 @@ def make_islvars_with_var_primes(var_names, param_names): """ + def append_marker(l, mark): + new_l = [] + for s in l: + new_l.append(s+mark) + return new_l + return isl.make_zero_and_vars( - var_names+append_apostrophes(var_names), param_names) + var_names+append_marker(var_names, marker), param_names) -def append_apostrophes(strings): +def append_marker_to_strings(strings, marker="'"): if not isinstance(strings, list): - raise ValueError("append_apostrophes did not receive a list") + raise ValueError("append_marker_to_strings did not receive a list") else: - return [s+"'" for s in strings] + return [s+marker for s in strings] + + +def append_apostrophes(strings): + return append_marker_to_strings(strings, marker="'") def _union_of_isl_sets_or_maps(set_list): -- GitLab From d253a097f1d32ebac8dcb2634c827a87875f10cc Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Dec 2019 17:15:01 -0600 Subject: [PATCH 153/183] separate dependency specification (legacy kernels) from schedule checking --- __init__.py | 62 +++++++++++++++++--------- example_pairwise_schedule_validity.py | 8 +++- sched_check_utils.py | 2 +- schedule.py | 14 +++--- test/test_invalid_scheds.py | 22 +++++++--- test/test_valid_scheds.py | 63 +++++++++++++++------------ 6 files changed, 108 insertions(+), 63 deletions(-) diff --git a/__init__.py b/__init__.py index f0e953548..76c14acb5 100644 --- a/__init__.py +++ b/__init__.py @@ -1,24 +1,8 @@ -# TODO create a set of broken kernels to test against -# (small kernels to test a specific case) -# TODO work on granularity of encapsulation, encapsulate some of this in -# separate functions -def check_schedule_validity( - knl, - verbose=False, - _use_scheduled_kernel_to_obtain_loop_priority=False): - +def get_statement_pair_dependency_sets_from_legacy_knl(knl): from schedule_checker.dependency import ( create_dependencies_from_legacy_knl, - create_dependency_constraint, - ) - from schedule_checker.schedule import LexSchedule - from schedule_checker.lexicographic_order_map import ( - get_statement_ordering_map, - ) - from schedule_checker.sched_check_utils import ( - prettier_map_string, ) # Preprocess if not already preprocessed @@ -49,6 +33,38 @@ def check_schedule_validity( dep_set.statement_after.within_inames) ]) + return deps_and_domains + + +# TODO create a set of broken kernels to test against +# (small kernels to test a specific case) +# TODO work on granularity of encapsulation, encapsulate some of this in +# separate functions +def check_schedule_validity( + knl, + deps_and_domains, + verbose=False, + _use_scheduled_kernel_to_obtain_loop_priority=False): + + from schedule_checker.dependency import ( + create_dependency_constraint, + ) + from schedule_checker.schedule import LexSchedule + from schedule_checker.lexicographic_order_map import ( + get_statement_ordering_map, + ) + from schedule_checker.sched_check_utils import ( + prettier_map_string, + ) + + # Preprocess if not already preprocessed + from loopy.kernel import KernelState + if knl.state < KernelState.PREPROCESSED: + from loopy import preprocess_kernel + preprocessed_knl = preprocess_kernel(knl) + else: + preprocessed_knl = knl + if verbose: print("="*80) print("StatementDependencies w/domains:") @@ -100,10 +116,12 @@ def check_schedule_validity( # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency - sched = LexSchedule(scheduled_knl, include_only_insn_ids=[ - s_before.insn_id, - s_after.insn_id - ]) + sched = LexSchedule(scheduled_knl, scheduled_knl.schedule, + include_only_insn_ids=[ + s_before.insn_id, + s_after.insn_id + ], + prohibited_var_names=scheduled_knl.all_inames()) #print("-"*80) #print("LexSchedule before processing:") @@ -176,6 +194,8 @@ def check_schedule_validity( sched.unused_param_name, sched.statement_var_name, ) + # TODO specify lp_insn_id_to_lex_sched_id independently of schedule creation + # so that dependency constraint creation can happen before schedule is created # align constraint map spaces to match sio so we can compare them if verbose: diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 0c5b1f61f..581001111 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -1,6 +1,9 @@ import loopy as lp import numpy as np -from schedule_checker import check_schedule_validity +from schedule_checker import ( + get_statement_pair_dependency_sets_from_legacy_knl, + check_schedule_validity, +) # Choose kernel ---------------------------------------------------------- @@ -275,7 +278,8 @@ if knl_choice == "loop_carried_deps": ) -sched_is_valid = check_schedule_validity(knl, verbose=True) +deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) +sched_is_valid = check_schedule_validity(knl, deps_and_domains, verbose=True) print("is sched valid? constraint map subset of SIO?") print(sched_is_valid) diff --git a/sched_check_utils.py b/sched_check_utils.py index a91aef3a3..c4658efc1 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -354,7 +354,7 @@ def get_concurrent_inames(knl): return conc_inames, all_inames-conc_inames -def _get_insn_id_from_sched_item(knl, sched_item): +def _get_insn_id_from_sched_item(sched_item): # TODO could use loopy's sched_item_to_insn_id() from loopy.schedule import Barrier if isinstance(sched_item, Barrier): diff --git a/schedule.py b/schedule.py index 34af2cfbb..5243ad03b 100644 --- a/schedule.py +++ b/schedule.py @@ -86,7 +86,9 @@ class LexSchedule(object): def __init__( self, knl, + sched_items_ordered, include_only_insn_ids=None, + prohibited_var_names=[], ): """ :arg knl: A :class:`LoopKernel` whose instructions will be @@ -103,11 +105,11 @@ class LexSchedule(object): # make sure we don't have an iname name conflict assert not any( - iname == self.statement_var_name for iname in knl.all_inames()) + iname == self.statement_var_name for iname in prohibited_var_names) assert not any( - iname == self.unused_param_name for iname in knl.all_inames()) + iname == self.unused_param_name for iname in prohibited_var_names) - if ((include_only_insn_ids is None and len(knl.schedule) > 2) + if ((include_only_insn_ids is None and len(sched_items_ordered) > 2) or len(include_only_insn_ids) > 2): raise NotImplementedError( "LexSchedule currently does not produce program orderings " @@ -116,12 +118,12 @@ class LexSchedule(object): from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.kernel.data import ConcurrentTag - # go through knl.schedule and generate self.lex_schedule + # go through sched_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] - for sched_item in knl.schedule: + for sched_item in sched_items_ordered: if isinstance(sched_item, EnterLoop): iname = sched_item.iname if knl.iname_tags_of_type(iname, ConcurrentTag): @@ -165,7 +167,7 @@ class LexSchedule(object): from schedule_checker.sched_check_utils import ( _get_insn_id_from_sched_item, ) - lp_insn_id = _get_insn_id_from_sched_item(knl, sched_item) + lp_insn_id = _get_insn_id_from_sched_item(sched_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/test/test_invalid_scheds.py b/test/test_invalid_scheds.py index db85e10c4..323b79b8c 100644 --- a/test/test_invalid_scheds.py +++ b/test/test_invalid_scheds.py @@ -28,7 +28,11 @@ from pyopencl.tools import ( # noqa as pytest_generate_tests) import loopy as lp import numpy as np -from schedule_checker import check_schedule_validity +from schedule_checker import ( + get_statement_pair_dependency_sets_from_legacy_knl, + check_schedule_validity, +) + def test_invalid_prioritiy_detection(): @@ -54,19 +58,26 @@ def test_invalid_prioritiy_detection(): knl0 = lp.prioritize_loops(ref_knl, "h,i") knl0 = lp.prioritize_loops(ref_knl, "i,j") knl0 = lp.prioritize_loops(knl0, "j,k") - assert check_schedule_validity(knl0) + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl0) + sched_is_valid = check_schedule_validity(knl0, deps_and_domains) + assert sched_is_valid # no error: knl1 = lp.prioritize_loops(ref_knl, "h,i,k") knl1 = lp.prioritize_loops(knl1, "h,j,k") - assert check_schedule_validity(knl1) + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl1) + sched_is_valid = check_schedule_validity(knl1, deps_and_domains) + assert sched_is_valid # error (cycle): knl2 = lp.prioritize_loops(ref_knl, "h,i,j") knl2 = lp.prioritize_loops(knl2, "j,k") knl2 = lp.prioritize_loops(knl2, "k,i") try: - check_schedule_validity(knl2) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl2) + sched_is_valid = check_schedule_validity(knl2, deps_and_domains) # should raise error assert False except ValueError as e: @@ -76,7 +87,8 @@ def test_invalid_prioritiy_detection(): knl3 = lp.prioritize_loops(ref_knl, "h,i,j,k") knl3 = lp.prioritize_loops(knl3, "h,j,i,k") try: - check_schedule_validity(knl3) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl3) + sched_is_valid = check_schedule_validity(knl3, deps_and_domains) # should raise error assert False except ValueError as e: diff --git a/test/test_valid_scheds.py b/test/test_valid_scheds.py index 6603c7a93..b0c178b6f 100644 --- a/test/test_valid_scheds.py +++ b/test/test_valid_scheds.py @@ -28,7 +28,10 @@ from pyopencl.tools import ( # noqa as pytest_generate_tests) import loopy as lp import numpy as np -from schedule_checker import check_schedule_validity +from schedule_checker import ( + get_statement_pair_dependency_sets_from_legacy_knl, + check_schedule_validity, +) def test_loop_prioritization(): @@ -62,7 +65,10 @@ def test_loop_prioritization(): {"b": np.float32, "d": np.float32, "f": np.float32}) knl = lp.prioritize_loops(knl, "i,k") knl = lp.prioritize_loops(knl, "i,j") - assert check_schedule_validity(knl) + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) + sched_is_valid = check_schedule_validity(knl, deps_and_domains) + assert sched_is_valid def test_matmul(): @@ -83,7 +89,10 @@ def test_matmul(): knl = lp.add_prefetch(knl, "a", ["k_inner", "i_inner"], default_tag="l.auto") knl = lp.add_prefetch(knl, "b", ["j_inner", "k_inner"], default_tag="l.auto") knl = lp.prioritize_loops(knl, "k_outer,k_inner") - assert check_schedule_validity(knl) + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) + sched_is_valid = check_schedule_validity(knl, deps_and_domains) + assert sched_is_valid def test_scan(): @@ -115,7 +124,10 @@ def test_dependent_domain(): lang_version=(2018, 2), ) knl = lp.realize_reduction(knl, force_scan=True) - assert check_schedule_validity(knl) + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) + sched_is_valid = check_schedule_validity(knl, deps_and_domains) + assert sched_is_valid def test_stroud_bernstein(): @@ -152,27 +164,10 @@ def test_stroud_bernstein(): knl = lp.split_iname(knl, "el_outer", 2, outer_tag="g.0", inner_tag="ilp", slabs=(0, 1)) knl = lp.tag_inames(knl, dict(i2="l.1", alpha1="unr", alpha2="unr")) - assert check_schedule_validity(knl) - -def test_ilp(): - knl = lp.make_kernel( - "{[i,j,ilp_iname]: 0 <= i,j < n and 0 <= ilp_iname < 4}", - """ - for i - for j - for ilp_iname - tmp[i,j,ilp_iname] = 3.14 - end - end - end - """, - name="ilp_kernel", - assumptions="n>=1 and n mod 4 = 0", - ) - knl = lp.tag_inames(knl, {"j": "l.0", "ilp_iname": "ilp"}) - #knl = lp.prioritize_loops(knl, "i_outer_outer,i_outer_inner,i_inner,a") - assert check_schedule_validity(knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) + sched_is_valid = check_schedule_validity(knl, deps_and_domains) + assert sched_is_valid def test_barrier(): @@ -194,7 +189,10 @@ def test_barrier(): knl = lp.split_iname(knl, "i", 2, outer_tag="g.0", inner_tag="l.0") knl = lp.split_iname(knl, "ii", 2, outer_tag="g.0", inner_tag="l.0") - assert check_schedule_validity(knl) + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) + sched_is_valid = check_schedule_validity(knl, deps_and_domains) + assert sched_is_valid def test_nop(): @@ -214,7 +212,10 @@ def test_nop(): "...", seq_dependencies=True) knl = lp.fix_parameters(knl, dim=3) - assert check_schedule_validity(knl) + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) + sched_is_valid = check_schedule_validity(knl, deps_and_domains) + assert sched_is_valid def test_multi_domain(): @@ -244,7 +245,10 @@ def test_multi_domain(): knl = lp.prioritize_loops(knl, "x,xx,i") knl = lp.prioritize_loops(knl, "i,j") knl = lp.prioritize_loops(knl, "j,k") - assert check_schedule_validity(knl) + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) + sched_is_valid = check_schedule_validity(knl, deps_and_domains) + assert sched_is_valid def test_loop_carried_deps(): @@ -263,7 +267,10 @@ def test_loop_carried_deps(): assumptions="n >= 1", lang_version=(2018, 2) ) - assert check_schedule_validity(knl) + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) + sched_is_valid = check_schedule_validity(knl, deps_and_domains) + assert sched_is_valid if __name__ == "__main__": -- GitLab From 6d59a6288abbec5c0cfd4884cb6412b67ce5a143 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Dec 2019 17:34:56 -0600 Subject: [PATCH 154/183] no longer passing fully scheduled kernel to LexSchedule.__init__; instead pass schedule items (a subset of which may be tested within scheduling step) --- __init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/__init__.py b/__init__.py index 76c14acb5..e840a35be 100644 --- a/__init__.py +++ b/__init__.py @@ -6,6 +6,7 @@ def get_statement_pair_dependency_sets_from_legacy_knl(knl): ) # Preprocess if not already preprocessed + # note that kernels must always be preprocessed before scheduling from loopy.kernel import KernelState if knl.state < KernelState.PREPROCESSED: from loopy import preprocess_kernel @@ -58,6 +59,7 @@ def check_schedule_validity( ) # Preprocess if not already preprocessed + # note that kernels must always be preprocessed before scheduling from loopy.kernel import KernelState if knl.state < KernelState.PREPROCESSED: from loopy import preprocess_kernel @@ -116,7 +118,8 @@ def check_schedule_validity( # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency - sched = LexSchedule(scheduled_knl, scheduled_knl.schedule, + all_schedule_items = scheduled_knl.schedule + sched = LexSchedule(preprocessed_knl, all_schedule_items, include_only_insn_ids=[ s_before.insn_id, s_after.insn_id -- GitLab From 77e92c6ad84985221d723d2e9a64200f77ba2705 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 2 Dec 2019 18:16:48 -0600 Subject: [PATCH 155/183] don't use any scheduled kernel in schedule checking; instead, pass in list of schedule items; also pass in prohibited var names instead of getting them from scheduled_knl.all_inames() --- __init__.py | 26 +++--- example_pairwise_schedule_validity.py | 29 ++++++- test/test_invalid_scheds.py | 58 +++++++++++-- test/test_valid_scheds.py | 118 +++++++++++++++++--------- 4 files changed, 169 insertions(+), 62 deletions(-) diff --git a/__init__.py b/__init__.py index e840a35be..d92794c62 100644 --- a/__init__.py +++ b/__init__.py @@ -44,6 +44,8 @@ def get_statement_pair_dependency_sets_from_legacy_knl(knl): def check_schedule_validity( knl, deps_and_domains, + schedule_items, + prohibited_var_names=set(), verbose=False, _use_scheduled_kernel_to_obtain_loop_priority=False): @@ -67,6 +69,9 @@ def check_schedule_validity( else: preprocessed_knl = knl + if not prohibited_var_names: + prohibited_var_names = preprocessed_knl.all_inames() + if verbose: print("="*80) print("StatementDependencies w/domains:") @@ -75,25 +80,19 @@ def check_schedule_validity( print(dom_before) print(dom_after) - # get a schedule to check - if preprocessed_knl.schedule is None: - from loopy import get_one_scheduled_kernel - scheduled_knl = get_one_scheduled_kernel(preprocessed_knl) - else: - scheduled_knl = preprocessed_knl - if verbose: # Print kernel info ------------------------------------------------------ print("="*80) - print("Kernel:") - print(scheduled_knl) + #print("Kernel:") + #print(scheduled_knl) #from loopy import generate_code_v2 #print(generate_code_v2(scheduled_knl).device_code()) print("="*80) - print("Iname tags: %s" % (scheduled_knl.iname_to_tags)) + #print("Iname tags: %s" % (scheduled_knl.iname_to_tags)) print("="*80) print("Loopy schedule:") - for sched_item in scheduled_knl.schedule: + #for sched_item in scheduled_knl.schedule: + for sched_item in schedule_items: print(sched_item) #print("scheduled iname order:") #print(sched_iname_order) @@ -118,13 +117,12 @@ def check_schedule_validity( # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency - all_schedule_items = scheduled_knl.schedule - sched = LexSchedule(preprocessed_knl, all_schedule_items, + sched = LexSchedule(preprocessed_knl, schedule_items, include_only_insn_ids=[ s_before.insn_id, s_after.insn_id ], - prohibited_var_names=scheduled_knl.all_inames()) + prohibited_var_names=prohibited_var_names) #print("-"*80) #print("LexSchedule before processing:") diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 581001111..0b83a1780 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -4,6 +4,11 @@ from schedule_checker import ( get_statement_pair_dependency_sets_from_legacy_knl, check_schedule_validity, ) +from loopy.kernel import KernelState +from loopy import ( + preprocess_kernel, + get_one_scheduled_kernel, +) # Choose kernel ---------------------------------------------------------- @@ -277,9 +282,31 @@ if knl_choice == "loop_carried_deps": lang_version=(2018, 2) ) +unprocessed_knl = knl.copy() + +deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + +# get a schedule to check +if knl.state < KernelState.PREPROCESSED: + knl = preprocess_kernel(knl) +knl = get_one_scheduled_kernel(knl) +print("kernel schedueld") +schedule_items = knl.schedule +print("checking validity") +sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items, verbose=True) + +""" deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) -sched_is_valid = check_schedule_validity(knl, deps_and_domains, verbose=True) + +# get a schedule to check +from loopy import get_one_scheduled_kernel +scheduled_knl = get_one_scheduled_kernel(knl) +schedule_items = scheduled_knl.schedule + +sched_is_valid = check_schedule_validity(knl, deps_and_domains, schedule_items, verbose=True) +""" print("is sched valid? constraint map subset of SIO?") print(sched_is_valid) diff --git a/test/test_invalid_scheds.py b/test/test_invalid_scheds.py index 323b79b8c..5f43909cf 100644 --- a/test/test_invalid_scheds.py +++ b/test/test_invalid_scheds.py @@ -32,7 +32,11 @@ from schedule_checker import ( get_statement_pair_dependency_sets_from_legacy_knl, check_schedule_validity, ) - +from loopy.kernel import KernelState +from loopy import ( + preprocess_kernel, + get_one_scheduled_kernel, +) def test_invalid_prioritiy_detection(): @@ -59,16 +63,34 @@ def test_invalid_prioritiy_detection(): knl0 = lp.prioritize_loops(ref_knl, "i,j") knl0 = lp.prioritize_loops(knl0, "j,k") - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl0) - sched_is_valid = check_schedule_validity(knl0, deps_and_domains) + unprocessed_knl = knl0.copy() + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + + # get a schedule to check + if knl0.state < KernelState.PREPROCESSED: + knl0 = preprocess_kernel(knl0) + knl0 = get_one_scheduled_kernel(knl0) + schedule_items = knl0.schedule + + sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid # no error: knl1 = lp.prioritize_loops(ref_knl, "h,i,k") knl1 = lp.prioritize_loops(knl1, "h,j,k") - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl1) - sched_is_valid = check_schedule_validity(knl1, deps_and_domains) + unprocessed_knl = knl1.copy() + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + + # get a schedule to check + if knl1.state < KernelState.PREPROCESSED: + knl1 = preprocess_kernel(knl1) + knl1 = get_one_scheduled_kernel(knl1) + schedule_items = knl1.schedule + + sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid # error (cycle): @@ -76,8 +98,17 @@ def test_invalid_prioritiy_detection(): knl2 = lp.prioritize_loops(knl2, "j,k") knl2 = lp.prioritize_loops(knl2, "k,i") try: - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl2) - sched_is_valid = check_schedule_validity(knl2, deps_and_domains) + unprocessed_knl = knl2.copy() + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + + # get a schedule to check + if knl2.state < KernelState.PREPROCESSED: + knl2 = preprocess_kernel(knl2) + knl2 = get_one_scheduled_kernel(knl2) + schedule_items = knl2.schedule + + sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) # should raise error assert False except ValueError as e: @@ -87,8 +118,17 @@ def test_invalid_prioritiy_detection(): knl3 = lp.prioritize_loops(ref_knl, "h,i,j,k") knl3 = lp.prioritize_loops(knl3, "h,j,i,k") try: - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl3) - sched_is_valid = check_schedule_validity(knl3, deps_and_domains) + unprocessed_knl = knl3.copy() + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + + # get a schedule to check + if knl3.state < KernelState.PREPROCESSED: + knl3 = preprocess_kernel(knl3) + knl3 = get_one_scheduled_kernel(knl3) + schedule_items = knl3.schedule + + sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) # should raise error assert False except ValueError as e: diff --git a/test/test_valid_scheds.py b/test/test_valid_scheds.py index b0c178b6f..0ed14502e 100644 --- a/test/test_valid_scheds.py +++ b/test/test_valid_scheds.py @@ -32,7 +32,11 @@ from schedule_checker import ( get_statement_pair_dependency_sets_from_legacy_knl, check_schedule_validity, ) - +from loopy.kernel import KernelState +from loopy import ( + preprocess_kernel, + get_one_scheduled_kernel, +) def test_loop_prioritization(): knl = lp.make_kernel( @@ -66,8 +70,17 @@ def test_loop_prioritization(): knl = lp.prioritize_loops(knl, "i,k") knl = lp.prioritize_loops(knl, "i,j") - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) - sched_is_valid = check_schedule_validity(knl, deps_and_domains) + unprocessed_knl = knl.copy() + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + + # get a schedule to check + if knl.state < KernelState.PREPROCESSED: + knl = preprocess_kernel(knl) + knl = get_one_scheduled_kernel(knl) + schedule_items = knl.schedule + + sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid @@ -90,8 +103,17 @@ def test_matmul(): knl = lp.add_prefetch(knl, "b", ["j_inner", "k_inner"], default_tag="l.auto") knl = lp.prioritize_loops(knl, "k_outer,k_inner") - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) - sched_is_valid = check_schedule_validity(knl, deps_and_domains) + unprocessed_knl = knl.copy() + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + + # get a schedule to check + if knl.state < KernelState.PREPROCESSED: + knl = preprocess_kernel(knl) + knl = get_one_scheduled_kernel(knl) + schedule_items = knl.schedule + + sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid @@ -125,8 +147,17 @@ def test_dependent_domain(): ) knl = lp.realize_reduction(knl, force_scan=True) - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) - sched_is_valid = check_schedule_validity(knl, deps_and_domains) + unprocessed_knl = knl.copy() + + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + + # get a schedule to check + if knl.state < KernelState.PREPROCESSED: + knl = preprocess_kernel(knl) + knl = get_one_scheduled_kernel(knl) + schedule_items = knl.schedule + + sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid @@ -165,33 +196,17 @@ def test_stroud_bernstein(): inner_tag="ilp", slabs=(0, 1)) knl = lp.tag_inames(knl, dict(i2="l.1", alpha1="unr", alpha2="unr")) - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) - sched_is_valid = check_schedule_validity(knl, deps_and_domains) - assert sched_is_valid + unprocessed_knl = knl.copy() + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) -def test_barrier(): - np.random.seed(17) - cnst = np.random.randn(16) - knl = lp.make_kernel( - "{[i, ii]: 0<=i, ii Date: Mon, 2 Dec 2019 19:23:51 -0600 Subject: [PATCH 156/183] updated todo --- __init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/__init__.py b/__init__.py index d92794c62..5c7fde8df 100644 --- a/__init__.py +++ b/__init__.py @@ -195,8 +195,8 @@ def check_schedule_validity( sched.unused_param_name, sched.statement_var_name, ) - # TODO specify lp_insn_id_to_lex_sched_id independently of schedule creation - # so that dependency constraint creation can happen before schedule is created + # TODO figure out how to keep a consistent lp_insn_id_to_lex_sched_id map + # when dependency creation is separate from schedule checking # align constraint map spaces to match sio so we can compare them if verbose: -- GitLab From 9967e37e08cb7e8a46da9742021d6f1eb4d40a7f Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 10 Dec 2019 05:40:12 -0600 Subject: [PATCH 157/183] changed schedule into two separate maps, one for the 'before' instruction and one for the 'after' instruction, so that unused inames don't have to be part of the map; changed dependency creation from legacy kernels to match; now in_dims and out_dims of statement-instance-ordering and dependencies do not have to match (may contain different inames) --- __init__.py | 55 ++++++----- dependency.py | 34 ++++--- lexicographic_order_map.py | 12 ++- sched_check_utils.py | 8 +- schedule.py | 188 +++++++++++++++++++++++++------------ 5 files changed, 197 insertions(+), 100 deletions(-) diff --git a/__init__.py b/__init__.py index 5c7fde8df..e0ae56a90 100644 --- a/__init__.py +++ b/__init__.py @@ -80,7 +80,6 @@ def check_schedule_validity( print(dom_before) print(dom_after) - if verbose: # Print kernel info ------------------------------------------------------ print("="*80) #print("Kernel:") @@ -91,18 +90,15 @@ def check_schedule_validity( #print("Iname tags: %s" % (scheduled_knl.iname_to_tags)) print("="*80) print("Loopy schedule:") - #for sched_item in scheduled_knl.schedule: for sched_item in schedule_items: print(sched_item) #print("scheduled iname order:") #print(sched_iname_order) - # For each dependency, create+test schedule containing pair of insns------ - - if verbose: print("="*80) print("Looping through dep pairs...") + # For each dependency, create+test schedule containing pair of insns------ sched_is_valid = True for statement_pair_dep_set, dom_before, dom_after in deps_and_domains: if verbose: @@ -117,12 +113,13 @@ def check_schedule_validity( # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency - sched = LexSchedule(preprocessed_knl, schedule_items, - include_only_insn_ids=[ - s_before.insn_id, - s_after.insn_id - ], - prohibited_var_names=prohibited_var_names) + sched = LexSchedule( + preprocessed_knl, + schedule_items, + s_before.insn_id, + s_after.insn_id, + prohibited_var_names=prohibited_var_names, + ) #print("-"*80) #print("LexSchedule before processing:") @@ -139,26 +136,30 @@ def check_schedule_validity( # Get an isl map representing the LexSchedule; # this requires the iname domains - assert len(sched) in [1, 2] - if len(sched) == 1: - assert dom_before == dom_after - # get a mapping from lex schedule id to relevant inames domain - sid_to_dom = { + # TODO if sid_to_dom_before/after always contain single pair, + # maybe don't use dict + sid_to_dom_before = { lp_insn_id_to_lex_sched_id[s_before.insn_id]: dom_before, + } + sid_to_dom_after = { lp_insn_id_to_lex_sched_id[s_after.insn_id]: dom_after, } - sched_map_symbolic = sched.create_symbolic_isl_map(sid_to_dom) + sched_map_symbolic_before, sched_map_symbolic_after = \ + sched.create_symbolic_isl_map( + sid_to_dom_before, + sid_to_dom_after, + ) if verbose: - print("sid_to_dom:\n", sid_to_dom) + print("sid_to_dom_before:\n", sid_to_dom_before) + print("sid_to_dom_after:\n", sid_to_dom_after) print("LexSchedule after creating symbolic isl map:") print(sched) print("LexSched:") - print(prettier_map_string(sched_map_symbolic)) - #print("space (statement instances -> lex time):") - #print(sched_map_symbolic.space) + print(prettier_map_string(sched_map_symbolic_before)) + print(prettier_map_string(sched_map_symbolic_after)) #print("-"*80) # get map representing lexicographic ordering @@ -172,10 +173,14 @@ def check_schedule_validity( print("-"*80) """ + # TODO which direction does this composition go? # create statement instance ordering, # maps each statement instance to all statement instances occuring later sio = get_statement_ordering_map( - sched_map_symbolic, lex_order_map_symbolic) + sched_map_symbolic_before, + sched_map_symbolic_after, + lex_order_map_symbolic, + ) if verbose: print("statement instance ordering:") @@ -222,11 +227,11 @@ def check_schedule_validity( ) # align out dims + sio_out_names = sio.space.get_var_names(isl.dim_type.out) aligned_constraint_map = reorder_dims_by_name( aligned_constraint_map, isl.dim_type.out, - append_apostrophes(sio_in_names), - # TODO sio out names are only pretending to have apostrophes; confusing + sio_out_names, add_missing=False, new_names_are_permutation_only=True, ) @@ -243,7 +248,7 @@ def check_schedule_validity( == sio.space.get_var_names(isl.dim_type.in_)) assert ( aligned_constraint_map.space.get_var_names(isl.dim_type.out) - == append_apostrophes(sio.space.get_var_names(isl.dim_type.out))) + == sio.space.get_var_names(isl.dim_type.out)) assert ( aligned_constraint_map.space.get_var_names(isl.dim_type.param) == sio.space.get_var_names(isl.dim_type.param)) diff --git a/dependency.py b/dependency.py index 197815951..56e6bcd73 100644 --- a/dependency.py +++ b/dependency.py @@ -128,7 +128,8 @@ def create_dependency_constraint( unused_param_name, statement_var_name, statement_var_pose=0, - all_dom_inames_ordered=None, + dom_inames_ordered_before=None, + dom_inames_ordered_after=None, ): """Create a statement dependency constraint represented as a map from each statement instance to statement instances that must occur later, @@ -192,23 +193,29 @@ def create_dependency_constraint( from schedule_checker.sched_check_utils import ( list_var_names_in_isl_sets, ) - if all_dom_inames_ordered is None: - all_dom_inames_ordered = list_var_names_in_isl_sets( - [dom_before_constraint_set, dom_after_constraint_set]) + if dom_inames_ordered_before is None: + dom_inames_ordered_before = list_var_names_in_isl_sets( + [dom_before_constraint_set]) + if dom_inames_ordered_after is None: + dom_inames_ordered_after = list_var_names_in_isl_sets( + [dom_after_constraint_set]) # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} islvars = make_islvars_with_var_primes( - [statement_var_name]+all_dom_inames_ordered, - [unused_param_name]) + var_names_in=[statement_var_name]+dom_inames_ordered_before, + param_names=[unused_param_name], + var_names_out=[statement_var_name]+dom_inames_ordered_after, + ) statement_var_name_prime = statement_var_name+"'" # get (ordered) list of unused before/after inames + # TODO are there ever unused inames now that we're separating the in/out spaces? inames_before_unused = [] - for iname in all_dom_inames_ordered: + for iname in dom_inames_ordered_before: if iname not in dom_before_constraint_set.get_var_names(isl.dim_type.out): inames_before_unused.append(iname) inames_after_unused = [] - for iname in all_dom_inames_ordered: + for iname in dom_inames_ordered_after: if iname not in dom_after_constraint_set.get_var_names(isl.dim_type.out): inames_after_unused.append(iname + "'") @@ -336,7 +343,10 @@ def create_dependency_constraint( # convert constraint set to map all_constraints_map = _convert_constraint_set_to_map( - all_constraints_set, len(all_dom_inames_ordered) + 1) # +1 for statement var + all_constraints_set, + mv_count=len(dom_inames_ordered_after)+1, # +1 for statement var + src_position=len(dom_inames_ordered_before)+1, # +1 for statement var + ) # now apply domain sets to constraint variables @@ -352,12 +362,12 @@ def create_dependency_constraint( # insert inames missing from doms to enable intersection domain_to_intersect = reorder_dims_by_name( domain_to_intersect, isl.dim_type.out, - [statement_var_name] + all_dom_inames_ordered, + [statement_var_name] + dom_inames_ordered_before, add_missing=True) range_to_intersect = reorder_dims_by_name( range_to_intersect, isl.dim_type.out, - append_apostrophes([statement_var_name] + all_dom_inames_ordered), + append_apostrophes([statement_var_name] + dom_inames_ordered_after), add_missing=True) # intersect doms @@ -507,6 +517,8 @@ def create_arbitrary_dependency_constraint( all_dom_inames_ordered=None, ): + # TODO update after allowing different inames for before/after + from schedule_checker.sched_check_utils import ( make_islvars_with_var_primes, #append_apostrophes, diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 356fb8731..ccfb9d6f9 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -1,7 +1,8 @@ import islpy as isl -def get_statement_ordering_map(sched_map, lex_map): +def get_statement_ordering_map( + sched_map_before, sched_map_after, lex_map, out_marker="'"): """Return a mapping that maps each statement instance to all statement instances occuring later. @@ -24,8 +25,13 @@ def get_statement_ordering_map(sched_map, lex_map): """ - # TODO apostrophes aren't really there for range, this is confusing - return sched_map.apply_range(lex_map).apply_range(sched_map.reverse()) + # TODO determine which order is correct + sio = sched_map_before.apply_range(lex_map).apply_range(sched_map_after.reverse()) + # append marker to out names + for i in range(sio.dim(isl.dim_type.out)): + sio = sio.set_dim_name(isl.dim_type.out, i, sio.get_dim_name( + isl.dim_type.out, i)+out_marker) + return sio def get_lex_order_constraint(islvars, before_names, after_names): diff --git a/sched_check_utils.py b/sched_check_utils.py index c4658efc1..fa4e3e3eb 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -114,7 +114,8 @@ def create_new_isl_set_with_primes(old_isl_set, marker="'"): return new_set -def make_islvars_with_var_primes(var_names, param_names, marker="'"): +def make_islvars_with_var_primes( + var_names_in, param_names, marker="'", var_names_out=None): """Return a dictionary from variable and parameter names to :class:`PwAff` instances that represent each of the variables and parameters, including @@ -140,8 +141,11 @@ def make_islvars_with_var_primes(var_names, param_names, marker="'"): new_l.append(s+mark) return new_l + if var_names_out is None: + var_names_out = var_names_in[:] + return isl.make_zero_and_vars( - var_names+append_marker(var_names, marker), param_names) + var_names_in+append_marker(var_names_out, marker), param_names) def append_marker_to_strings(strings, marker="'"): diff --git a/schedule.py b/schedule.py index 5243ad03b..80002455e 100644 --- a/schedule.py +++ b/schedule.py @@ -87,7 +87,8 @@ class LexSchedule(object): self, knl, sched_items_ordered, - include_only_insn_ids=None, + before_insn_id, + after_insn_id, prohibited_var_names=[], ): """ @@ -99,9 +100,11 @@ class LexSchedule(object): to None, all insructions will be included. """ + # TODO update docs now that we have two schedules - # list of LexScheduleStatements - self.lex_schedule = [] + # LexScheduleStatements + self.lex_sched_stmt_before = None + self.lex_sched_stmt_after = None # make sure we don't have an iname name conflict assert not any( @@ -109,12 +112,6 @@ class LexSchedule(object): assert not any( iname == self.unused_param_name for iname in prohibited_var_names) - if ((include_only_insn_ids is None and len(sched_items_ordered) > 2) - or len(include_only_insn_ids) > 2): - raise NotImplementedError( - "LexSchedule currently does not produce program orderings " - "with greater than 2 statements.") - from loopy.schedule import (EnterLoop, LeaveLoop, Barrier, RunInstruction) from loopy.kernel.data import ConcurrentTag @@ -123,6 +120,7 @@ class LexSchedule(object): # 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_sid = 0 for sched_item in sched_items_ordered: if isinstance(sched_item, EnterLoop): iname = sched_item.iname @@ -139,7 +137,7 @@ class LexSchedule(object): # don't increment lex dim val enumerating items in current block, # otherwise, this loop is next item in current code block, so # increment lex dim val enumerating items in current code block - if self.lex_schedule: # if the schedule is not empty + if self.lex_sched_stmt_before or self.lex_sched_stmt_after: # if either statement has been set # this lex value will correspond to everything inside this loop # we will add new lex dimensions to enuerate items inside loop next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 @@ -163,6 +161,7 @@ class LexSchedule(object): next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 # if we didn't add any statements while in this loop, we might # sometimes be able to skip increment, but it's not hurting anything + # TODO might not need this increment period? elif isinstance(sched_item, (RunInstruction, Barrier)): from schedule_checker.sched_check_utils import ( _get_insn_id_from_sched_item, @@ -178,22 +177,58 @@ class LexSchedule(object): # if include_only_insn_ids list was passed, # only process insns found in list, # otherwise process all instructions - if (include_only_insn_ids is None - or lp_insn_id in include_only_insn_ids): + if lp_insn_id == before_insn_id and lp_insn_id == after_insn_id: + # add before sched item + self.lex_sched_stmt_before = ( + LexScheduleStatement( + insn_id=lp_insn_id, + int_id=next_sid, # int representing insn + ), + next_insn_lex_pt[:] + ) + # add after sched item + self.lex_sched_stmt_after = ( + LexScheduleStatement( + insn_id=lp_insn_id, + int_id=next_sid, # int representing insn + ), + next_insn_lex_pt[:] + ) - # add sched item - self.lex_schedule.append(( + # increment lex dim val enumerating items in current code block + next_insn_lex_pt[-1] = next_insn_lex_pt[-1] + 1 + next_sid += 1 + elif lp_insn_id == before_insn_id: + # add before sched item + self.lex_sched_stmt_before = ( LexScheduleStatement( insn_id=lp_insn_id, - int_id=len(self.lex_schedule), # int representing insn + 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 + elif lp_insn_id == after_insn_id: + # add after sched item + self.lex_sched_stmt_after = ( + 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 else: pass + # to save time, stop when we've created both statements + if self.lex_sched_stmt_before and self.lex_sched_stmt_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 @@ -204,10 +239,13 @@ class LexSchedule(object): ``int_id`` refer to the ``insn_id`` and ``int_id`` attributes of :class:`LexScheduleStatement`. """ - return dict([(stmt.insn_id, stmt.int_id) for stmt, _ in self.lex_schedule]) + return { + self.lex_sched_stmt_before[0].insn_id: self.lex_sched_stmt_before[0].int_id, + self.lex_sched_stmt_after[0].insn_id: self.lex_sched_stmt_after[0].int_id, + } def max_lex_dims(self): - return max(len(lex_pt) for _, lex_pt in self.lex_schedule) + return max([len(self.lex_sched_stmt_before[1]), len(self.lex_sched_stmt_after[1])]) def pad_lex_pts_with_zeros(self): """Find the maximum number of lexicographic dimensions represented @@ -218,15 +256,24 @@ class LexSchedule(object): """ max_lex_dim = self.max_lex_dims() - new_sched = [] - for stmt, lex_pt in self.lex_schedule: - new_sched.append((stmt, lex_pt + [0]*(max_lex_dim-len(lex_pt)))) - self.lex_schedule = new_sched + self.lex_sched_stmt_before = ( + self.lex_sched_stmt_before[0], + self.lex_sched_stmt_before[1][:] + [0]*( + max_lex_dim-len(self.lex_sched_stmt_before[1])) + ) + self.lex_sched_stmt_after = ( + self.lex_sched_stmt_after[0], + self.lex_sched_stmt_after[1][:] + [0]*( + max_lex_dim-len(self.lex_sched_stmt_after[1])) + ) def create_symbolic_isl_map( self, - sid_to_dom, - dom_inames_ordered=None): + sid_to_dom_before, + sid_to_dom_after, + dom_inames_ordered_before=None, + dom_inames_ordered_after=None, + ): """Create an isl map representing lex schedule as a mapping from each statement instance to all statement instances occuring later. @@ -253,31 +300,47 @@ class LexSchedule(object): add_dims_to_isl_set ) - assert len(sid_to_dom) == len(self.lex_schedule) + # TODO if sid_to_dom_before/after always contain single pair, + # maybe don't use dict + assert len(sid_to_dom_before) == 1 + assert len(sid_to_dom_after) == 1 from schedule_checker.sched_check_utils import ( list_var_names_in_isl_sets, ) - if dom_inames_ordered is None: - dom_inames_ordered = list_var_names_in_isl_sets(sid_to_dom.values()) + if dom_inames_ordered_before is None: + dom_inames_ordered_before = list_var_names_in_isl_sets( + sid_to_dom_before.values()) + if dom_inames_ordered_after is None: + dom_inames_ordered_after = list_var_names_in_isl_sets( + sid_to_dom_after.values()) # create an isl space # {('statement', used in >=1 statement domain>) -> # (lexicographic ordering dims)} + from schedule_checker.sched_check_utils import get_isl_space params_sched = [self.unused_param_name] - in_names_sched = [self.statement_var_name] + dom_inames_ordered[:] out_names_sched = self.get_lex_var_names() - from schedule_checker.sched_check_utils import get_isl_space - sched_space = get_isl_space(params_sched, in_names_sched, out_names_sched) + + 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 = [] - for stmt, _ in self.lex_schedule: - doms_to_intersect.append( - add_dims_to_isl_set( - sid_to_dom[stmt.int_id], isl.dim_type.set, - [self.statement_var_name], 0)) + doms_to_intersect_before = [ + add_dims_to_isl_set( + sid_to_dom_before[self.lex_sched_stmt_before[0].int_id], isl.dim_type.set, + [self.statement_var_name], 0), + ] + doms_to_intersect_after = [ + add_dims_to_isl_set( + sid_to_dom_after[self.lex_sched_stmt_after[0].int_id], isl.dim_type.set, + [self.statement_var_name], 0), + ] # The isl map representing the schedule maps # statement instances -> lex time @@ -290,13 +353,22 @@ class LexSchedule(object): # Add all inames from combined domains to map domain tuples. # create isl map - return create_symbolic_isl_map_from_tuples( - zip( - [((stmt.int_id,) + tuple(dom_inames_ordered), lex_pt) - for stmt, lex_pt in self.lex_schedule], - doms_to_intersect - ), - sched_space, self.unused_param_name, self.statement_var_name) + return ( + create_symbolic_isl_map_from_tuples( + zip( + [((self.lex_sched_stmt_before[0].int_id,) + tuple(dom_inames_ordered_before), + self.lex_sched_stmt_before[1])], + doms_to_intersect_before + ), + sched_space_before, self.unused_param_name, self.statement_var_name), + create_symbolic_isl_map_from_tuples( + zip( + [((self.lex_sched_stmt_after[0].int_id,) + tuple(dom_inames_ordered_after), + self.lex_sched_stmt_after[1])], + doms_to_intersect_after + ), + sched_space_after, self.unused_param_name, self.statement_var_name) + ) def get_lex_var_names(self): return [self.lex_var_prefix+str(i) @@ -315,27 +387,25 @@ class LexSchedule(object): return create_lex_order_map( n_dims, before_names=self.get_lex_var_names()) - def __bool__(self): - return bool(self.lex_schedule) - def __nonzero__(self): return self.__bool__() def __eq__(self, other): - return self.lex_schedule == other.lex_schedule - - def __iter__(self): - return iter(self.lex_schedule) - - def __len__(self): - return len(self.lex_schedule) + return (self.lex_sched_stmt_before == other.lex_sched_stmt_before and + self.lex_sched_stmt_after == other.lex_sched_stmt_after) def __str__(self): - sched_str = "{\n" - for stmt, lex_pt in self.lex_schedule: - domain_elem = "[%s=%s,]" % ( - self.statement_var_name, - stmt.int_id) - sched_str += "%s -> %s;\n" % (domain_elem, lex_pt) + sched_str = "Before: {\n" + domain_elem = "[%s=%s,]" % ( + self.statement_var_name, + self.lex_sched_stmt_before[0].int_id) + sched_str += "%s -> %s;\n" % (domain_elem, self.lex_sched_stmt_before[1]) + sched_str += "}\n" + + sched_str += "After: {\n" + domain_elem += "[%s=%s,]" % ( + self.statement_var_name, + self.lex_sched_stmt_after[0].int_id) + sched_str += "%s -> %s;\n" % (domain_elem, self.lex_sched_stmt_after[1]) sched_str += "}" return sched_str -- GitLab From 77151322f97bf2cea7b39a552b464a04e4a24299 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 13 Dec 2019 11:53:17 -0600 Subject: [PATCH 158/183] added function to get all dependency maps (from legacy kernel) --- __init__.py | 51 +++++++++++++++++++++++++++ example_pairwise_schedule_validity.py | 12 +++++++ 2 files changed, 63 insertions(+) diff --git a/__init__.py b/__init__.py index e0ae56a90..4828c9410 100644 --- a/__init__.py +++ b/__init__.py @@ -291,3 +291,54 @@ def check_schedule_validity( print("===========================================================") return sched_is_valid + + +def get_dependency_maps( + deps_and_domains, + schedule_items, + loop_priority, + ): + + from schedule_checker.dependency import ( + create_dependency_constraint, + ) + from schedule_checker.sched_check_utils import ( + prettier_map_string, + ) + + # create map from loopy insn ids to ints + lp_insn_id_to_lex_sched_id = {} # TODO + next_sid = 0 + from loopy.schedule import Barrier, RunInstruction + for sched_item in schedule_items: + if isinstance(sched_item, (RunInstruction, Barrier)): + from schedule_checker.sched_check_utils import ( + _get_insn_id_from_sched_item, + ) + lp_insn_id = _get_insn_id_from_sched_item(sched_item) + lp_insn_id_to_lex_sched_id[lp_insn_id] = next_sid + next_sid += 1 + + all_constraint_maps = [] + for statement_pair_dep_set, dom_before, dom_after in deps_and_domains: + + # create a map representing constraints from the dependency, + # maps statement instance to all statement instances that must occur later + all_constraint_maps.append( + create_dependency_constraint( + statement_pair_dep_set, + dom_before, + dom_after, + loop_priority, + lp_insn_id_to_lex_sched_id, + "unused", # TODO shouldn't be necessary + "statement", + ) + ) + + for constraint_map in all_constraint_maps: + print("") + print(prettier_map_string(constraint_map)) + print("") + + return all_constraint_maps diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 0b83a1780..2ccdefffb 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -3,6 +3,7 @@ import numpy as np from schedule_checker import ( get_statement_pair_dependency_sets_from_legacy_knl, check_schedule_validity, + get_dependency_maps, ) from loopy.kernel import KernelState from loopy import ( @@ -310,3 +311,14 @@ sched_is_valid = check_schedule_validity(knl, deps_and_domains, schedule_items, print("is sched valid? constraint map subset of SIO?") print(sched_is_valid) + + +print("="*80) +print("testing dep sort") +print("="*80) + +dep_maps = get_dependency_maps( + deps_and_domains, + schedule_items, + knl.loop_priority, + ) -- GitLab From 1a21bf155be460b290e65b0c741fb914ce7c8aef Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Dec 2019 09:22:44 -0600 Subject: [PATCH 159/183] create a SAME dep and compare to dep map to determine whether we will need an edge in our dependency graph --- __init__.py | 60 +++++++++++++++++++++++---- example_pairwise_schedule_validity.py | 3 +- 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/__init__.py b/__init__.py index 4828c9410..39655a529 100644 --- a/__init__.py +++ b/__init__.py @@ -297,10 +297,13 @@ def get_dependency_maps( deps_and_domains, schedule_items, loop_priority, + knl, # TODO avoid passing this in ): from schedule_checker.dependency import ( create_dependency_constraint, + StatementPairDependencySet, + DependencyType as dt, ) from schedule_checker.sched_check_utils import ( prettier_map_string, @@ -319,26 +322,65 @@ def get_dependency_maps( lp_insn_id_to_lex_sched_id[lp_insn_id] = next_sid next_sid += 1 - all_constraint_maps = [] + from schedule_checker.sched_check_utils import ( + get_concurrent_inames, + ) + conc_inames, non_conc_inames = get_concurrent_inames(knl) + + deps_domains_and_constraint_maps = [] # TODO refactor this (maybe make a new data structure) for statement_pair_dep_set, dom_before, dom_after in deps_and_domains: + dep_constraint_map = create_dependency_constraint( + statement_pair_dep_set, + dom_before, + dom_after, + loop_priority, + lp_insn_id_to_lex_sched_id, + "unused", # TODO shouldn't be necessary + "statement", + ) + + # create "same" dep for these two insns + s_before = statement_pair_dep_set.statement_before + s_after = statement_pair_dep_set.statement_after + shared_nc_inames = s_before.within_inames & s_after.within_inames & non_conc_inames + same_dep_set = StatementPairDependencySet( + s_before, + s_after, + {dt.SAME: shared_nc_inames} + ) + same_dep_constraint_map = create_dependency_constraint( + same_dep_set, + dom_before, + dom_after, + loop_priority, + lp_insn_id_to_lex_sched_id, + "unused", # TODO shouldn't be necessary + "statement", + ) + + # see whether we should create an edge in our statement dep graph + # TODO is this the right test? + same_is_subset = same_dep_constraint_map.is_subset(dep_constraint_map) + # create a map representing constraints from the dependency, # maps statement instance to all statement instances that must occur later - all_constraint_maps.append( - create_dependency_constraint( + deps_domains_and_constraint_maps.append( + ( statement_pair_dep_set, dom_before, dom_after, - loop_priority, - lp_insn_id_to_lex_sched_id, - "unused", # TODO shouldn't be necessary - "statement", + dep_constraint_map, + same_is_subset, ) ) - for constraint_map in all_constraint_maps: + for spds, _, _, constraint_map, same_is_subset in deps_domains_and_constraint_maps: print("") + print("dep: %s" % (spds)) + print("map: ") print(prettier_map_string(constraint_map)) + print(same_is_subset) print("") - return all_constraint_maps + return deps_domains_and_constraint_maps diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 2ccdefffb..dfc79bdc8 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -317,8 +317,9 @@ print("="*80) print("testing dep sort") print("="*80) -dep_maps = get_dependency_maps( +dep_domains_and_maps = get_dependency_maps( deps_and_domains, schedule_items, knl.loop_priority, + knl, ) -- GitLab From 8d8a9eb42d45b36fbb8583e9460df4a4191d6027 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 16 Dec 2019 09:38:37 -0600 Subject: [PATCH 160/183] create graph representing ordering of statements based on dependencies --- example_pairwise_schedule_validity.py | 18 ++++++++++++++++++ sched_check_utils.py | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index dfc79bdc8..453708f1c 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -5,6 +5,9 @@ from schedule_checker import ( check_schedule_validity, get_dependency_maps, ) +from schedule_checker.sched_check_utils import ( + create_graph_from_pairs, +) from loopy.kernel import KernelState from loopy import ( preprocess_kernel, @@ -323,3 +326,18 @@ dep_domains_and_maps = get_dependency_maps( knl.loop_priority, knl, ) + +dep_graph_pairs = [ + ( + statement_pair_dep_set.statement_before.insn_id, + statement_pair_dep_set.statement_after.insn_id + ) + for statement_pair_dep_set, _, _, _, same_is_subset in dep_domains_and_maps + if same_is_subset + ] + +dep_graph = create_graph_from_pairs(dep_graph_pairs) + +print("dep_graph:") +for k, v in dep_graph.items(): + print("%s: %s" % (k, v)) diff --git a/sched_check_utils.py b/sched_check_utils.py index fa4e3e3eb..df8c07797 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -482,6 +482,13 @@ def get_orderings_of_length_n( return orderings +def create_graph_from_pairs(before_after_pairs): + # create key for every before + graph = dict([(before, set()) for before, _ in before_after_pairs]) + for before, after in before_after_pairs: + graph[before] = graph[before] | set([after, ]) + return graph + # only used for example purposes: -- GitLab From 3d5f85f769976d7f39f304d439f5b2afe6e2159b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 19 Dec 2019 17:59:22 -0600 Subject: [PATCH 161/183] change dep graph edge criterion to S&C not empty --- __init__.py | 22 ++++++++++++---------- example_pairwise_schedule_validity.py | 4 ++-- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/__init__.py b/__init__.py index 39655a529..308827778 100644 --- a/__init__.py +++ b/__init__.py @@ -360,8 +360,17 @@ def get_dependency_maps( ) # see whether we should create an edge in our statement dep graph - # TODO is this the right test? - same_is_subset = same_dep_constraint_map.is_subset(dep_constraint_map) + intersect_dep_and_same = same_dep_constraint_map & dep_constraint_map + intersect_not_empty = not bool(intersect_dep_and_same.is_empty()) + + """ + print("") + print("dep: %s" % (statement_pair_dep_set)) + print("map: ") + print(prettier_map_string(dep_constraint_map)) + print(intersect_not_empty) + print(intersect_dep_and_same) + """ # create a map representing constraints from the dependency, # maps statement instance to all statement instances that must occur later @@ -371,16 +380,9 @@ def get_dependency_maps( dom_before, dom_after, dep_constraint_map, - same_is_subset, + intersect_not_empty, ) ) - - for spds, _, _, constraint_map, same_is_subset in deps_domains_and_constraint_maps: - print("") - print("dep: %s" % (spds)) - print("map: ") - print(prettier_map_string(constraint_map)) - print(same_is_subset) print("") return deps_domains_and_constraint_maps diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 453708f1c..bf7f0b232 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -332,8 +332,8 @@ dep_graph_pairs = [ statement_pair_dep_set.statement_before.insn_id, statement_pair_dep_set.statement_after.insn_id ) - for statement_pair_dep_set, _, _, _, same_is_subset in dep_domains_and_maps - if same_is_subset + for statement_pair_dep_set, _, _, _, add_edge in dep_domains_and_maps + if add_edge ] dep_graph = create_graph_from_pairs(dep_graph_pairs) -- GitLab From d439535322d4773a3f1691aa1f3fc7160a176175 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 4 Jan 2020 20:23:21 -0600 Subject: [PATCH 162/183] fixing flake8 issues --- example_pairwise_schedule_validity.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index bf7f0b232..697e7f68c 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -288,7 +288,8 @@ if knl_choice == "loop_carried_deps": unprocessed_knl = knl.copy() -deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) +deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -309,7 +310,8 @@ from loopy import get_one_scheduled_kernel scheduled_knl = get_one_scheduled_kernel(knl) schedule_items = scheduled_knl.schedule -sched_is_valid = check_schedule_validity(knl, deps_and_domains, schedule_items, verbose=True) +sched_is_valid = check_schedule_validity( + knl, deps_and_domains, schedule_items, verbose=True) """ print("is sched valid? constraint map subset of SIO?") @@ -329,11 +331,11 @@ dep_domains_and_maps = get_dependency_maps( dep_graph_pairs = [ ( - statement_pair_dep_set.statement_before.insn_id, - statement_pair_dep_set.statement_after.insn_id + statement_pair_dep_set.statement_before.insn_id, + statement_pair_dep_set.statement_after.insn_id ) for statement_pair_dep_set, _, _, _, add_edge in dep_domains_and_maps - if add_edge + if add_edge ] dep_graph = create_graph_from_pairs(dep_graph_pairs) -- GitLab From 211f272a2e2dc5f9907b7a4bfaddd45475f4509a Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 6 Jan 2020 19:39:29 -0600 Subject: [PATCH 163/183] in get_dependency_maps(), allow for schedule item ids to be passed as strings instead of shedule items --- __init__.py | 9 +++++++-- example_pairwise_schedule_validity.py | 27 ++++++++++++++++++++------- sched_check_utils.py | 1 + 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/__init__.py b/__init__.py index 308827778..be235f11d 100644 --- a/__init__.py +++ b/__init__.py @@ -295,7 +295,7 @@ def check_schedule_validity( def get_dependency_maps( deps_and_domains, - schedule_items, + schedule_items, # TODO always pass these as strings since we only need the name? loop_priority, knl, # TODO avoid passing this in ): @@ -321,6 +321,10 @@ def get_dependency_maps( lp_insn_id = _get_insn_id_from_sched_item(sched_item) lp_insn_id_to_lex_sched_id[lp_insn_id] = next_sid next_sid += 1 + elif isinstance(sched_item, str): + # a string was passed, assume it's the insn_id + lp_insn_id_to_lex_sched_id[sched_item] = next_sid + next_sid += 1 from schedule_checker.sched_check_utils import ( get_concurrent_inames, @@ -336,7 +340,7 @@ def get_dependency_maps( dom_after, loop_priority, lp_insn_id_to_lex_sched_id, - "unused", # TODO shouldn't be necessary + "unused", # TODO shouldn't be necessary anymore "statement", ) @@ -374,6 +378,7 @@ def get_dependency_maps( # create a map representing constraints from the dependency, # maps statement instance to all statement instances that must occur later + # TODO instead of tuple, store all this in a class deps_domains_and_constraint_maps.append( ( statement_pair_dep_set, diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index 697e7f68c..d47d5b54f 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -288,7 +288,7 @@ if knl_choice == "loop_carried_deps": unprocessed_knl = knl.copy() -deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( +legacy_deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( unprocessed_knl) # get a schedule to check @@ -300,10 +300,10 @@ schedule_items = knl.schedule print("checking validity") sched_is_valid = check_schedule_validity( - unprocessed_knl, deps_and_domains, schedule_items, verbose=True) + unprocessed_knl, legacy_deps_and_domains, schedule_items, verbose=True) """ -deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) +legacy_deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(knl) # get a schedule to check from loopy import get_one_scheduled_kernel @@ -311,7 +311,7 @@ scheduled_knl = get_one_scheduled_kernel(knl) schedule_items = scheduled_knl.schedule sched_is_valid = check_schedule_validity( - knl, deps_and_domains, schedule_items, verbose=True) + knl, legacy_deps_and_domains, schedule_items, verbose=True) """ print("is sched valid? constraint map subset of SIO?") @@ -322,22 +322,35 @@ print("="*80) print("testing dep sort") print("="*80) -dep_domains_and_maps = get_dependency_maps( - deps_and_domains, +# create maps representing legacy deps +# (includes bool representing result of test for dep graph edge) +legacy_dep_domains_and_maps = get_dependency_maps( + legacy_deps_and_domains, schedule_items, knl.loop_priority, knl, ) +# tuples in legacy_dep_domains_and_maps look like this: +# ( +# statement_pair_dep_set, +# dom_before, +# dom_after, +# dep_constraint_map, +# intersect_not_empty, +# ) + +# get dep graph edges dep_graph_pairs = [ ( statement_pair_dep_set.statement_before.insn_id, statement_pair_dep_set.statement_after.insn_id ) - for statement_pair_dep_set, _, _, _, add_edge in dep_domains_and_maps + for statement_pair_dep_set, _, _, _, add_edge in legacy_dep_domains_and_maps if add_edge ] +# create dep graph from edges dep_graph = create_graph_from_pairs(dep_graph_pairs) print("dep_graph:") diff --git a/sched_check_utils.py b/sched_check_utils.py index df8c07797..ee3cbb532 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -489,6 +489,7 @@ def create_graph_from_pairs(before_after_pairs): graph[before] = graph[before] | set([after, ]) return graph + # only used for example purposes: -- GitLab From d920778491f489c5b998a2e966ee47f2440473e3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 8 Jan 2020 18:40:07 -0600 Subject: [PATCH 164/183] moved get_dependency_maps to dependency.py --- __init__.py | 100 -------------------------- dependency.py | 87 ++++++++++++++++++++++ example_pairwise_schedule_validity.py | 4 +- 3 files changed, 90 insertions(+), 101 deletions(-) diff --git a/__init__.py b/__init__.py index be235f11d..e0ae56a90 100644 --- a/__init__.py +++ b/__init__.py @@ -291,103 +291,3 @@ def check_schedule_validity( print("===========================================================") return sched_is_valid - - -def get_dependency_maps( - deps_and_domains, - schedule_items, # TODO always pass these as strings since we only need the name? - loop_priority, - knl, # TODO avoid passing this in - ): - - from schedule_checker.dependency import ( - create_dependency_constraint, - StatementPairDependencySet, - DependencyType as dt, - ) - from schedule_checker.sched_check_utils import ( - prettier_map_string, - ) - - # create map from loopy insn ids to ints - lp_insn_id_to_lex_sched_id = {} # TODO - next_sid = 0 - from loopy.schedule import Barrier, RunInstruction - for sched_item in schedule_items: - if isinstance(sched_item, (RunInstruction, Barrier)): - from schedule_checker.sched_check_utils import ( - _get_insn_id_from_sched_item, - ) - lp_insn_id = _get_insn_id_from_sched_item(sched_item) - lp_insn_id_to_lex_sched_id[lp_insn_id] = next_sid - next_sid += 1 - elif isinstance(sched_item, str): - # a string was passed, assume it's the insn_id - lp_insn_id_to_lex_sched_id[sched_item] = next_sid - next_sid += 1 - - from schedule_checker.sched_check_utils import ( - get_concurrent_inames, - ) - conc_inames, non_conc_inames = get_concurrent_inames(knl) - - deps_domains_and_constraint_maps = [] # TODO refactor this (maybe make a new data structure) - for statement_pair_dep_set, dom_before, dom_after in deps_and_domains: - - dep_constraint_map = create_dependency_constraint( - statement_pair_dep_set, - dom_before, - dom_after, - loop_priority, - lp_insn_id_to_lex_sched_id, - "unused", # TODO shouldn't be necessary anymore - "statement", - ) - - # create "same" dep for these two insns - s_before = statement_pair_dep_set.statement_before - s_after = statement_pair_dep_set.statement_after - shared_nc_inames = s_before.within_inames & s_after.within_inames & non_conc_inames - same_dep_set = StatementPairDependencySet( - s_before, - s_after, - {dt.SAME: shared_nc_inames} - ) - same_dep_constraint_map = create_dependency_constraint( - same_dep_set, - dom_before, - dom_after, - loop_priority, - lp_insn_id_to_lex_sched_id, - "unused", # TODO shouldn't be necessary - "statement", - ) - - # see whether we should create an edge in our statement dep graph - intersect_dep_and_same = same_dep_constraint_map & dep_constraint_map - intersect_not_empty = not bool(intersect_dep_and_same.is_empty()) - - """ - print("") - print("dep: %s" % (statement_pair_dep_set)) - print("map: ") - print(prettier_map_string(dep_constraint_map)) - print(intersect_not_empty) - print(intersect_dep_and_same) - """ - - # create a map representing constraints from the dependency, - # maps statement instance to all statement instances that must occur later - # TODO instead of tuple, store all this in a class - deps_domains_and_constraint_maps.append( - ( - statement_pair_dep_set, - dom_before, - dom_after, - dep_constraint_map, - intersect_not_empty, - ) - ) - print("") - - return deps_domains_and_constraint_maps diff --git a/dependency.py b/dependency.py index 56e6bcd73..9e4af1f96 100644 --- a/dependency.py +++ b/dependency.py @@ -793,3 +793,90 @@ def get_dependency_sources_and_sinks(knl, sched_item_ids): sinks = sched_item_ids - dependees return sources, sinks + + +def get_dependency_maps( + deps_and_domains, + schedule_items, # TODO always pass these as strings since we only need the name? + loop_priority, + knl, # TODO avoid passing this in + ): + + from schedule_checker.sched_check_utils import ( + prettier_map_string, + ) + dt = DependencyType + + # create map from loopy insn ids to ints + lp_insn_id_to_lex_sched_id = {} # TODO + next_sid = 0 + from loopy.schedule import Barrier, RunInstruction + for sched_item in schedule_items: + if isinstance(sched_item, (RunInstruction, Barrier)): + from schedule_checker.sched_check_utils import ( + _get_insn_id_from_sched_item, + ) + lp_insn_id = _get_insn_id_from_sched_item(sched_item) + lp_insn_id_to_lex_sched_id[lp_insn_id] = next_sid + next_sid += 1 + elif isinstance(sched_item, str): + # a string was passed, assume it's the insn_id + lp_insn_id_to_lex_sched_id[sched_item] = next_sid + next_sid += 1 + + from schedule_checker.sched_check_utils import ( + get_concurrent_inames, + ) + conc_inames, non_conc_inames = get_concurrent_inames(knl) + + deps_domains_and_constraint_maps = [] # TODO refactor this (maybe make a new data structure) + for statement_pair_dep_set, dom_before, dom_after in deps_and_domains: + + dep_constraint_map = create_dependency_constraint( + statement_pair_dep_set, + dom_before, + dom_after, + loop_priority, + lp_insn_id_to_lex_sched_id, + "unused", # TODO shouldn't be necessary anymore + "statement", + ) + + # create "same" dep for these two insns + s_before = statement_pair_dep_set.statement_before + s_after = statement_pair_dep_set.statement_after + shared_nc_inames = s_before.within_inames & s_after.within_inames & non_conc_inames + same_dep_set = StatementPairDependencySet( + s_before, + s_after, + {dt.SAME: shared_nc_inames} + ) + same_dep_constraint_map = create_dependency_constraint( + same_dep_set, + dom_before, + dom_after, + loop_priority, + lp_insn_id_to_lex_sched_id, + "unused", # TODO shouldn't be necessary + "statement", + ) + + # see whether we should create an edge in our statement dep graph + intersect_dep_and_same = same_dep_constraint_map & dep_constraint_map + intersect_not_empty = not bool(intersect_dep_and_same.is_empty()) + + # create a map representing constraints from the dependency, + # maps statement instance to all statement instances that must occur later + # TODO instead of tuple, store all this in a class + deps_domains_and_constraint_maps.append( + ( + statement_pair_dep_set, + dom_before, + dom_after, + dep_constraint_map, + intersect_not_empty, + ) + ) + print("") + + return deps_domains_and_constraint_maps diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index d47d5b54f..b8c3663e6 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -3,11 +3,13 @@ import numpy as np from schedule_checker import ( get_statement_pair_dependency_sets_from_legacy_knl, check_schedule_validity, - get_dependency_maps, ) from schedule_checker.sched_check_utils import ( create_graph_from_pairs, ) +from schedule_checker.dependency import ( + get_dependency_maps, +) from loopy.kernel import KernelState from loopy import ( preprocess_kernel, -- GitLab From 9b2628e561acc64d246c12a7cab42bcecda9aa94 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 8 Jan 2020 19:05:11 -0600 Subject: [PATCH 165/183] encapsulate dep info previously held in tuple --- dependency.py | 38 ++++++++++++++++++++------- example_pairwise_schedule_validity.py | 19 +++----------- 2 files changed, 32 insertions(+), 25 deletions(-) diff --git a/dependency.py b/dependency.py index 9e4af1f96..c00c9cad7 100644 --- a/dependency.py +++ b/dependency.py @@ -795,6 +795,24 @@ def get_dependency_sources_and_sinks(knl, sched_item_ids): return sources, sinks +class DependencyInfo(object): + # TODO rename + # TODO use Record? + def __init__( + self, + statement_pair_dep_set, + dom_before, + dom_after, + dep_constraint_map, + is_edge_in_dep_graph, # { dep & SAME } != empty + ): + self.statement_pair_dep_set = statement_pair_dep_set + self.dom_before = dom_before + self.dom_after = dom_after + self.dep_constraint_map = dep_constraint_map + self.is_edge_in_dep_graph = is_edge_in_dep_graph + + def get_dependency_maps( deps_and_domains, schedule_items, # TODO always pass these as strings since we only need the name? @@ -829,7 +847,7 @@ def get_dependency_maps( ) conc_inames, non_conc_inames = get_concurrent_inames(knl) - deps_domains_and_constraint_maps = [] # TODO refactor this (maybe make a new data structure) + dep_info_list = [] for statement_pair_dep_set, dom_before, dom_after in deps_and_domains: dep_constraint_map = create_dependency_constraint( @@ -868,15 +886,15 @@ def get_dependency_maps( # create a map representing constraints from the dependency, # maps statement instance to all statement instances that must occur later # TODO instead of tuple, store all this in a class - deps_domains_and_constraint_maps.append( - ( - statement_pair_dep_set, - dom_before, - dom_after, - dep_constraint_map, - intersect_not_empty, + dep_info_list.append( + DependencyInfo( + statement_pair_dep_set, + dom_before, + dom_after, + dep_constraint_map, + intersect_not_empty, + ) ) - ) print("") - return deps_domains_and_constraint_maps + return dep_info_list diff --git a/example_pairwise_schedule_validity.py b/example_pairwise_schedule_validity.py index b8c3663e6..542f6ee6f 100644 --- a/example_pairwise_schedule_validity.py +++ b/example_pairwise_schedule_validity.py @@ -326,31 +326,20 @@ print("="*80) # create maps representing legacy deps # (includes bool representing result of test for dep graph edge) -legacy_dep_domains_and_maps = get_dependency_maps( +legacy_dep_info_list = get_dependency_maps( legacy_deps_and_domains, schedule_items, knl.loop_priority, knl, ) -# tuples in legacy_dep_domains_and_maps look like this: -# ( -# statement_pair_dep_set, -# dom_before, -# dom_after, -# dep_constraint_map, -# intersect_not_empty, -# ) - # get dep graph edges dep_graph_pairs = [ ( - statement_pair_dep_set.statement_before.insn_id, - statement_pair_dep_set.statement_after.insn_id + dep.statement_pair_dep_set.statement_before.insn_id, + dep.statement_pair_dep_set.statement_after.insn_id ) - for statement_pair_dep_set, _, _, _, add_edge in legacy_dep_domains_and_maps - if add_edge - ] + for dep in legacy_dep_info_list if dep.is_edge_in_dep_graph] # create dep graph from edges dep_graph = create_graph_from_pairs(dep_graph_pairs) -- GitLab From 6f55ce11e9491b32c6401ba1d0d1c6799ca29566 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Jan 2020 05:40:44 -0600 Subject: [PATCH 166/183] sid_to_dom dicts now only contain one item, so no longer use dict --- __init__.py | 19 ++++--------------- example_wave_equation.py | 8 ++++++-- schedule.py | 19 ++++++++----------- 3 files changed, 18 insertions(+), 28 deletions(-) diff --git a/__init__.py b/__init__.py index e0ae56a90..6381c9cf7 100644 --- a/__init__.py +++ b/__init__.py @@ -136,25 +136,15 @@ def check_schedule_validity( # Get an isl map representing the LexSchedule; # this requires the iname domains - # get a mapping from lex schedule id to relevant inames domain - # TODO if sid_to_dom_before/after always contain single pair, - # maybe don't use dict - sid_to_dom_before = { - lp_insn_id_to_lex_sched_id[s_before.insn_id]: dom_before, - } - sid_to_dom_after = { - lp_insn_id_to_lex_sched_id[s_after.insn_id]: dom_after, - } - sched_map_symbolic_before, sched_map_symbolic_after = \ sched.create_symbolic_isl_map( - sid_to_dom_before, - sid_to_dom_after, + dom_before, + dom_after, ) if verbose: - print("sid_to_dom_before:\n", sid_to_dom_before) - print("sid_to_dom_after:\n", sid_to_dom_after) + print("dom_before:\n", dom_before) + print("dom_after:\n", dom_after) print("LexSchedule after creating symbolic isl map:") print(sched) print("LexSched:") @@ -215,7 +205,6 @@ def check_schedule_validity( import islpy as isl from schedule_checker.sched_check_utils import ( reorder_dims_by_name, - append_apostrophes, ) sio_in_names = sio.space.get_var_names(isl.dim_type.in_) aligned_constraint_map = reorder_dims_by_name( diff --git a/example_wave_equation.py b/example_wave_equation.py index 2be546a78..5860641b0 100644 --- a/example_wave_equation.py +++ b/example_wave_equation.py @@ -176,7 +176,9 @@ sid_to_dom = { sid_after: inames_domain_after, } -sched_map_symbolic = sched.create_symbolic_isl_map(sid_to_dom) +#sched_map_symbolic = sched.create_symbolic_isl_map(sid_to_dom) +sched_map_symbolic = sched.create_symbolic_isl_map( + inames_domain_before, inames_domain_after) # {{{ verbose @@ -449,7 +451,9 @@ sid_to_dom = { sid_after: inames_domain_after_mapped, } -sched_map_symbolic = sched.create_symbolic_isl_map(sid_to_dom) +#sched_map_symbolic = sched.create_symbolic_isl_map(sid_to_dom) +sched_map_symbolic = sched.create_symbolic_isl_map( + inames_domain_before_mapped, inames_domain_after_mapped) # {{{ verbose diff --git a/schedule.py b/schedule.py index 80002455e..661225805 100644 --- a/schedule.py +++ b/schedule.py @@ -269,8 +269,8 @@ class LexSchedule(object): def create_symbolic_isl_map( self, - sid_to_dom_before, - sid_to_dom_after, + dom_before, + dom_after, dom_inames_ordered_before=None, dom_inames_ordered_after=None, ): @@ -300,20 +300,15 @@ class LexSchedule(object): add_dims_to_isl_set ) - # TODO if sid_to_dom_before/after always contain single pair, - # maybe don't use dict - assert len(sid_to_dom_before) == 1 - assert len(sid_to_dom_after) == 1 - from schedule_checker.sched_check_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( - sid_to_dom_before.values()) + [dom_before]) if dom_inames_ordered_after is None: dom_inames_ordered_after = list_var_names_in_isl_sets( - sid_to_dom_after.values()) + [dom_after]) # create an isl space # {('statement', used in >=1 statement domain>) -> @@ -333,12 +328,14 @@ class LexSchedule(object): # intersection with sched map later doms_to_intersect_before = [ add_dims_to_isl_set( - sid_to_dom_before[self.lex_sched_stmt_before[0].int_id], isl.dim_type.set, + #sid_to_dom_before[self.lex_sched_stmt_before[0].int_id], isl.dim_type.set, + dom_before, isl.dim_type.set, [self.statement_var_name], 0), ] doms_to_intersect_after = [ add_dims_to_isl_set( - sid_to_dom_after[self.lex_sched_stmt_after[0].int_id], isl.dim_type.set, + #sid_to_dom_after[self.lex_sched_stmt_after[0].int_id], isl.dim_type.set, + dom_after, isl.dim_type.set, [self.statement_var_name], 0), ] -- GitLab From c0e6d5793836553827f34a673465738ab6e2823d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Jan 2020 06:06:03 -0600 Subject: [PATCH 167/183] add LexScheduleStatementInstance to use instead of a two-tuple holding a LexScheduleStatement and a point in lex space --- __init__.py | 1 - schedule.py | 125 +++++++++++++++++++++++++++++----------------------- 2 files changed, 69 insertions(+), 57 deletions(-) diff --git a/__init__.py b/__init__.py index 6381c9cf7..e3e9bd293 100644 --- a/__init__.py +++ b/__init__.py @@ -163,7 +163,6 @@ def check_schedule_validity( print("-"*80) """ - # TODO which direction does this composition go? # create statement instance ordering, # maps each statement instance to all statement instances occuring later sio = get_statement_ordering_map( diff --git a/schedule.py b/schedule.py index 661225805..38b6d66cc 100644 --- a/schedule.py +++ b/schedule.py @@ -2,7 +2,7 @@ import islpy as isl class LexScheduleStatement(object): - """A representation of a Loopy statement instance. + """A representation of a Loopy statement. .. attribute:: insn_id @@ -42,6 +42,23 @@ class LexScheduleStatement(object): self.insn_id, int_id, within_inames) +class LexScheduleStatementInstance(object): + """A representation of a Loopy statement instance. + + """ + + 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. @@ -103,8 +120,8 @@ class LexSchedule(object): # TODO update docs now that we have two schedules # LexScheduleStatements - self.lex_sched_stmt_before = None - self.lex_sched_stmt_after = None + self.stmt_instance_before = None + self.stmt_instance_after = None # make sure we don't have an iname name conflict assert not any( @@ -137,7 +154,7 @@ class LexSchedule(object): # don't increment lex dim val enumerating items in current block, # otherwise, this loop is next item in current code block, so # increment lex dim val enumerating items in current code block - if self.lex_sched_stmt_before or self.lex_sched_stmt_after: # if either statement has been set + if self.stmt_instance_before or self.stmt_instance_after: # if either statement has been set # this lex value will correspond to everything inside this loop # we will add new lex dimensions to enuerate items inside loop next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 @@ -179,47 +196,43 @@ class LexSchedule(object): # otherwise process all instructions if lp_insn_id == before_insn_id and lp_insn_id == after_insn_id: # add before sched item - self.lex_sched_stmt_before = ( - LexScheduleStatement( - insn_id=lp_insn_id, - int_id=next_sid, # int representing insn - ), - next_insn_lex_pt[:] - ) + 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.lex_sched_stmt_after = ( - LexScheduleStatement( - insn_id=lp_insn_id, - int_id=next_sid, # int representing insn - ), - next_insn_lex_pt[:] - ) + 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 elif lp_insn_id == before_insn_id: # add before sched item - self.lex_sched_stmt_before = ( - LexScheduleStatement( - insn_id=lp_insn_id, - int_id=next_sid, # int representing insn - ), - next_insn_lex_pt[:] - ) + 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 elif lp_insn_id == after_insn_id: # add after sched item - self.lex_sched_stmt_after = ( - LexScheduleStatement( - insn_id=lp_insn_id, - int_id=next_sid, # int representing insn - ), - next_insn_lex_pt[:] - ) + 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 @@ -227,7 +240,7 @@ class LexSchedule(object): else: pass # to save time, stop when we've created both statements - if self.lex_sched_stmt_before and self.lex_sched_stmt_after: + if self.stmt_instance_before and self.stmt_instance_after: break # at this point, lex_schedule may contain lex points missing dimensions, @@ -240,12 +253,12 @@ class LexSchedule(object): :class:`LexScheduleStatement`. """ return { - self.lex_sched_stmt_before[0].insn_id: self.lex_sched_stmt_before[0].int_id, - self.lex_sched_stmt_after[0].insn_id: self.lex_sched_stmt_after[0].int_id, + 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.lex_sched_stmt_before[1]), len(self.lex_sched_stmt_after[1])]) + 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 @@ -256,15 +269,15 @@ class LexSchedule(object): """ max_lex_dim = self.max_lex_dims() - self.lex_sched_stmt_before = ( - self.lex_sched_stmt_before[0], - self.lex_sched_stmt_before[1][:] + [0]*( - max_lex_dim-len(self.lex_sched_stmt_before[1])) + 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.lex_sched_stmt_after = ( - self.lex_sched_stmt_after[0], - self.lex_sched_stmt_after[1][:] + [0]*( - max_lex_dim-len(self.lex_sched_stmt_after[1])) + 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_symbolic_isl_map( @@ -328,13 +341,13 @@ class LexSchedule(object): # intersection with sched map later doms_to_intersect_before = [ add_dims_to_isl_set( - #sid_to_dom_before[self.lex_sched_stmt_before[0].int_id], isl.dim_type.set, + #sid_to_dom_before[self.stmt_instance_before.stmt.int_id], isl.dim_type.set, dom_before, isl.dim_type.set, [self.statement_var_name], 0), ] doms_to_intersect_after = [ add_dims_to_isl_set( - #sid_to_dom_after[self.lex_sched_stmt_after[0].int_id], isl.dim_type.set, + #sid_to_dom_after[self.stmt_instance_after.stmt.int_id], isl.dim_type.set, dom_after, isl.dim_type.set, [self.statement_var_name], 0), ] @@ -353,15 +366,15 @@ class LexSchedule(object): return ( create_symbolic_isl_map_from_tuples( zip( - [((self.lex_sched_stmt_before[0].int_id,) + tuple(dom_inames_ordered_before), - self.lex_sched_stmt_before[1])], + [((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.unused_param_name, self.statement_var_name), create_symbolic_isl_map_from_tuples( zip( - [((self.lex_sched_stmt_after[0].int_id,) + tuple(dom_inames_ordered_after), - self.lex_sched_stmt_after[1])], + [((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.unused_param_name, self.statement_var_name) @@ -388,21 +401,21 @@ class LexSchedule(object): return self.__bool__() def __eq__(self, other): - return (self.lex_sched_stmt_before == other.lex_sched_stmt_before and - self.lex_sched_stmt_after == other.lex_sched_stmt_after) + 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.lex_sched_stmt_before[0].int_id) - sched_str += "%s -> %s;\n" % (domain_elem, self.lex_sched_stmt_before[1]) + 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.lex_sched_stmt_after[0].int_id) - sched_str += "%s -> %s;\n" % (domain_elem, self.lex_sched_stmt_after[1]) + 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 -- GitLab From 58dba1f52486c68a548f102a40c798d8888ab108 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Mon, 13 Jan 2020 11:47:59 -0600 Subject: [PATCH 168/183] switch notation so that primes are used to denote statement *before* (dependee) rather than statement after (depender) --- dependency.py | 121 ++++++++++++++++--------------------- lexicographic_order_map.py | 17 +++--- sched_check_utils.py | 4 +- 3 files changed, 63 insertions(+), 79 deletions(-) diff --git a/dependency.py b/dependency.py index c00c9cad7..c72219222 100644 --- a/dependency.py +++ b/dependency.py @@ -1,6 +1,9 @@ import islpy as isl +# TODO update all documentation/comments after apostrophe switched to +# *before* statement/inames + class DependencyType: """Strings specifying a particular type of dependency relationship. @@ -209,15 +212,18 @@ def create_dependency_constraint( statement_var_name_prime = statement_var_name+"'" # get (ordered) list of unused before/after inames - # TODO are there ever unused inames now that we're separating the in/out spaces? inames_before_unused = [] for iname in dom_inames_ordered_before: if iname not in dom_before_constraint_set.get_var_names(isl.dim_type.out): - inames_before_unused.append(iname) + inames_before_unused.append(iname + "'") inames_after_unused = [] for iname in dom_inames_ordered_after: if iname not in dom_after_constraint_set.get_var_names(isl.dim_type.out): - inames_after_unused.append(iname + "'") + inames_after_unused.append(iname) + + # TODO are there ever unused inames now that we're separating the in/out spaces? + if inames_before_unused or inames_after_unused: + assert False # initialize constraints to False # this will disappear as soon as we add a constraint @@ -237,7 +243,7 @@ def create_dependency_constraint( if dep_type == dt.SAME: constraint_set = create_elementwise_comparison_conjunction_set( - inames_list, inames_prime, islvars, op="eq") + inames_prime, inames_list, islvars, op="eq") elif dep_type == dt.PRIOR: priority_known = False @@ -317,14 +323,15 @@ def create_dependency_constraint( # TODO handle case where inames list is empty constraint_set = get_lex_order_constraint( islvars, - inames_list_nest_ordered, inames_list_nest_ordered_prime, + inames_list_nest_ordered, ) else: # priority not known # PRIOR requires upper left quadrant happen before: constraint_set = create_elementwise_comparison_conjunction_set( - inames_list, inames_prime, islvars, op="lt") + inames_prime, inames_list, islvars, op="lt") + # TODO remove, this shouldn't happen anymore # set unused vars == unused dummy param for iname in inames_before_unused+inames_after_unused: constraint_set = constraint_set & islvars[iname].eq_set( @@ -333,9 +340,9 @@ def create_dependency_constraint( # set statement_var_name == statement # s_before_int = insn_id_to_int[statement_dep_set.statement_before.insn_id] s_after_int = insn_id_to_int[statement_dep_set.statement_after.insn_id] - constraint_set = constraint_set & islvars[statement_var_name].eq_set( - islvars[0]+s_before_int) constraint_set = constraint_set & islvars[statement_var_name_prime].eq_set( + islvars[0]+s_before_int) + constraint_set = constraint_set & islvars[statement_var_name].eq_set( islvars[0]+s_after_int) # union this constraint_set with all_constraints_set @@ -351,23 +358,23 @@ def create_dependency_constraint( # now apply domain sets to constraint variables # add statement variable to doms to enable intersection - domain_to_intersect = add_dims_to_isl_set( - dom_before_constraint_set, isl.dim_type.out, - [statement_var_name], statement_var_pose) - range_constraint_set = create_new_isl_set_with_primes(dom_after_constraint_set) range_to_intersect = add_dims_to_isl_set( - range_constraint_set, isl.dim_type.out, + dom_after_constraint_set, isl.dim_type.out, + [statement_var_name], statement_var_pose) + domain_constraint_set = create_new_isl_set_with_primes(dom_before_constraint_set) + domain_to_intersect = add_dims_to_isl_set( + domain_constraint_set, isl.dim_type.out, [statement_var_name_prime], statement_var_pose) # insert inames missing from doms to enable intersection domain_to_intersect = reorder_dims_by_name( domain_to_intersect, isl.dim_type.out, - [statement_var_name] + dom_inames_ordered_before, + append_apostrophes([statement_var_name] + dom_inames_ordered_before), add_missing=True) range_to_intersect = reorder_dims_by_name( range_to_intersect, isl.dim_type.out, - append_apostrophes([statement_var_name] + dom_inames_ordered_after), + [statement_var_name] + dom_inames_ordered_after, add_missing=True) # intersect doms @@ -417,11 +424,11 @@ def _create_5pt_stencil_dependency_constraint( inames_before_unused = [] for iname in all_dom_inames_ordered: if iname not in dom_before_constraint_set.get_var_names(isl.dim_type.out): - inames_before_unused.append(iname) + inames_before_unused.append(iname + "'") inames_after_unused = [] for iname in all_dom_inames_ordered: if iname not in dom_after_constraint_set.get_var_names(isl.dim_type.out): - inames_after_unused.append(iname + "'") + inames_after_unused.append(iname) # initialize constraints to False # this will disappear as soon as we add a constraint @@ -446,30 +453,29 @@ def _create_5pt_stencil_dependency_constraint( """ # local dep: constraint_set = ( - islvars[time_iname_prime].eq_set(islvars[time_iname] + one) & + islvars[time_iname].eq_set(islvars[time_iname_prime] + one) & ( - (islvars[space_iname_prime]-two).lt_set(islvars[space_iname]) & - islvars[space_iname].lt_set(islvars[space_iname_prime]+two) + (islvars[space_iname]-two).lt_set(islvars[space_iname_prime]) & + islvars[space_iname_prime].lt_set(islvars[space_iname]+two) ) #( - #(islvars[space_iname]-two).lt_set(islvars[space_iname_prime]) & - # islvars[space_iname_prime].lt_set(islvars[space_iname]+two) + #(islvars[space_iname_prime]-two).lt_set(islvars[space_iname]) & + # islvars[space_iname].lt_set(islvars[space_iname_prime]+two) #) | - islvars[time_iname_prime].eq_set(islvars[time_iname] + two) & - islvars[space_iname].eq_set(islvars[space_iname_prime]) + islvars[time_iname].eq_set(islvars[time_iname_prime] + two) & + islvars[space_iname_prime].eq_set(islvars[space_iname]) ) - # set unused vars == unused dummy param for iname in inames_before_unused+inames_after_unused: constraint_set = constraint_set & islvars[iname].eq_set( islvars[unused_param_name]) # set statement_var_name == statement # - constraint_set = constraint_set & islvars[statement_var_name].eq_set( - islvars[0]+sid_before) constraint_set = constraint_set & islvars[statement_var_name_prime].eq_set( + islvars[0]+sid_before) + constraint_set = constraint_set & islvars[statement_var_name].eq_set( islvars[0]+sid_after) # convert constraint set to map @@ -479,23 +485,23 @@ def _create_5pt_stencil_dependency_constraint( # now apply domain sets to constraint variables # add statement variable to doms to enable intersection - domain_to_intersect = add_dims_to_isl_set( - dom_before_constraint_set, isl.dim_type.out, - [statement_var_name], statement_var_pose) - range_constraint_set = create_new_isl_set_with_primes(dom_after_constraint_set) range_to_intersect = add_dims_to_isl_set( - range_constraint_set, isl.dim_type.out, + dom_after_constraint_set, isl.dim_type.out, + [statement_var_name], statement_var_pose) + domain_constraint_set = create_new_isl_set_with_primes(dom_before_constraint_set) + domain_to_intersect = add_dims_to_isl_set( + domain_constraint_set, isl.dim_type.out, [statement_var_name_prime], statement_var_pose) # insert inames missing from doms to enable intersection domain_to_intersect = reorder_dims_by_name( domain_to_intersect, isl.dim_type.out, - [statement_var_name] + all_dom_inames_ordered, + append_apostrophes([statement_var_name] + all_dom_inames_ordered), add_missing=True) range_to_intersect = reorder_dims_by_name( range_to_intersect, isl.dim_type.out, - append_apostrophes([statement_var_name] + all_dom_inames_ordered), + [statement_var_name] + all_dom_inames_ordered, add_missing=True) # intersect doms @@ -518,6 +524,7 @@ def create_arbitrary_dependency_constraint( ): # TODO update after allowing different inames for before/after + # TODO test after switching primes to before vars from schedule_checker.sched_check_utils import ( make_islvars_with_var_primes, @@ -549,12 +556,12 @@ def create_arbitrary_dependency_constraint( inames_before_unused = [] for iname in all_dom_inames_ordered: if iname not in dom_before_constraint_set.get_var_names(isl.dim_type.out): - inames_before_unused.append(iname) + inames_before_unused.append(iname + "p") inames_after_unused = [] for iname in all_dom_inames_ordered: if iname not in dom_after_constraint_set.get_var_names(isl.dim_type.out): #inames_after_unused.append(iname + "'") - inames_after_unused.append(iname + "p") # TODO figure out before/after notation + inames_after_unused.append(iname) # TODO figure out before/after notation # initialize constraints to False # this will disappear as soon as we add a constraint @@ -604,41 +611,15 @@ def create_arbitrary_dependency_constraint( 1/0 all_constraints_set = all_constraints_set | conj_constraint - #TODO deleteme - """ - space_iname = "ix" - time_iname = "it" - - space_iname_prime = space_iname + "'" - time_iname_prime = time_iname + "'" - one = islvars[0] + 1 - two = islvars[0] + 2 - # local dep: - constraint_set = ( - islvars[time_iname_prime].eq_set(islvars[time_iname] + one) & - ( - (islvars[space_iname_prime]-two).lt_set(islvars[space_iname]) & - islvars[space_iname].lt_set(islvars[space_iname_prime]+two) - ) - #( - #(islvars[space_iname]-two).lt_set(islvars[space_iname_prime]) & - # islvars[space_iname_prime].lt_set(islvars[space_iname]+two) - #) - | - islvars[time_iname_prime].eq_set(islvars[time_iname] + two) & - islvars[space_iname].eq_set(islvars[space_iname_prime]) - ) - """ - # set unused vars == unused dummy param for iname in inames_before_unused+inames_after_unused: all_constraints_set = all_constraints_set & islvars[iname].eq_set( islvars[unused_param_name]) # set statement_var_name == statement # - all_constraints_set = all_constraints_set & islvars[statement_var_name].eq_set( - islvars[0]+sid_before) all_constraints_set = all_constraints_set & islvars[statement_var_name_prime].eq_set( + islvars[0]+sid_before) + all_constraints_set = all_constraints_set & islvars[statement_var_name].eq_set( islvars[0]+sid_after) # convert constraint set to map @@ -648,14 +629,14 @@ def create_arbitrary_dependency_constraint( # now apply domain sets to constraint variables # add statement variable to doms to enable intersection - domain_to_intersect = add_dims_to_isl_set( - dom_before_constraint_set, isl.dim_type.out, + range_to_intersect = add_dims_to_isl_set( + dom_after_constraint_set, isl.dim_type.out, [statement_var_name], statement_var_pose) - range_constraint_set = create_new_isl_set_with_primes( - dom_after_constraint_set, + domain_constraint_set = create_new_isl_set_with_primes( + dom_before_constraint_set, marker="p") # TODO figure out before/after notation - range_to_intersect = add_dims_to_isl_set( - range_constraint_set, isl.dim_type.out, + domain_to_intersect = add_dims_to_isl_set( + domain_constraint_set, isl.dim_type.out, [statement_var_name_prime], statement_var_pose) # insert inames missing from doms to enable intersection diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index ccfb9d6f9..52afadaa0 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -2,7 +2,7 @@ import islpy as isl def get_statement_ordering_map( - sched_map_before, sched_map_after, lex_map, out_marker="'"): + sched_map_before, sched_map_after, lex_map, before_marker="'"): """Return a mapping that maps each statement instance to all statement instances occuring later. @@ -25,12 +25,11 @@ def get_statement_ordering_map( """ - # TODO determine which order is correct sio = sched_map_before.apply_range(lex_map).apply_range(sched_map_after.reverse()) - # append marker to out names - for i in range(sio.dim(isl.dim_type.out)): - sio = sio.set_dim_name(isl.dim_type.out, i, sio.get_dim_name( - isl.dim_type.out, i)+out_marker) + # 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 @@ -109,8 +108,10 @@ 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: - from schedule_checker.sched_check_utils import append_apostrophes - after_names = append_apostrophes(before_names) + from schedule_checker.sched_check_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 diff --git a/sched_check_utils.py b/sched_check_utils.py index ee3cbb532..9d64ac221 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -2,6 +2,8 @@ import islpy as isl # TODO remove assertions once satisified they are unnecessary +# TODO update all documentation/comments after apostrophe switched to +# *before* statement/inames def prettier_map_string(isl_map): @@ -145,7 +147,7 @@ def make_islvars_with_var_primes( var_names_out = var_names_in[:] return isl.make_zero_and_vars( - var_names_in+append_marker(var_names_out, marker), param_names) + append_marker(var_names_in, marker) + var_names_out, param_names) def append_marker_to_strings(strings, marker="'"): -- GitLab From 4c3b68b4eca4d63506b3a914966b6a211e378b5d Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Jan 2020 19:16:05 -0600 Subject: [PATCH 169/183] store iname domains for before/after insn inside the StatementPairDependencySet instead of separately --- __init__.py | 33 +++++----------- dependency.py | 71 ++++++++++++++++++---------------- example_dependency_checking.py | 14 ++----- example_wave_equation.py | 2 - 4 files changed, 52 insertions(+), 68 deletions(-) diff --git a/__init__.py b/__init__.py index e3e9bd293..c965be217 100644 --- a/__init__.py +++ b/__init__.py @@ -21,20 +21,7 @@ def get_statement_pair_dependency_sets_from_legacy_knl(knl): # For each set of insns within a given iname subset, find sources and sinks, # then make PRIOR dep from all sinks to all sources at previous iterations. - statement_pair_dep_sets = create_dependencies_from_legacy_knl(preprocessed_knl) - - # get separate domains for before.within_inames and after.within_inames - deps_and_domains = [] - for dep_set in statement_pair_dep_sets: - deps_and_domains.append([ - dep_set, - preprocessed_knl.get_inames_domain( - dep_set.statement_before.within_inames), - preprocessed_knl.get_inames_domain( - dep_set.statement_after.within_inames) - ]) - - return deps_and_domains + return create_dependencies_from_legacy_knl(preprocessed_knl) # TODO create a set of broken kernels to test against @@ -75,10 +62,10 @@ def check_schedule_validity( if verbose: print("="*80) print("StatementDependencies w/domains:") - for dep_set, dom_before, dom_after in deps_and_domains: + for dep_set in deps_and_domains: print(dep_set) - print(dom_before) - print(dom_after) + print(dep_set.dom_before) + print(dep_set.dom_after) # Print kernel info ------------------------------------------------------ print("="*80) @@ -100,7 +87,12 @@ def check_schedule_validity( # For each dependency, create+test schedule containing pair of insns------ sched_is_valid = True - for statement_pair_dep_set, dom_before, dom_after in deps_and_domains: + for statement_pair_dep_set in deps_and_domains: + s_before = statement_pair_dep_set.statement_before + s_after = statement_pair_dep_set.statement_after + dom_before = statement_pair_dep_set.dom_before + dom_after = statement_pair_dep_set.dom_after + if verbose: print("="*80) print("statement dep set:") @@ -108,9 +100,6 @@ def check_schedule_validity( print("dom_before:", dom_before) print("dom_after:", dom_after) - s_before = statement_pair_dep_set.statement_before - s_after = statement_pair_dep_set.statement_after - # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency sched = LexSchedule( @@ -182,8 +171,6 @@ def check_schedule_validity( # maps statement instance to all statement instances that must occur later constraint_map = create_dependency_constraint( statement_pair_dep_set, - dom_before, - dom_after, knl.loop_priority, lp_insn_id_to_lex_sched_id, sched.unused_param_name, diff --git a/dependency.py b/dependency.py index c72219222..3f2318ed1 100644 --- a/dependency.py +++ b/dependency.py @@ -65,10 +65,14 @@ class StatementPairDependencySet(object): statement_before, statement_after, deps, # {dep_type: iname_set} + dom_before=None, + dom_after=None, ): self.statement_before = statement_before self.statement_after = statement_after self.deps = deps + self.dom_before = dom_before + self.dom_after = dom_after def __str__(self): result = "%s --before->\n%s iff\n " % ( @@ -124,8 +128,6 @@ def _convert_constraint_set_to_map(constraint_set, mv_count, src_position=None): def create_dependency_constraint( statement_dep_set, - dom_before_constraint_set, - dom_after_constraint_set, loop_priorities, insn_id_to_int, unused_param_name, @@ -198,10 +200,10 @@ def create_dependency_constraint( ) if dom_inames_ordered_before is None: dom_inames_ordered_before = list_var_names_in_isl_sets( - [dom_before_constraint_set]) + [statement_dep_set.dom_before]) if dom_inames_ordered_after is None: dom_inames_ordered_after = list_var_names_in_isl_sets( - [dom_after_constraint_set]) + [statement_dep_set.dom_after]) # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} islvars = make_islvars_with_var_primes( @@ -214,11 +216,11 @@ def create_dependency_constraint( # get (ordered) list of unused before/after inames inames_before_unused = [] for iname in dom_inames_ordered_before: - if iname not in dom_before_constraint_set.get_var_names(isl.dim_type.out): + if iname not in statement_dep_set.dom_before.get_var_names(isl.dim_type.out): inames_before_unused.append(iname + "'") inames_after_unused = [] for iname in dom_inames_ordered_after: - if iname not in dom_after_constraint_set.get_var_names(isl.dim_type.out): + if iname not in statement_dep_set.dom_after.get_var_names(isl.dim_type.out): inames_after_unused.append(iname) # TODO are there ever unused inames now that we're separating the in/out spaces? @@ -359,9 +361,9 @@ def create_dependency_constraint( # add statement variable to doms to enable intersection range_to_intersect = add_dims_to_isl_set( - dom_after_constraint_set, isl.dim_type.out, + statement_dep_set.dom_after, isl.dim_type.out, [statement_var_name], statement_var_pose) - domain_constraint_set = create_new_isl_set_with_primes(dom_before_constraint_set) + domain_constraint_set = create_new_isl_set_with_primes(statement_dep_set.dom_before) domain_to_intersect = add_dims_to_isl_set( domain_constraint_set, isl.dim_type.out, [statement_var_name_prime], statement_var_pose) @@ -688,23 +690,24 @@ def create_dependencies_from_legacy_knl(knl): statement_dep_sets = [] for insn_after in knl.instructions: for insn_before_id in insn_after.depends_on: - dep_dict = {} insn_before = knl.id_to_insn[insn_before_id] insn_before_inames = insn_before.within_inames insn_after_inames = insn_after.within_inames shared_inames = insn_before_inames & insn_after_inames shared_non_conc_inames = shared_inames & non_conc_inames - dep_dict[dt.SAME] = shared_non_conc_inames - - s_before = LexScheduleStatement( - insn_id=insn_before.id, - within_inames=insn_before_inames) - s_after = LexScheduleStatement( - insn_id=insn_after.id, - within_inames=insn_after_inames) statement_dep_sets.append( - StatementPairDependencySet(s_before, s_after, dep_dict)) + StatementPairDependencySet( + LexScheduleStatement( + insn_id=insn_before.id, + within_inames=insn_before_inames), + LexScheduleStatement( + insn_id=insn_after.id, + within_inames=insn_after_inames), + {dt.SAME: shared_non_conc_inames}, + knl.get_inames_domain(insn_before_inames), + knl.get_inames_domain(insn_after_inames), + )) # loop-carried deps ------------------------------------------ @@ -732,16 +735,18 @@ def create_dependencies_from_legacy_knl(knl): shared_inames = sink_insn_inames & source_insn_inames shared_non_conc_inames = shared_inames & non_conc_inames - dep_dict[dt.PRIOR] = shared_non_conc_inames - - s_before = LexScheduleStatement( - insn_id=sink_id, - within_inames=sink_insn_inames) - s_after = LexScheduleStatement( - insn_id=source_id, - within_inames=source_insn_inames) statement_dep_sets.append( - StatementPairDependencySet(s_before, s_after, dep_dict)) + StatementPairDependencySet( + LexScheduleStatement( + insn_id=sink_id, + within_inames=sink_insn_inames), + LexScheduleStatement( + insn_id=source_id, + within_inames=source_insn_inames), + {dt.PRIOR: shared_non_conc_inames}, + knl.get_inames_domain(sink_insn_inames), + knl.get_inames_domain(source_insn_inames), + )) return statement_dep_sets @@ -829,12 +834,10 @@ def get_dependency_maps( conc_inames, non_conc_inames = get_concurrent_inames(knl) dep_info_list = [] - for statement_pair_dep_set, dom_before, dom_after in deps_and_domains: + for statement_pair_dep_set in deps_and_domains: dep_constraint_map = create_dependency_constraint( statement_pair_dep_set, - dom_before, - dom_after, loop_priority, lp_insn_id_to_lex_sched_id, "unused", # TODO shouldn't be necessary anymore @@ -844,16 +847,18 @@ def get_dependency_maps( # create "same" dep for these two insns s_before = statement_pair_dep_set.statement_before s_after = statement_pair_dep_set.statement_after + dom_before = statement_pair_dep_set.dom_before + dom_after = statement_pair_dep_set.dom_after shared_nc_inames = s_before.within_inames & s_after.within_inames & non_conc_inames same_dep_set = StatementPairDependencySet( s_before, s_after, - {dt.SAME: shared_nc_inames} + {dt.SAME: shared_nc_inames}, + dom_before, + dom_after, ) same_dep_constraint_map = create_dependency_constraint( same_dep_set, - dom_before, - dom_after, loop_priority, lp_insn_id_to_lex_sched_id, "unused", # TODO shouldn't be necessary diff --git a/example_dependency_checking.py b/example_dependency_checking.py index 52c554607..54ab553db 100644 --- a/example_dependency_checking.py +++ b/example_dependency_checking.py @@ -107,26 +107,20 @@ s0 = LexScheduleStatement(insn_id="0", within_inames={"i", "j"}) s1 = LexScheduleStatement(insn_id="1", within_inames={"i", "j"}) insnid_to_int_sid = {"0": 0, "1": 1} +dom_before = knl.get_inames_domain(s0.within_inames) +dom_after = knl.get_inames_domain(s1.within_inames) + statement_pair_dep_set = StatementPairDependencySet( - s0, s1, {dt.SAME: ["i", "j"]}) + s0, s1, {dt.SAME: ["i", "j"]}, dom_before, dom_after) # SAME({i,j}) means: # insn0{i,j} happens before insn1{i',j'} iff i = i' and j = j' print("Statement pair dependency set:") print(statement_pair_dep_set) -dom_before = knl.get_inames_domain( - statement_pair_dep_set.statement_before.within_inames - ) -dom_after = knl.get_inames_domain( - statement_pair_dep_set.statement_after.within_inames - ) - loop_priority = None constraint_map = create_dependency_constraint( statement_pair_dep_set, - dom_before, - dom_after, loop_priority, insnid_to_int_sid, unused_param_name, diff --git a/example_wave_equation.py b/example_wave_equation.py index 5860641b0..af6e52f2f 100644 --- a/example_wave_equation.py +++ b/example_wave_equation.py @@ -14,8 +14,6 @@ from schedule_checker.sched_check_utils import ( append_apostrophes, ) from schedule_checker.dependency import ( - create_dependencies_from_legacy_knl, - create_dependency_constraint, create_arbitrary_dependency_constraint, ) from dependency import _create_5pt_stencil_dependency_constraint -- GitLab From 1e1b6e9238577bf0ab59f5a55c7d27f7263ceae6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Jan 2020 21:06:50 -0600 Subject: [PATCH 170/183] added append_marker_to_isl_map_var_names() --- sched_check_utils.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sched_check_utils.py b/sched_check_utils.py index 9d64ac221..32317cccb 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -108,6 +108,7 @@ def create_new_isl_set_with_primes(old_isl_set, marker="'"): apostrophes appended to dim_type.set dimension names. """ + # TODO this is a special case of append_marker_to_isl_map_var_names new_set = old_isl_set.copy() for i in range(old_isl_set.n_dim()): @@ -116,6 +117,27 @@ def create_new_isl_set_with_primes(old_isl_set, marker="'"): return new_set +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. + + .. return: 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 make_islvars_with_var_primes( var_names_in, param_names, marker="'", var_names_out=None): """Return a dictionary from variable and parameter names -- GitLab From 85b04a4ff2f45d0c7516f6a6766ae7cfad97cf2e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Jan 2020 21:09:13 -0600 Subject: [PATCH 171/183] updated example_wave_equation.py to be consistent with recent changes to schedule checking functions (schedules containing before+after map instead of single mapping, LexSchedule requiring list of sched items, markers being applied to dependee instead of depender) --- example_wave_equation.py | 91 ++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/example_wave_equation.py b/example_wave_equation.py index af6e52f2f..6afa3044b 100644 --- a/example_wave_equation.py +++ b/example_wave_equation.py @@ -12,6 +12,7 @@ from schedule_checker.sched_check_utils import ( prettier_map_string, reorder_dims_by_name, append_apostrophes, + append_marker_to_isl_map_var_names, ) from schedule_checker.dependency import ( create_arbitrary_dependency_constraint, @@ -105,7 +106,8 @@ print(prettier_map_string(constraint_map)) """ # TODO testing new dep map constraint_map = create_arbitrary_dependency_constraint( - "itp = it + 1 and ixp - 2 < ix and ix < ixp + 2 or itp = it + 2 and ix = ixp", + #"itp = it + 1 and ixp - 2 < ix and ix < ixp + 2 or itp = it + 2 and ix = ixp", + "it = itp + 1 and ix - 2 < ixp and ixp < ix + 2 or it = itp + 2 and ixp = ix", # primes moved to 'before' statement inames_domain_before, inames_domain_after, sid_before = sid_before, @@ -120,7 +122,7 @@ print("constraint_map before mapping:") print(prettier_map_string(constraint_map)) # TODO (left off here) # TODO decide on before/after notation and make consistent -1/0 +#1/0 verbose = False verbose = True @@ -156,18 +158,11 @@ if verbose: # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency -sched = LexSchedule(scheduled_knl, include_only_insn_ids=[ - str(sid_before), - str(sid_after) - ]) +sched = LexSchedule(scheduled_knl, scheduled_knl.schedule, str(sid_before), str(sid_after)) # Get an isl map representing the LexSchedule; # this requires the iname domains -assert len(sched) in [1, 2] -if len(sched) == 1: - assert inames_domain_before == inames_domain_after - # get a mapping from lex schedule id to relevant inames domain sid_to_dom = { sid_before: inames_domain_before, @@ -175,7 +170,7 @@ sid_to_dom = { } #sched_map_symbolic = sched.create_symbolic_isl_map(sid_to_dom) -sched_map_symbolic = sched.create_symbolic_isl_map( +sched_map_symbolic_before, sched_map_symbolic_after = sched.create_symbolic_isl_maps( inames_domain_before, inames_domain_after) # {{{ verbose @@ -185,7 +180,8 @@ if verbose: print("LexSchedule after creating symbolic isl map:") print(sched) print("LexSched:") - print(prettier_map_string(sched_map_symbolic)) + print(prettier_map_string(sched_map_symbolic_before)) + print(prettier_map_string(sched_map_symbolic_after)) #print("space (statement instances -> lex time):") #print(sched_map_symbolic.space) #print("-"*80) @@ -211,7 +207,10 @@ if verbose: # create statement instance ordering, # maps each statement instance to all statement instances occuring later sio = get_statement_ordering_map( - sched_map_symbolic, lex_order_map_symbolic) + sched_map_symbolic_before, + sched_map_symbolic_after, + lex_order_map_symbolic, + before_marker="p") # {{{ verbose @@ -244,11 +243,11 @@ aligned_constraint_map = reorder_dims_by_name( ) # align out dims +sio_out_names = sio.space.get_var_names(isl.dim_type.out) aligned_constraint_map = reorder_dims_by_name( aligned_constraint_map, isl.dim_type.out, - append_apostrophes(sio_in_names), - # TODO sio out names are only pretending to have apostrophes; confusing + sio_out_names, add_missing=False, new_names_are_permutation_only=True, ) @@ -269,7 +268,7 @@ assert ( == sio.space.get_var_names(isl.dim_type.in_)) assert ( aligned_constraint_map.space.get_var_names(isl.dim_type.out) - == append_apostrophes(sio.space.get_var_names(isl.dim_type.out))) + == sio.space.get_var_names(isl.dim_type.out)) assert ( aligned_constraint_map.space.get_var_names(isl.dim_type.param) == sio.space.get_var_names(isl.dim_type.param)) @@ -354,11 +353,16 @@ m2 = isl.BasicMap( "16*(tx - tt) + itx - itt = ix - it and " "16*(tx + tt + tparity) + itt + itx = ix + it and " "0<=tparity<2 and 0 <= itx - itt < 16 and 0 <= itt+itx < 16}") +#m2_primes_after = isl.BasicMap( +# "[nx,nt,unused] -> {[statement, ix, it] -> [statement'=statement, tx', tt', tparity', itt', itx']: " +# "16*(tx' - tt') + itx' - itt' = ix - it and " +# "16*(tx' + tt' + tparity') + itt' + itx' = ix + it and " +# "0<=tparity'<2 and 0 <= itx' - itt' < 16 and 0 <= itt'+itx' < 16}") m2_prime = isl.BasicMap( - "[nx,nt,unused] -> {[statement, ix, it] -> [statement'=statement, tx', tt', tparity', itt', itx']: " - "16*(tx' - tt') + itx' - itt' = ix - it and " - "16*(tx' + tt' + tparity') + itt' + itx' = ix + it and " - "0<=tparity'<2 and 0 <= itx' - itt' < 16 and 0 <= itt'+itx' < 16}") + "[nx,nt,unused] -> {[statement', ix', it'] -> [statement=statement', tx, tt, tparity, itt, itx]: " + "16*(tx - tt) + itx - itt = ix' - it' and " + "16*(tx + tt + tparity) + itt + itx = ix' + it' and " + "0<=tparity<2 and 0 <= itx - itt < 16 and 0 <= itt+itx < 16}") # TODO note order must match statement_iname_premap_order @@ -370,7 +374,7 @@ knl = lp.map_domain(ref_knl, m) knl = lp.prioritize_loops(knl, "tt,tparity,tx,itt,itx") print("code after mapping:") print(generate_code_v2(knl).device_code()) -1/0 +#1/0 print("constraint_map before apply_range:") print(prettier_map_string(constraint_map)) @@ -378,7 +382,12 @@ print(prettier_map_string(constraint_map)) mapped_constraint_map = constraint_map.apply_range(m2) print("constraint_map after apply_range:") print(prettier_map_string(mapped_constraint_map)) -mapped_constraint_map = mapped_constraint_map.apply_domain(m2) +#mapped_constraint_map = mapped_constraint_map.apply_domain(m2) +mapped_constraint_map = mapped_constraint_map.apply_domain(m2_prime) +# put primes on *before* names +mapped_constraint_map = append_marker_to_isl_map_var_names( + mapped_constraint_map, isl.dim_type.in_, marker="'") + print("constraint_map after apply_domain:") print(prettier_map_string(mapped_constraint_map)) @@ -431,18 +440,16 @@ if verbose: # Create a mapping of {statement instance: lex point} # including only instructions involved in this dependency -sched = LexSchedule(scheduled_knl, include_only_insn_ids=[ +sched = LexSchedule( + scheduled_knl, + scheduled_knl.schedule, str(sid_before), str(sid_after) - ]) + ) # Get an isl map representing the LexSchedule; # this requires the iname domains -assert len(sched) in [1, 2] -if len(sched) == 1: - assert inames_domain_before_mapped == inames_domain_after_mapped - # get a mapping from lex schedule id to relevant inames domain sid_to_dom = { sid_before: inames_domain_before_mapped, @@ -450,7 +457,7 @@ sid_to_dom = { } #sched_map_symbolic = sched.create_symbolic_isl_map(sid_to_dom) -sched_map_symbolic = sched.create_symbolic_isl_map( +sched_map_symbolic_before, sched_map_symbolic_after = sched.create_symbolic_isl_maps( inames_domain_before_mapped, inames_domain_after_mapped) # {{{ verbose @@ -460,7 +467,8 @@ if verbose: print("LexSchedule after creating symbolic isl map:") print(sched) print("LexSched:") - print(prettier_map_string(sched_map_symbolic)) + print(prettier_map_string(sched_map_symbolic_before)) + print(prettier_map_string(sched_map_symbolic_after)) #print("space (statement instances -> lex time):") #print(sched_map_symbolic.space) #print("-"*80) @@ -486,7 +494,10 @@ if verbose: # create statement instance ordering, # maps each statement instance to all statement instances occuring later sio = get_statement_ordering_map( - sched_map_symbolic, lex_order_map_symbolic) + sched_map_symbolic_before, + sched_map_symbolic_after, + lex_order_map_symbolic, + before_marker="'") # {{{ verbose @@ -518,20 +529,12 @@ aligned_constraint_map = reorder_dims_by_name( new_names_are_permutation_only=True, ) -#print(".....") -#print(aligned_constraint_map.space) -#print("...") -#print(set(aligned_constraint_map.get_var_names(isl.dim_type.out))) -#ppp = append_apostrophes(sio_in_names) -#print(ppp) -#print(set(aligned_constraint_map.get_var_names(isl.dim_type.out)).issubset(ppp)) # align out dims +sio_out_names = sio.space.get_var_names(isl.dim_type.out) aligned_constraint_map = reorder_dims_by_name( aligned_constraint_map, isl.dim_type.out, - #append_apostrophes(sio_in_names), - sio_in_names, # TODO WHY no apostrophes? - # TODO sio out names are only pretending to have apostrophes; confusing + sio_out_names, add_missing=False, new_names_are_permutation_only=True, ) @@ -552,11 +555,7 @@ assert ( == sio.space.get_var_names(isl.dim_type.in_)) assert ( aligned_constraint_map.space.get_var_names(isl.dim_type.out) - == append_apostrophes(sio.space.get_var_names(isl.dim_type.out)) - ) or ( # TODO why no appostrophes? - aligned_constraint_map.space.get_var_names(isl.dim_type.out) - == sio.space.get_var_names(isl.dim_type.out) - ) + == sio.space.get_var_names(isl.dim_type.out)) assert ( aligned_constraint_map.space.get_var_names(isl.dim_type.param) == sio.space.get_var_names(isl.dim_type.param)) -- GitLab From f3cce6e351f877ad29e196336cc0fece2d62fbc6 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Wed, 15 Jan 2020 21:49:38 -0600 Subject: [PATCH 172/183] updated variable names, function names/signatures, and documentation based on the following recent changes: 1) schedule represented as two maps instead of one (one for depender and one for dependee), 2) dependee inames get apostrophe marker instead of depender, 3) iname domains for before/after insns stored inside StatementPairDependencySet instead of separately, 4) created LexScheduleStatementInstance to hold both LexScheduleStatement and the point(s) in lexicographic time in which it occurs --- __init__.py | 27 ++++++++--- dependency.py | 89 +++++++++++++++++++++--------------- lexicographic_order_map.py | 47 +++++++++++-------- sched_check_utils.py | 28 ++++++------ schedule.py | 94 +++++++++++++++++++++++++------------- 5 files changed, 174 insertions(+), 111 deletions(-) diff --git a/__init__.py b/__init__.py index c965be217..5b8062070 100644 --- a/__init__.py +++ b/__init__.py @@ -1,6 +1,24 @@ def get_statement_pair_dependency_sets_from_legacy_knl(knl): + """Return a list of :class:`StatementPairDependySet` instances created + for a :class:`loopy.LoopKernel` containing legacy depencencies. Create + the new dependencies according to the following rules. (1) If + a dependency exists between ``insn0`` and ``insn1``, create the dependnecy + ``SAME(SNC)`` where ``SNC`` is the set of non-concurrent inames used + by both ``insn0`` and ``insn1``, and ``SAME`` is the relationship specified + by the ``SAME`` attribute of :class:`DependencyType`. (2) For each subset + of non-concurrent inames used by any instruction, find the set of all + instructions using those inames, create a directed graph with these + instructions as nodes and edges representing a 'happens before' + relationship specfied by each dependency, find the sources and sinks within + this graph, and connect each sink to each source (sink happens before + source) with a ``PRIOR(SNC)`` dependency, where ``PRIOR`` is the + relationship specified by the ``PRIOR`` attribute of + :class:`DependencyType`. + + """ + from schedule_checker.dependency import ( create_dependencies_from_legacy_knl, ) @@ -14,12 +32,7 @@ def get_statement_pair_dependency_sets_from_legacy_knl(knl): else: preprocessed_knl = knl - # Create StatementPairDependencySet(s) from kernel dependencies ----------------- - - # Introduce SAME dep for set of shared, non-concurrent inames. - - # For each set of insns within a given iname subset, find sources and sinks, - # then make PRIOR dep from all sinks to all sources at previous iterations. + # Create StatementPairDependencySet(s) from kernel dependencies return create_dependencies_from_legacy_knl(preprocessed_knl) @@ -126,7 +139,7 @@ def check_schedule_validity( # this requires the iname domains sched_map_symbolic_before, sched_map_symbolic_after = \ - sched.create_symbolic_isl_map( + sched.create_symbolic_isl_maps( dom_before, dom_after, ) diff --git a/dependency.py b/dependency.py index 3f2318ed1..39ce21d28 100644 --- a/dependency.py +++ b/dependency.py @@ -12,11 +12,11 @@ class DependencyType: A :class:`str` specifying the following dependency relationship: If ``S = {i, j, ...}`` is a set of inames used in both statements - ``insn0`` and ``insn1``, and ``{i, j, ...}`` represent the values - of the inames in ``insn0``, and ``{i', j', ...}`` represent the + ``insn0`` and ``insn1``, and ``{i', j', ...}`` represent the values + of the inames in ``insn0``, and ``{i, j, ...}`` represent the values of the inames in ``insn1``, then the dependency ``insn0 happens before insn1 iff SAME({i, j})`` specifies that - ``insn0 happens before insn1 iff {i = i' and j = j' and ...}``. + ``insn0 happens before insn1 iff {i' = i and j' = j and ...}``. Note that ``SAME({}) = True``. .. attribute:: PRIOR @@ -24,16 +24,16 @@ class DependencyType: A :class:`str` specifying the following dependency relationship: If ``S = {i, j, k, ...}`` is a set of inames used in both statements - ``insn0`` and ``insn1``, and ``{i, j, k, ...}`` represent the values - of the inames in ``insn0``, and ``{i', j', k', ...}`` represent the + ``insn0`` and ``insn1``, and ``{i', j', k', ...}`` represent the values + of the inames in ``insn0``, and ``{i, j, k, ...}`` represent the values of the inames in ``insn1``, then the dependency ``insn0 happens before insn1 iff PRIOR({i, j, k})`` specifies one of two possibilities, depending on whether the loop nest ordering is known. If the loop nest ordering is unknown, then - ``insn0 happens before insn1 iff {i < i' and j < j' and k < k' ...}``. + ``insn0 happens before insn1 iff {i' < i and j' < j and k' < k ...}``. If the loop nest ordering is known, the condition becomes - ``{i, j, k, ...}`` is lexicographically less than ``{i', j', k', ...}``, - i.e., ``i < i' or (i = i' and j < j') or (i = i' and j = j' and k < k') ...``. + ``{i', j', k', ...}`` is lexicographically less than ``{i, j, k, ...}``, + i.e., ``i' < i or (i' = i and j' < j) or (i' = i and j' = j and k' < k) ...``. """ @@ -58,6 +58,16 @@ class StatementPairDependencySet(object): the Loopy kernel inames involved in that particular dependency relationship. + .. attribute:: dom_before + + A :class:`islpy.BasicSet` representing the domain for the + dependee statement. + + .. attribute:: dom_after + + A :class:`islpy.BasicSet` representing the domain for the + dependee statement. + """ def __init__( @@ -138,20 +148,14 @@ def create_dependency_constraint( ): """Create a statement dependency constraint represented as a map from each statement instance to statement instances that must occur later, - i.e., ``{[s=0, i, j] -> [s'=1, i', j'] : condition on {i, j, i', j'}}`` + i.e., ``{[s'=0, i', j'] -> [s=1, i, j] : condition on {i', j', i, j}}`` indicates that statement ``0`` comes before statment ``1`` when the - specified condition on inames ``i,j,i',j'`` is met. ``i'`` and ``j'`` - are the values of inames ``i`` and ``j`` in second statement instance. + specified condition on inames ``i',j',i,j`` is met. ``i'`` and ``j'`` + are the values of inames ``i`` and ``j`` in first statement instance. .. arg statement_dep_set: A :class:`StatementPairDependencySet` describing the dependency relationship between the two statements. - .. arg dom_before_constraint_set: A :class:`islpy.BasicSet` specifying the - domain for the 'before' statement in the relationship. - - .. arg dom_after_constraint_set: A :class:`islpy.BasicSet` specifying the - domain for the 'after' statement in the relationship. - .. arg loop_priorities: A list of tuples from the ``loop_priority`` attribute of :class:`loopy.LoopKernel` specifying the loop nest ordering rules. @@ -177,8 +181,11 @@ def create_dependency_constraint( statement instance tuples holds the dimension representing the statement id. Defaults to ``0``. - .. arg all_dom_inames_ordered: A :class:`list` of :class:`str` specifying - an order for the dimensions representing inames. + .. arg all_dom_inames_ordered_before: A :class:`list` of :class:`str` + specifying an order for the dimensions representing dependee inames. + + .. arg all_dom_inames_ordered_after: A :class:`list` of :class:`str` + specifying an order for the dimensions representing depender inames. .. return: An :class:`islpy.Map` mapping each statement instance to all statement instances that must occur later according to the constraints. @@ -186,7 +193,7 @@ def create_dependency_constraint( """ from schedule_checker.sched_check_utils import ( - make_islvars_with_var_primes, + make_islvars_with_marker, append_apostrophes, add_dims_to_isl_set, reorder_dims_by_name, @@ -206,11 +213,12 @@ def create_dependency_constraint( [statement_dep_set.dom_after]) # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} - islvars = make_islvars_with_var_primes( - var_names_in=[statement_var_name]+dom_inames_ordered_before, - param_names=[unused_param_name], - var_names_out=[statement_var_name]+dom_inames_ordered_after, - ) + islvars = make_islvars_with_marker( + var_names_needing_marker=[statement_var_name]+dom_inames_ordered_before, + other_var_names=[statement_var_name]+dom_inames_ordered_after, + param_names=[unused_param_name], + marker="'", + ) statement_var_name_prime = statement_var_name+"'" # get (ordered) list of unused before/after inames @@ -386,6 +394,7 @@ def create_dependency_constraint( return map_with_loop_domain_constraints +# TODO no longer used, remove def _create_5pt_stencil_dependency_constraint( dom_before_constraint_set, dom_after_constraint_set, @@ -400,7 +409,7 @@ def _create_5pt_stencil_dependency_constraint( ): from schedule_checker.sched_check_utils import ( - make_islvars_with_var_primes, + make_islvars_with_marker, append_apostrophes, add_dims_to_isl_set, reorder_dims_by_name, @@ -417,9 +426,12 @@ def _create_5pt_stencil_dependency_constraint( [dom_before_constraint_set, dom_after_constraint_set]) # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} - islvars = make_islvars_with_var_primes( - [statement_var_name]+all_dom_inames_ordered, - [unused_param_name]) + islvars = make_islvars_with_marker( + var_names_needing_marker=[statement_var_name]+all_dom_inames_ordered, + other_var_names=[statement_var_name]+all_dom_inames_ordered, + param_names=[unused_param_name], + marker="'", + ) statement_var_name_prime = statement_var_name+"'" # get (ordered) list of unused before/after inames @@ -525,11 +537,10 @@ def create_arbitrary_dependency_constraint( all_dom_inames_ordered=None, ): - # TODO update after allowing different inames for before/after # TODO test after switching primes to before vars from schedule_checker.sched_check_utils import ( - make_islvars_with_var_primes, + make_islvars_with_marker, #append_apostrophes, append_marker_to_strings, add_dims_to_isl_set, @@ -547,10 +558,12 @@ def create_arbitrary_dependency_constraint( [dom_before_constraint_set, dom_after_constraint_set]) # create some (ordered) isl vars to use, e.g., {s, i, j, s', i', j'} - islvars = make_islvars_with_var_primes( - [statement_var_name]+all_dom_inames_ordered, - [unused_param_name], - marker="p") # TODO figure out before/after notation + islvars = make_islvars_with_marker( + var_names_needing_marker=[statement_var_name]+all_dom_inames_ordered, + other_var_names=[statement_var_name]+all_dom_inames_ordered, + param_names=[unused_param_name], + marker="p", + ) # TODO figure out before/after notation #statement_var_name_prime = statement_var_name+"'" statement_var_name_prime = statement_var_name+"p" # TODO figure out before/after notation @@ -644,12 +657,12 @@ def create_arbitrary_dependency_constraint( # insert inames missing from doms to enable intersection domain_to_intersect = reorder_dims_by_name( domain_to_intersect, isl.dim_type.out, - [statement_var_name] + all_dom_inames_ordered, + append_marker_to_strings([statement_var_name] + all_dom_inames_ordered, "p"), # TODO figure out before/after notation add_missing=True) range_to_intersect = reorder_dims_by_name( range_to_intersect, isl.dim_type.out, - append_marker_to_strings([statement_var_name] + all_dom_inames_ordered, "p"), # TODO figure out before/after notation + [statement_var_name] + all_dom_inames_ordered, add_missing=True) # intersect doms @@ -665,7 +678,7 @@ def create_dependencies_from_legacy_knl(knl): the new dependencies according to the following rules. (1) If a dependency exists between ``insn0`` and ``insn1``, create the dependnecy ``SAME(SNC)`` where ``SNC`` is the set of non-concurrent inames used - by both ``insn0 and ``insn1``, and ``SAME`` is the relationship specified + by both ``insn0`` and ``insn1``, and ``SAME`` is the relationship specified by the ``SAME`` attribute of :class:`DependencyType`. (2) For each subset of non-concurrent inames used by any instruction, find the set of all instructions using those inames, create a directed graph with these diff --git a/lexicographic_order_map.py b/lexicographic_order_map.py index 52afadaa0..7abe6b0c5 100644 --- a/lexicographic_order_map.py +++ b/lexicographic_order_map.py @@ -6,26 +6,32 @@ def get_statement_ordering_map( """Return a mapping that maps each statement instance to all statement instances occuring later. - .. arg sched_map: An :class:`islpy.Map` representing a schedule - as a mapping from each statement instance to a point in - a lexicographic ordering. + .. 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') ...} + {[i0', i1', i2', ...] -> [i0, i1, i2, ...] : + i0' < i0 or (i0' = i0 and i1' < i1) + or (i0' = i0 and i1' = i1 and i2' < i2) ...} .. return: 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 S -> L -> S^-1, where S - is the schedule map and L is the lexicographic ordering map. + 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()) + 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( @@ -53,12 +59,12 @@ def get_lex_order_constraint(islvars, before_names, after_names): time that occurs after. (see example below) .. return: 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:: + 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')} + {[i0', i1', i2', i0, i1, i2] : + i0' < i0 or (i0' = i0 and i1' < i1) + or (i0' = i0 and i1' = i1 and i2' < i2)} """ @@ -96,12 +102,12 @@ def create_lex_order_map( .. return: 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') - or (i0 = i0' and i1 = i1' and i2 < i2')} + {[i0', i1', i2'] -> [i0, i1, i2] : + i0' < i0 or (i0' = i0 and i1' < i1) + or (i0' = i0 and i1' = i1 and i2' < i2)} """ @@ -120,7 +126,8 @@ def create_lex_order_map( before_names+after_names, []) - lex_order_constraint = get_lex_order_constraint(islvars, 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( diff --git a/sched_check_utils.py b/sched_check_utils.py index 32317cccb..f9183d2c2 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -108,12 +108,13 @@ def create_new_isl_set_with_primes(old_isl_set, marker="'"): apostrophes appended to dim_type.set dimension names. """ - # TODO this is a special case of append_marker_to_isl_map_var_names + # TODO this is just a special case of append_marker_to_isl_map_var_names new_set = old_isl_set.copy() for i in range(old_isl_set.n_dim()): - new_set = new_set.set_dim_name(isl.dim_type.set, i, old_isl_set.get_dim_name( - isl.dim_type.set, i)+marker) + new_set = new_set.set_dim_name( + isl.dim_type.set, i, old_isl_set.get_dim_name( + isl.dim_type.set, i)+marker) return new_set @@ -138,16 +139,18 @@ def append_marker_to_isl_map_var_names(old_isl_map, dim_type, marker="'"): return new_map -def make_islvars_with_var_primes( - var_names_in, param_names, marker="'", var_names_out=None): +def make_islvars_with_marker( + var_names_needing_marker, other_var_names, param_names, marker="'"): """Return a dictionary from variable and parameter names to :class:`PwAff` instances that represent each of - the variables and parameters, including - both the variables in `var_names` and a copy of each - variable with an apostrophe appended. + the variables and parameters, appending marker to + var_names_needing_marker. - .. arg var_names: A :class:`list` of :class:`str` elements - representing variable names. + .. arg var_names_needing_marker: A :class:`list` of :class:`str` + elements representing variable names to have markers appended. + + .. arg other_var_names: A :class:`list` of :class:`str` + elements representing variable names to be included as-is. .. arg param_names: A :class:`list` of :class:`str` elements representing parameter names. @@ -165,11 +168,8 @@ def make_islvars_with_var_primes( new_l.append(s+mark) return new_l - if var_names_out is None: - var_names_out = var_names_in[:] - return isl.make_zero_and_vars( - append_marker(var_names_in, marker) + var_names_out, param_names) + append_marker(var_names_needing_marker, marker) + other_var_names, param_names) def append_marker_to_strings(strings, marker="'"): diff --git a/schedule.py b/schedule.py index 38b6d66cc..f221c1595 100644 --- a/schedule.py +++ b/schedule.py @@ -45,6 +45,15 @@ class LexScheduleStatement(object): class LexScheduleStatementInstance(object): """A representation of a Loopy statement instance. + .. attribute:: stmt + + A :class:`LexScheduleStatement`. + + .. attribute:: lex_pt + + A list of :class:`int` or as :class:`str` Loopy inames representing + a point or set of points in a lexicographic ordering. + """ def __init__( @@ -63,12 +72,21 @@ class LexSchedule(object): """A program ordering represented as a mapping from statement instances to points in a lexicographic ordering. - .. attribute:: lex_schedule + .. 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` Loopy inames. + + .. attribute:: stmt_instance_after - A :class:`list` of (:class:`LexScheduleStatement`, :class:`list`) - tuples, representing the program ordering as a map from - statement instances to points in a lexicographic ordering. Points - in lexicographic ordering are represented as list of :class:`int`. + 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` Loopy inames. .. attribute:: unused_param_name @@ -109,15 +127,23 @@ class LexSchedule(object): prohibited_var_names=[], ): """ - :arg knl: A :class:`LoopKernel` whose instructions will be + :arg knl: A :class:`LoopKernel` whose schedule items will be described by this :class:`LexSchedule`. - :arg include_only_insn_ids: A list of :class:`str` instruction ids - specifying which instructions to include in the mapping. If set - to None, all insructions will be included. + :arg sched_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). """ - # TODO update docs now that we have two schedules # LexScheduleStatements self.stmt_instance_before = None @@ -280,31 +306,39 @@ class LexSchedule(object): max_lex_dim-len(self.stmt_instance_after.lex_pt)) ) - def create_symbolic_isl_map( + def create_symbolic_isl_maps( self, dom_before, dom_after, dom_inames_ordered_before=None, dom_inames_ordered_after=None, ): - """Create an isl map representing lex schedule as a mapping - from each statement instance to all statement instances - occuring later. + """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 sid_to_dom: A :class:`dict` mapping integer ids to domains, - where integer ids are instances of the ``int_id`` attribute of - :class:`LexScheduleStatement`, and domains are the - :class:`islpy.BasicSet` representing the domain for this - 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: A list of :class:`str` representing - the union of inames used in all statement instances. - ``statement_var_name`` and ``dom_inames_ordered`` 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 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. - .. return: An :class:`islpy.Map` representing a schedule - as a mapping from each statement instance to a point in - a lexicographic ordering. + .. return: 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. """ @@ -352,15 +386,11 @@ class LexSchedule(object): [self.statement_var_name], 0), ] - # The isl map representing the schedule maps + # Each isl map representing the schedule maps # statement instances -> lex time - # The 'in_' dim vars need to match for all sched items in the map, - # Instructions that use fewer inames will still need to - # have the unused inames in their 'in_' dim vars, so we'll - # include them and set them equal to a dummy variable. # Right now, statement tuples consist of single int. - # Add all inames from combined domains to map domain tuples. + # Add all inames from domains to map domain tuples. # create isl map return ( -- GitLab From 94315283fa9f3fec865837b0620906c6b3a6b0f5 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 25 Jan 2020 16:24:45 -0600 Subject: [PATCH 173/183] add hashing functions to classes to avoid PersistentDict error --- dependency.py | 19 ++++++++++++++++++- schedule.py | 12 ++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/dependency.py b/dependency.py index 39ce21d28..e3a6f2388 100644 --- a/dependency.py +++ b/dependency.py @@ -84,6 +84,23 @@ class StatementPairDependencySet(object): self.dom_before = dom_before self.dom_after = dom_after + def __lt__(self, other): + return self.__hash__() < other.__hash__() + + 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.statement_before) + key_builder.rec(key_hash, self.statement_after) + key_builder.rec(key_hash, self.deps) + key_builder.rec(key_hash, self.dom_before) + key_builder.rec(key_hash, self.dom_after) + def __str__(self): result = "%s --before->\n%s iff\n " % ( self.statement_before, self.statement_after) @@ -761,7 +778,7 @@ def create_dependencies_from_legacy_knl(knl): knl.get_inames_domain(source_insn_inames), )) - return statement_dep_sets + return set(statement_dep_sets) def get_dependency_sources_and_sinks(knl, sched_item_ids): diff --git a/schedule.py b/schedule.py index f221c1595..a1876d43a 100644 --- a/schedule.py +++ b/schedule.py @@ -29,6 +29,18 @@ class LexScheduleStatement(object): self.int_id = int_id self.within_inames = 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: int_id = ":%d" % (self.int_id) -- GitLab From a59918f40682d4f99c3a7372051306feef1aeda1 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Sat, 25 Jan 2020 16:25:46 -0600 Subject: [PATCH 174/183] add legacy deps using lp.add_dependencies_v2 since these are no longer automatically generated when scheduling --- test/test_invalid_scheds.py | 14 ++++++++++---- test/test_valid_scheds.py | 8 ++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/test/test_invalid_scheds.py b/test/test_invalid_scheds.py index 5f43909cf..a822ea9df 100644 --- a/test/test_invalid_scheds.py +++ b/test/test_invalid_scheds.py @@ -66,6 +66,7 @@ def test_invalid_prioritiy_detection(): unprocessed_knl = knl0.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + knl0 = lp.add_dependencies_v2(knl0, deps_and_domains) # get a schedule to check if knl0.state < KernelState.PREPROCESSED: @@ -83,6 +84,7 @@ def test_invalid_prioritiy_detection(): unprocessed_knl = knl1.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + knl1 = lp.add_dependencies_v2(knl1, deps_and_domains) # get a schedule to check if knl1.state < KernelState.PREPROCESSED: @@ -96,8 +98,9 @@ def test_invalid_prioritiy_detection(): # error (cycle): knl2 = lp.prioritize_loops(ref_knl, "h,i,j") knl2 = lp.prioritize_loops(knl2, "j,k") - knl2 = lp.prioritize_loops(knl2, "k,i") try: + knl2 = lp.prioritize_loops(knl2, "k,i") + """ unprocessed_knl = knl2.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) @@ -109,15 +112,17 @@ def test_invalid_prioritiy_detection(): schedule_items = knl2.schedule sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + """ # should raise error assert False except ValueError as e: - assert "invalid priorities" in str(e) + assert "cycle detected" in str(e) # error (inconsistent priorities): knl3 = lp.prioritize_loops(ref_knl, "h,i,j,k") - knl3 = lp.prioritize_loops(knl3, "h,j,i,k") try: + knl3 = lp.prioritize_loops(knl3, "h,j,i,k") + """ unprocessed_knl = knl3.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) @@ -129,10 +134,11 @@ def test_invalid_prioritiy_detection(): schedule_items = knl3.schedule sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + """ # should raise error assert False except ValueError as e: - assert "invalid priorities" in str(e) + assert "cycle detected" in str(e) if __name__ == "__main__": diff --git a/test/test_valid_scheds.py b/test/test_valid_scheds.py index 0ed14502e..d6cbde674 100644 --- a/test/test_valid_scheds.py +++ b/test/test_valid_scheds.py @@ -73,6 +73,8 @@ def test_loop_prioritization(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + knl = lp.add_dependencies_v2(knl, deps_and_domains) + # TODO why is this failing to find valid schedule? # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -106,6 +108,7 @@ def test_matmul(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -150,6 +153,7 @@ def test_dependent_domain(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -199,6 +203,7 @@ def test_stroud_bernstein(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -231,6 +236,7 @@ def test_nop(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -273,6 +279,7 @@ def test_multi_domain(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -304,6 +311,7 @@ def test_loop_carried_deps(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: -- GitLab From 04e24f95b9e0edab81f8d947eb9df89d2a5025f3 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Fri, 14 Feb 2020 16:50:46 -0600 Subject: [PATCH 175/183] remove unused inames from test kernels --- test/test_valid_scheds.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/test/test_valid_scheds.py b/test/test_valid_scheds.py index d6cbde674..3cb100e09 100644 --- a/test/test_valid_scheds.py +++ b/test/test_valid_scheds.py @@ -41,9 +41,9 @@ from loopy import ( def test_loop_prioritization(): knl = lp.make_kernel( [ - "{[i,ii]: 0<=i Date: Fri, 14 Feb 2020 18:31:15 -0600 Subject: [PATCH 176/183] removed TODO that was fixed in loopy.schedule --- test/test_valid_scheds.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_valid_scheds.py b/test/test_valid_scheds.py index 3cb100e09..e98a52ada 100644 --- a/test/test_valid_scheds.py +++ b/test/test_valid_scheds.py @@ -38,6 +38,7 @@ from loopy import ( get_one_scheduled_kernel, ) + def test_loop_prioritization(): knl = lp.make_kernel( [ @@ -74,7 +75,6 @@ def test_loop_prioritization(): deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) knl = lp.add_dependencies_v2(knl, deps_and_domains) - # TODO why is this failing to find valid schedule? # get a schedule to check if knl.state < KernelState.PREPROCESSED: -- GitLab From a49a087a2eb123a35058fc92a5e4b791530499b9 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Thu, 20 Feb 2020 19:17:32 -0600 Subject: [PATCH 177/183] adding __eq__() funcs to StatementPairDependencySet and LexScheduleStatement to avoid sets with duplicate deps --- dependency.py | 10 ++++++++++ schedule.py | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/dependency.py b/dependency.py index e3a6f2388..2fa13a0f0 100644 --- a/dependency.py +++ b/dependency.py @@ -84,6 +84,15 @@ class StatementPairDependencySet(object): self.dom_before = dom_before self.dom_after = dom_after + def __eq__(self, other): + return ( + self.statement_before == other.statement_before and + self.statement_after == other.statement_after and + self.deps == other.deps and + self.dom_before == other.dom_before and + self.dom_after == other.dom_after + ) + def __lt__(self, other): return self.__hash__() < other.__hash__() @@ -835,6 +844,7 @@ def get_dependency_maps( loop_priority, knl, # TODO avoid passing this in ): + # TODO document from schedule_checker.sched_check_utils import ( prettier_map_string, diff --git a/schedule.py b/schedule.py index a1876d43a..bbdea1806 100644 --- a/schedule.py +++ b/schedule.py @@ -29,6 +29,13 @@ class LexScheduleStatement(object): 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)) -- GitLab From ee92f518e7634d8c2c90568614247122ee454388 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 25 Feb 2020 09:50:08 -0600 Subject: [PATCH 178/183] fix flake8 issues --- dependency.py | 68 +++++++++++++++++++++----------------------- sched_check_utils.py | 9 +++--- schedule.py | 46 +++++++++++++++++++----------- 3 files changed, 67 insertions(+), 56 deletions(-) diff --git a/dependency.py b/dependency.py index 2fa13a0f0..a780a036d 100644 --- a/dependency.py +++ b/dependency.py @@ -1,9 +1,6 @@ import islpy as isl -# TODO update all documentation/comments after apostrophe switched to -# *before* statement/inames - class DependencyType: """Strings specifying a particular type of dependency relationship. @@ -86,11 +83,11 @@ class StatementPairDependencySet(object): def __eq__(self, other): return ( - self.statement_before == other.statement_before and - self.statement_after == other.statement_after and - self.deps == other.deps and - self.dom_before == other.dom_before and - self.dom_after == other.dom_after + self.statement_before == other.statement_before + and self.statement_after == other.statement_after + and self.deps == other.deps + and self.dom_before == other.dom_before + and self.dom_after == other.dom_after ) def __lt__(self, other): @@ -397,7 +394,8 @@ def create_dependency_constraint( range_to_intersect = add_dims_to_isl_set( statement_dep_set.dom_after, isl.dim_type.out, [statement_var_name], statement_var_pose) - domain_constraint_set = create_new_isl_set_with_primes(statement_dep_set.dom_before) + domain_constraint_set = create_new_isl_set_with_primes( + statement_dep_set.dom_before) domain_to_intersect = add_dims_to_isl_set( domain_constraint_set, isl.dim_type.out, [statement_var_name_prime], statement_var_pose) @@ -493,18 +491,12 @@ def _create_5pt_stencil_dependency_constraint( """ # local dep: constraint_set = ( - islvars[time_iname].eq_set(islvars[time_iname_prime] + one) & - ( + islvars[time_iname].eq_set(islvars[time_iname_prime] + one) & ( (islvars[space_iname]-two).lt_set(islvars[space_iname_prime]) & - islvars[space_iname_prime].lt_set(islvars[space_iname]+two) - ) - #( - #(islvars[space_iname_prime]-two).lt_set(islvars[space_iname]) & - # islvars[space_iname].lt_set(islvars[space_iname_prime]+two) - #) + islvars[space_iname_prime].lt_set(islvars[space_iname]+two)) | - islvars[time_iname].eq_set(islvars[time_iname_prime] + two) & - islvars[space_iname_prime].eq_set(islvars[space_iname]) + (islvars[time_iname].eq_set(islvars[time_iname_prime] + two) + & islvars[space_iname_prime].eq_set(islvars[space_iname])) ) # set unused vars == unused dummy param @@ -589,9 +581,10 @@ def create_arbitrary_dependency_constraint( other_var_names=[statement_var_name]+all_dom_inames_ordered, param_names=[unused_param_name], marker="p", - ) # TODO figure out before/after notation + ) # TODO figure out before/after notation #statement_var_name_prime = statement_var_name+"'" - statement_var_name_prime = statement_var_name+"p" # TODO figure out before/after notation + statement_var_name_prime = statement_var_name+"p" + # TODO figure out before/after notation # get (ordered) list of unused before/after inames inames_before_unused = [] @@ -602,7 +595,8 @@ def create_arbitrary_dependency_constraint( for iname in all_dom_inames_ordered: if iname not in dom_after_constraint_set.get_var_names(isl.dim_type.out): #inames_after_unused.append(iname + "'") - inames_after_unused.append(iname) # TODO figure out before/after notation + inames_after_unused.append(iname) + # TODO figure out before/after notation # initialize constraints to False # this will disappear as soon as we add a constraint @@ -612,8 +606,10 @@ def create_arbitrary_dependency_constraint( from loopy.symbolic import aff_from_expr or_constraint_strs = constraint_str.split("or") + def _quant(s): return "(" + s + ")" + def _diff(s0, s1): return _quant(s0) + "-" + _quant(s1) @@ -626,13 +622,13 @@ def create_arbitrary_dependency_constraint( lhs, rhs = cons_str.split("<=") conj_constraint = conj_constraint.add_constraint( isl.Constraint.inequality_from_aff( - aff_from_expr(space, parse(_diff(rhs,lhs))))) + aff_from_expr(space, parse(_diff(rhs, lhs))))) # TODO something more robust than this string meddling^ elif ">=" in cons_str: lhs, rhs = cons_str.split(">=") conj_constraint = conj_constraint.add_constraint( isl.Constraint.inequality_from_aff( - aff_from_expr(space, parse(_diff(lhs,rhs))))) + aff_from_expr(space, parse(_diff(lhs, rhs))))) elif "<" in cons_str: lhs, rhs = cons_str.split("<") conj_constraint = conj_constraint.add_constraint( @@ -658,10 +654,14 @@ def create_arbitrary_dependency_constraint( islvars[unused_param_name]) # set statement_var_name == statement # - all_constraints_set = all_constraints_set & islvars[statement_var_name_prime].eq_set( - islvars[0]+sid_before) - all_constraints_set = all_constraints_set & islvars[statement_var_name].eq_set( - islvars[0]+sid_after) + all_constraints_set = ( + all_constraints_set & islvars[statement_var_name_prime].eq_set( + islvars[0]+sid_before) + ) + all_constraints_set = ( + all_constraints_set & islvars[statement_var_name].eq_set( + islvars[0]+sid_after) + ) # convert constraint set to map all_constraints_map = _convert_constraint_set_to_map( @@ -683,7 +683,8 @@ def create_arbitrary_dependency_constraint( # insert inames missing from doms to enable intersection domain_to_intersect = reorder_dims_by_name( domain_to_intersect, isl.dim_type.out, - append_marker_to_strings([statement_var_name] + all_dom_inames_ordered, "p"), # TODO figure out before/after notation + append_marker_to_strings( # TODO figure out before/after notation + [statement_var_name] + all_dom_inames_ordered, "p"), add_missing=True) range_to_intersect = reorder_dims_by_name( range_to_intersect, @@ -768,7 +769,6 @@ def create_dependencies_from_legacy_knl(knl): # in future, consider inserting single no-op source and sink for source_id in sources: for sink_id in sinks: - dep_dict = {} sink_insn_inames = knl.id_to_insn[sink_id].within_inames source_insn_inames = knl.id_to_insn[source_id].within_inames shared_inames = sink_insn_inames & source_insn_inames @@ -840,15 +840,12 @@ class DependencyInfo(object): def get_dependency_maps( deps_and_domains, - schedule_items, # TODO always pass these as strings since we only need the name? + schedule_items, # TODO always pass as strings since we only need the name? loop_priority, knl, # TODO avoid passing this in ): # TODO document - from schedule_checker.sched_check_utils import ( - prettier_map_string, - ) dt = DependencyType # create map from loopy insn ids to ints @@ -889,7 +886,8 @@ def get_dependency_maps( s_after = statement_pair_dep_set.statement_after dom_before = statement_pair_dep_set.dom_before dom_after = statement_pair_dep_set.dom_after - shared_nc_inames = s_before.within_inames & s_after.within_inames & non_conc_inames + shared_nc_inames = ( + s_before.within_inames & s_after.within_inames & non_conc_inames) same_dep_set = StatementPairDependencySet( s_before, s_after, diff --git a/sched_check_utils.py b/sched_check_utils.py index f9183d2c2..6fefa1483 100644 --- a/sched_check_utils.py +++ b/sched_check_utils.py @@ -47,9 +47,9 @@ def reorder_dims_by_name( .. 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. + 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. .. return: An :class:`islpy.Set` matching `isl_set` with the dimension order matching `desired_dims_ordered`, optionally @@ -169,7 +169,8 @@ def make_islvars_with_marker( return new_l return isl.make_zero_and_vars( - append_marker(var_names_needing_marker, marker) + other_var_names, param_names) + append_marker(var_names_needing_marker, marker) + + other_var_names, param_names) def append_marker_to_strings(strings, marker="'"): diff --git a/schedule.py b/schedule.py index bbdea1806..4c99f45ce 100644 --- a/schedule.py +++ b/schedule.py @@ -31,9 +31,9 @@ class LexScheduleStatement(object): 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 + self.insn_id == other.insn_id + and self.int_id == other.int_id + and self.within_inames == other.within_inames ) def __hash__(self): @@ -78,7 +78,7 @@ class LexScheduleStatementInstance(object): def __init__( self, stmt, # a LexScheduleStatement - lex_pt, # [string/int, ] + lex_pt, # [string/int, ] ): self.stmt = stmt self.lex_pt = lex_pt @@ -195,11 +195,13 @@ class LexSchedule(object): "with ConcurrentTag(s) in schedule for kernel %s. " "Ignoring this loop." % (iname, knl.name)) continue + # if the schedule is empty, this is the first schedule item, so # don't increment lex dim val enumerating items in current block, # otherwise, this loop is next item in current code block, so # increment lex dim val enumerating items in current code block - if self.stmt_instance_before or self.stmt_instance_after: # if either statement has been set + if self.stmt_instance_before or self.stmt_instance_after: + # (if either statement has been set) # this lex value will correspond to everything inside this loop # we will add new lex dimensions to enuerate items inside loop next_insn_lex_pt[-1] = next_insn_lex_pt[-1]+1 @@ -298,12 +300,16 @@ class LexSchedule(object): :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, + 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)]) + 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 @@ -383,10 +389,12 @@ class LexSchedule(object): params_sched = [self.unused_param_name] out_names_sched = self.get_lex_var_names() - in_names_sched_before = [self.statement_var_name] + dom_inames_ordered_before[:] + 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[:] + 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) @@ -394,13 +402,11 @@ class LexSchedule(object): # intersection with sched map later doms_to_intersect_before = [ add_dims_to_isl_set( - #sid_to_dom_before[self.stmt_instance_before.stmt.int_id], isl.dim_type.set, dom_before, isl.dim_type.set, [self.statement_var_name], 0), ] doms_to_intersect_after = [ add_dims_to_isl_set( - #sid_to_dom_after[self.stmt_instance_after.stmt.int_id], isl.dim_type.set, dom_after, isl.dim_type.set, [self.statement_var_name], 0), ] @@ -415,14 +421,19 @@ class LexSchedule(object): 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)], + [( + (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.unused_param_name, 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.stmt.int_id,) + + tuple(dom_inames_ordered_after), self.stmt_instance_after.lex_pt)], doms_to_intersect_after ), @@ -450,8 +461,9 @@ class LexSchedule(object): return self.__bool__() def __eq__(self, other): - return (self.stmt_instance_before == other.stmt_instance_before and - self.stmt_instance_after == other.stmt_instance_after) + 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" -- GitLab From 2188f2836a41ddcc548c5468389559136f71ef03 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 25 Feb 2020 09:59:02 -0600 Subject: [PATCH 179/183] ask if loopy hasattr add_dependencies_v2 before using it (so that future MR isn't dependent on loopy/iname-sets-in-loop-priorities branch --- test/test_invalid_scheds.py | 6 ++++-- test/test_valid_scheds.py | 22 +++++++++++++++------- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/test/test_invalid_scheds.py b/test/test_invalid_scheds.py index a822ea9df..2eb31b0fa 100644 --- a/test/test_invalid_scheds.py +++ b/test/test_invalid_scheds.py @@ -66,7 +66,8 @@ def test_invalid_prioritiy_detection(): unprocessed_knl = knl0.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) - knl0 = lp.add_dependencies_v2(knl0, deps_and_domains) + if hasattr(lp, "add_dependencies_v2"): + knl0 = lp.add_dependencies_v2(knl0, deps_and_domains) # get a schedule to check if knl0.state < KernelState.PREPROCESSED: @@ -84,7 +85,8 @@ def test_invalid_prioritiy_detection(): unprocessed_knl = knl1.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) - knl1 = lp.add_dependencies_v2(knl1, deps_and_domains) + if hasattr(lp, "add_dependencies_v2"): + knl1 = lp.add_dependencies_v2(knl1, deps_and_domains) # get a schedule to check if knl1.state < KernelState.PREPROCESSED: diff --git a/test/test_valid_scheds.py b/test/test_valid_scheds.py index e98a52ada..d897d72bf 100644 --- a/test/test_valid_scheds.py +++ b/test/test_valid_scheds.py @@ -74,7 +74,9 @@ def test_loop_prioritization(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) - knl = lp.add_dependencies_v2(knl, deps_and_domains) + if hasattr(lp, "add_dependencies_v2"): + knl = lp.add_dependencies_v2(knl, deps_and_domains) + # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -108,7 +110,8 @@ def test_matmul(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) - knl = lp.add_dependencies_v2(knl, deps_and_domains) + if hasattr(lp, "add_dependencies_v2"): + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -155,7 +158,8 @@ def test_dependent_domain(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) - knl = lp.add_dependencies_v2(knl, deps_and_domains) + if hasattr(lp, "add_dependencies_v2"): + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -205,7 +209,8 @@ def test_stroud_bernstein(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) - knl = lp.add_dependencies_v2(knl, deps_and_domains) + if hasattr(lp, "add_dependencies_v2"): + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -238,7 +243,8 @@ def test_nop(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) - knl = lp.add_dependencies_v2(knl, deps_and_domains) + if hasattr(lp, "add_dependencies_v2"): + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -281,7 +287,8 @@ def test_multi_domain(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) - knl = lp.add_dependencies_v2(knl, deps_and_domains) + if hasattr(lp, "add_dependencies_v2"): + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: @@ -313,7 +320,8 @@ def test_loop_carried_deps(): unprocessed_knl = knl.copy() deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) - knl = lp.add_dependencies_v2(knl, deps_and_domains) + if hasattr(lp, "add_dependencies_v2"): + knl = lp.add_dependencies_v2(knl, deps_and_domains) # get a schedule to check if knl.state < KernelState.PREPROCESSED: -- GitLab From 0eb9fe5d758ef3ce62fb0baafd0fcb021912959e Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 25 Feb 2020 10:04:49 -0600 Subject: [PATCH 180/183] fixing flake8 issues --- test/test_invalid_scheds.py | 25 +++++++++++++-------- test/test_valid_scheds.py | 43 ++++++++++++++++++++++++------------- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/test/test_invalid_scheds.py b/test/test_invalid_scheds.py index 2eb31b0fa..0b06fb9c2 100644 --- a/test/test_invalid_scheds.py +++ b/test/test_invalid_scheds.py @@ -27,7 +27,6 @@ from pyopencl.tools import ( # noqa pytest_generate_tests_for_pyopencl as pytest_generate_tests) import loopy as lp -import numpy as np from schedule_checker import ( get_statement_pair_dependency_sets_from_legacy_knl, check_schedule_validity, @@ -65,7 +64,8 @@ def test_invalid_prioritiy_detection(): unprocessed_knl = knl0.copy() - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) if hasattr(lp, "add_dependencies_v2"): knl0 = lp.add_dependencies_v2(knl0, deps_and_domains) @@ -75,7 +75,8 @@ def test_invalid_prioritiy_detection(): knl0 = get_one_scheduled_kernel(knl0) schedule_items = knl0.schedule - sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid # no error: @@ -84,7 +85,8 @@ def test_invalid_prioritiy_detection(): unprocessed_knl = knl1.copy() - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) if hasattr(lp, "add_dependencies_v2"): knl1 = lp.add_dependencies_v2(knl1, deps_and_domains) @@ -94,7 +96,8 @@ def test_invalid_prioritiy_detection(): knl1 = get_one_scheduled_kernel(knl1) schedule_items = knl1.schedule - sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid # error (cycle): @@ -105,7 +108,8 @@ def test_invalid_prioritiy_detection(): """ unprocessed_knl = knl2.copy() - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) # get a schedule to check if knl2.state < KernelState.PREPROCESSED: @@ -113,7 +117,8 @@ def test_invalid_prioritiy_detection(): knl2 = get_one_scheduled_kernel(knl2) schedule_items = knl2.schedule - sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) """ # should raise error assert False @@ -127,7 +132,8 @@ def test_invalid_prioritiy_detection(): """ unprocessed_knl = knl3.copy() - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) # get a schedule to check if knl3.state < KernelState.PREPROCESSED: @@ -135,7 +141,8 @@ def test_invalid_prioritiy_detection(): knl3 = get_one_scheduled_kernel(knl3) schedule_items = knl3.schedule - sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) """ # should raise error assert False diff --git a/test/test_valid_scheds.py b/test/test_valid_scheds.py index d897d72bf..f12211dce 100644 --- a/test/test_valid_scheds.py +++ b/test/test_valid_scheds.py @@ -73,18 +73,19 @@ def test_loop_prioritization(): unprocessed_knl = knl.copy() - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) if hasattr(lp, "add_dependencies_v2"): knl = lp.add_dependencies_v2(knl, deps_and_domains) - # get a schedule to check if knl.state < KernelState.PREPROCESSED: knl = preprocess_kernel(knl) knl = get_one_scheduled_kernel(knl) schedule_items = knl.schedule - sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid @@ -109,7 +110,8 @@ def test_matmul(): unprocessed_knl = knl.copy() - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) if hasattr(lp, "add_dependencies_v2"): knl = lp.add_dependencies_v2(knl, deps_and_domains) @@ -119,7 +121,8 @@ def test_matmul(): knl = get_one_scheduled_kernel(knl) schedule_items = knl.schedule - sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid @@ -157,7 +160,8 @@ def test_dependent_domain(): unprocessed_knl = knl.copy() - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) if hasattr(lp, "add_dependencies_v2"): knl = lp.add_dependencies_v2(knl, deps_and_domains) @@ -167,7 +171,8 @@ def test_dependent_domain(): knl = get_one_scheduled_kernel(knl) schedule_items = knl.schedule - sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid @@ -208,7 +213,8 @@ def test_stroud_bernstein(): unprocessed_knl = knl.copy() - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) if hasattr(lp, "add_dependencies_v2"): knl = lp.add_dependencies_v2(knl, deps_and_domains) @@ -218,7 +224,8 @@ def test_stroud_bernstein(): knl = get_one_scheduled_kernel(knl) schedule_items = knl.schedule - sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid @@ -242,7 +249,8 @@ def test_nop(): unprocessed_knl = knl.copy() - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) if hasattr(lp, "add_dependencies_v2"): knl = lp.add_dependencies_v2(knl, deps_and_domains) @@ -252,7 +260,8 @@ def test_nop(): knl = get_one_scheduled_kernel(knl) schedule_items = knl.schedule - sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid @@ -286,7 +295,8 @@ def test_multi_domain(): unprocessed_knl = knl.copy() - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) if hasattr(lp, "add_dependencies_v2"): knl = lp.add_dependencies_v2(knl, deps_and_domains) @@ -296,7 +306,8 @@ def test_multi_domain(): knl = get_one_scheduled_kernel(knl) schedule_items = knl.schedule - sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid @@ -319,7 +330,8 @@ def test_loop_carried_deps(): unprocessed_knl = knl.copy() - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl(unprocessed_knl) + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) if hasattr(lp, "add_dependencies_v2"): knl = lp.add_dependencies_v2(knl, deps_and_domains) @@ -329,7 +341,8 @@ def test_loop_carried_deps(): knl = get_one_scheduled_kernel(knl) schedule_items = knl.schedule - sched_is_valid = check_schedule_validity(unprocessed_knl, deps_and_domains, schedule_items) + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) assert sched_is_valid -- GitLab From eee9dcb1ffc6c1ef91267a8fe30c0200bf0a8821 Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 25 Feb 2020 10:17:20 -0600 Subject: [PATCH 181/183] check whether loopy hasattr constrain_loop_nesting and alter test accordingly; makes tests pass whether or not we have branch loopy/iname-sets-in-loop-priorities --- test/test_invalid_scheds.py | 66 +++++++++++++++++++++---------------- 1 file changed, 38 insertions(+), 28 deletions(-) diff --git a/test/test_invalid_scheds.py b/test/test_invalid_scheds.py index 0b06fb9c2..05073502a 100644 --- a/test/test_invalid_scheds.py +++ b/test/test_invalid_scheds.py @@ -104,50 +104,60 @@ def test_invalid_prioritiy_detection(): knl2 = lp.prioritize_loops(ref_knl, "h,i,j") knl2 = lp.prioritize_loops(knl2, "j,k") try: - knl2 = lp.prioritize_loops(knl2, "k,i") - """ - unprocessed_knl = knl2.copy() + if hasattr(lp, "constrain_loop_nesting"): + knl2 = lp.constrain_loop_nesting(knl2, "k,i") + else: + knl2 = lp.prioritize_loops(knl2, "k,i") - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( - unprocessed_knl) + unprocessed_knl = knl2.copy() - # get a schedule to check - if knl2.state < KernelState.PREPROCESSED: - knl2 = preprocess_kernel(knl2) - knl2 = get_one_scheduled_kernel(knl2) - schedule_items = knl2.schedule + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) - sched_is_valid = check_schedule_validity( - unprocessed_knl, deps_and_domains, schedule_items) - """ + # get a schedule to check + if knl2.state < KernelState.PREPROCESSED: + knl2 = preprocess_kernel(knl2) + knl2 = get_one_scheduled_kernel(knl2) + schedule_items = knl2.schedule + + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) # should raise error assert False except ValueError as e: - assert "cycle detected" in str(e) + if hasattr(lp, "constrain_loop_nesting"): + assert "cycle detected" in str(e) + else: + assert "invalid priorities" in str(e) # error (inconsistent priorities): knl3 = lp.prioritize_loops(ref_knl, "h,i,j,k") try: - knl3 = lp.prioritize_loops(knl3, "h,j,i,k") - """ - unprocessed_knl = knl3.copy() + if hasattr(lp, "constrain_loop_nesting"): + knl3 = lp.constrain_loop_nesting(knl3, "h,j,i,k") + else: + knl3 = lp.prioritize_loops(knl3, "h,j,i,k") - deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( - unprocessed_knl) + unprocessed_knl = knl3.copy() - # get a schedule to check - if knl3.state < KernelState.PREPROCESSED: - knl3 = preprocess_kernel(knl3) - knl3 = get_one_scheduled_kernel(knl3) - schedule_items = knl3.schedule + deps_and_domains = get_statement_pair_dependency_sets_from_legacy_knl( + unprocessed_knl) - sched_is_valid = check_schedule_validity( - unprocessed_knl, deps_and_domains, schedule_items) - """ + # get a schedule to check + if knl3.state < KernelState.PREPROCESSED: + knl3 = preprocess_kernel(knl3) + knl3 = get_one_scheduled_kernel(knl3) + schedule_items = knl3.schedule + + sched_is_valid = check_schedule_validity( + unprocessed_knl, deps_and_domains, schedule_items) # should raise error assert False except ValueError as e: - assert "cycle detected" in str(e) + if hasattr(lp, "constrain_loop_nesting"): + assert "cycle detected" in str(e) + else: + assert "invalid priorities" in str(e) if __name__ == "__main__": -- GitLab From 6876844e6e7fc6602e30a123b08a2e7f998ace4b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 25 Feb 2020 11:27:38 -0600 Subject: [PATCH 182/183] preparing to move schedule_checker files into loopy while preserving git history --- __init__.py => schedule_checker/__init__.py | 0 dependency.py => schedule_checker/dependency.py | 0 .../example_dependency_checking.py | 0 .../example_lex_map_creation.py | 0 .../example_pairwise_schedule_validity.py | 0 .../example_wave_equation.py | 0 .../lexicographic_order_map.py | 0 sched_check_utils.py => schedule_checker/sched_check_utils.py | 0 schedule.py => schedule_checker/schedule.py | 0 {test => schedule_checker/test}/test_invalid_scheds.py | 0 {test => schedule_checker/test}/test_valid_scheds.py | 0 version.py => schedule_checker/version.py | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename __init__.py => schedule_checker/__init__.py (100%) rename dependency.py => schedule_checker/dependency.py (100%) rename example_dependency_checking.py => schedule_checker/example_dependency_checking.py (100%) rename example_lex_map_creation.py => schedule_checker/example_lex_map_creation.py (100%) rename example_pairwise_schedule_validity.py => schedule_checker/example_pairwise_schedule_validity.py (100%) rename example_wave_equation.py => schedule_checker/example_wave_equation.py (100%) rename lexicographic_order_map.py => schedule_checker/lexicographic_order_map.py (100%) rename sched_check_utils.py => schedule_checker/sched_check_utils.py (100%) rename schedule.py => schedule_checker/schedule.py (100%) rename {test => schedule_checker/test}/test_invalid_scheds.py (100%) rename {test => schedule_checker/test}/test_valid_scheds.py (100%) rename version.py => schedule_checker/version.py (100%) diff --git a/__init__.py b/schedule_checker/__init__.py similarity index 100% rename from __init__.py rename to schedule_checker/__init__.py diff --git a/dependency.py b/schedule_checker/dependency.py similarity index 100% rename from dependency.py rename to schedule_checker/dependency.py diff --git a/example_dependency_checking.py b/schedule_checker/example_dependency_checking.py similarity index 100% rename from example_dependency_checking.py rename to schedule_checker/example_dependency_checking.py diff --git a/example_lex_map_creation.py b/schedule_checker/example_lex_map_creation.py similarity index 100% rename from example_lex_map_creation.py rename to schedule_checker/example_lex_map_creation.py diff --git a/example_pairwise_schedule_validity.py b/schedule_checker/example_pairwise_schedule_validity.py similarity index 100% rename from example_pairwise_schedule_validity.py rename to schedule_checker/example_pairwise_schedule_validity.py diff --git a/example_wave_equation.py b/schedule_checker/example_wave_equation.py similarity index 100% rename from example_wave_equation.py rename to schedule_checker/example_wave_equation.py diff --git a/lexicographic_order_map.py b/schedule_checker/lexicographic_order_map.py similarity index 100% rename from lexicographic_order_map.py rename to schedule_checker/lexicographic_order_map.py diff --git a/sched_check_utils.py b/schedule_checker/sched_check_utils.py similarity index 100% rename from sched_check_utils.py rename to schedule_checker/sched_check_utils.py diff --git a/schedule.py b/schedule_checker/schedule.py similarity index 100% rename from schedule.py rename to schedule_checker/schedule.py diff --git a/test/test_invalid_scheds.py b/schedule_checker/test/test_invalid_scheds.py similarity index 100% rename from test/test_invalid_scheds.py rename to schedule_checker/test/test_invalid_scheds.py diff --git a/test/test_valid_scheds.py b/schedule_checker/test/test_valid_scheds.py similarity index 100% rename from test/test_valid_scheds.py rename to schedule_checker/test/test_valid_scheds.py diff --git a/version.py b/schedule_checker/version.py similarity index 100% rename from version.py rename to schedule_checker/version.py -- GitLab From 91125cdfff9746d97dd12074349da55000426e4b Mon Sep 17 00:00:00 2001 From: jdsteve2 Date: Tue, 25 Feb 2020 11:33:08 -0600 Subject: [PATCH 183/183] moving schedule_checker into schedule --- {schedule_checker => loopy/schedule/schedule_checker}/__init__.py | 0 .../schedule/schedule_checker}/dependency.py | 0 .../schedule/schedule_checker}/example_dependency_checking.py | 0 .../schedule/schedule_checker}/example_lex_map_creation.py | 0 .../schedule_checker}/example_pairwise_schedule_validity.py | 0 .../schedule/schedule_checker}/example_wave_equation.py | 0 .../schedule/schedule_checker}/lexicographic_order_map.py | 0 .../schedule/schedule_checker}/sched_check_utils.py | 0 {schedule_checker => loopy/schedule/schedule_checker}/schedule.py | 0 .../schedule/schedule_checker}/test/test_invalid_scheds.py | 0 .../schedule/schedule_checker}/test/test_valid_scheds.py | 0 {schedule_checker => loopy/schedule/schedule_checker}/version.py | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename {schedule_checker => loopy/schedule/schedule_checker}/__init__.py (100%) rename {schedule_checker => loopy/schedule/schedule_checker}/dependency.py (100%) rename {schedule_checker => loopy/schedule/schedule_checker}/example_dependency_checking.py (100%) rename {schedule_checker => loopy/schedule/schedule_checker}/example_lex_map_creation.py (100%) rename {schedule_checker => loopy/schedule/schedule_checker}/example_pairwise_schedule_validity.py (100%) rename {schedule_checker => loopy/schedule/schedule_checker}/example_wave_equation.py (100%) rename {schedule_checker => loopy/schedule/schedule_checker}/lexicographic_order_map.py (100%) rename {schedule_checker => loopy/schedule/schedule_checker}/sched_check_utils.py (100%) rename {schedule_checker => loopy/schedule/schedule_checker}/schedule.py (100%) rename {schedule_checker => loopy/schedule/schedule_checker}/test/test_invalid_scheds.py (100%) rename {schedule_checker => loopy/schedule/schedule_checker}/test/test_valid_scheds.py (100%) rename {schedule_checker => loopy/schedule/schedule_checker}/version.py (100%) diff --git a/schedule_checker/__init__.py b/loopy/schedule/schedule_checker/__init__.py similarity index 100% rename from schedule_checker/__init__.py rename to loopy/schedule/schedule_checker/__init__.py diff --git a/schedule_checker/dependency.py b/loopy/schedule/schedule_checker/dependency.py similarity index 100% rename from schedule_checker/dependency.py rename to loopy/schedule/schedule_checker/dependency.py diff --git a/schedule_checker/example_dependency_checking.py b/loopy/schedule/schedule_checker/example_dependency_checking.py similarity index 100% rename from schedule_checker/example_dependency_checking.py rename to loopy/schedule/schedule_checker/example_dependency_checking.py diff --git a/schedule_checker/example_lex_map_creation.py b/loopy/schedule/schedule_checker/example_lex_map_creation.py similarity index 100% rename from schedule_checker/example_lex_map_creation.py rename to loopy/schedule/schedule_checker/example_lex_map_creation.py diff --git a/schedule_checker/example_pairwise_schedule_validity.py b/loopy/schedule/schedule_checker/example_pairwise_schedule_validity.py similarity index 100% rename from schedule_checker/example_pairwise_schedule_validity.py rename to loopy/schedule/schedule_checker/example_pairwise_schedule_validity.py diff --git a/schedule_checker/example_wave_equation.py b/loopy/schedule/schedule_checker/example_wave_equation.py similarity index 100% rename from schedule_checker/example_wave_equation.py rename to loopy/schedule/schedule_checker/example_wave_equation.py diff --git a/schedule_checker/lexicographic_order_map.py b/loopy/schedule/schedule_checker/lexicographic_order_map.py similarity index 100% rename from schedule_checker/lexicographic_order_map.py rename to loopy/schedule/schedule_checker/lexicographic_order_map.py diff --git a/schedule_checker/sched_check_utils.py b/loopy/schedule/schedule_checker/sched_check_utils.py similarity index 100% rename from schedule_checker/sched_check_utils.py rename to loopy/schedule/schedule_checker/sched_check_utils.py diff --git a/schedule_checker/schedule.py b/loopy/schedule/schedule_checker/schedule.py similarity index 100% rename from schedule_checker/schedule.py rename to loopy/schedule/schedule_checker/schedule.py diff --git a/schedule_checker/test/test_invalid_scheds.py b/loopy/schedule/schedule_checker/test/test_invalid_scheds.py similarity index 100% rename from schedule_checker/test/test_invalid_scheds.py rename to loopy/schedule/schedule_checker/test/test_invalid_scheds.py diff --git a/schedule_checker/test/test_valid_scheds.py b/loopy/schedule/schedule_checker/test/test_valid_scheds.py similarity index 100% rename from schedule_checker/test/test_valid_scheds.py rename to loopy/schedule/schedule_checker/test/test_valid_scheds.py diff --git a/schedule_checker/version.py b/loopy/schedule/schedule_checker/version.py similarity index 100% rename from schedule_checker/version.py rename to loopy/schedule/schedule_checker/version.py -- GitLab