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
693b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  # symbols. Use default log names.
703b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  $ %prog --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.
773b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  $ %prog --log=foo.log --trace=foo.data
78f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch"""
79f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
80f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
81f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochJS_ORIGIN = "js"
823b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch
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
176109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      percent = 100.0 * count / self.self_ticks
177109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      offset = lines[i][0]
178109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch      if percent >= 0.01:
179109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        # 5 spaces for tick count
180109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        # 1 space following
181109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        # 1 for '|'
182109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        # 1 space following
183109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        # 6 for the percentage number, incl. the '.'
184109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        # 1 for the '%' sign
185109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        # => 15
186109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        print "%5d | %6.2f%% %x(%d): %s" % (count, percent, offset, offset, lines[i][1])
187f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
188109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch        print "%s %x(%d): %s" % (" " * 15, offset, offset, lines[i][1])
189f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print
190f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert total_count == self.self_ticks, \
191f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "Lost ticks (%d != %d) in %s" % (total_count, self.self_ticks, self)
192f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
193f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __str__(self):
194f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return "%s [0x%x, 0x%x) size: %d origin: %s" % (
195f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.name,
196f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.start_address,
197f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.end_address,
198f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.end_address - self.start_address,
199f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.origin)
200f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def _GetDisasmLines(self, arch, options):
2023b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    if self.origin == JS_ORIGIN:
203e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      inplace = False
204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      filename = options.log + ".ll"
205f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    else:
206e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      inplace = True
207e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch      filename = self.origin
208e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    return disasm.GetDisasmLines(filename,
209e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                 self.origin_offset,
210e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                 self.end_address - self.start_address,
211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                 arch,
212e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                                 inplace)
213f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
214f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
215f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodePage(object):
216f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Group of adjacent code objects."""
217f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  SHIFT = 20  # 1M pages
219f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  SIZE = (1 << SHIFT)
220f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  MASK = ~(SIZE - 1)
221f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
222f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
223f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def PageAddress(address):
224f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return address & CodePage.MASK
225f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
226f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
227f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def PageId(address):
228f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return address >> CodePage.SHIFT
229f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
230f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
231f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def PageAddressFromId(id):
232f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return id << CodePage.SHIFT
233f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
234f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, address):
235f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.address = address
236f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_objects = []
237f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
238f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Add(self, code):
239f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_objects.append(code)
240f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
241f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Remove(self, code):
242f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_objects.remove(code)
243f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
244f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Find(self, pc):
245f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    code_objects = self.code_objects
246f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for i, code in enumerate(code_objects):
247f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if code.start_address <= pc < code.end_address:
248f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code_objects[0], code_objects[i] = code, code_objects[0]
249f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        return code
250f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return None
251f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
252f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __iter__(self):
253f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return self.code_objects.__iter__()
254f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
255f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
256f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodeMap(object):
257f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Code object map."""
258f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
259f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self):
260f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.pages = {}
261f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.min_address = 1 << 64
262f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.max_address = -1
263f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
264f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Add(self, code, max_pages=-1):
265f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    page_id = CodePage.PageId(code.start_address)
266f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1)
267f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    pages = 0
268f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    while page_id < limit_id:
269f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if max_pages >= 0 and pages > max_pages:
270f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        print >>sys.stderr, \
271f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            "Warning: page limit (%d) reached for %s [%s]" % (
272f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            max_pages, code.name, code.origin)
273f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        break
274f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if page_id in self.pages:
275f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        page = self.pages[page_id]
276f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
277f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        page = CodePage(CodePage.PageAddressFromId(page_id))
278f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.pages[page_id] = page
279f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page.Add(code)
280f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page_id += 1
281f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      pages += 1
282f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.min_address = min(self.min_address, code.start_address)
283f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.max_address = max(self.max_address, code.end_address)
284f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
285f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Remove(self, code):
286f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    page_id = CodePage.PageId(code.start_address)
287f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1)
288f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    removed = False
289f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    while page_id < limit_id:
290f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if page_id not in self.pages:
291f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        page_id += 1
292f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        continue
293f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page = self.pages[page_id]
294f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page.Remove(code)
295f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      removed = True
296f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      page_id += 1
297f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return removed
298f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
299f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def AllCode(self):
300f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for page in self.pages.itervalues():
301f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      for code in page:
302f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if CodePage.PageAddress(code.start_address) == page.address:
303f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          yield code
304f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
305f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def UsedCode(self):
306f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for code in self.AllCode():
307f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if code.IsUsed():
308f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        yield code
309f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
310f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Print(self):
311f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for code in self.AllCode():
312f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print code
313f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
314f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Find(self, pc):
315f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if pc < self.min_address or pc >= self.max_address:
316f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return None
317f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    page_id = CodePage.PageId(pc)
318f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if page_id not in self.pages:
319f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return None
320f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return self.pages[page_id].Find(pc)
321f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
322f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
323f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodeInfo(object):
324f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Generic info about generated code objects."""
325f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
326f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, arch, header_size):
327f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.arch = arch
328f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.header_size = header_size
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,
338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    "x64": ctypes.c_uint64,
339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    "arm64": ctypes.c_uint64
340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  }
341f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _CODE_CREATE_TAG = "C"
343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _CODE_MOVE_TAG = "M"
344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  _CODE_MOVING_GC_TAG = "G"
345f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
3463b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch  def __init__(self, log_name, code_map):
347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_file = open(log_name, "r")
348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log = mmap.mmap(self.log_file.fileno(), 0, mmap.MAP_PRIVATE)
349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_pos = 0
350f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.code_map = code_map
351f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.arch = self.log[:self.log.find("\0")]
353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_pos += len(self.arch) + 1
354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    assert self.arch in LogReader._ARCH_TO_POINTER_TYPE_MAP, \
355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        "Unsupported architecture %s" % self.arch
356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    pointer_type = LogReader._ARCH_TO_POINTER_TYPE_MAP[self.arch]
357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.code_create_struct = LogReader._DefineStruct([
359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("name_size", ctypes.c_int32),
360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("code_address", pointer_type),
361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("code_size", ctypes.c_int32)])
362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.code_move_struct = LogReader._DefineStruct([
364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("from_address", pointer_type),
365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("to_address", pointer_type)])
366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.code_delete_struct = LogReader._DefineStruct([
368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        ("address", pointer_type)])
369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def ReadUpToGC(self):
371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    while self.log_pos < self.log.size():
372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      tag = self.log[self.log_pos]
373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      self.log_pos += 1
374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._CODE_MOVING_GC_TAG:
376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        return
377f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._CODE_CREATE_TAG:
379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        event = self.code_create_struct.from_buffer(self.log, self.log_pos)
380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += ctypes.sizeof(event)
381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        start_address = event.code_address
382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        end_address = start_address + event.code_size
3833b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch        name = self.log[self.log_pos:self.log_pos + event.name_size]
3843b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch        origin = JS_ORIGIN
385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += event.name_size
386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        origin_offset = self.log_pos
387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += event.code_size
388f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code = Code(name, start_address, end_address, origin, origin_offset)
389f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        conficting_code = self.code_map.Find(start_address)
390f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if conficting_code:
3913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          if not (conficting_code.start_address == code.start_address and
3923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            conficting_code.end_address == code.end_address):
3933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            self.code_map.Remove(conficting_code)
3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch          else:
3953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            LogReader._HandleCodeConflict(conficting_code, code)
3963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            # TODO(vitalyr): this warning is too noisy because of our
3973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            # attempts to reconstruct code log from the snapshot.
3983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            # print >>sys.stderr, \
3993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            #     "Warning: Skipping duplicate code log entry %s" % code
4003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            continue
401f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.code_map.Add(code)
402f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        continue
403f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      if tag == LogReader._CODE_MOVE_TAG:
405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        event = self.code_move_struct.from_buffer(self.log, self.log_pos)
406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.log_pos += ctypes.sizeof(event)
407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        old_start_address = event.from_address
408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        new_start_address = event.to_address
409f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if old_start_address == new_start_address:
410f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          # Skip useless code move entries.
411f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
412f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code = self.code_map.Find(old_start_address)
413f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if not code:
414f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          print >>sys.stderr, "Warning: Not found %x" % old_start_address
415f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
416f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        assert code.start_address == old_start_address, \
417f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            "Inexact move address %x for %s" % (old_start_address, code)
418f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.code_map.Remove(code)
419f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        size = code.end_address - code.start_address
420f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code.start_address = new_start_address
421f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code.end_address = new_start_address + size
422f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.code_map.Add(code)
423f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        continue
424f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      assert False, "Unknown tag %s" % tag
426f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
427f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Dispose(self):
428f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.log.close()
429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.log_file.close()
430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  @staticmethod
432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def _DefineStruct(fields):
433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    class Struct(ctypes.Structure):
434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      _fields_ = fields
435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    return Struct
436f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
437f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
438f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _HandleCodeConflict(old_code, new_code):
439f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert (old_code.start_address == new_code.start_address and
440f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            old_code.end_address == new_code.end_address), \
441f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "Conficting code log entries %s and %s" % (old_code, new_code)
442f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if old_code.name == new_code.name:
443f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return
444f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Code object may be shared by a few functions. Collect the full
445f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # set of names.
446f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    old_code.AddName(new_code.name)
447f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
448f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
449f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass Descriptor(object):
450f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Descriptor of a structure in the binary trace log."""
451f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
452f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  CTYPE_MAP = {
453f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    "u16": ctypes.c_uint16,
454f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    "u32": ctypes.c_uint32,
455f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    "u64": ctypes.c_uint64
456f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  }
457f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
458f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, fields):
459f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    class TraceItem(ctypes.Structure):
460f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      _fields_ = Descriptor.CtypesFields(fields)
461f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
462f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      def __str__(self):
463f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        return ", ".join("%s: %s" % (field, self.__getattribute__(field))
464f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                         for field, _ in TraceItem._fields_)
465f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
466f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.ctype = TraceItem
467f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
468f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Read(self, trace, offset):
469f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return self.ctype.from_buffer(trace, offset)
470f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
471f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  @staticmethod
472f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def CtypesFields(fields):
473f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return [(field, Descriptor.CTYPE_MAP[format]) for (field, format) in fields]
474f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
475f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
476f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# Please see http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=tree;f=tools/perf
477f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# for the gory details.
478f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
479f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
480b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: struct perf_file_header in kernel/tools/perf/util/header.h
481f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochTRACE_HEADER_DESC = Descriptor([
482f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("magic", "u64"),
483f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("size", "u64"),
484f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("attr_size", "u64"),
485f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("attrs_offset", "u64"),
486f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("attrs_size", "u64"),
487f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("data_offset", "u64"),
488f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("data_size", "u64"),
489f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("event_types_offset", "u64"),
490f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("event_types_size", "u64")
491f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
492f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
493f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
494b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/linux/perf_event.h
495f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_EVENT_ATTR_DESC = Descriptor([
496f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("type", "u32"),
497f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("size", "u32"),
498f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("config", "u64"),
499f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("sample_period_or_freq", "u64"),
500f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("sample_type", "u64"),
501f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("read_format", "u64"),
502f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("flags", "u64"),
503f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("wakeup_events_or_watermark", "u32"),
504b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ("bp_type", "u32"),
505f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("bp_addr", "u64"),
506b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  ("bp_len", "u64")
507f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
508f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
509f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
510b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/linux/perf_event.h
511f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_EVENT_HEADER_DESC = Descriptor([
512f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("type", "u32"),
513f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("misc", "u16"),
514f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("size", "u16")
515f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
516f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
517f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
518014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch# Reference: kernel/tools/perf/util/event.h
519f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_MMAP_EVENT_BODY_DESC = Descriptor([
520f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("pid", "u32"),
521f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("tid", "u32"),
522f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("addr", "u64"),
523f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("len", "u64"),
524f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("pgoff", "u64")
525f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch])
526f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
527014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch# Reference: kernel/tools/perf/util/event.h
528014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochPERF_MMAP2_EVENT_BODY_DESC = Descriptor([
529014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ("pid", "u32"),
530014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ("tid", "u32"),
531014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ("addr", "u64"),
532014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ("len", "u64"),
533014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ("pgoff", "u64"),
534014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ("maj", "u32"),
535014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ("min", "u32"),
536014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ("ino", "u64"),
537014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ("ino_generation", "u64"),
538014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ("prot", "u32"),
539014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  ("flags","u32")
540014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch])
541f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
542f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# perf_event_attr.sample_type bits control the set of
543f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# perf_sample_event fields.
544f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_IP = 1 << 0
545f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_TID = 1 << 1
546f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_TIME = 1 << 2
547f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_ADDR = 1 << 3
548f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_READ = 1 << 4
549f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_CALLCHAIN = 1 << 5
550f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_ID = 1 << 6
551f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_CPU = 1 << 7
552f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_PERIOD = 1 << 8
553f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_STREAM_ID = 1 << 9
554f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_RAW = 1 << 10
555f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
556f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
557b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/perf_event.h, the comment for PERF_RECORD_SAMPLE.
558f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_EVENT_BODY_FIELDS = [
559f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("ip", "u64", PERF_SAMPLE_IP),
560f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("pid", "u32", PERF_SAMPLE_TID),
561f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("tid", "u32", PERF_SAMPLE_TID),
562f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("time", "u64", PERF_SAMPLE_TIME),
563f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("addr", "u64", PERF_SAMPLE_ADDR),
564f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("id", "u64", PERF_SAMPLE_ID),
565f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("stream_id", "u64", PERF_SAMPLE_STREAM_ID),
566f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("cpu", "u32", PERF_SAMPLE_CPU),
567f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("res", "u32", PERF_SAMPLE_CPU),
568f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("period", "u64", PERF_SAMPLE_PERIOD),
569f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Don't want to handle read format that comes after the period and
570f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # before the callchain and has variable size.
571f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ("nr", "u64", PERF_SAMPLE_CALLCHAIN)
572f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Raw data follows the callchain and is ignored.
573f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch]
574f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
575f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
576f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_EVENT_IP_FORMAT = "u64"
577f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
578f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
579f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_RECORD_MMAP = 1
580014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochPERF_RECORD_MMAP2 = 10
581f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_RECORD_SAMPLE = 9
582f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
583f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
584f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass TraceReader(object):
585f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  """Perf (linux-2.6/tools/perf) trace file reader."""
586f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
587f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  _TRACE_HEADER_MAGIC = 4993446653023372624
588f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
589f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self, trace_name):
590f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace_file = open(trace_name, "r")
591f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace = mmap.mmap(self.trace_file.fileno(), 0, mmap.MAP_PRIVATE)
592f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace_header = TRACE_HEADER_DESC.Read(self.trace, 0)
593f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.trace_header.magic != TraceReader._TRACE_HEADER_MAGIC:
594f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print >>sys.stderr, "Warning: unsupported trace header magic"
595f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.offset = self.trace_header.data_offset
596f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.limit = self.trace_header.data_offset + self.trace_header.data_size
597f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert self.limit <= self.trace.size(), \
598f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "Trace data limit exceeds trace file size"
599f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.header_size = ctypes.sizeof(PERF_EVENT_HEADER_DESC.ctype)
600f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert self.trace_header.attrs_size != 0, \
601f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        "No perf event attributes found in the trace"
602f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    perf_event_attr = PERF_EVENT_ATTR_DESC.Read(self.trace,
603f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                                                self.trace_header.attrs_offset)
604f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.sample_event_body_desc = self._SampleEventBodyDesc(
605f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        perf_event_attr.sample_type)
606f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.callchain_supported = \
607f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        (perf_event_attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0
608f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.callchain_supported:
609f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.ip_struct = Descriptor.CTYPE_MAP[PERF_SAMPLE_EVENT_IP_FORMAT]
610f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      self.ip_size = ctypes.sizeof(self.ip_struct)
611f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
612f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def ReadEventHeader(self):
613f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if self.offset >= self.limit:
614f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return None, 0
615f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    offset = self.offset
616f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    header = PERF_EVENT_HEADER_DESC.Read(self.trace, self.offset)
617f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.offset += header.size
618f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return header, offset
619f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
620f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def ReadMmap(self, header, offset):
621f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    mmap_info = PERF_MMAP_EVENT_BODY_DESC.Read(self.trace,
622f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                                               offset + self.header_size)
6233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    # Read null-terminated filename.
624f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info):
6253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch                          offset + header.size]
626b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    mmap_info.filename = HOST_ROOT + filename[:filename.find(chr(0))]
627f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return mmap_info
628f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
629014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  def ReadMmap2(self, header, offset):
630014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    mmap_info = PERF_MMAP2_EVENT_BODY_DESC.Read(self.trace,
631014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                                                offset + self.header_size)
632014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    # Read null-terminated filename.
633014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info):
634014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                          offset + header.size]
635014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    mmap_info.filename = HOST_ROOT + filename[:filename.find(chr(0))]
636014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return mmap_info
637014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
638f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def ReadSample(self, header, offset):
639f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    sample = self.sample_event_body_desc.Read(self.trace,
640f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                                              offset + self.header_size)
641f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not self.callchain_supported:
642f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return sample
643f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    sample.ips = []
644f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    offset += self.header_size + ctypes.sizeof(sample)
645f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for _ in xrange(sample.nr):
646f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      sample.ips.append(
647f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.ip_struct.from_buffer(self.trace, offset).value)
648f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      offset += self.ip_size
649f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return sample
650f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
651f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Dispose(self):
652f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace.close()
653f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.trace_file.close()
654f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
655f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _SampleEventBodyDesc(self, sample_type):
656f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert (sample_type & PERF_SAMPLE_READ) == 0, \
657f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch           "Can't hande read format in samples"
658f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    fields = [(field, format)
659f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              for (field, format, bit) in PERF_SAMPLE_EVENT_BODY_FIELDS
660f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              if (bit & sample_type) != 0]
661f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return Descriptor(fields)
662f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
663f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
664f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_SECTION_HEADER_RE = re.compile(
665f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r"^\s*\d+\s(\.\S+)\s+[a-f0-9]")
666f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_SYMBOL_LINE_RE = re.compile(
667f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r"^([a-f0-9]+)\s(.{7})\s(\S+)\s+([a-f0-9]+)\s+(?:\.hidden\s+)?(.*)$")
668f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_DYNAMIC_SYMBOLS_START_RE = re.compile(
6693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  r"^DYNAMIC SYMBOL TABLE")
6703ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochOBJDUMP_SKIP_RE = re.compile(
6713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  r"^.*ld\.so\.cache$")
672f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochKERNEL_ALLSYMS_FILE = "/proc/kallsyms"
673f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_KERNEL_ALLSYMS_RE = re.compile(
674f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r".*kallsyms.*")
675f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochKERNEL_ALLSYMS_LINE_RE = re.compile(
676f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  r"^([a-f0-9]+)\s(?:t|T)\s(\S+)$")
677f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
678f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
679f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass LibraryRepo(object):
680f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def __init__(self):
681f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.infos = []
682f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.names = set()
683f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.ticks = {}
684f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
685014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
686014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  def HasDynamicSymbols(self, filename):
687014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if filename.endswith(".ko"): return False
688014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    process = subprocess.Popen(
689014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      "%s -h %s" % (OBJDUMP_BIN, filename),
690014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
691014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    pipe = process.stdout
692014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    try:
693014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      for line in pipe:
694014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        match = OBJDUMP_SECTION_HEADER_RE.match(line)
695014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        if match and match.group(1) == 'dynsym': return True
696014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    finally:
697014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      pipe.close()
698014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    assert process.wait() == 0, "Failed to objdump -h %s" % filename
699014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    return False
700014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
701014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
702f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Load(self, mmap_info, code_map, options):
703f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Skip kernel mmaps when requested using the fact that their tid
704f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # is 0.
705f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if mmap_info.tid == 0 and not options.kernel:
706f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return True
7073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if OBJDUMP_SKIP_RE.match(mmap_info.filename):
7083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      return True
709f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if PERF_KERNEL_ALLSYMS_RE.match(mmap_info.filename):
710f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return self._LoadKernelSymbols(code_map)
711f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.infos.append(mmap_info)
712f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    mmap_info.ticks = 0
713f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    mmap_info.unique_name = self._UniqueMmapName(mmap_info)
714f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not os.path.exists(mmap_info.filename):
715f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return True
716f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Request section headers (-h), symbols (-t), and dynamic symbols
717f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # (-T) from objdump.
718f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # Unfortunately, section headers span two lines, so we have to
719f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # keep the just seen section name (from the first line in each
720f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    # section header) in the after_section variable.
721014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    if self.HasDynamicSymbols(mmap_info.filename):
722b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      dynamic_symbols = "-T"
723014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    else:
724014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      dynamic_symbols = ""
725f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    process = subprocess.Popen(
726b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "%s -h -t %s -C %s" % (OBJDUMP_BIN, dynamic_symbols, mmap_info.filename),
727f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
728f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    pipe = process.stdout
729f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    after_section = None
730f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    code_sections = set()
731f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    reloc_sections = set()
732f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    dynamic = False
733f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    try:
734f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      for line in pipe:
735f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if after_section:
736f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if line.find("CODE") != -1:
737f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            code_sections.add(after_section)
738f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if line.find("RELOC") != -1:
739f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            reloc_sections.add(after_section)
740f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          after_section = None
741f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
742f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
743f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        match = OBJDUMP_SECTION_HEADER_RE.match(line)
744f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if match:
745f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          after_section = match.group(1)
746f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
747f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
748f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if OBJDUMP_DYNAMIC_SYMBOLS_START_RE.match(line):
749f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          dynamic = True
750f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          continue
751f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
752f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        match = OBJDUMP_SYMBOL_LINE_RE.match(line)
753f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if match:
754f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          start_address = int(match.group(1), 16)
755f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          origin_offset = start_address
756f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          flags = match.group(2)
757f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          section = match.group(3)
758f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if section in code_sections:
759f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            if dynamic or section in reloc_sections:
760f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              start_address += mmap_info.addr
761f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            size = int(match.group(4), 16)
762f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            name = match.group(5)
763f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            origin = mmap_info.filename
764f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            code_map.Add(Code(name, start_address, start_address + size,
765f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                              origin, origin_offset))
766f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    finally:
767f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      pipe.close()
768f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    assert process.wait() == 0, "Failed to objdump %s" % mmap_info.filename
769f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
770f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def Tick(self, pc):
771f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for i, mmap_info in enumerate(self.infos):
772f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if mmap_info.addr <= pc < (mmap_info.addr + mmap_info.len):
773f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        mmap_info.ticks += 1
774f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        self.infos[0], self.infos[i] = mmap_info, self.infos[0]
775f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        return True
776f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return False
777f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
778f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _UniqueMmapName(self, mmap_info):
779f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    name = mmap_info.filename
780f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    index = 1
781f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    while name in self.names:
782f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      name = "%s-%d" % (mmap_info.filename, index)
783f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      index += 1
784f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    self.names.add(name)
785f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return name
786f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
787f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  def _LoadKernelSymbols(self, code_map):
788f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not os.path.exists(KERNEL_ALLSYMS_FILE):
789f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print >>sys.stderr, "Warning: %s not found" % KERNEL_ALLSYMS_FILE
790f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      return False
791f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    kallsyms = open(KERNEL_ALLSYMS_FILE, "r")
792f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    code = None
793f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    for line in kallsyms:
794f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      match = KERNEL_ALLSYMS_LINE_RE.match(line)
795f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if match:
796f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        start_address = int(match.group(1), 16)
797f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        end_address = start_address
798f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        name = match.group(2)
799f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        if code:
800f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          code.end_address = start_address
801f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          code_map.Add(code, 16)
802f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code = Code(name, start_address, end_address, "kernel", 0)
803f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    return True
804f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
805f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochdef PrintReport(code_map, library_repo, arch, ticks, options):
807f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "Ticks per symbol:"
808f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  used_code = [code for code in code_map.UsedCode()]
809f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  used_code.sort(key=lambda x: x.self_ticks, reverse=True)
810f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  for i, code in enumerate(used_code):
811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    code_ticks = code.self_ticks
812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    print "%10d %5.1f%% %s [%s]" % (code_ticks, 100. * code_ticks / ticks,
813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                                    code.FullName(), code.origin)
814f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if options.disasm_all or i < options.disasm_top:
815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      code.PrintAnnotated(arch, options)
816f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print
817f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "Ticks per library:"
818b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  mmap_infos = [m for m in library_repo.infos if m.ticks > 0]
819f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  mmap_infos.sort(key=lambda m: m.ticks, reverse=True)
820f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  for mmap_info in mmap_infos:
821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    mmap_ticks = mmap_info.ticks
822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    print "%10d %5.1f%% %s" % (mmap_ticks, 100. * mmap_ticks / ticks,
823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                               mmap_info.unique_name)
824f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
825f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
826f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochdef PrintDot(code_map, options):
827f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "digraph G {"
828f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  for code in code_map.UsedCode():
829f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if code.self_ticks < 10:
830f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      continue
831f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print "n%d [shape=box,label=\"%s\"];" % (code.id, code.name)
832f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if code.callee_ticks:
833f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      for callee, ticks in code.callee_ticks.iteritems():
834f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        print "n%d -> n%d [label=\"%d\"];" % (code.id, callee.id, ticks)
835f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  print "}"
836f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
837f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
838f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochif __name__ == "__main__":
839f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser = optparse.OptionParser(USAGE)
840f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--log",
841f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default="v8.log",
842f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="V8 log file name [default: %default]")
843f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--trace",
844f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default="perf.data",
845f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="perf trace file name [default: %default]")
846f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--kernel",
847f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
848f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
849f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="process kernel entries [default: %default]")
850f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--disasm-top",
851f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=0,
852f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    type="int",
853f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help=("number of top symbols to disassemble and annotate "
854f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                          "[default: %default]"))
855f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--disasm-all",
856f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
857f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
858f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help=("disassemble and annotate all used symbols "
859f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                          "[default: %default]"))
860f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--dot",
861f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
862f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
863f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="produce dot output (WIP) [default: %default]")
864f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  parser.add_option("--quiet", "-q",
865f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    default=False,
866f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    action="store_true",
867f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch                    help="no auxiliary messages [default: %default]")
868b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  parser.add_option("--gc-fake-mmap",
869b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    default="/tmp/__v8_gc__",
870b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    help="gc fake mmap file [default: %default]")
871b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  parser.add_option("--objdump",
872b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    default="/usr/bin/objdump",
873b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    help="objdump tool to use [default: %default]")
874b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  parser.add_option("--host-root",
875b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    default="",
876b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    help="Path to the host root [default: %default]")
877f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  options, args = parser.parse_args()
878f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
879f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  if not options.quiet:
8803b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch    print "V8 log: %s, %s.ll" % (options.log, options.log)
881f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print "Perf trace file: %s" % options.trace
882f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
883b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  V8_GC_FAKE_MMAP = options.gc_fake_mmap
884b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  HOST_ROOT = options.host_root
885b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if os.path.exists(options.objdump):
886b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    disasm.OBJDUMP_BIN = options.objdump
887b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    OBJDUMP_BIN = options.objdump
888b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  else:
889b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    print "Cannot find %s, falling back to default objdump" % options.objdump
890b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
891f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Stats.
892f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  events = 0
893f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  ticks = 0
894f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  missed_ticks = 0
895f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  really_missed_ticks = 0
896b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  optimized_ticks = 0
897b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  generated_ticks = 0
898b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  v8_internal_ticks = 0
899f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  mmap_time = 0
900f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  sample_time = 0
901f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  # Initialize the log reader.
903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  code_map = CodeMap()
904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  log_reader = LogReader(log_name=options.log + ".ll",
9053b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch                         code_map=code_map)
906f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  if not options.quiet:
907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    print "Generated code architecture: %s" % log_reader.arch
908f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    print
909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    sys.stdout.flush()
910f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
911f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  # Process the code and trace logs.
912f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  library_repo = LibraryRepo()
913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  log_reader.ReadUpToGC()
914f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  trace_reader = TraceReader(options.trace)
915f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  while True:
916f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    header, offset = trace_reader.ReadEventHeader()
917f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not header:
918f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      break
919f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    events += 1
920f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if header.type == PERF_RECORD_MMAP:
921f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      start = time.time()
922f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      mmap_info = trace_reader.ReadMmap(header, offset)
923b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if mmap_info.filename == HOST_ROOT + V8_GC_FAKE_MMAP:
924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        log_reader.ReadUpToGC()
925f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
926f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        library_repo.Load(mmap_info, code_map, options)
927f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      mmap_time += time.time() - start
928014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    elif header.type == PERF_RECORD_MMAP2:
929014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      start = time.time()
930014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      mmap_info = trace_reader.ReadMmap2(header, offset)
931014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      if mmap_info.filename == HOST_ROOT + V8_GC_FAKE_MMAP:
932014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        log_reader.ReadUpToGC()
933014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      else:
934014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch        library_repo.Load(mmap_info, code_map, options)
935014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch      mmap_time += time.time() - start
936f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    elif header.type == PERF_RECORD_SAMPLE:
937f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      ticks += 1
938f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      start = time.time()
939f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      sample = trace_reader.ReadSample(header, offset)
940f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      code = code_map.Find(sample.ip)
941f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if code:
942f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        code.Tick(sample.ip)
943b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if code.codetype == Code.OPTIMIZED:
944b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          optimized_ticks += 1
945b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        elif code.codetype == Code.FULL_CODEGEN:
946b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          generated_ticks += 1
947b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        elif code.codetype == Code.V8INTERNAL:
948b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch          v8_internal_ticks += 1
949f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      else:
950f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        missed_ticks += 1
951f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if not library_repo.Tick(sample.ip) and not code:
952f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        really_missed_ticks += 1
953f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      if trace_reader.callchain_supported:
954f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch        for ip in sample.ips:
955f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          caller_code = code_map.Find(ip)
956f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch          if caller_code:
957f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            if code:
958f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch              caller_code.CalleeTick(code)
959f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch            code = caller_code
960f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      sample_time += time.time() - start
961f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
962f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  if options.dot:
963f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    PrintDot(code_map, options)
964f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  else:
965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    PrintReport(code_map, library_repo, log_reader.arch, ticks, options)
966f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
967f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch    if not options.quiet:
968b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      def PrintTicks(number, total, description):
969b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        print("%10d %5.1f%% ticks in %s" %
970b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch              (number, 100.0*number/total, description))
971f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print
972f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "Stats:"
973f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d total trace events" % events
974f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d total ticks" % ticks
975f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d ticks not in symbols" % missed_ticks
976b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      unaccounted = "unaccounted ticks"
977b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      if really_missed_ticks > 0:
978b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        unaccounted += " (probably in the kernel, try --kernel)"
979b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      PrintTicks(really_missed_ticks, ticks, unaccounted)
980b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      PrintTicks(optimized_ticks, ticks, "ticks in optimized code")
981b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      PrintTicks(generated_ticks, ticks, "ticks in other lazily compiled code")
982b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      PrintTicks(v8_internal_ticks, ticks, "ticks in v8::internal::*")
983f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d total symbols" % len([c for c in code_map.AllCode()])
984f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%10d used symbols" % len([c for c in code_map.UsedCode()])
985f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%9.2fs library processing time" % mmap_time
986f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch      print "%9.2fs tick processing time" % sample_time
987f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch
988f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  log_reader.Dispose()
989f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch  trace_reader.Dispose()
990