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 6import sys 7 8 9action = sys.argv[1] 10 11if 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 20filename = sys.argv[2] 21maps = {} 22root_maps = [] 23transitions = {} 24annotations = {} 25 26 27class 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 37class 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 45def 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 53def AnnotateExistingMap(raw_map): 54 return "%s_%d" % (raw_map, annotations[raw_map]) 55 56 57def AddMap(pointer, origin): 58 pointer = RegisterNewMap(pointer) 59 maps[pointer] = Map(pointer, origin) 60 return pointer 61 62 63def 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 86with 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 122def 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 129def CountTransitions(m): 130 if m not in transitions: return 0 131 return len(transitions[m]) 132 133 134def 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 147if 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 152elif action == "dot": 153 print("digraph g {") 154 for m in root_maps: 155 DotPrint(m, maps[m].origin) 156 print("}") 157 158elif 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