1958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier#!/usr/bin/env python
2958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier# Copyright 2014 the V8 project authors. All rights reserved.
3958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier# Use of this source code is governed by a BSD-style license that can be
4958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier# found in the LICENSE file.
5958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
6958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierimport sys
7958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
8958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
9958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernieraction = sys.argv[1]
10958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
11958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierif action in ["help", "-h", "--help"] or len(sys.argv) != 3:
12958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  print("Usage: %s <action> <inputfile>, where action can be: \n"
13958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        "help    Print this message\n"
14958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        "plain   Print ASCII tree to stdout\n"
15958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        "dot     Print dot file to stdout\n"
16958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        "count   Count most frequent transition reasons\n" % sys.argv[0])
17958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  sys.exit(0)
18958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
19958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
20958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierfilename = sys.argv[2]
21958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Berniermaps = {}
22958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierroot_maps = []
23958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Berniertransitions = {}
24958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierannotations = {}
25958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
26958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
27958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierclass Map(object):
28958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
29958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  def __init__(self, pointer, origin):
30958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    self.pointer = pointer
31958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    self.origin = origin
32958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
33958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  def __str__(self):
34958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    return "%s (%s)" % (self.pointer, self.origin)
35958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
36958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
37958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierclass Transition(object):
38958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
39958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  def __init__(self, from_map, to_map, reason):
40958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    self.from_map = from_map
41958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    self.to_map = to_map
42958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    self.reason = reason
43958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
44958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
45958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierdef RegisterNewMap(raw_map):
46958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  if raw_map in annotations:
47958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    annotations[raw_map] += 1
48958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  else:
49958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    annotations[raw_map] = 0
50958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  return AnnotateExistingMap(raw_map)
51958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
52958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
53958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierdef AnnotateExistingMap(raw_map):
54958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  return "%s_%d" % (raw_map, annotations[raw_map])
55958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
56958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
57958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierdef AddMap(pointer, origin):
58958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  pointer = RegisterNewMap(pointer)
59958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  maps[pointer] = Map(pointer, origin)
60958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  return pointer
61958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
62958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
63958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierdef AddTransition(from_map, to_map, reason):
64958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  from_map = AnnotateExistingMap(from_map)
65958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  to_map = AnnotateExistingMap(to_map)
66958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  if from_map not in transitions:
67958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    transitions[from_map] = {}
68958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  targets = transitions[from_map]
69958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  if to_map in targets:
70958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    # Some events get printed twice, that's OK. In some cases, ignore the
71958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    # second output...
72958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    old_reason = targets[to_map].reason
73958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    if old_reason.startswith("ReplaceDescriptors"):
74958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      return
75958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    # ...and in others use it for additional detail.
76958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    if reason in []:
77958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      targets[to_map].reason = reason
78958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      return
79958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    # Unexpected duplicate events? Warn.
80958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    print("// warning: already have a transition from %s to %s, reason: %s" %
81958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier            (from_map, to_map, targets[to_map].reason))
82958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    return
83958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  targets[to_map] = Transition(from_map, to_map, reason)
84958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
85958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
86958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierwith open(filename, "r") as f:
87958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  last_to_map = ""
88958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  for line in f:
89958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    if not line.startswith("[TraceMaps: "): continue
90958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    words = line.split(" ")
91958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    event = words[1]
92958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    if event == "InitialMap":
93958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      assert words[2] == "map="
94958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      assert words[4] == "SFI="
95958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      new_map = AddMap(words[3], "SFI#%s" % words[5])
96958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      root_maps.append(new_map)
97958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      continue
98958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    if words[2] == "from=" and words[4] == "to=":
99958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      from_map = words[3]
100958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      to_map = words[5]
101958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      if from_map not in annotations:
102958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        print("// warning: unknown from_map %s" % from_map)
103958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        new_map = AddMap(from_map, "<unknown>")
104958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        root_maps.append(new_map)
105958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      if to_map != last_to_map:
106958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        AddMap(to_map, "<transition> (%s)" % event)
107958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      last_to_map = to_map
108958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      if event in ["Transition", "NoTransition"]:
109958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        assert words[6] == "name=", line
110958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        reason = "%s: %s" % (event, words[7])
111958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      elif event in ["Normalize", "ReplaceDescriptors", "SlowToFast"]:
112958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        assert words[6] == "reason=", line
113958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        reason = "%s: %s" % (event, words[7])
114958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        if words[8].strip() != "]":
115958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier          reason = "%s_%s" % (reason, words[8])
116958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      else:
117958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        reason = event
118958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      AddTransition(from_map, to_map, reason)
119958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      continue
120958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
121958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
122958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierdef PlainPrint(m, indent, label):
123958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  print("%s%s (%s)" % (indent, m, label))
124958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  if m in transitions:
125958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    for t in transitions[m]:
126958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      PlainPrint(t, indent + "  ", transitions[m][t].reason)
127958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
128958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
129958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierdef CountTransitions(m):
130958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  if m not in transitions: return 0
131958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  return len(transitions[m])
132958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
133958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
134958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierdef DotPrint(m, label):
135958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  print("m%s [label=\"%s\"]" % (m[2:], label))
136958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  if m in transitions:
137958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    for t in transitions[m]:
138958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      # GraphViz doesn't like node labels looking like numbers, so use
139958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      # "m..." instead of "0x...".
140958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      print("m%s -> m%s" % (m[2:], t[2:]))
141958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      reason = transitions[m][t].reason
142958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      reason = reason.replace("\\", "BACKSLASH")
143958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      reason = reason.replace("\"", "\\\"")
144958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      DotPrint(t, reason)
145958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
146958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
147958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierif action == "plain":
148958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  root_maps = sorted(root_maps, key=CountTransitions, reverse=True)
149958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  for m in root_maps:
150958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    PlainPrint(m, "", maps[m].origin)
151958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
152958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierelif action == "dot":
153958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  print("digraph g {")
154958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  for m in root_maps:
155958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    DotPrint(m, maps[m].origin)
156958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  print("}")
157958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier
158958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernierelif action == "count":
159958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  reasons = {}
160958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  for s in transitions:
161958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    for t in transitions[s]:
162958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      reason = transitions[s][t].reason
163958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      if reason not in reasons:
164958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        reasons[reason] = 1
165958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier      else:
166958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier        reasons[reason] += 1
167958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  reasons_list = []
168958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  for r in reasons:
169958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    reasons_list.append("%8d %s" % (reasons[r], r))
170958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  reasons_list.sort(reverse=True)
171958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier  for r in reasons_list[:20]:
172958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier    print r
173