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:
48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  $ perf record -R -e cycles -c 10000 -f -i ./d8 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
57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochIMPORTANT:
58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  The kernel has an internal maximum for events per second, it is 100K by
59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  default. That's not enough for "-c 10000". Set it to some higher value:
60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  $ echo 10000000 | sudo tee /proc/sys/kernel/perf_event_max_sample_rate
61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  You can also make the warning about kernel address maps go away:
62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  $ echo 0 | sudo tee /proc/sys/kernel/kptr_restrict
63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochWe have a convenience script that handles all of the above for you:
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  $ tools/run-llprof.sh ./d8 bench.js
66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
67f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochExamples:
68f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Print flat profile with annotated disassembly for the 10 top
69f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # symbols. Use default log names and include the snapshot log.
70f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  $ %prog --snapshot --disasm-top=10
71f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
72f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Print flat profile with annotated disassembly for all used symbols.
73f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Use default log names and include kernel symbols into analysis.
74f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  $ %prog --disasm-all --kernel
75f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
76f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Print flat profile. Use custom log names.
77f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  $ %prog --log=foo.log --snapshot-log=snap-foo.log --trace=foo.data --snapshot
78f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch"""
79f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
80f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
81f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochJS_ORIGIN = "js"
82f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochJS_SNAPSHOT_ORIGIN = "js-snapshot"
83f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
84f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass Code(object):
85f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Code object."""
86f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
87f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  _id = 0
88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  UNKNOWN = 0
89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  V8INTERNAL = 1
90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  FULL_CODEGEN = 2
91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  OPTIMIZED = 3
92f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
93f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, name, start_address, end_address, origin, origin_offset):
94f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.id = Code._id
95f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    Code._id += 1
96f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.name = name
97f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.other_names = None
98f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.start_address = start_address
99f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.end_address = end_address
100f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.origin = origin
101f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.origin_offset = origin_offset
102f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.self_ticks = 0
103f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.self_ticks_map = None
104f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.callee_ticks = None
105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if name.startswith("LazyCompile:*"):
106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      self.codetype = Code.OPTIMIZED
107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    elif name.startswith("LazyCompile:"):
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      self.codetype = Code.FULL_CODEGEN
109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    elif name.startswith("v8::internal::"):
110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      self.codetype = Code.V8INTERNAL
111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    else:
112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      self.codetype = Code.UNKNOWN
113f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
114f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def AddName(self, name):
115f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert self.name != name
116f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.other_names is None:
117f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.other_names = [name]
118f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return
119f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not name in self.other_names:
120f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.other_names.append(name)
121f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
122f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def FullName(self):
123f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.other_names is None:
124f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return self.name
125f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.other_names.sort()
126f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return "%s (aka %s)" % (self.name, ", ".join(self.other_names))
127f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
128f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def IsUsed(self):
129f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return self.self_ticks > 0 or self.callee_ticks is not None
130f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
131f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Tick(self, pc):
132f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.self_ticks += 1
133f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.self_ticks_map is None:
134f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.self_ticks_map = collections.defaultdict(lambda: 0)
135f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    offset = pc - self.start_address
136f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.self_ticks_map[offset] += 1
137f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
138f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def CalleeTick(self, callee):
139f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.callee_ticks is None:
140f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.callee_ticks = collections.defaultdict(lambda: 0)
141f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.callee_ticks[callee] += 1
142f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def PrintAnnotated(self, arch, options):
144f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.self_ticks_map is None:
145f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      ticks_map = []
146f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    else:
147f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      ticks_map = self.self_ticks_map.items()
148f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Convert the ticks map to offsets and counts arrays so that later
149f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # we can do binary search in the offsets array.
150f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    ticks_map.sort(key=lambda t: t[0])
151f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    ticks_offsets = [t[0] for t in ticks_map]
152f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    ticks_counts = [t[1] for t in ticks_map]
153f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Get a list of disassembled lines and their addresses.
154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    lines = self._GetDisasmLines(arch, options)
155f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if len(lines) == 0:
156f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return
157f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Print annotated lines.
158f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    address = lines[0][0]
159f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    total_count = 0
160f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for i in xrange(len(lines)):
161f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      start_offset = lines[i][0] - address
162f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if i == len(lines) - 1:
163f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        end_offset = self.end_address - self.start_address
164f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
165f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        end_offset = lines[i + 1][0] - address
166f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      # Ticks (reported pc values) are not always precise, i.e. not
167f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      # necessarily point at instruction starts. So we have to search
168f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      # for ticks that touch the current instruction line.
169f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      j = bisect.bisect_left(ticks_offsets, end_offset)
170f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      count = 0
171f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      for offset, cnt in reversed(zip(ticks_offsets[:j], ticks_counts[:j])):
172f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if offset < start_offset:
173f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          break
174f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        count += cnt
175f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      total_count += count
176f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      count = 100.0 * count / self.self_ticks
177f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if count >= 0.01:
178e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        print "%15.2f %x: %s" % (count, lines[i][0], lines[i][1])
179f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
180e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        print "%s %x: %s" % (" " * 15, lines[i][0], lines[i][1])
181f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print
182f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert total_count == self.self_ticks, \
183f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "Lost ticks (%d != %d) in %s" % (total_count, self.self_ticks, self)
184f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
185f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __str__(self):
186f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return "%s [0x%x, 0x%x) size: %d origin: %s" % (
187f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.name,
188f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.start_address,
189f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.end_address,
190f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.end_address - self.start_address,
191f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.origin)
192f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def _GetDisasmLines(self, arch, options):
194f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.origin == JS_ORIGIN or self.origin == JS_SNAPSHOT_ORIGIN:
195e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      inplace = False
196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      filename = options.log + ".ll"
197f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    else:
198e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      inplace = True
199e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      filename = self.origin
200e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    return disasm.GetDisasmLines(filename,
201e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                 self.origin_offset,
202e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                 self.end_address - self.start_address,
203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                 arch,
204e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                 inplace)
205f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
206f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
207f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodePage(object):
208f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Group of adjacent code objects."""
209f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  SHIFT = 20  # 1M pages
211f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  SIZE = (1 << SHIFT)
212f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  MASK = ~(SIZE - 1)
213f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
214f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
215f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def PageAddress(address):
216f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return address & CodePage.MASK
217f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
218f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
219f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def PageId(address):
220f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return address >> CodePage.SHIFT
221f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
222f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
223f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def PageAddressFromId(id):
224f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return id << CodePage.SHIFT
225f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
226f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, address):
227f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.address = address
228f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_objects = []
229f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
230f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Add(self, code):
231f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_objects.append(code)
232f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
233f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Remove(self, code):
234f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_objects.remove(code)
235f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
236f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Find(self, pc):
237f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    code_objects = self.code_objects
238f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for i, code in enumerate(code_objects):
239f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if code.start_address <= pc < code.end_address:
240f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code_objects[0], code_objects[i] = code, code_objects[0]
241f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        return code
242f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return None
243f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
244f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __iter__(self):
245f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return self.code_objects.__iter__()
246f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
247f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
248f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodeMap(object):
249f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Code object map."""
250f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
251f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self):
252f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.pages = {}
253f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.min_address = 1 << 64
254f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.max_address = -1
255f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
256f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Add(self, code, max_pages=-1):
257f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    page_id = CodePage.PageId(code.start_address)
258f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1)
259f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    pages = 0
260f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    while page_id < limit_id:
261f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if max_pages >= 0 and pages > max_pages:
262f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        print >>sys.stderr, \
263f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            "Warning: page limit (%d) reached for %s [%s]" % (
264f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            max_pages, code.name, code.origin)
265f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        break
266f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if page_id in self.pages:
267f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        page = self.pages[page_id]
268f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
269f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        page = CodePage(CodePage.PageAddressFromId(page_id))
270f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.pages[page_id] = page
271f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page.Add(code)
272f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page_id += 1
273f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      pages += 1
274f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.min_address = min(self.min_address, code.start_address)
275f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.max_address = max(self.max_address, code.end_address)
276f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
277f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Remove(self, code):
278f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    page_id = CodePage.PageId(code.start_address)
279f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1)
280f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    removed = False
281f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    while page_id < limit_id:
282f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if page_id not in self.pages:
283f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        page_id += 1
284f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        continue
285f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page = self.pages[page_id]
286f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page.Remove(code)
287f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      removed = True
288f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page_id += 1
289f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return removed
290f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
291f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def AllCode(self):
292f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for page in self.pages.itervalues():
293f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      for code in page:
294f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if CodePage.PageAddress(code.start_address) == page.address:
295f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          yield code
296f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
297f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def UsedCode(self):
298f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for code in self.AllCode():
299f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if code.IsUsed():
300f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        yield code
301f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
302f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Print(self):
303f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for code in self.AllCode():
304f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print code
305f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
306f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Find(self, pc):
307f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if pc < self.min_address or pc >= self.max_address:
308f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return None
309f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    page_id = CodePage.PageId(pc)
310f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if page_id not in self.pages:
311f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return None
312f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return self.pages[page_id].Find(pc)
313f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
314f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
315f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodeInfo(object):
316f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Generic info about generated code objects."""
317f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
318f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, arch, header_size):
319f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.arch = arch
320f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.header_size = header_size
321f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
322f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochclass SnapshotLogReader(object):
324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  """V8 snapshot log reader."""
325f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _SNAPSHOT_CODE_NAME_RE = re.compile(
327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    r"snapshot-code-name,(\d+),\"(.*)\"")
328f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def __init__(self, log_name):
330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_name = log_name
331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def ReadNameMap(self):
333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    log = open(self.log_name, "r")
334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    try:
335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      snapshot_pos_to_name = {}
336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      for line in log:
337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        match = SnapshotLogReader._SNAPSHOT_CODE_NAME_RE.match(line)
338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if match:
339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          pos = int(match.group(1))
340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          name = match.group(2)
341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          snapshot_pos_to_name[pos] = name
342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    finally:
343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      log.close()
344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    return snapshot_pos_to_name
345f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
346f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochclass LogReader(object):
348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  """V8 low-level (binary) log reader."""
349f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _ARCH_TO_POINTER_TYPE_MAP = {
351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    "ia32": ctypes.c_uint32,
352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    "arm": ctypes.c_uint32,
3533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    "mips": ctypes.c_uint32,
354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    "x64": ctypes.c_uint64,
355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    "arm64": ctypes.c_uint64
356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
357f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _CODE_CREATE_TAG = "C"
359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _CODE_MOVE_TAG = "M"
360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _CODE_DELETE_TAG = "D"
361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _SNAPSHOT_POSITION_TAG = "P"
362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _CODE_MOVING_GC_TAG = "G"
363f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def __init__(self, log_name, code_map, snapshot_pos_to_name):
365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_file = open(log_name, "r")
366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log = mmap.mmap(self.log_file.fileno(), 0, mmap.MAP_PRIVATE)
367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_pos = 0
368f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_map = code_map
369f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.snapshot_pos_to_name = snapshot_pos_to_name
370f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.address_to_snapshot_name = {}
371f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.arch = self.log[:self.log.find("\0")]
373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_pos += len(self.arch) + 1
374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    assert self.arch in LogReader._ARCH_TO_POINTER_TYPE_MAP, \
375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        "Unsupported architecture %s" % self.arch
376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    pointer_type = LogReader._ARCH_TO_POINTER_TYPE_MAP[self.arch]
377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.code_create_struct = LogReader._DefineStruct([
379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("name_size", ctypes.c_int32),
380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("code_address", pointer_type),
381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("code_size", ctypes.c_int32)])
382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.code_move_struct = LogReader._DefineStruct([
384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("from_address", pointer_type),
385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("to_address", pointer_type)])
386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.code_delete_struct = LogReader._DefineStruct([
388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("address", pointer_type)])
389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.snapshot_position_struct = LogReader._DefineStruct([
391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("address", pointer_type),
392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("position", ctypes.c_int32)])
393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def ReadUpToGC(self):
395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    while self.log_pos < self.log.size():
396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      tag = self.log[self.log_pos]
397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      self.log_pos += 1
398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._CODE_MOVING_GC_TAG:
400f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.address_to_snapshot_name.clear()
401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        return
402f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._CODE_CREATE_TAG:
404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        event = self.code_create_struct.from_buffer(self.log, self.log_pos)
405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += ctypes.sizeof(event)
406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        start_address = event.code_address
407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        end_address = start_address + event.code_size
408f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if start_address in self.address_to_snapshot_name:
409f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          name = self.address_to_snapshot_name[start_address]
410f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          origin = JS_SNAPSHOT_ORIGIN
411f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        else:
412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          name = self.log[self.log_pos:self.log_pos + event.name_size]
413f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          origin = JS_ORIGIN
414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += event.name_size
415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        origin_offset = self.log_pos
416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += event.code_size
417f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code = Code(name, start_address, end_address, origin, origin_offset)
418f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        conficting_code = self.code_map.Find(start_address)
419f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if conficting_code:
4203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          if not (conficting_code.start_address == code.start_address and
4213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            conficting_code.end_address == code.end_address):
4223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            self.code_map.Remove(conficting_code)
4233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          else:
4243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            LogReader._HandleCodeConflict(conficting_code, code)
4253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            # TODO(vitalyr): this warning is too noisy because of our
4263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            # attempts to reconstruct code log from the snapshot.
4273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            # print >>sys.stderr, \
4283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            #     "Warning: Skipping duplicate code log entry %s" % code
4293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            continue
430f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.code_map.Add(code)
431f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        continue
432f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._CODE_MOVE_TAG:
434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        event = self.code_move_struct.from_buffer(self.log, self.log_pos)
435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += ctypes.sizeof(event)
436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        old_start_address = event.from_address
437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        new_start_address = event.to_address
438f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if old_start_address == new_start_address:
439f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          # Skip useless code move entries.
440f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
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 move address %x for %s" % (old_start_address, code)
447f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.code_map.Remove(code)
448f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        size = code.end_address - code.start_address
449f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code.start_address = new_start_address
450f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code.end_address = new_start_address + size
451f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.code_map.Add(code)
452f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        continue
453f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._CODE_DELETE_TAG:
455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        event = self.code_delete_struct.from_buffer(self.log, self.log_pos)
456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += ctypes.sizeof(event)
457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        old_start_address = event.address
458f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code = self.code_map.Find(old_start_address)
459f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if not code:
460f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          print >>sys.stderr, "Warning: Not found %x" % old_start_address
461f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
462f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        assert code.start_address == old_start_address, \
463f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            "Inexact delete address %x for %s" % (old_start_address, code)
464f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.code_map.Remove(code)
465f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        continue
466f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._SNAPSHOT_POSITION_TAG:
468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        event = self.snapshot_position_struct.from_buffer(self.log,
469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                                          self.log_pos)
470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += ctypes.sizeof(event)
471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        start_address = event.address
472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        snapshot_pos = event.position
473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        if snapshot_pos in self.snapshot_pos_to_name:
474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch          self.address_to_snapshot_name[start_address] = \
475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch              self.snapshot_pos_to_name[snapshot_pos]
476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        continue
477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      assert False, "Unknown tag %s" % tag
479f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
480f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Dispose(self):
481f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.log.close()
482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_file.close()
483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  @staticmethod
485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def _DefineStruct(fields):
486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    class Struct(ctypes.Structure):
487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      _fields_ = fields
488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    return Struct
489f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
490f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
491f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _HandleCodeConflict(old_code, new_code):
492f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert (old_code.start_address == new_code.start_address and
493f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            old_code.end_address == new_code.end_address), \
494f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "Conficting code log entries %s and %s" % (old_code, new_code)
495f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if old_code.name == new_code.name:
496f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return
497f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Code object may be shared by a few functions. Collect the full
498f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # set of names.
499f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    old_code.AddName(new_code.name)
500f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
501f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
502f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass Descriptor(object):
503f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Descriptor of a structure in the binary trace log."""
504f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
505f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CTYPE_MAP = {
506f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    "u16": ctypes.c_uint16,
507f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    "u32": ctypes.c_uint32,
508f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    "u64": ctypes.c_uint64
509f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  }
510f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
511f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, fields):
512f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    class TraceItem(ctypes.Structure):
513f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      _fields_ = Descriptor.CtypesFields(fields)
514f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
515f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      def __str__(self):
516f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        return ", ".join("%s: %s" % (field, self.__getattribute__(field))
517f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                         for field, _ in TraceItem._fields_)
518f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
519f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.ctype = TraceItem
520f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
521f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Read(self, trace, offset):
522f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return self.ctype.from_buffer(trace, offset)
523f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
524f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
525f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def CtypesFields(fields):
526f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return [(field, Descriptor.CTYPE_MAP[format]) for (field, format) in fields]
527f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
528f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
529f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# Please see http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=tree;f=tools/perf
530f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# for the gory details.
531f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
532f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
533b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: struct perf_file_header in kernel/tools/perf/util/header.h
534f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochTRACE_HEADER_DESC = Descriptor([
535f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("magic", "u64"),
536f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("size", "u64"),
537f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("attr_size", "u64"),
538f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("attrs_offset", "u64"),
539f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("attrs_size", "u64"),
540f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("data_offset", "u64"),
541f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("data_size", "u64"),
542f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("event_types_offset", "u64"),
543f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("event_types_size", "u64")
544f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
545f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
546f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
547b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/linux/perf_event.h
548f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_EVENT_ATTR_DESC = Descriptor([
549f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("type", "u32"),
550f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("size", "u32"),
551f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("config", "u64"),
552f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("sample_period_or_freq", "u64"),
553f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("sample_type", "u64"),
554f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("read_format", "u64"),
555f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("flags", "u64"),
556f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("wakeup_events_or_watermark", "u32"),
557b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ("bp_type", "u32"),
558f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("bp_addr", "u64"),
559b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ("bp_len", "u64")
560f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
561f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
562f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
563b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/linux/perf_event.h
564f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_EVENT_HEADER_DESC = Descriptor([
565f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("type", "u32"),
566f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("misc", "u16"),
567f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("size", "u16")
568f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
569f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
570f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
571b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: kernel/events/core.c
572f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_MMAP_EVENT_BODY_DESC = Descriptor([
573f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("pid", "u32"),
574f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("tid", "u32"),
575f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("addr", "u64"),
576f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("len", "u64"),
577f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("pgoff", "u64")
578f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
579f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
580f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
581f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# perf_event_attr.sample_type bits control the set of
582f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# perf_sample_event fields.
583f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_IP = 1 << 0
584f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_TID = 1 << 1
585f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_TIME = 1 << 2
586f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_ADDR = 1 << 3
587f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_READ = 1 << 4
588f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_CALLCHAIN = 1 << 5
589f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_ID = 1 << 6
590f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_CPU = 1 << 7
591f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_PERIOD = 1 << 8
592f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_STREAM_ID = 1 << 9
593f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_RAW = 1 << 10
594f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
595f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
596b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/perf_event.h, the comment for PERF_RECORD_SAMPLE.
597f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_EVENT_BODY_FIELDS = [
598f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("ip", "u64", PERF_SAMPLE_IP),
599f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("pid", "u32", PERF_SAMPLE_TID),
600f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("tid", "u32", PERF_SAMPLE_TID),
601f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("time", "u64", PERF_SAMPLE_TIME),
602f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("addr", "u64", PERF_SAMPLE_ADDR),
603f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("id", "u64", PERF_SAMPLE_ID),
604f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("stream_id", "u64", PERF_SAMPLE_STREAM_ID),
605f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("cpu", "u32", PERF_SAMPLE_CPU),
606f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("res", "u32", PERF_SAMPLE_CPU),
607f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("period", "u64", PERF_SAMPLE_PERIOD),
608f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Don't want to handle read format that comes after the period and
609f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # before the callchain and has variable size.
610f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("nr", "u64", PERF_SAMPLE_CALLCHAIN)
611f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Raw data follows the callchain and is ignored.
612f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch]
613f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
614f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
615f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_EVENT_IP_FORMAT = "u64"
616f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
617f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
618f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_RECORD_MMAP = 1
619f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_RECORD_SAMPLE = 9
620f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
621f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
622f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass TraceReader(object):
623f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Perf (linux-2.6/tools/perf) trace file reader."""
624f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
625f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  _TRACE_HEADER_MAGIC = 4993446653023372624
626f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
627f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, trace_name):
628f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace_file = open(trace_name, "r")
629f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace = mmap.mmap(self.trace_file.fileno(), 0, mmap.MAP_PRIVATE)
630f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace_header = TRACE_HEADER_DESC.Read(self.trace, 0)
631f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.trace_header.magic != TraceReader._TRACE_HEADER_MAGIC:
632f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print >>sys.stderr, "Warning: unsupported trace header magic"
633f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.offset = self.trace_header.data_offset
634f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.limit = self.trace_header.data_offset + self.trace_header.data_size
635f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert self.limit <= self.trace.size(), \
636f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "Trace data limit exceeds trace file size"
637f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.header_size = ctypes.sizeof(PERF_EVENT_HEADER_DESC.ctype)
638f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert self.trace_header.attrs_size != 0, \
639f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "No perf event attributes found in the trace"
640f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    perf_event_attr = PERF_EVENT_ATTR_DESC.Read(self.trace,
641f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                                                self.trace_header.attrs_offset)
642f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.sample_event_body_desc = self._SampleEventBodyDesc(
643f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        perf_event_attr.sample_type)
644f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.callchain_supported = \
645f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        (perf_event_attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0
646f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.callchain_supported:
647f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.ip_struct = Descriptor.CTYPE_MAP[PERF_SAMPLE_EVENT_IP_FORMAT]
648f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.ip_size = ctypes.sizeof(self.ip_struct)
649f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
650f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def ReadEventHeader(self):
651f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.offset >= self.limit:
652f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return None, 0
653f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    offset = self.offset
654f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    header = PERF_EVENT_HEADER_DESC.Read(self.trace, self.offset)
655f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.offset += header.size
656f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return header, offset
657f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
658f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def ReadMmap(self, header, offset):
659f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    mmap_info = PERF_MMAP_EVENT_BODY_DESC.Read(self.trace,
660f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                                               offset + self.header_size)
6613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    # Read null-terminated filename.
662f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info):
6633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                          offset + header.size]
664b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    mmap_info.filename = HOST_ROOT + filename[:filename.find(chr(0))]
665f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return mmap_info
666f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
667f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def ReadSample(self, header, offset):
668f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    sample = self.sample_event_body_desc.Read(self.trace,
669f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                                              offset + self.header_size)
670f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not self.callchain_supported:
671f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return sample
672f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    sample.ips = []
673f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    offset += self.header_size + ctypes.sizeof(sample)
674f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for _ in xrange(sample.nr):
675f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      sample.ips.append(
676f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.ip_struct.from_buffer(self.trace, offset).value)
677f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      offset += self.ip_size
678f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return sample
679f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
680f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Dispose(self):
681f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace.close()
682f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace_file.close()
683f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
684f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _SampleEventBodyDesc(self, sample_type):
685f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert (sample_type & PERF_SAMPLE_READ) == 0, \
686f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch           "Can't hande read format in samples"
687f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    fields = [(field, format)
688f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              for (field, format, bit) in PERF_SAMPLE_EVENT_BODY_FIELDS
689f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              if (bit & sample_type) != 0]
690f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return Descriptor(fields)
691f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
692f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
693f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_SECTION_HEADER_RE = re.compile(
694f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r"^\s*\d+\s(\.\S+)\s+[a-f0-9]")
695f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_SYMBOL_LINE_RE = re.compile(
696f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r"^([a-f0-9]+)\s(.{7})\s(\S+)\s+([a-f0-9]+)\s+(?:\.hidden\s+)?(.*)$")
697f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_DYNAMIC_SYMBOLS_START_RE = re.compile(
6983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  r"^DYNAMIC SYMBOL TABLE")
6993ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochOBJDUMP_SKIP_RE = re.compile(
7003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  r"^.*ld\.so\.cache$")
701f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochKERNEL_ALLSYMS_FILE = "/proc/kallsyms"
702f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_KERNEL_ALLSYMS_RE = re.compile(
703f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r".*kallsyms.*")
704f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochKERNEL_ALLSYMS_LINE_RE = re.compile(
705f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r"^([a-f0-9]+)\s(?:t|T)\s(\S+)$")
706f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
707f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
708f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass LibraryRepo(object):
709f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self):
710f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.infos = []
711f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.names = set()
712f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.ticks = {}
713f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
714f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Load(self, mmap_info, code_map, options):
715f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Skip kernel mmaps when requested using the fact that their tid
716f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # is 0.
717f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if mmap_info.tid == 0 and not options.kernel:
718f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return True
7193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if OBJDUMP_SKIP_RE.match(mmap_info.filename):
7203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      return True
721f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if PERF_KERNEL_ALLSYMS_RE.match(mmap_info.filename):
722f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return self._LoadKernelSymbols(code_map)
723f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.infos.append(mmap_info)
724f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    mmap_info.ticks = 0
725f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    mmap_info.unique_name = self._UniqueMmapName(mmap_info)
726f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not os.path.exists(mmap_info.filename):
727f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return True
728f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Request section headers (-h), symbols (-t), and dynamic symbols
729f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # (-T) from objdump.
730f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Unfortunately, section headers span two lines, so we have to
731f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # keep the just seen section name (from the first line in each
732f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # section header) in the after_section variable.
733b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if mmap_info.filename.endswith(".ko"):
734b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      dynamic_symbols = ""
735b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    else:
736b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      dynamic_symbols = "-T"
737f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    process = subprocess.Popen(
738b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "%s -h -t %s -C %s" % (OBJDUMP_BIN, dynamic_symbols, mmap_info.filename),
739f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
740f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    pipe = process.stdout
741f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    after_section = None
742f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    code_sections = set()
743f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    reloc_sections = set()
744f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    dynamic = False
745f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    try:
746f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      for line in pipe:
747f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if after_section:
748f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if line.find("CODE") != -1:
749f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            code_sections.add(after_section)
750f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if line.find("RELOC") != -1:
751f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            reloc_sections.add(after_section)
752f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          after_section = None
753f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
754f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
755f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        match = OBJDUMP_SECTION_HEADER_RE.match(line)
756f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if match:
757f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          after_section = match.group(1)
758f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
759f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
760f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if OBJDUMP_DYNAMIC_SYMBOLS_START_RE.match(line):
761f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          dynamic = True
762f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
763f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
764f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        match = OBJDUMP_SYMBOL_LINE_RE.match(line)
765f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if match:
766f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          start_address = int(match.group(1), 16)
767f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          origin_offset = start_address
768f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          flags = match.group(2)
769f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          section = match.group(3)
770f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if section in code_sections:
771f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            if dynamic or section in reloc_sections:
772f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              start_address += mmap_info.addr
773f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            size = int(match.group(4), 16)
774f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            name = match.group(5)
775f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            origin = mmap_info.filename
776f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            code_map.Add(Code(name, start_address, start_address + size,
777f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                              origin, origin_offset))
778f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    finally:
779f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      pipe.close()
780f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert process.wait() == 0, "Failed to objdump %s" % mmap_info.filename
781f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
782f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Tick(self, pc):
783f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for i, mmap_info in enumerate(self.infos):
784f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if mmap_info.addr <= pc < (mmap_info.addr + mmap_info.len):
785f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        mmap_info.ticks += 1
786f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.infos[0], self.infos[i] = mmap_info, self.infos[0]
787f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        return True
788f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return False
789f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
790f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _UniqueMmapName(self, mmap_info):
791f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    name = mmap_info.filename
792f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    index = 1
793f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    while name in self.names:
794f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      name = "%s-%d" % (mmap_info.filename, index)
795f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      index += 1
796f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.names.add(name)
797f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return name
798f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
799f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _LoadKernelSymbols(self, code_map):
800f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not os.path.exists(KERNEL_ALLSYMS_FILE):
801f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print >>sys.stderr, "Warning: %s not found" % KERNEL_ALLSYMS_FILE
802f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return False
803f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    kallsyms = open(KERNEL_ALLSYMS_FILE, "r")
804f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    code = None
805f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for line in kallsyms:
806f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      match = KERNEL_ALLSYMS_LINE_RE.match(line)
807f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if match:
808f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        start_address = int(match.group(1), 16)
809f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        end_address = start_address
810f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        name = match.group(2)
811f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if code:
812f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          code.end_address = start_address
813f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          code_map.Add(code, 16)
814f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code = Code(name, start_address, end_address, "kernel", 0)
815f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return True
816f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
817f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochdef PrintReport(code_map, library_repo, arch, ticks, options):
819f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "Ticks per symbol:"
820f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  used_code = [code for code in code_map.UsedCode()]
821f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  used_code.sort(key=lambda x: x.self_ticks, reverse=True)
822f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  for i, code in enumerate(used_code):
823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    code_ticks = code.self_ticks
824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    print "%10d %5.1f%% %s [%s]" % (code_ticks, 100. * code_ticks / ticks,
825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    code.FullName(), code.origin)
826f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if options.disasm_all or i < options.disasm_top:
827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      code.PrintAnnotated(arch, options)
828f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print
829f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "Ticks per library:"
830b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  mmap_infos = [m for m in library_repo.infos if m.ticks > 0]
831f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  mmap_infos.sort(key=lambda m: m.ticks, reverse=True)
832f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  for mmap_info in mmap_infos:
833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    mmap_ticks = mmap_info.ticks
834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    print "%10d %5.1f%% %s" % (mmap_ticks, 100. * mmap_ticks / ticks,
835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                               mmap_info.unique_name)
836f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
837f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
838f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochdef PrintDot(code_map, options):
839f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "digraph G {"
840f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  for code in code_map.UsedCode():
841f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if code.self_ticks < 10:
842f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      continue
843f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print "n%d [shape=box,label=\"%s\"];" % (code.id, code.name)
844f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if code.callee_ticks:
845f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      for callee, ticks in code.callee_ticks.iteritems():
846f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        print "n%d -> n%d [label=\"%d\"];" % (code.id, callee.id, ticks)
847f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "}"
848f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
849f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
850f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochif __name__ == "__main__":
851f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser = optparse.OptionParser(USAGE)
852f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--snapshot-log",
853f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default="obj/release/snapshot.log",
854f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="V8 snapshot log file name [default: %default]")
855f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--log",
856f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default="v8.log",
857f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="V8 log file name [default: %default]")
858f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--snapshot",
859f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
860f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
861f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="process V8 snapshot log [default: %default]")
862f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--trace",
863f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default="perf.data",
864f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="perf trace file name [default: %default]")
865f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--kernel",
866f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
867f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
868f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="process kernel entries [default: %default]")
869f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--disasm-top",
870f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=0,
871f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    type="int",
872f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help=("number of top symbols to disassemble and annotate "
873f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                          "[default: %default]"))
874f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--disasm-all",
875f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
876f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
877f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help=("disassemble and annotate all used symbols "
878f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                          "[default: %default]"))
879f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--dot",
880f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
881f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
882f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="produce dot output (WIP) [default: %default]")
883f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--quiet", "-q",
884f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
885f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
886f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="no auxiliary messages [default: %default]")
887b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  parser.add_option("--gc-fake-mmap",
888b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    default="/tmp/__v8_gc__",
889b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    help="gc fake mmap file [default: %default]")
890b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  parser.add_option("--objdump",
891b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    default="/usr/bin/objdump",
892b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    help="objdump tool to use [default: %default]")
893b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  parser.add_option("--host-root",
894b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    default="",
895b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    help="Path to the host root [default: %default]")
896f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  options, args = parser.parse_args()
897f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
898f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  if not options.quiet:
899f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if options.snapshot:
900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      print "V8 logs: %s, %s, %s.ll" % (options.snapshot_log,
901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        options.log,
902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                        options.log)
903f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    else:
904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      print "V8 log: %s, %s.ll (no snapshot)" % (options.log, options.log)
905f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print "Perf trace file: %s" % options.trace
906f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
907b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  V8_GC_FAKE_MMAP = options.gc_fake_mmap
908b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  HOST_ROOT = options.host_root
909b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if os.path.exists(options.objdump):
910b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    disasm.OBJDUMP_BIN = options.objdump
911b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    OBJDUMP_BIN = options.objdump
912b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  else:
913b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    print "Cannot find %s, falling back to default objdump" % options.objdump
914b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
915f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Stats.
916f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  events = 0
917f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ticks = 0
918f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  missed_ticks = 0
919f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  really_missed_ticks = 0
920b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  optimized_ticks = 0
921b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  generated_ticks = 0
922b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8_internal_ticks = 0
923f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  mmap_time = 0
924f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  sample_time = 0
925f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  # Process the snapshot log to fill the snapshot name map.
927f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  snapshot_name_map = {}
928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  if options.snapshot:
929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    snapshot_log_reader = SnapshotLogReader(log_name=options.snapshot_log)
930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    snapshot_name_map = snapshot_log_reader.ReadNameMap()
931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  # Initialize the log reader.
933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  code_map = CodeMap()
934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  log_reader = LogReader(log_name=options.log + ".ll",
935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         code_map=code_map,
936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                         snapshot_pos_to_name=snapshot_name_map)
937f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  if not options.quiet:
938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    print "Generated code architecture: %s" % log_reader.arch
939f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print
940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    sys.stdout.flush()
941f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
942f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Process the code and trace logs.
943f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  library_repo = LibraryRepo()
944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  log_reader.ReadUpToGC()
945f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  trace_reader = TraceReader(options.trace)
946f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  while True:
947f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    header, offset = trace_reader.ReadEventHeader()
948f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not header:
949f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      break
950f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    events += 1
951f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if header.type == PERF_RECORD_MMAP:
952f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      start = time.time()
953f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      mmap_info = trace_reader.ReadMmap(header, offset)
954b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if mmap_info.filename == HOST_ROOT + V8_GC_FAKE_MMAP:
955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        log_reader.ReadUpToGC()
956f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
957f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        library_repo.Load(mmap_info, code_map, options)
958f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      mmap_time += time.time() - start
959f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    elif header.type == PERF_RECORD_SAMPLE:
960f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      ticks += 1
961f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      start = time.time()
962f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      sample = trace_reader.ReadSample(header, offset)
963f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      code = code_map.Find(sample.ip)
964f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if code:
965f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code.Tick(sample.ip)
966b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if code.codetype == Code.OPTIMIZED:
967b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          optimized_ticks += 1
968b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        elif code.codetype == Code.FULL_CODEGEN:
969b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          generated_ticks += 1
970b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        elif code.codetype == Code.V8INTERNAL:
971b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          v8_internal_ticks += 1
972f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
973f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        missed_ticks += 1
974f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if not library_repo.Tick(sample.ip) and not code:
975f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        really_missed_ticks += 1
976f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if trace_reader.callchain_supported:
977f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        for ip in sample.ips:
978f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          caller_code = code_map.Find(ip)
979f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if caller_code:
980f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            if code:
981f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              caller_code.CalleeTick(code)
982f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            code = caller_code
983f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      sample_time += time.time() - start
984f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
985f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  if options.dot:
986f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    PrintDot(code_map, options)
987f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  else:
988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    PrintReport(code_map, library_repo, log_reader.arch, ticks, options)
989f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
990f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not options.quiet:
991b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      def PrintTicks(number, total, description):
992b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print("%10d %5.1f%% ticks in %s" %
993b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch              (number, 100.0*number/total, description))
994f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print
995f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "Stats:"
996f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d total trace events" % events
997f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d total ticks" % ticks
998f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d ticks not in symbols" % missed_ticks
999b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      unaccounted = "unaccounted ticks"
1000b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if really_missed_ticks > 0:
1001b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        unaccounted += " (probably in the kernel, try --kernel)"
1002b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      PrintTicks(really_missed_ticks, ticks, unaccounted)
1003b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      PrintTicks(optimized_ticks, ticks, "ticks in optimized code")
1004b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      PrintTicks(generated_ticks, ticks, "ticks in other lazily compiled code")
1005b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      PrintTicks(v8_internal_ticks, ticks, "ticks in v8::internal::*")
1006f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d total symbols" % len([c for c in code_map.AllCode()])
1007f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d used symbols" % len([c for c in code_map.UsedCode()])
1008f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%9.2fs library processing time" % mmap_time
1009f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%9.2fs tick processing time" % sample_time
1010f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
1011f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  log_reader.Dispose()
1012f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  trace_reader.Dispose()
1013