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