Browse Source

Make the callgraph module-aware

Nick Mathewson 8 years ago
parent
commit
2123f0a2f9
2 changed files with 47 additions and 5 deletions
  1. 45 5
      scripts/maint/analyze_callgraph.py
  2. 2 0
      scripts/maint/display_callgraph.py

+ 45 - 5
scripts/maint/analyze_callgraph.py

@@ -9,19 +9,28 @@ import os
 class Parser:
   def __init__(self):
     self.calls = {}
+    self.definedIn = {}
 
   def enter_func(self, name):
-    if self.infunc and not self.extern:
+    if self.infunc and not self.extern and self.calledfns:
+      if self.infunc in self.definedIn:
+        #print "{}: {} or {}?".format(
+        #  self.infunc, self.definedIn[self.infunc], self.module)
+        self.definedIn[self.infunc] = 'nil'
+      else:
+        self.definedIn[self.infunc] = self.module
       self.calls.setdefault(self.infunc, set()).update( self.calledfns )
 
     self.calledfns = set()
     self.infunc = name
     self.extern = False
 
-  def parse_callgraph_file(self, inp):
+  def parse_callgraph_file(self, inp, module):
     self.infunc = None
     self.extern = False
     self.calledfns = set()
+    self.module = module
+
     for line in inp:
        m = re.match(r"Call graph node for function: '([^']+)'", line)
        if m:
@@ -189,13 +198,27 @@ def connection_bottlenecks(callgraph):
 if __name__ == '__main__':
     p = Parser()
     for fname in sys.argv[1:]:
+      modname = re.sub(r'.*/', '', fname).replace('.callgraph', '.c')
       with open(fname, 'r') as f:
-        p.parse_callgraph_file(f)
+        p.parse_callgraph_file(f, modname)
 
-    sys.stdout.flush
+    sys.stdout.flush()
 
     print "Building callgraph"
     callgraph = p.extract_callgraph()
+    inModule = p.definedIn
+
+    print "Deriving module callgraph"
+    modCallgraph = {}
+    for fn in callgraph:
+      fnMod = inModule[fn]
+      for called in callgraph[fn]:
+        try:
+          calledMod = inModule[called]
+        except KeyError:
+            continue
+        modCallgraph.setdefault(fnMod, set()).add(calledMod)
+    del modCallgraph['nil']
 
     print "Finding strongly connected components"
     sccs = strongly_connected_components(callgraph)
@@ -206,11 +229,28 @@ if __name__ == '__main__':
     print "Finding bottlenecks..."
     bottlenecks = connection_bottlenecks(callgraph)
 
+    print "Finding module SCCs"
+    modSCCS = strongly_connected_components(modCallgraph)
+
+    print "Finding module TC"
+    modTC = transitive_closure(modCallgraph)
+
+    print "Finding module bottlenecks"
+    modB = connection_bottlenecks(modCallgraph)
+
     data = {
       'callgraph' : callgraph,
       'sccs' : sccs,
       'closure' : closure,
-      'bottlenecks' : bottlenecks }
+      'bottlenecks' : bottlenecks,
+      'modules' : p.definedIn,
+      'modItems' : {
+        'callgraph' : modCallgraph,
+        'sccs' : modSCCS,
+        'closure' : modTC,
+        'bottlenecks' : modB,
+      }
+    }
 
     with open('callgraph.pkl', 'w') as f:
       cPickle.dump(data, f)

+ 2 - 0
scripts/maint/display_callgraph.py

@@ -4,6 +4,8 @@ import cPickle
 
 data = cPickle.load(open("callgraph.pkl"))
 
+# data = data['modItems']
+
 callgraph = data['callgraph']
 closure = data['closure']
 sccs = data['sccs']