Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/env python
      2 # Copyright 2014 the V8 project authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 import sys
      7 
      8 
      9 action = sys.argv[1]
     10 
     11 if action in ["help", "-h", "--help"] or len(sys.argv) != 3:
     12   print("Usage: %s <action> <inputfile>, where action can be: \n"
     13         "help    Print this message\n"
     14         "plain   Print ASCII tree to stdout\n"
     15         "dot     Print dot file to stdout\n"
     16         "count   Count most frequent transition reasons\n" % sys.argv[0])
     17   sys.exit(0)
     18 
     19 
     20 filename = sys.argv[2]
     21 maps = {}
     22 root_maps = []
     23 transitions = {}
     24 annotations = {}
     25 
     26 
     27 class Map(object):
     28 
     29   def __init__(self, pointer, origin):
     30     self.pointer = pointer
     31     self.origin = origin
     32 
     33   def __str__(self):
     34     return "%s (%s)" % (self.pointer, self.origin)
     35 
     36 
     37 class Transition(object):
     38 
     39   def __init__(self, from_map, to_map, reason):
     40     self.from_map = from_map
     41     self.to_map = to_map
     42     self.reason = reason
     43 
     44 
     45 def RegisterNewMap(raw_map):
     46   if raw_map in annotations:
     47     annotations[raw_map] += 1
     48   else:
     49     annotations[raw_map] = 0
     50   return AnnotateExistingMap(raw_map)
     51 
     52 
     53 def AnnotateExistingMap(raw_map):
     54   return "%s_%d" % (raw_map, annotations[raw_map])
     55 
     56 
     57 def AddMap(pointer, origin):
     58   pointer = RegisterNewMap(pointer)
     59   maps[pointer] = Map(pointer, origin)
     60   return pointer
     61 
     62 
     63 def AddTransition(from_map, to_map, reason):
     64   from_map = AnnotateExistingMap(from_map)
     65   to_map = AnnotateExistingMap(to_map)
     66   if from_map not in transitions:
     67     transitions[from_map] = {}
     68   targets = transitions[from_map]
     69   if to_map in targets:
     70     # Some events get printed twice, that's OK. In some cases, ignore the
     71     # second output...
     72     old_reason = targets[to_map].reason
     73     if old_reason.startswith("ReplaceDescriptors"):
     74       return
     75     # ...and in others use it for additional detail.
     76     if reason in []:
     77       targets[to_map].reason = reason
     78       return
     79     # Unexpected duplicate events? Warn.
     80     print("// warning: already have a transition from %s to %s, reason: %s" %
     81             (from_map, to_map, targets[to_map].reason))
     82     return
     83   targets[to_map] = Transition(from_map, to_map, reason)
     84 
     85 
     86 with open(filename, "r") as f:
     87   last_to_map = ""
     88   for line in f:
     89     if not line.startswith("[TraceMaps: "): continue
     90     words = line.split(" ")
     91     event = words[1]
     92     if event == "InitialMap":
     93       assert words[2] == "map="
     94       assert words[4] == "SFI="
     95       new_map = AddMap(words[3], "SFI#%s" % words[5])
     96       root_maps.append(new_map)
     97       continue
     98     if words[2] == "from=" and words[4] == "to=":
     99       from_map = words[3]
    100       to_map = words[5]
    101       if from_map not in annotations:
    102         print("// warning: unknown from_map %s" % from_map)
    103         new_map = AddMap(from_map, "<unknown>")
    104         root_maps.append(new_map)
    105       if to_map != last_to_map:
    106         AddMap(to_map, "<transition> (%s)" % event)
    107       last_to_map = to_map
    108       if event in ["Transition", "NoTransition"]:
    109         assert words[6] == "name=", line
    110         reason = "%s: %s" % (event, words[7])
    111       elif event in ["Normalize", "ReplaceDescriptors", "SlowToFast"]:
    112         assert words[6] == "reason=", line
    113         reason = "%s: %s" % (event, words[7])
    114         if words[8].strip() != "]":
    115           reason = "%s_%s" % (reason, words[8])
    116       else:
    117         reason = event
    118       AddTransition(from_map, to_map, reason)
    119       continue
    120 
    121 
    122 def PlainPrint(m, indent, label):
    123   print("%s%s (%s)" % (indent, m, label))
    124   if m in transitions:
    125     for t in transitions[m]:
    126       PlainPrint(t, indent + "  ", transitions[m][t].reason)
    127 
    128 
    129 def CountTransitions(m):
    130   if m not in transitions: return 0
    131   return len(transitions[m])
    132 
    133 
    134 def DotPrint(m, label):
    135   print("m%s [label=\"%s\"]" % (m[2:], label))
    136   if m in transitions:
    137     for t in transitions[m]:
    138       # GraphViz doesn't like node labels looking like numbers, so use
    139       # "m..." instead of "0x...".
    140       print("m%s -> m%s" % (m[2:], t[2:]))
    141       reason = transitions[m][t].reason
    142       reason = reason.replace("\\", "BACKSLASH")
    143       reason = reason.replace("\"", "\\\"")
    144       DotPrint(t, reason)
    145 
    146 
    147 if action == "plain":
    148   root_maps = sorted(root_maps, key=CountTransitions, reverse=True)
    149   for m in root_maps:
    150     PlainPrint(m, "", maps[m].origin)
    151 
    152 elif action == "dot":
    153   print("digraph g {")
    154   for m in root_maps:
    155     DotPrint(m, maps[m].origin)
    156   print("}")
    157 
    158 elif action == "count":
    159   reasons = {}
    160   for s in transitions:
    161     for t in transitions[s]:
    162       reason = transitions[s][t].reason
    163       if reason not in reasons:
    164         reasons[reason] = 1
    165       else:
    166         reasons[reason] += 1
    167   reasons_list = []
    168   for r in reasons:
    169     reasons_list.append("%8d %s" % (reasons[r], r))
    170   reasons_list.sort(reverse=True)
    171   for r in reasons_list[:20]:
    172     print r
    173