1f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#!/usr/bin/env python 2f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Copyright 2014 The Chromium Authors. All rights reserved. 3f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Use of this source code is governed by a BSD-style license that can be 4f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# found in the LICENSE file. 5f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 6f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport argparse, os, sys, json, subprocess, pickle, StringIO 7f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 8f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochparser = argparse.ArgumentParser( 9f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch description = 10f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch "Process the Blink points-to graph generated by the Blink GC plugin.") 11f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 12f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochparser.add_argument( 13f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch '-', dest='use_stdin', action='store_true', 14f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch help='Read JSON graph files from stdin') 15f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 16f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochparser.add_argument( 17f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch '-c', '--detect-cycles', action='store_true', 18f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch help='Detect cycles containing GC roots') 19f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 20f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochparser.add_argument( 21f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch '-s', '--print-stats', action='store_true', 22f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch help='Statistics about ref-counted and traced objects') 23f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 24f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochparser.add_argument( 25f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch '-v', '--verbose', action='store_true', 26f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch help='Verbose output') 27f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 28f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochparser.add_argument( 29f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch '--ignore-cycles', default=None, metavar='FILE', 30f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch help='File with cycles to ignore') 31f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 32f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochparser.add_argument( 33f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch '--ignore-classes', nargs='*', default=[], metavar='CLASS', 34f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch help='Classes to ignore when detecting cycles') 35f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 36f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochparser.add_argument( 37f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch '--pickle-graph', default=None, metavar='FILE', 38f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch help='File to read/save the graph from/to') 39f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 40f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochparser.add_argument( 41f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 'files', metavar='FILE_OR_DIR', nargs='*', default=[], 42f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch help='JSON graph files or directories containing them') 43f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 44f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Command line args after parsing. 45f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochargs = None 46f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 47f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Map from node labels to nodes. 48f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochgraph = {} 49f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 50f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Set of root nodes. 51f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochroots = [] 52f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 53f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# List of cycles to ignore. 54f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochignored_cycles = [] 55f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 56f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Global flag to determine exit code. 57f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochglobal_reported_error = False 58f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 59f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef set_reported_error(value): 60f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch global global_reported_error 61f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch global_reported_error = value 62f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 63f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef reported_error(): 64f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return global_reported_error 65f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 66f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef log(msg): 67f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if args.verbose: 68f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch print msg 69f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 70f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochglobal_inc_copy = 0 71f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef inc_copy(): 72f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch global global_inc_copy 73f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch global_inc_copy += 1 74f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 75f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef get_node(name): 76f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return graph.setdefault(name, Node(name)) 77f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 78f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochptr_types = ('raw', 'ref', 'mem') 79f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 80f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef inc_ptr(dst, ptr): 81f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if ptr in ptr_types: 82f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch node = graph.get(dst) 83f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if not node: return 84f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch node.counts[ptr] += 1 85f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 86f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef add_counts(s1, s2): 87f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for (k, v) in s2.iteritems(): 88f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch s1[k] += s2[k] 89f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 90f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Representation of graph nodes. Basically a map of directed edges. 91f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochclass Node: 92f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def __init__(self, name): 93f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.name = name 94f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.edges = {} 95f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.reset() 96f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def __repr__(self): 97f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return "%s(%s) %s" % (self.name, self.visited, self.edges) 98f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def update_node(self, decl): 99f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # Currently we don't track any node info besides its edges. 100f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch pass 101f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def update_edge(self, e): 102f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch new_edge = Edge(**e) 103f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch edge = self.edges.get(new_edge.key) 104f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if edge: 105f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # If an edge exist, its kind is the strongest of the two. 106f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch edge.kind = max(edge.kind, new_edge.kind) 107f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch else: 108f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.edges[new_edge.key] = new_edge 109f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def super_edges(self): 110f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return [ e for e in self.edges.itervalues() if e.is_super() ] 111f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def subclass_edges(self): 112f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return [ e for e in self.edges.itervalues() if e.is_subclass() ] 113f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def reset(self): 114f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.cost = sys.maxint 115f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.visited = False 116f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.path = None 117f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.counts = {} 118f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for ptr in ptr_types: 119f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.counts[ptr] = 0 120f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def update_counts(self): 121f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for e in self.edges.itervalues(): 122f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch inc_ptr(e.dst, e.ptr) 123f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 124f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Representation of directed graph edges. 125f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochclass Edge: 126f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def __init__(self, **decl): 127f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.src = decl['src'] 128f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.dst = decl['dst'] 129f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.lbl = decl['lbl'] 130f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.ptr = decl['ptr'] 131f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.kind = decl['kind'] # 0 = weak, 1 = strong, 2 = root 132f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.loc = decl['loc'] 133f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # The label does not uniquely determine an edge from a node. We 134f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # define the semi-unique key to be the concatenation of the 135f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # label and dst name. This is sufficient to track the strongest 136f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # edge to a particular type. For example, if the field A::m_f 137f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # has type HashMap<WeakMember<B>, Member<B>> we will have a 138f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # strong edge with key m_f#B from A to B. 139f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch self.key = '%s#%s' % (self.lbl, self.dst) 140f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def __repr__(self): 141f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return '%s (%s) => %s' % (self.src, self.lbl, self.dst) 142f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def is_root(self): 143f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return self.kind == 2 144f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def is_weak(self): 145f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return self.kind == 0 146f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def keeps_alive(self): 147f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return self.kind > 0 148f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def is_subclass(self): 149f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return self.lbl.startswith('<subclass>') 150f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch def is_super(self): 151f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return self.lbl.startswith('<super>') 152f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 153f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef parse_file(filename): 154f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch obj = json.load(open(filename)) 155f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return obj 156f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 157f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef build_graphs_in_dir(dirname): 158f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # TODO: Use plateform independent code, eg, os.walk 159f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch files = subprocess.check_output( 160f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ['find', dirname, '-name', '*.graph.json']).split('\n') 161f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Found %d files" % len(files)) 162f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for f in files: 163f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch f.strip() 164f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if len(f) < 1: 165f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch continue 166f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch build_graph(f) 167f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 168f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef build_graph(filename): 169f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for decl in parse_file(filename): 170f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if decl.has_key('name'): 171f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # Add/update a node entry 172f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch name = decl['name'] 173f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch node = get_node(name) 174f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch node.update_node(decl) 175f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch else: 176f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # Add/update an edge entry 177f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch name = decl['src'] 178f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch node = get_node(name) 179f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch node.update_edge(decl) 180f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 181f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Copy all non-weak edges from super classes to their subclasses. 182f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# This causes all fields of a super to be considered fields of a 183f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# derived class without tranitively relating derived classes with 184f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# each other. For example, if B <: A, C <: A, and for some D, D => B, 185f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# we don't want that to entail that D => C. 186f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef copy_super_edges(edge): 187f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if edge.is_weak() or not edge.is_super(): 188f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return 189f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch inc_copy() 190f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # Make the super-class edge weak (prohibits processing twice). 191f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch edge.kind = 0 192f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # If the super class is not in our graph exit early. 193f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch super_node = graph.get(edge.dst) 194f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if super_node is None: return 195f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # Recursively copy all super-class edges. 196f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for e in super_node.super_edges(): 197f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch copy_super_edges(e) 198f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # Copy strong super-class edges (ignoring sub-class edges) to the sub class. 199f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch sub_node = graph[edge.src] 200f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for e in super_node.edges.itervalues(): 201f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if e.keeps_alive() and not e.is_subclass(): 202f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch new_edge = Edge( 203f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch src = sub_node.name, 204f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch dst = e.dst, 205f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch lbl = '%s <: %s' % (super_node.name, e.lbl), 206f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ptr = e.ptr, 207f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch kind = e.kind, 208f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch loc = e.loc, 209f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ) 210f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch sub_node.edges[new_edge.key] = new_edge 211f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # Add a strong sub-class edge. 212f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch sub_edge = Edge( 213f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch src = super_node.name, 214f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch dst = sub_node.name, 215f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch lbl = '<subclass>', 216f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ptr = edge.ptr, 217f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch kind = 1, 218f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch loc = edge.loc, 219f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ) 220f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch super_node.edges[sub_edge.key] = sub_edge 221f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 222f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef complete_graph(): 223f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for node in graph.itervalues(): 224f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for edge in node.super_edges(): 225f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch copy_super_edges(edge) 226f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for edge in node.edges.itervalues(): 227f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if edge.is_root(): 228f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch roots.append(edge) 229f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Copied edges down <super> edges for %d graph nodes" % global_inc_copy) 230f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 231f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef reset_graph(): 232f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for n in graph.itervalues(): 233f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch n.reset() 234f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 235f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef shortest_path(start, end): 236f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch start.cost = 0 237f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch minlist = [start] 238f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch while len(minlist) > 0: 239f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch minlist.sort(key=lambda n: -n.cost) 240f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch current = minlist.pop() 241f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch current.visited = True 242f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if current == end or current.cost >= end.cost + 1: 243f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return 244f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for e in current.edges.itervalues(): 245f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if not e.keeps_alive(): 246f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch continue 247f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch dst = graph.get(e.dst) 248f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if dst is None or dst.visited: 249f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch continue 250f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if current.cost < dst.cost: 251f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch dst.cost = current.cost + 1 252f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch dst.path = e 253f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch minlist.append(dst) 254f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 255f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef detect_cycles(): 256f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for root_edge in roots: 257f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch reset_graph() 258f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # Mark ignored classes as already visited 259f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for ignore in args.ignore_classes: 260f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch name = ignore.find("::") > 0 and ignore or ("blink::" + ignore) 261f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch node = graph.get(name) 262f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if node: 263f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch node.visited = True 264f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch src = graph[root_edge.src] 265f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch dst = graph.get(root_edge.dst) 266f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if src.visited: 267f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch continue 268f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if root_edge.dst == "WTF::String": 269f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch continue 270f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if dst is None: 271f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch print "\nPersistent root to incomplete destination object:" 272f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch print root_edge 273f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch set_reported_error(True) 274f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch continue 275f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # Find the shortest path from the root target (dst) to its host (src) 276f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch shortest_path(dst, src) 277f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if src.cost < sys.maxint: 278f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch report_cycle(root_edge) 279f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 280f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef is_ignored_cycle(cycle): 281f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for block in ignored_cycles: 282f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if block_match(cycle, block): 283f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return True 284f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 285f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef block_match(b1, b2): 286f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if len(b1) != len(b2): 287f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return False 288f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for (l1, l2) in zip(b1, b2): 289f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if l1 != l2: 290f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return False 291f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return True 292f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 293f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef report_cycle(root_edge): 294f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch dst = graph[root_edge.dst] 295f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch path = [] 296f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch edge = root_edge 297f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch dst.path = None 298f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch while edge: 299f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch path.append(edge) 300f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch edge = graph[edge.src].path 301f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch path.append(root_edge) 302f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch path.reverse() 303f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch # Find the max loc length for pretty printing. 304f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch max_loc = 0 305f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for p in path: 306f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if len(p.loc) > max_loc: 307f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch max_loc = len(p.loc) 308f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch out = StringIO.StringIO() 309f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for p in path[:-1]: 310f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch print >>out, (p.loc + ':').ljust(max_loc + 1), p 311f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch sout = out.getvalue() 312f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if not is_ignored_cycle(sout): 313f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch print "\nFound a potentially leaking cycle starting from a GC root:\n", sout 314f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch set_reported_error(True) 315f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 316f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef load_graph(): 317f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch global graph 318f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch global roots 319f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Reading graph from pickled file: " + args.pickle_graph) 320f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch dump = pickle.load(open(args.pickle_graph, 'rb')) 321f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch graph = dump[0] 322f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch roots = dump[1] 323f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 324f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef save_graph(): 325f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Saving graph to pickle file: " + args.pickle_graph) 326f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch dump = (graph, roots) 327f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch pickle.dump(dump, open(args.pickle_graph, 'wb')) 328f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 329f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef read_ignored_cycles(): 330f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch global ignored_cycles 331f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if not args.ignore_cycles: 332f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return 333f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Reading ignored cycles from file: " + args.ignore_cycles) 334f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch block = [] 335f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for l in open(args.ignore_cycles): 336f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch line = l.strip() 337f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if not line or line.startswith('Found'): 338f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if len(block) > 0: 339f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ignored_cycles.append(block) 340f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch block = [] 341f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch else: 342f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch block += l 343f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if len(block) > 0: 344f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ignored_cycles.append(block) 345f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 346f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochgc_bases = ( 347f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 'blink::GarbageCollected', 348f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 'blink::GarbageCollectedFinalized', 349f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 'blink::GarbageCollectedMixin', 350f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch) 351f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochref_bases = ( 352f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 'WTF::RefCounted', 353f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 'WTF::ThreadSafeRefCounted', 354f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch) 355f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochgcref_bases = ( 356f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 'blink::RefCountedGarbageCollected', 357f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 'blink::ThreadSafeRefCountedGarbageCollected', 358f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch) 359f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochref_mixins = ( 360f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 'blink::EventTarget', 361f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 'blink::EventTargetWithInlineData', 362f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 'blink::ActiveDOMObject', 363f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch) 364f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 365f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef print_stats(): 366f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch gcref_managed = [] 367f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ref_managed = [] 368f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch gc_managed = [] 369f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch hierarchies = [] 370f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 371f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for node in graph.itervalues(): 372f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch node.update_counts() 373f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for sup in node.super_edges(): 374f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if sup.dst in gcref_bases: 375f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch gcref_managed.append(node) 376f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch elif sup.dst in ref_bases: 377f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ref_managed.append(node) 378f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch elif sup.dst in gc_bases: 379f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch gc_managed.append(node) 380f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 381f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch groups = [("GC manged ", gc_managed), 382f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ("ref counted ", ref_managed), 383f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch ("in transition", gcref_managed)] 384f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch total = sum([len(g) for (s,g) in groups]) 385f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for (s, g) in groups: 386f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch percent = len(g) * 100 / total 387f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch print "%2d%% is %s (%d hierarchies)" % (percent, s, len(g)) 388f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 389f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for base in gcref_managed: 390f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch stats = dict({ 'classes': 0, 'ref-mixins': 0 }) 391f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for ptr in ptr_types: stats[ptr] = 0 392f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch hierarchy_stats(base, stats) 393f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch hierarchies.append((base, stats)) 394f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 395f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch print "\nHierarchies in transition (RefCountedGarbageCollected):" 396f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch hierarchies.sort(key=lambda (n,s): -s['classes']) 397f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for (node, stats) in hierarchies: 398f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch total = stats['mem'] + stats['ref'] + stats['raw'] 399f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch print ( 400f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch "%s %3d%% of %-30s: %3d cls, %3d mem, %3d ref, %3d raw, %3d ref-mixins" % 401f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch (stats['ref'] == 0 and stats['ref-mixins'] == 0 and "*" or " ", 402f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch total == 0 and 100 or stats['mem'] * 100 / total, 403f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch node.name.replace('blink::', ''), 404f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch stats['classes'], 405f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch stats['mem'], 406f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch stats['ref'], 407f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch stats['raw'], 408f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch stats['ref-mixins'], 409f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch )) 410f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 411f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef hierarchy_stats(node, stats): 412f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if not node: return 413f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch stats['classes'] += 1 414f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch add_counts(stats, node.counts) 415f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for edge in node.super_edges(): 416f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if edge.dst in ref_mixins: 417f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch stats['ref-mixins'] += 1 418f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for edge in node.subclass_edges(): 419f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch hierarchy_stats(graph.get(edge.dst), stats) 420f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 421f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef main(): 422f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch global args 423f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch args = parser.parse_args() 424f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if not (args.detect_cycles or args.print_stats): 425f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch print "Please select an operation to perform (eg, -c to detect cycles)" 426f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch parser.print_help() 427f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return 1 428f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if args.pickle_graph and os.path.isfile(args.pickle_graph): 429f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch load_graph() 430f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch else: 431f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if args.use_stdin: 432f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Reading files from stdin") 433f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for f in sys.stdin: 434f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch build_graph(f.strip()) 435f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch else: 436f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Reading files and directories from command line") 437f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if len(args.files) == 0: 438f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch print "Please provide files or directores for building the graph" 439f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch parser.print_help() 440f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return 1 441f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch for f in args.files: 442f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if os.path.isdir(f): 443f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Building graph from files in directory: " + f) 444f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch build_graphs_in_dir(f) 445f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch else: 446f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Building graph from file: " + f) 447f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch build_graph(f) 448f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Completing graph construction (%d graph nodes)" % len(graph)) 449f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch complete_graph() 450f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if args.pickle_graph: 451f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch save_graph() 452f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if args.detect_cycles: 453f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch read_ignored_cycles() 454f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Detecting cycles containg GC roots") 455f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch detect_cycles() 456f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if args.print_stats: 457f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch log("Printing statistics") 458f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch print_stats() 459f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch if reported_error(): 460f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return 1 461f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch return 0 462f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch 463f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochif __name__ == '__main__': 464f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch sys.exit(main()) 465