def check(self, checker): for place, number in utils.multiset( [edge.place for edge in self.edges_in]).items(): if number != 1: raise utils.PtpException( "There can be at most one input edge " "between place and transition", self.get_source()) if self.collective: inscriptions = [ inscription for edge in self.edges_out for inscription in edge.inscriptions if inscription.is_collective() ] if len(inscriptions) > 1: raise utils.PtpException( "At most one collective inscription may be defined", inscriptions[-1].source) if inscriptions: op = inscriptions[0].get_collective_operation() need_root = op == "scatter" or op == "gather" or op == "bcast" if not self.root and need_root: raise utils.PtpException("Root not defined", self.get_source()) else: need_root = False if not need_root and self.root: raise utils.PtpException( "Root cannot be defined for this operation", self.get_source()) for edge in self.edges_in: edge.check_edge_in(checker) for edge in self.edges_out: edge.check_edge_out(checker) if self.guard: checker.check_expression(self.guard, self.get_input_decls(), "bool", self.get_source("guard")) if self.time_substitution: decls = self.get_decls() decls.set("ctx", "casr::Context", force=True) decls.set("transitionTime", "ca::IntTime", self.get_source(), force=True) checker.check_expression(self.time_substitution, decls, "ca::IntTime", self.get_source()) if self.clock_substitution: decls = self.get_decls() decls.set("ctx", "casr::Context", force=True) decls.set("clockTime", "ca::IntTime", self.get_source(), force=True) checker.check_expression(self.clock_substitution, decls, "ca::IntTime", self.get_source())
def check_edge_out(self, checker): if not self.expr: raise utils.PtpException( "Main expression of output inscription is empty", self.source) if self.edge.transition.collective and self.target is not None: raise utils.PtpException( "Output edges of collective transitions cannot contain '@'", self.source) allowed = ["bulk", "multicast", "if", "seq"] if self.edge.transition.collective: if self.edge.transition.root: allowed.append("root") allowed += ["scatter", "gather", "allgather", "bcast"] self.check_config(allowed) if self.check_config_with_expression("if"): decls = self.edge.transition.get_input_decls_with_size(self.source) checker.check_expression(self.config["if"], decls, "bool", self.source) if self.check_config_with_expression("seq"): if not utils.is_integer(self.config["seq"]): raise utils.PtpException( "Parameter of 'seq' has to be a constant integer", self.source) self.config["seq"] = int(self.config["seq"]) if self.target is not None: checker.check_expression(self.target, self.edge.transition.get_decls(), self.target_type, self.source) self.check(checker)
def check_config_with_expression(self, name, variable=False): if name in self.config: if self.config[name] is None: raise utils.PtpException( "'{0}' requires an expression".format(name), self.source) if variable and \ not self.edge.transition.net.project.is_expr_variable(self.config[name]): raise utils.PtpException( "'{0}' requires an variable".format(name)) return True else: return False
def set(self, var, t, source=None, force=False): if not force and var in self.types: if self.types[var] != t: if source is None: source = self.source msg = "Invalid type of variable '{0}' ({1}/{2})".format( var, self.types[var], t) raise utils.PtpException(msg, source) else: self.types[var] = t
def check_edge_in(self, checker): self.check(checker) for inscription in self.inscriptions: inscription.check_edge_in(checker) if self.size_substitution: raise utils.PtpException( "Size substition can be used only for output edges", self.source)
def check_edge_in(self, checker): if self.target is not None: raise utils.PtpException("Input edges cannot contain '@'", self.source) allowed = [ "bulk", "guard", "svar", "filter", "from", "if", "sort_by_source" ] if self.edge.transition.collective and self.edge.transition.root: allowed.append("root") self.check_config(allowed) if self.check_config_with_expression("svar", variable=True): decls = self.edge.transition.get_input_decls() checker.check_expression(self.config["svar"], decls, self.get_svar_type(), self.source) if self.check_config_with_expression("filter"): decls = self.edge.transition.get_input_decls() checker.check_expression(self.config["filter"], decls, "bool", self.source) if self.check_config_with_expression("from"): decls = self.edge.transition.get_input_decls() checker.check_expression(self.config["from"], decls, "int", self.source) if self.check_config_with_expression("guard"): decls = self.edge.transition.get_input_decls_with_size(self.source) checker.check_expression(self.config["guard"], decls, "bool", self.source) if self.check_config_with_expression("if"): decls = self.edge.transition.get_input_decls_with_size(self.source) checker.check_expression(self.config["if"], decls, "bool", self.source) self.check(checker) if "sort_by_source" in self.config and "bulk" not in self.config: raise utils.PtpException("Configuration option 'sort_by_source' " "can be used only with 'bulk'")
def check(self, checker): for place in self.places: place.check(checker) for transition in self.transitions: transition.check(checker) for area in self.areas: area.check(checker) place = utils.check_uniquness(self.get_input_places(), lambda p: p.interface_input) if place is not None: raise utils.PtpException("Input iterfaces have not unique names", place.get_source("type")) place = utils.check_uniquness(self.get_output_places(), lambda p: p.interface_output) if place is not None: raise utils.PtpException("Output iterfaces have not unique names", place.get_source("type"))
def check(self, checker): if self.has_expr(): op = self.get_collective_operation() if op == "scatter": checker.check_expression(self.expr, self.edge.transition.get_decls(), get_container_type(self.type), self.source) elif op == "gather" or op == "allgather": t = self.edge.transition.net.project.parse_typename( self.type, self.source) if len(t) < 2 or len(t[1]) < 0 or t[0] != "std::vector": raise utils.PtpException("Invalid type of expression", self.source) typename = t[1][0] checker.check_expression(self.expr, self.edge.transition.get_decls(), typename, self.source) else: checker.check_expression(self.expr, self.edge.transition.get_decls(), self.type, self.source)
def analyze_transition(tr): variable_sources = { } # string -> uid - which inscriptions carry input variables reuse_tokens = { } # uid -> uid - identification number of token for output inscpription fresh_tokens = [] # (uid, type) - what tokens has to be created for output used_tokens = [ ] # [uid] - Tokens from input inscriptions that are reused on output variable_sources_out = {} # string -> uid or None bulk_overtake = [] # [uid] overtaken_variables = set() def inscription_out_weight(inscription): # Reorder edges, bulk edges first because we want them send first # Otherwise it can cause problems like in sending results in "workers" example s = inscription.config.get("seq") if s is None: seq = 0 else: seq = int(s) * 3 if inscription.is_bulk(): return seq # Unconditional edges has higher priority if inscription.is_conditioned(): return seq + 2 else: return seq + 1 def inscription_in_weight(inscription): if inscription.is_conditioned(): return 1 else: return 0 inscriptions_in = sum((edge.inscriptions for edge in tr.edges_in), []) inscriptions_in.sort(key=inscription_in_weight) inscriptions_out = sum((edge.inscriptions for edge in tr.edges_out), []) inscriptions_out.sort(key=inscription_out_weight) variable_sources = get_variable_sources(inscriptions_in) # Order input inscriptions by variable dependancy inscriptions_in = utils.topological_ordering(inscriptions_in, is_dependant) if inscriptions_in is None: raise utils.PtpException("Circle variable dependancy", tr.get_source()) # Try reuse tokens for inscription in inscriptions_out: if inscription.is_bulk() or not inscription.is_local(): continue # Bulk and nonlocal edge cannot use token reusage if not inscription.is_expr_variable(): continue # Current implementation reuses tokens only for variable expression if inscription.is_collective(): continue # Collective operations cannot use token reusage token_uid = variable_sources.get(inscription.expr) if token_uid is None or token_uid in used_tokens: # Variable is not taken from input as token # or token is already reused --> reusage not possible continue reuse_tokens[inscription.uid] = token_uid used_tokens.append(token_uid) # Setup fresh variables where token was not reused for inscription in inscriptions_out: if not inscription.is_expr_variable(): continue # We are interested only in variables variable = inscription.expr if variable in variable_sources: # Variable take from input so we do not have to deal here with it continue if variable in variable_sources_out: # Variable already prepared for output continue if inscription.is_bulk(): # No token, just build variable variable_sources_out[variable] = None continue if inscription.is_local(): # Local send, we prepare token fresh_tokens.append((inscription.uid, inscription.edge.place.type)) variable_sources_out[variable] = inscription.uid reuse_tokens[ inscription.uid] = inscription.uid # Use this fresh new token else: # Just create variable variable_sources_out[variable] = None for inscription in reversed(inscriptions_out): # Now we are checking overtake. It has to be in reversed order # becacase overtake has to be the last operation on variable if not inscription.is_bulk() or not inscription.is_expr_variable(): continue # We are interested only in variables and bulk inscriptions if inscription.expr not in overtaken_variables: overtaken_variables.add(inscription.expr) bulk_overtake.append(inscription.uid) for inscription in inscriptions_out: for variable in inscription.get_other_variables(): if variable not in variable_sources and \ variable not in variable_sources_out: variable_sources_out[variable] = None tr.inscriptions_in = inscriptions_in tr.inscriptions_out = inscriptions_out tr.variable_sources = variable_sources tr.reuse_tokens = reuse_tokens tr.variable_sources_out = variable_sources_out tr.fresh_tokens = fresh_tokens tr.bulk_overtake = bulk_overtake
def check(self, checker): bulk = any(inscription.is_bulk() for inscription in self.inscriptions) if bulk and len(self.inscriptions) > 1: raise utils.PtpException( "Bulk inscription cannot be combined with others", self.source)
def check_config(self, valid_keys): invalid_key = utils.key_not_in_list(self.config, valid_keys) if invalid_key is not None: raise utils.PtpException( "Invalid config item '{0}'".format(invalid_key), self.source)