def __init__(self, trace, content_lens=None, frame_lens=None, activity=None): """Create from a LoadingTrace (or json of a trace). Args: trace: (LoadingTrace/JSON) Loading trace or JSON of a trace. content_lens: (ContentClassificationLens) Lens used to annotate the nodes, or None. frame_lens: (FrameLoadLens) Lens used to augment graph with load nodes. activity: (ActivityLens) Lens used to augment the edges with the activity. """ if type(trace) == dict: trace = loading_trace.LoadingTrace.FromJsonDict(trace) self._trace = trace self._content_lens = content_lens self._frame_lens = frame_lens self._activity_lens = activity self._BuildDag(trace) # Sort before splitting children so that we can correctly dectect if a # reparented child is actually a dependency for a child of its new parent. try: for n in dag.TopologicalSort(self._nodes): self._SplitChildrenByTime(self._node_info[n.Index()]) except AssertionError as exc: sys.stderr.write('Bad topological sort: %s\n' 'Skipping child split\n' % str(exc)) self._cache_all = False self._node_filter = lambda _: True
def Cost(self, path_list=None): """Compute cost of current model. Args: path_list: if not None, gets a list of NodeInfo in the longest path. Returns: Cost of the longest path. """ costs = [0] * len(self._nodes) for n in dag.TopologicalSort(self._nodes, self._node_filter): cost = 0 if n.Predecessors(): cost = max([costs[p.Index()] + self._EdgeCost(p, n) for p in n.Predecessors()]) if not self._cache_all: cost += self._NodeCost(n) costs[n.Index()] = cost max_cost = max(costs) assert max_cost > 0 # Otherwise probably the filter went awry. if path_list is not None: del path_list[:-1] n = (i for i in self._nodes if costs[i.Index()] == max_cost).next() path_list.append(self._node_info[n.Index()]) while n.Predecessors(): n = reduce(lambda costliest, next: next if (self._node_filter(next) and cost[next.Index()] > cost[costliest.Index()]) else costliest, n.Predecessors()) path_list.insert(0, self._node_info[n.Index()]) return max_cost
def MakeGraphviz(self, output, highlight=None): """Output a graphviz representation of our DAG. Args: output: a file-like output stream which recieves a graphviz dot. highlight: a list of node items to emphasize. Any resource url which contains any highlight text will be distinguished in the output. """ output.write("""digraph dependencies { rankdir = LR; """) orphans = set() try: sorted_nodes = dag.TopologicalSort(self._nodes, node_filter=self._node_filter) except AssertionError as exc: sys.stderr.write('Bad topological sort: %s\n' 'Writing children in order\n' % str(exc)) sorted_nodes = self._nodes for n in sorted_nodes: if not n.Successors() and not n.Predecessors(): orphans.add(n) if orphans: output.write("""subgraph cluster_orphans { color=black; label="Orphans"; """) for n in orphans: output.write(self._GraphvizNode(n.Index(), highlight)) output.write('}\n') output.write("""subgraph cluster_nodes { color=invis; """) for n in sorted_nodes: if not n.Successors() and not n.Predecessors(): continue output.write(self._GraphvizNode(n.Index(), highlight)) for n in sorted_nodes: for s in n.Successors(): style = 'color = orange' annotations = self._EdgeAnnotation(n, s) if 'parser' in annotations: style = 'color = red' elif 'stack' in annotations: style = 'color = blue' elif 'script_inferred' in annotations: style = 'color = purple' if 'timing' in annotations: style += '; style=dashed' arrow = '[%s; label="%s"]' % (style, self._EdgeCost(n, s)) output.write('%d -> %d %s;\n' % (n.Index(), s.Index(), arrow)) output.write('}\n}\n')
def Nodes(self, sort=False): """Return iterable of all nodes via their NodeInfos. Args: sort: if true, return nodes in sorted order. This may prune additional nodes from the unsorted list (eg, non-root, non-ad nodes reachable only by ad nodes) Returns: Iterable of node infos. """ if sort: return ( self._node_info[n.Index()] for n in dag.TopologicalSort(self._nodes, self._node_filter)) return (n for n in self._node_info if self._node_filter(n.Node()))
def __init__(self, requests): """Create from a parsed request set. Args: requests: [RequestData, ...] filtered RequestData from loading.log_parser. """ self._BuildDag(requests) self._global_start = min([n.StartTime() for n in self._node_info]) # Sort before splitting children so that we can correctly dectect if a # reparented child is actually a dependency for a child of its new parent. try: for n in dag.TopologicalSort(self._nodes): self._SplitChildrenByTime(self._node_info[n.Index()]) except AssertionError as exc: sys.stderr.write('Bad topological sort: %s\n' 'Skipping child split\n' % str(exc)) self._cache_all = False self._node_filter = lambda _: True
def SortedIndicies(self, graph): return [n.Index() for n in dag.TopologicalSort(graph._nodes)]
def SortedIndicies(self, graph, node_filter=None): return [n.Index() for n in dag.TopologicalSort(graph, node_filter)]