1f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#!/usr/bin/env python
2f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#
33ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch# Copyright 2012 the V8 project authors. All rights reserved.
4f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# Redistribution and use in source and binary forms, with or without
5f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# modification, are permitted provided that the following conditions are
6f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# met:
7f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#
8f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#     * Redistributions of source code must retain the above copyright
9f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#       notice, this list of conditions and the following disclaimer.
10f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#     * Redistributions in binary form must reproduce the above
11f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#       copyright notice, this list of conditions and the following
12f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#       disclaimer in the documentation and/or other materials provided
13f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#       with the distribution.
14f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#     * Neither the name of Google Inc. nor the names of its
15f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#       contributors may be used to endorse or promote products derived
16f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#       from this software without specific prior written permission.
17f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#
18f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
30f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport bisect
31f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport collections
32f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport ctypes
33e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochimport disasm
34f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport mmap
35f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport optparse
36f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport os
37f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport re
38f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport subprocess
39f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport sys
40f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport time
41f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
42f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
43f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochUSAGE="""usage: %prog [OPTION]...
44f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
45f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochAnalyses V8 and perf logs to produce profiles.
46f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
47f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPerf logs can be collected using a command like:
48f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  $ perf record -R -e cycles -c 10000 -f -i ./shell bench.js --ll-prof
49f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # -R: collect all data
50f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # -e cycles: use cpu-cycles event (run "perf list" for details)
51f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # -c 10000: write a sample after each 10000 events
52f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # -f: force output file overwrite
53f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # -i: limit profiling to our process and the kernel
54f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # --ll-prof shell flag enables the right V8 logs
55f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochThis will produce a binary trace file (perf.data) that %prog can analyse.
56f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
57f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochExamples:
58f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Print flat profile with annotated disassembly for the 10 top
59f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # symbols. Use default log names and include the snapshot log.
60f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  $ %prog --snapshot --disasm-top=10
61f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
62f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Print flat profile with annotated disassembly for all used symbols.
63f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Use default log names and include kernel symbols into analysis.
64f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  $ %prog --disasm-all --kernel
65f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
66f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Print flat profile. Use custom log names.
67f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  $ %prog --log=foo.log --snapshot-log=snap-foo.log --trace=foo.data --snapshot
68f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch"""
69f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
70f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
71f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# Must match kGcFakeMmap.
72f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochV8_GC_FAKE_MMAP = "/tmp/__v8_gc__"
73f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
74f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochJS_ORIGIN = "js"
75f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochJS_SNAPSHOT_ORIGIN = "js-snapshot"
76f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
77e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen MurdochOBJDUMP_BIN = disasm.OBJDUMP_BIN
78f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
79f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
80f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass Code(object):
81f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Code object."""
82f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
83f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  _id = 0
84f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
85f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, name, start_address, end_address, origin, origin_offset):
86f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.id = Code._id
87f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    Code._id += 1
88f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.name = name
89f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.other_names = None
90f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.start_address = start_address
91f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.end_address = end_address
92f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.origin = origin
93f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.origin_offset = origin_offset
94f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.self_ticks = 0
95f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.self_ticks_map = None
96f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.callee_ticks = None
97f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
98f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def AddName(self, name):
99f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert self.name != name
100f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.other_names is None:
101f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.other_names = [name]
102f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return
103f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not name in self.other_names:
104f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.other_names.append(name)
105f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
106f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def FullName(self):
107f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.other_names is None:
108f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return self.name
109f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.other_names.sort()
110f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return "%s (aka %s)" % (self.name, ", ".join(self.other_names))
111f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
112f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def IsUsed(self):
113f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return self.self_ticks > 0 or self.callee_ticks is not None
114f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
115f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Tick(self, pc):
116f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.self_ticks += 1
117f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.self_ticks_map is None:
118f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.self_ticks_map = collections.defaultdict(lambda: 0)
119f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    offset = pc - self.start_address
120f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.self_ticks_map[offset] += 1
121f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
122f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def CalleeTick(self, callee):
123f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.callee_ticks is None:
124f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.callee_ticks = collections.defaultdict(lambda: 0)
125f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.callee_ticks[callee] += 1
126f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
127257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def PrintAnnotated(self, arch, options):
128f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.self_ticks_map is None:
129f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      ticks_map = []
130f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    else:
131f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      ticks_map = self.self_ticks_map.items()
132f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Convert the ticks map to offsets and counts arrays so that later
133f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # we can do binary search in the offsets array.
134f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    ticks_map.sort(key=lambda t: t[0])
135f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    ticks_offsets = [t[0] for t in ticks_map]
136f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    ticks_counts = [t[1] for t in ticks_map]
137f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Get a list of disassembled lines and their addresses.
138257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    lines = self._GetDisasmLines(arch, options)
139f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if len(lines) == 0:
140f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return
141f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Print annotated lines.
142f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    address = lines[0][0]
143f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    total_count = 0
144f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for i in xrange(len(lines)):
145f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      start_offset = lines[i][0] - address
146f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if i == len(lines) - 1:
147f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        end_offset = self.end_address - self.start_address
148f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
149f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        end_offset = lines[i + 1][0] - address
150f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      # Ticks (reported pc values) are not always precise, i.e. not
151f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      # necessarily point at instruction starts. So we have to search
152f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      # for ticks that touch the current instruction line.
153f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      j = bisect.bisect_left(ticks_offsets, end_offset)
154f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      count = 0
155f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      for offset, cnt in reversed(zip(ticks_offsets[:j], ticks_counts[:j])):
156f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if offset < start_offset:
157f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          break
158f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        count += cnt
159f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      total_count += count
160f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      count = 100.0 * count / self.self_ticks
161f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if count >= 0.01:
162e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        print "%15.2f %x: %s" % (count, lines[i][0], lines[i][1])
163f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
164e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        print "%s %x: %s" % (" " * 15, lines[i][0], lines[i][1])
165f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print
166f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert total_count == self.self_ticks, \
167f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "Lost ticks (%d != %d) in %s" % (total_count, self.self_ticks, self)
168f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
169f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __str__(self):
170f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return "%s [0x%x, 0x%x) size: %d origin: %s" % (
171f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.name,
172f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.start_address,
173f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.end_address,
174f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.end_address - self.start_address,
175f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.origin)
176f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
177257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def _GetDisasmLines(self, arch, options):
178f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.origin == JS_ORIGIN or self.origin == JS_SNAPSHOT_ORIGIN:
179e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      inplace = False
180257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      filename = options.log + ".ll"
181f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    else:
182e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      inplace = True
183e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      filename = self.origin
184e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    return disasm.GetDisasmLines(filename,
185e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                 self.origin_offset,
186e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                 self.end_address - self.start_address,
187257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                 arch,
188e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                 inplace)
189f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
190f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
191f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodePage(object):
192f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Group of adjacent code objects."""
193f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
194f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  SHIFT = 12  # 4K pages
195f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  SIZE = (1 << SHIFT)
196f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  MASK = ~(SIZE - 1)
197f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
198f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
199f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def PageAddress(address):
200f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return address & CodePage.MASK
201f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
202f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
203f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def PageId(address):
204f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return address >> CodePage.SHIFT
205f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
206f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
207f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def PageAddressFromId(id):
208f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return id << CodePage.SHIFT
209f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
210f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, address):
211f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.address = address
212f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_objects = []
213f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
214f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Add(self, code):
215f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_objects.append(code)
216f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
217f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Remove(self, code):
218f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_objects.remove(code)
219f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
220f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Find(self, pc):
221f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    code_objects = self.code_objects
222f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for i, code in enumerate(code_objects):
223f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if code.start_address <= pc < code.end_address:
224f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code_objects[0], code_objects[i] = code, code_objects[0]
225f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        return code
226f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return None
227f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
228f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __iter__(self):
229f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return self.code_objects.__iter__()
230f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
231f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
232f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodeMap(object):
233f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Code object map."""
234f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
235f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self):
236f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.pages = {}
237f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.min_address = 1 << 64
238f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.max_address = -1
239f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
240f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Add(self, code, max_pages=-1):
241f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    page_id = CodePage.PageId(code.start_address)
242f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1)
243f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    pages = 0
244f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    while page_id < limit_id:
245f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if max_pages >= 0 and pages > max_pages:
246f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        print >>sys.stderr, \
247f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            "Warning: page limit (%d) reached for %s [%s]" % (
248f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            max_pages, code.name, code.origin)
249f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        break
250f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if page_id in self.pages:
251f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        page = self.pages[page_id]
252f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
253f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        page = CodePage(CodePage.PageAddressFromId(page_id))
254f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.pages[page_id] = page
255f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page.Add(code)
256f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page_id += 1
257f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      pages += 1
258f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.min_address = min(self.min_address, code.start_address)
259f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.max_address = max(self.max_address, code.end_address)
260f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
261f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Remove(self, code):
262f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    page_id = CodePage.PageId(code.start_address)
263f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1)
264f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    removed = False
265f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    while page_id < limit_id:
266f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if page_id not in self.pages:
267f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        page_id += 1
268f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        continue
269f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page = self.pages[page_id]
270f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page.Remove(code)
271f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      removed = True
272f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page_id += 1
273f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return removed
274f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
275f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def AllCode(self):
276f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for page in self.pages.itervalues():
277f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      for code in page:
278f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if CodePage.PageAddress(code.start_address) == page.address:
279f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          yield code
280f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
281f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def UsedCode(self):
282f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for code in self.AllCode():
283f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if code.IsUsed():
284f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        yield code
285f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
286f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Print(self):
287f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for code in self.AllCode():
288f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print code
289f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
290f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Find(self, pc):
291f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if pc < self.min_address or pc >= self.max_address:
292f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return None
293f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    page_id = CodePage.PageId(pc)
294f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if page_id not in self.pages:
295f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return None
296f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return self.pages[page_id].Find(pc)
297f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
298f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
299f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodeInfo(object):
300f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Generic info about generated code objects."""
301f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
302f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, arch, header_size):
303f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.arch = arch
304f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.header_size = header_size
305f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
306f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
307257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochclass SnapshotLogReader(object):
308257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  """V8 snapshot log reader."""
309f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
310257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _SNAPSHOT_CODE_NAME_RE = re.compile(
311257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    r"snapshot-code-name,(\d+),\"(.*)\"")
312f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
313257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def __init__(self, log_name):
314257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_name = log_name
315257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
316257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def ReadNameMap(self):
317257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    log = open(self.log_name, "r")
318257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    try:
319257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      snapshot_pos_to_name = {}
320257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      for line in log:
321257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        match = SnapshotLogReader._SNAPSHOT_CODE_NAME_RE.match(line)
322257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if match:
323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          pos = int(match.group(1))
324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          name = match.group(2)
325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          snapshot_pos_to_name[pos] = name
326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    finally:
327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      log.close()
328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    return snapshot_pos_to_name
329f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
330f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochclass LogReader(object):
332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  """V8 low-level (binary) log reader."""
333f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _ARCH_TO_POINTER_TYPE_MAP = {
335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    "ia32": ctypes.c_uint32,
336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    "arm": ctypes.c_uint32,
3373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    "mips": ctypes.c_uint32,
338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    "x64": ctypes.c_uint64
339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
340f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _CODE_CREATE_TAG = "C"
342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _CODE_MOVE_TAG = "M"
343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _CODE_DELETE_TAG = "D"
344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _SNAPSHOT_POSITION_TAG = "P"
345257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _CODE_MOVING_GC_TAG = "G"
346f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def __init__(self, log_name, code_map, snapshot_pos_to_name):
348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_file = open(log_name, "r")
349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log = mmap.mmap(self.log_file.fileno(), 0, mmap.MAP_PRIVATE)
350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_pos = 0
351f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_map = code_map
352f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.snapshot_pos_to_name = snapshot_pos_to_name
353f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.address_to_snapshot_name = {}
354f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.arch = self.log[:self.log.find("\0")]
356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_pos += len(self.arch) + 1
357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    assert self.arch in LogReader._ARCH_TO_POINTER_TYPE_MAP, \
358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        "Unsupported architecture %s" % self.arch
359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    pointer_type = LogReader._ARCH_TO_POINTER_TYPE_MAP[self.arch]
360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.code_create_struct = LogReader._DefineStruct([
362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("name_size", ctypes.c_int32),
363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("code_address", pointer_type),
364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("code_size", ctypes.c_int32)])
365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.code_move_struct = LogReader._DefineStruct([
367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("from_address", pointer_type),
368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("to_address", pointer_type)])
369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.code_delete_struct = LogReader._DefineStruct([
371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("address", pointer_type)])
372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.snapshot_position_struct = LogReader._DefineStruct([
374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("address", pointer_type),
375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("position", ctypes.c_int32)])
376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def ReadUpToGC(self):
378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    while self.log_pos < self.log.size():
379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      tag = self.log[self.log_pos]
380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      self.log_pos += 1
381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._CODE_MOVING_GC_TAG:
383f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.address_to_snapshot_name.clear()
384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        return
385f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._CODE_CREATE_TAG:
387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        event = self.code_create_struct.from_buffer(self.log, self.log_pos)
388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += ctypes.sizeof(event)
389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        start_address = event.code_address
390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        end_address = start_address + event.code_size
391f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if start_address in self.address_to_snapshot_name:
392f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          name = self.address_to_snapshot_name[start_address]
393f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          origin = JS_SNAPSHOT_ORIGIN
394f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        else:
395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          name = self.log[self.log_pos:self.log_pos + event.name_size]
396f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          origin = JS_ORIGIN
397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += event.name_size
398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        origin_offset = self.log_pos
399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += event.code_size
400f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code = Code(name, start_address, end_address, origin, origin_offset)
401f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        conficting_code = self.code_map.Find(start_address)
402f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if conficting_code:
4033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          if not (conficting_code.start_address == code.start_address and
4043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            conficting_code.end_address == code.end_address):
4053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            self.code_map.Remove(conficting_code)
4063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          else:
4073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            LogReader._HandleCodeConflict(conficting_code, code)
4083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            # TODO(vitalyr): this warning is too noisy because of our
4093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            # attempts to reconstruct code log from the snapshot.
4103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            # print >>sys.stderr, \
4113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            #     "Warning: Skipping duplicate code log entry %s" % code
4123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            continue
413f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.code_map.Add(code)
414f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        continue
415f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._CODE_MOVE_TAG:
417257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        event = self.code_move_struct.from_buffer(self.log, self.log_pos)
418257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += ctypes.sizeof(event)
419257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        old_start_address = event.from_address
420257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        new_start_address = event.to_address
421f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if old_start_address == new_start_address:
422f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          # Skip useless code move entries.
423f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
424f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code = self.code_map.Find(old_start_address)
425f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if not code:
426f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          print >>sys.stderr, "Warning: Not found %x" % old_start_address
427f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
428f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        assert code.start_address == old_start_address, \
429f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            "Inexact move address %x for %s" % (old_start_address, code)
430f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.code_map.Remove(code)
431f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        size = code.end_address - code.start_address
432f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code.start_address = new_start_address
433f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code.end_address = new_start_address + size
434f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.code_map.Add(code)
435f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        continue
436f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._CODE_DELETE_TAG:
438257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        event = self.code_delete_struct.from_buffer(self.log, self.log_pos)
439257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += ctypes.sizeof(event)
440257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        old_start_address = event.address
441f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code = self.code_map.Find(old_start_address)
442f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if not code:
443f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          print >>sys.stderr, "Warning: Not found %x" % old_start_address
444f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
445f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        assert code.start_address == old_start_address, \
446f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            "Inexact delete address %x for %s" % (old_start_address, code)
447f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.code_map.Remove(code)
448f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        continue
449f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
450257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._SNAPSHOT_POSITION_TAG:
451257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        event = self.snapshot_position_struct.from_buffer(self.log,
452257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                          self.log_pos)
453257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += ctypes.sizeof(event)
454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        start_address = event.address
455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        snapshot_pos = event.position
456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if snapshot_pos in self.snapshot_pos_to_name:
457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          self.address_to_snapshot_name[start_address] = \
458257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              self.snapshot_pos_to_name[snapshot_pos]
459257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        continue
460257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
461257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      assert False, "Unknown tag %s" % tag
462f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
463f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Dispose(self):
464f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.log.close()
465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_file.close()
466257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  @staticmethod
468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def _DefineStruct(fields):
469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    class Struct(ctypes.Structure):
470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      _fields_ = fields
471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    return Struct
472f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
473f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
474f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _HandleCodeConflict(old_code, new_code):
475f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert (old_code.start_address == new_code.start_address and
476f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            old_code.end_address == new_code.end_address), \
477f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "Conficting code log entries %s and %s" % (old_code, new_code)
478f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if old_code.name == new_code.name:
479f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return
480f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Code object may be shared by a few functions. Collect the full
481f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # set of names.
482f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    old_code.AddName(new_code.name)
483f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
484f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
485f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass Descriptor(object):
486f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Descriptor of a structure in the binary trace log."""
487f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
488f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CTYPE_MAP = {
489f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    "u16": ctypes.c_uint16,
490f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    "u32": ctypes.c_uint32,
491f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    "u64": ctypes.c_uint64
492f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  }
493f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
494f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, fields):
495f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    class TraceItem(ctypes.Structure):
496f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      _fields_ = Descriptor.CtypesFields(fields)
497f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
498f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      def __str__(self):
499f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        return ", ".join("%s: %s" % (field, self.__getattribute__(field))
500f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                         for field, _ in TraceItem._fields_)
501f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
502f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.ctype = TraceItem
503f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
504f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Read(self, trace, offset):
505f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return self.ctype.from_buffer(trace, offset)
506f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
507f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
508f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def CtypesFields(fields):
509f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return [(field, Descriptor.CTYPE_MAP[format]) for (field, format) in fields]
510f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
511f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
512f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# Please see http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=tree;f=tools/perf
513f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# for the gory details.
514f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
515f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
516f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochTRACE_HEADER_DESC = Descriptor([
517f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("magic", "u64"),
518f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("size", "u64"),
519f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("attr_size", "u64"),
520f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("attrs_offset", "u64"),
521f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("attrs_size", "u64"),
522f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("data_offset", "u64"),
523f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("data_size", "u64"),
524f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("event_types_offset", "u64"),
525f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("event_types_size", "u64")
526f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
527f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
528f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
529f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_EVENT_ATTR_DESC = Descriptor([
530f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("type", "u32"),
531f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("size", "u32"),
532f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("config", "u64"),
533f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("sample_period_or_freq", "u64"),
534f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("sample_type", "u64"),
535f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("read_format", "u64"),
536f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("flags", "u64"),
537f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("wakeup_events_or_watermark", "u32"),
538f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("bt_type", "u32"),
539f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("bp_addr", "u64"),
540f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("bp_len", "u64"),
541f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
542f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
543f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
544f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_EVENT_HEADER_DESC = Descriptor([
545f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("type", "u32"),
546f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("misc", "u16"),
547f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("size", "u16")
548f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
549f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
550f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
551f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_MMAP_EVENT_BODY_DESC = Descriptor([
552f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("pid", "u32"),
553f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("tid", "u32"),
554f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("addr", "u64"),
555f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("len", "u64"),
556f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("pgoff", "u64")
557f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
558f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
559f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
560f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# perf_event_attr.sample_type bits control the set of
561f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# perf_sample_event fields.
562f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_IP = 1 << 0
563f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_TID = 1 << 1
564f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_TIME = 1 << 2
565f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_ADDR = 1 << 3
566f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_READ = 1 << 4
567f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_CALLCHAIN = 1 << 5
568f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_ID = 1 << 6
569f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_CPU = 1 << 7
570f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_PERIOD = 1 << 8
571f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_STREAM_ID = 1 << 9
572f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_RAW = 1 << 10
573f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
574f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
575f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_EVENT_BODY_FIELDS = [
576f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("ip", "u64", PERF_SAMPLE_IP),
577f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("pid", "u32", PERF_SAMPLE_TID),
578f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("tid", "u32", PERF_SAMPLE_TID),
579f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("time", "u64", PERF_SAMPLE_TIME),
580f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("addr", "u64", PERF_SAMPLE_ADDR),
581f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("id", "u64", PERF_SAMPLE_ID),
582f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("stream_id", "u64", PERF_SAMPLE_STREAM_ID),
583f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("cpu", "u32", PERF_SAMPLE_CPU),
584f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("res", "u32", PERF_SAMPLE_CPU),
585f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("period", "u64", PERF_SAMPLE_PERIOD),
586f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Don't want to handle read format that comes after the period and
587f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # before the callchain and has variable size.
588f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("nr", "u64", PERF_SAMPLE_CALLCHAIN)
589f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Raw data follows the callchain and is ignored.
590f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch]
591f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
592f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
593f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_EVENT_IP_FORMAT = "u64"
594f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
595f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
596f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_RECORD_MMAP = 1
597f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_RECORD_SAMPLE = 9
598f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
599f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
600f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass TraceReader(object):
601f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Perf (linux-2.6/tools/perf) trace file reader."""
602f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
603f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  _TRACE_HEADER_MAGIC = 4993446653023372624
604f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
605f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, trace_name):
606f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace_file = open(trace_name, "r")
607f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace = mmap.mmap(self.trace_file.fileno(), 0, mmap.MAP_PRIVATE)
608f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace_header = TRACE_HEADER_DESC.Read(self.trace, 0)
609f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.trace_header.magic != TraceReader._TRACE_HEADER_MAGIC:
610f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print >>sys.stderr, "Warning: unsupported trace header magic"
611f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.offset = self.trace_header.data_offset
612f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.limit = self.trace_header.data_offset + self.trace_header.data_size
613f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert self.limit <= self.trace.size(), \
614f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "Trace data limit exceeds trace file size"
615f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.header_size = ctypes.sizeof(PERF_EVENT_HEADER_DESC.ctype)
616f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert self.trace_header.attrs_size != 0, \
617f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "No perf event attributes found in the trace"
618f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    perf_event_attr = PERF_EVENT_ATTR_DESC.Read(self.trace,
619f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                                                self.trace_header.attrs_offset)
620f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.sample_event_body_desc = self._SampleEventBodyDesc(
621f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        perf_event_attr.sample_type)
622f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.callchain_supported = \
623f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        (perf_event_attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0
624f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.callchain_supported:
625f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.ip_struct = Descriptor.CTYPE_MAP[PERF_SAMPLE_EVENT_IP_FORMAT]
626f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.ip_size = ctypes.sizeof(self.ip_struct)
627f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
628f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def ReadEventHeader(self):
629f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.offset >= self.limit:
630f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return None, 0
631f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    offset = self.offset
632f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    header = PERF_EVENT_HEADER_DESC.Read(self.trace, self.offset)
633f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.offset += header.size
634f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return header, offset
635f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
636f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def ReadMmap(self, header, offset):
637f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    mmap_info = PERF_MMAP_EVENT_BODY_DESC.Read(self.trace,
638f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                                               offset + self.header_size)
6393fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    # Read null-terminated filename.
640f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info):
6413fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                          offset + header.size]
6423fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    mmap_info.filename = filename[:filename.find(chr(0))]
643f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return mmap_info
644f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
645f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def ReadSample(self, header, offset):
646f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    sample = self.sample_event_body_desc.Read(self.trace,
647f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                                              offset + self.header_size)
648f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not self.callchain_supported:
649f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return sample
650f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    sample.ips = []
651f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    offset += self.header_size + ctypes.sizeof(sample)
652f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for _ in xrange(sample.nr):
653f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      sample.ips.append(
654f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.ip_struct.from_buffer(self.trace, offset).value)
655f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      offset += self.ip_size
656f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return sample
657f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
658f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Dispose(self):
659f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace.close()
660f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace_file.close()
661f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
662f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _SampleEventBodyDesc(self, sample_type):
663f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert (sample_type & PERF_SAMPLE_READ) == 0, \
664f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch           "Can't hande read format in samples"
665f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    fields = [(field, format)
666f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              for (field, format, bit) in PERF_SAMPLE_EVENT_BODY_FIELDS
667f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              if (bit & sample_type) != 0]
668f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return Descriptor(fields)
669f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
670f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
671f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_SECTION_HEADER_RE = re.compile(
672f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r"^\s*\d+\s(\.\S+)\s+[a-f0-9]")
673f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_SYMBOL_LINE_RE = re.compile(
674f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r"^([a-f0-9]+)\s(.{7})\s(\S+)\s+([a-f0-9]+)\s+(?:\.hidden\s+)?(.*)$")
675f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_DYNAMIC_SYMBOLS_START_RE = re.compile(
6763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  r"^DYNAMIC SYMBOL TABLE")
6773ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochOBJDUMP_SKIP_RE = re.compile(
6783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  r"^.*ld\.so\.cache$")
679f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochKERNEL_ALLSYMS_FILE = "/proc/kallsyms"
680f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_KERNEL_ALLSYMS_RE = re.compile(
681f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r".*kallsyms.*")
682f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochKERNEL_ALLSYMS_LINE_RE = re.compile(
683f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r"^([a-f0-9]+)\s(?:t|T)\s(\S+)$")
684f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
685f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
686f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass LibraryRepo(object):
687f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self):
688f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.infos = []
689f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.names = set()
690f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.ticks = {}
691f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
692f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Load(self, mmap_info, code_map, options):
693f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Skip kernel mmaps when requested using the fact that their tid
694f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # is 0.
695f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if mmap_info.tid == 0 and not options.kernel:
696f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return True
6973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if OBJDUMP_SKIP_RE.match(mmap_info.filename):
6983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      return True
699f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if PERF_KERNEL_ALLSYMS_RE.match(mmap_info.filename):
700f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return self._LoadKernelSymbols(code_map)
701f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.infos.append(mmap_info)
702f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    mmap_info.ticks = 0
703f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    mmap_info.unique_name = self._UniqueMmapName(mmap_info)
704f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not os.path.exists(mmap_info.filename):
705f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return True
706f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Request section headers (-h), symbols (-t), and dynamic symbols
707f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # (-T) from objdump.
708f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Unfortunately, section headers span two lines, so we have to
709f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # keep the just seen section name (from the first line in each
710f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # section header) in the after_section variable.
711f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    process = subprocess.Popen(
712f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      "%s -h -t -T -C %s" % (OBJDUMP_BIN, mmap_info.filename),
713f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
714f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    pipe = process.stdout
715f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    after_section = None
716f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    code_sections = set()
717f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    reloc_sections = set()
718f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    dynamic = False
719f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    try:
720f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      for line in pipe:
721f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if after_section:
722f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if line.find("CODE") != -1:
723f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            code_sections.add(after_section)
724f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if line.find("RELOC") != -1:
725f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            reloc_sections.add(after_section)
726f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          after_section = None
727f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
728f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
729f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        match = OBJDUMP_SECTION_HEADER_RE.match(line)
730f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if match:
731f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          after_section = match.group(1)
732f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
733f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
734f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if OBJDUMP_DYNAMIC_SYMBOLS_START_RE.match(line):
735f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          dynamic = True
736f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
737f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
738f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        match = OBJDUMP_SYMBOL_LINE_RE.match(line)
739f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if match:
740f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          start_address = int(match.group(1), 16)
741f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          origin_offset = start_address
742f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          flags = match.group(2)
743f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          section = match.group(3)
744f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if section in code_sections:
745f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            if dynamic or section in reloc_sections:
746f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              start_address += mmap_info.addr
747f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            size = int(match.group(4), 16)
748f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            name = match.group(5)
749f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            origin = mmap_info.filename
750f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            code_map.Add(Code(name, start_address, start_address + size,
751f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                              origin, origin_offset))
752f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    finally:
753f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      pipe.close()
754f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert process.wait() == 0, "Failed to objdump %s" % mmap_info.filename
755f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
756f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Tick(self, pc):
757f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for i, mmap_info in enumerate(self.infos):
758f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if mmap_info.addr <= pc < (mmap_info.addr + mmap_info.len):
759f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        mmap_info.ticks += 1
760f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.infos[0], self.infos[i] = mmap_info, self.infos[0]
761f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        return True
762f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return False
763f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
764f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _UniqueMmapName(self, mmap_info):
765f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    name = mmap_info.filename
766f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    index = 1
767f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    while name in self.names:
768f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      name = "%s-%d" % (mmap_info.filename, index)
769f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      index += 1
770f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.names.add(name)
771f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return name
772f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
773f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _LoadKernelSymbols(self, code_map):
774f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not os.path.exists(KERNEL_ALLSYMS_FILE):
775f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print >>sys.stderr, "Warning: %s not found" % KERNEL_ALLSYMS_FILE
776f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return False
777f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    kallsyms = open(KERNEL_ALLSYMS_FILE, "r")
778f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    code = None
779f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for line in kallsyms:
780f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      match = KERNEL_ALLSYMS_LINE_RE.match(line)
781f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if match:
782f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        start_address = int(match.group(1), 16)
783f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        end_address = start_address
784f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        name = match.group(2)
785f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if code:
786f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          code.end_address = start_address
787f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          code_map.Add(code, 16)
788f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code = Code(name, start_address, end_address, "kernel", 0)
789f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return True
790f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
791f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
792257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochdef PrintReport(code_map, library_repo, arch, ticks, options):
793f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "Ticks per symbol:"
794f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  used_code = [code for code in code_map.UsedCode()]
795f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  used_code.sort(key=lambda x: x.self_ticks, reverse=True)
796f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  for i, code in enumerate(used_code):
797257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    code_ticks = code.self_ticks
798257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    print "%10d %5.1f%% %s [%s]" % (code_ticks, 100. * code_ticks / ticks,
799257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    code.FullName(), code.origin)
800f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if options.disasm_all or i < options.disasm_top:
801257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      code.PrintAnnotated(arch, options)
802f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print
803f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "Ticks per library:"
804f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  mmap_infos = [m for m in library_repo.infos]
805f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  mmap_infos.sort(key=lambda m: m.ticks, reverse=True)
806f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  for mmap_info in mmap_infos:
807257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    mmap_ticks = mmap_info.ticks
808257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    print "%10d %5.1f%% %s" % (mmap_ticks, 100. * mmap_ticks / ticks,
809257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                               mmap_info.unique_name)
810f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
811f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
812f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochdef PrintDot(code_map, options):
813f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "digraph G {"
814f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  for code in code_map.UsedCode():
815f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if code.self_ticks < 10:
816f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      continue
817f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print "n%d [shape=box,label=\"%s\"];" % (code.id, code.name)
818f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if code.callee_ticks:
819f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      for callee, ticks in code.callee_ticks.iteritems():
820f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        print "n%d -> n%d [label=\"%d\"];" % (code.id, callee.id, ticks)
821f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "}"
822f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
823f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
824f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochif __name__ == "__main__":
825f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser = optparse.OptionParser(USAGE)
826f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--snapshot-log",
827f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default="obj/release/snapshot.log",
828f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="V8 snapshot log file name [default: %default]")
829f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--log",
830f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default="v8.log",
831f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="V8 log file name [default: %default]")
832f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--snapshot",
833f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
834f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
835f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="process V8 snapshot log [default: %default]")
836f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--trace",
837f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default="perf.data",
838f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="perf trace file name [default: %default]")
839f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--kernel",
840f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
841f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
842f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="process kernel entries [default: %default]")
843f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--disasm-top",
844f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=0,
845f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    type="int",
846f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help=("number of top symbols to disassemble and annotate "
847f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                          "[default: %default]"))
848f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--disasm-all",
849f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
850f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
851f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help=("disassemble and annotate all used symbols "
852f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                          "[default: %default]"))
853f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--dot",
854f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
855f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
856f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="produce dot output (WIP) [default: %default]")
857f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--quiet", "-q",
858f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
859f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
860f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="no auxiliary messages [default: %default]")
861f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  options, args = parser.parse_args()
862f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
863f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  if not options.quiet:
864f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if options.snapshot:
865257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      print "V8 logs: %s, %s, %s.ll" % (options.snapshot_log,
866257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        options.log,
867257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        options.log)
868f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    else:
869257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      print "V8 log: %s, %s.ll (no snapshot)" % (options.log, options.log)
870f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print "Perf trace file: %s" % options.trace
871f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
872f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Stats.
873f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  events = 0
874f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ticks = 0
875f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  missed_ticks = 0
876f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  really_missed_ticks = 0
877f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  mmap_time = 0
878f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  sample_time = 0
879f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
880257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  # Process the snapshot log to fill the snapshot name map.
881f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  snapshot_name_map = {}
882257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if options.snapshot:
883257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    snapshot_log_reader = SnapshotLogReader(log_name=options.snapshot_log)
884257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    snapshot_name_map = snapshot_log_reader.ReadNameMap()
885257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
886257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  # Initialize the log reader.
887257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  code_map = CodeMap()
888257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  log_reader = LogReader(log_name=options.log + ".ll",
889257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         code_map=code_map,
890257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         snapshot_pos_to_name=snapshot_name_map)
891f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  if not options.quiet:
892257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    print "Generated code architecture: %s" % log_reader.arch
893f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print
894257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    sys.stdout.flush()
895f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
896f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Process the code and trace logs.
897f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  library_repo = LibraryRepo()
898257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  log_reader.ReadUpToGC()
899f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  trace_reader = TraceReader(options.trace)
900f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  while True:
901f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    header, offset = trace_reader.ReadEventHeader()
902f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not header:
903f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      break
904f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    events += 1
905f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if header.type == PERF_RECORD_MMAP:
906f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      start = time.time()
907f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      mmap_info = trace_reader.ReadMmap(header, offset)
908f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if mmap_info.filename == V8_GC_FAKE_MMAP:
909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        log_reader.ReadUpToGC()
910f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
911f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        library_repo.Load(mmap_info, code_map, options)
912f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      mmap_time += time.time() - start
913f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    elif header.type == PERF_RECORD_SAMPLE:
914f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      ticks += 1
915f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      start = time.time()
916f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      sample = trace_reader.ReadSample(header, offset)
917f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      code = code_map.Find(sample.ip)
918f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if code:
919f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code.Tick(sample.ip)
920f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
921f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        missed_ticks += 1
922f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if not library_repo.Tick(sample.ip) and not code:
923f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        really_missed_ticks += 1
924f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if trace_reader.callchain_supported:
925f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        for ip in sample.ips:
926f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          caller_code = code_map.Find(ip)
927f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if caller_code:
928f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            if code:
929f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              caller_code.CalleeTick(code)
930f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            code = caller_code
931f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      sample_time += time.time() - start
932f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
933f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  if options.dot:
934f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    PrintDot(code_map, options)
935f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  else:
936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    PrintReport(code_map, library_repo, log_reader.arch, ticks, options)
937f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
938f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not options.quiet:
939f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print
940f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "Stats:"
941f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d total trace events" % events
942f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d total ticks" % ticks
943f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d ticks not in symbols" % missed_ticks
944f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d unaccounted ticks" % really_missed_ticks
945f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d total symbols" % len([c for c in code_map.AllCode()])
946f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d used symbols" % len([c for c in code_map.UsedCode()])
947f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%9.2fs library processing time" % mmap_time
948f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%9.2fs tick processing time" % sample_time
949f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
950f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  log_reader.Dispose()
951f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  trace_reader.Dispose()
952