14a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#!/usr/bin/env python
24a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#
3f2038fb01417bcf7698b87a5dfaa4a861539618aerik.corry@gmail.com# Copyright 2012 the V8 project authors. All rights reserved.
44a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# Redistribution and use in source and binary forms, with or without
54a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# modification, are permitted provided that the following conditions are
64a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# met:
74a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#
84a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#     * Redistributions of source code must retain the above copyright
94a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#       notice, this list of conditions and the following disclaimer.
104a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#     * Redistributions in binary form must reproduce the above
114a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#       copyright notice, this list of conditions and the following
124a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#       disclaimer in the documentation and/or other materials provided
134a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#       with the distribution.
144a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#     * Neither the name of Google Inc. nor the names of its
154a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#       contributors may be used to endorse or promote products derived
164a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#       from this software without specific prior written permission.
174a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org#
184a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
194a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
204a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
214a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
224a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
234a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
244a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
254a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
264a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
274a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
284a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
294a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
304a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgimport bisect
314a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgimport collections
324a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgimport ctypes
333a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.orgimport disasm
344a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgimport mmap
354a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgimport optparse
364a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgimport os
374a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgimport re
384a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgimport subprocess
394a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgimport sys
404a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgimport time
414a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
424a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
434a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgUSAGE="""usage: %prog [OPTION]...
444a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
454a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgAnalyses V8 and perf logs to produce profiles.
464a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
474a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPerf logs can be collected using a command like:
485323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  $ perf record -R -e cycles -c 10000 -f -i ./d8 bench.js --ll-prof
494a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # -R: collect all data
504a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # -e cycles: use cpu-cycles event (run "perf list" for details)
514a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # -c 10000: write a sample after each 10000 events
524a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # -f: force output file overwrite
534a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # -i: limit profiling to our process and the kernel
544a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # --ll-prof shell flag enables the right V8 logs
554a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgThis will produce a binary trace file (perf.data) that %prog can analyse.
564a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
575323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.orgIMPORTANT:
585323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  The kernel has an internal maximum for events per second, it is 100K by
595323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  default. That's not enough for "-c 10000". Set it to some higher value:
605323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  $ echo 10000000 | sudo tee /proc/sys/kernel/perf_event_max_sample_rate
615323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  You can also make the warning about kernel address maps go away:
625323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  $ echo 0 | sudo tee /proc/sys/kernel/kptr_restrict
635323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org
645323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.orgWe have a convenience script that handles all of the above for you:
655323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  $ tools/run-llprof.sh ./d8 bench.js
665323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org
674a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgExamples:
684a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # Print flat profile with annotated disassembly for the 10 top
694a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # symbols. Use default log names and include the snapshot log.
704a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  $ %prog --snapshot --disasm-top=10
714a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
724a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # Print flat profile with annotated disassembly for all used symbols.
734a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # Use default log names and include kernel symbols into analysis.
744a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  $ %prog --disasm-all --kernel
754a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
764a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # Print flat profile. Use custom log names.
774a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  $ %prog --log=foo.log --snapshot-log=snap-foo.log --trace=foo.data --snapshot
784a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org"""
794a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
804a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
814a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgJS_ORIGIN = "js"
824a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgJS_SNAPSHOT_ORIGIN = "js-snapshot"
834a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
844a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgclass Code(object):
854a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  """Code object."""
864a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
874a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  _id = 0
885323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  UNKNOWN = 0
895323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  V8INTERNAL = 1
905323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  FULL_CODEGEN = 2
915323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  OPTIMIZED = 3
924a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
934a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def __init__(self, name, start_address, end_address, origin, origin_offset):
944a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.id = Code._id
954a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    Code._id += 1
964a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.name = name
974a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.other_names = None
984a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.start_address = start_address
994a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.end_address = end_address
1004a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.origin = origin
1014a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.origin_offset = origin_offset
1024a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.self_ticks = 0
1034a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.self_ticks_map = None
1044a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.callee_ticks = None
1055323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org    if name.startswith("LazyCompile:*"):
1065323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      self.codetype = Code.OPTIMIZED
1075323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org    elif name.startswith("LazyCompile:"):
1085323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      self.codetype = Code.FULL_CODEGEN
1095323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org    elif name.startswith("v8::internal::"):
1105323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      self.codetype = Code.V8INTERNAL
1115323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org    else:
1125323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      self.codetype = Code.UNKNOWN
1134a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
1144a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def AddName(self, name):
1154a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    assert self.name != name
1164a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if self.other_names is None:
1174a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      self.other_names = [name]
1184a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return
1194a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if not name in self.other_names:
1204a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      self.other_names.append(name)
1214a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
1224a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def FullName(self):
1234a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if self.other_names is None:
1244a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return self.name
1254a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.other_names.sort()
1264a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return "%s (aka %s)" % (self.name, ", ".join(self.other_names))
1274a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
1284a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def IsUsed(self):
1294a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return self.self_ticks > 0 or self.callee_ticks is not None
1304a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
1314a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Tick(self, pc):
1324a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.self_ticks += 1
1334a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if self.self_ticks_map is None:
1344a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      self.self_ticks_map = collections.defaultdict(lambda: 0)
1354a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    offset = pc - self.start_address
1364a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.self_ticks_map[offset] += 1
1374a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
1384a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def CalleeTick(self, callee):
1394a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if self.callee_ticks is None:
1404a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      self.callee_ticks = collections.defaultdict(lambda: 0)
1414a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.callee_ticks[callee] += 1
1424a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
1438e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  def PrintAnnotated(self, arch, options):
1444a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if self.self_ticks_map is None:
1454a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      ticks_map = []
1464a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    else:
1474a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      ticks_map = self.self_ticks_map.items()
1484a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # Convert the ticks map to offsets and counts arrays so that later
1494a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # we can do binary search in the offsets array.
1504a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    ticks_map.sort(key=lambda t: t[0])
1514a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    ticks_offsets = [t[0] for t in ticks_map]
1524a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    ticks_counts = [t[1] for t in ticks_map]
1534a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # Get a list of disassembled lines and their addresses.
1548e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    lines = self._GetDisasmLines(arch, options)
1554a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if len(lines) == 0:
1564a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return
1574a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # Print annotated lines.
1584a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    address = lines[0][0]
1594a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    total_count = 0
1604a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    for i in xrange(len(lines)):
1614a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      start_offset = lines[i][0] - address
1624a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if i == len(lines) - 1:
1634a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        end_offset = self.end_address - self.start_address
1644a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      else:
1654a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        end_offset = lines[i + 1][0] - address
1664a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      # Ticks (reported pc values) are not always precise, i.e. not
1674a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      # necessarily point at instruction starts. So we have to search
1684a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      # for ticks that touch the current instruction line.
1694a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      j = bisect.bisect_left(ticks_offsets, end_offset)
1704a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      count = 0
1714a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      for offset, cnt in reversed(zip(ticks_offsets[:j], ticks_counts[:j])):
1724a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if offset < start_offset:
1734a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          break
1744a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        count += cnt
1754a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      total_count += count
1764a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      count = 100.0 * count / self.self_ticks
1774a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if count >= 0.01:
1783a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org        print "%15.2f %x: %s" % (count, lines[i][0], lines[i][1])
1794a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      else:
1803a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org        print "%s %x: %s" % (" " * 15, lines[i][0], lines[i][1])
1814a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    print
1824a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    assert total_count == self.self_ticks, \
1834a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        "Lost ticks (%d != %d) in %s" % (total_count, self.self_ticks, self)
1844a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
1854a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def __str__(self):
1864a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return "%s [0x%x, 0x%x) size: %d origin: %s" % (
1874a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      self.name,
1884a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      self.start_address,
1894a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      self.end_address,
1904a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      self.end_address - self.start_address,
1914a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      self.origin)
1924a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
1938e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  def _GetDisasmLines(self, arch, options):
1944a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if self.origin == JS_ORIGIN or self.origin == JS_SNAPSHOT_ORIGIN:
1953a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org      inplace = False
1968e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      filename = options.log + ".ll"
1974a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    else:
1983a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org      inplace = True
1993a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org      filename = self.origin
2003a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org    return disasm.GetDisasmLines(filename,
2013a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org                                 self.origin_offset,
2023a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org                                 self.end_address - self.start_address,
2038e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org                                 arch,
2043a5fd78f0ca6c2827bb05f69a373d152a9ce6ff3fschneider@chromium.org                                 inplace)
2054a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2064a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2074a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgclass CodePage(object):
2084a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  """Group of adjacent code objects."""
2094a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2105323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  SHIFT = 20  # 1M pages
2114a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  SIZE = (1 << SHIFT)
2124a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  MASK = ~(SIZE - 1)
2134a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2144a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  @staticmethod
2154a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def PageAddress(address):
2164a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return address & CodePage.MASK
2174a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2184a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  @staticmethod
2194a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def PageId(address):
2204a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return address >> CodePage.SHIFT
2214a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2224a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  @staticmethod
2234a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def PageAddressFromId(id):
2244a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return id << CodePage.SHIFT
2254a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2264a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def __init__(self, address):
2274a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.address = address
2284a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.code_objects = []
2294a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2304a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Add(self, code):
2314a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.code_objects.append(code)
2324a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2334a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Remove(self, code):
2344a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.code_objects.remove(code)
2354a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2364a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Find(self, pc):
2374a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    code_objects = self.code_objects
2384a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    for i, code in enumerate(code_objects):
2394a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if code.start_address <= pc < code.end_address:
2404a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        code_objects[0], code_objects[i] = code, code_objects[0]
2414a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        return code
2424a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return None
2434a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2444a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def __iter__(self):
2454a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return self.code_objects.__iter__()
2464a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2474a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2484a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgclass CodeMap(object):
2494a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  """Code object map."""
2504a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2514a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def __init__(self):
2524a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.pages = {}
2534a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.min_address = 1 << 64
2544a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.max_address = -1
2554a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2564a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Add(self, code, max_pages=-1):
2574a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    page_id = CodePage.PageId(code.start_address)
2584a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1)
2594a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    pages = 0
2604a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    while page_id < limit_id:
2614a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if max_pages >= 0 and pages > max_pages:
2624a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        print >>sys.stderr, \
2634a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            "Warning: page limit (%d) reached for %s [%s]" % (
2644a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            max_pages, code.name, code.origin)
2654a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        break
2664a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if page_id in self.pages:
2674a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        page = self.pages[page_id]
2684a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      else:
2694a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        page = CodePage(CodePage.PageAddressFromId(page_id))
2704a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        self.pages[page_id] = page
2714a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      page.Add(code)
2724a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      page_id += 1
2734a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      pages += 1
2744a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.min_address = min(self.min_address, code.start_address)
2754a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.max_address = max(self.max_address, code.end_address)
2764a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2774a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Remove(self, code):
2784a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    page_id = CodePage.PageId(code.start_address)
2794a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1)
2804a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    removed = False
2814a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    while page_id < limit_id:
2824a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if page_id not in self.pages:
2834a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        page_id += 1
2844a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        continue
2854a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      page = self.pages[page_id]
2864a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      page.Remove(code)
2874a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      removed = True
2884a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      page_id += 1
2894a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return removed
2904a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2914a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def AllCode(self):
2924a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    for page in self.pages.itervalues():
2934a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      for code in page:
2944a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if CodePage.PageAddress(code.start_address) == page.address:
2954a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          yield code
2964a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
2974a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def UsedCode(self):
2984a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    for code in self.AllCode():
2994a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if code.IsUsed():
3004a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        yield code
3014a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3024a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Print(self):
3034a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    for code in self.AllCode():
3044a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print code
3054a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3064a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Find(self, pc):
3074a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if pc < self.min_address or pc >= self.max_address:
3084a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return None
3094a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    page_id = CodePage.PageId(pc)
3104a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if page_id not in self.pages:
3114a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return None
3124a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return self.pages[page_id].Find(pc)
3134a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3144a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3154a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgclass CodeInfo(object):
3164a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  """Generic info about generated code objects."""
3174a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3184a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def __init__(self, arch, header_size):
3194a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.arch = arch
3204a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.header_size = header_size
3214a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3224a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3238e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.orgclass SnapshotLogReader(object):
3248e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  """V8 snapshot log reader."""
3254a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3268e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  _SNAPSHOT_CODE_NAME_RE = re.compile(
3278e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    r"snapshot-code-name,(\d+),\"(.*)\"")
3284a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3298e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  def __init__(self, log_name):
3308e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    self.log_name = log_name
3318e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org
3328e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  def ReadNameMap(self):
3338e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    log = open(self.log_name, "r")
3348e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    try:
3358e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      snapshot_pos_to_name = {}
3368e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      for line in log:
3378e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        match = SnapshotLogReader._SNAPSHOT_CODE_NAME_RE.match(line)
3388e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        if match:
3398e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org          pos = int(match.group(1))
3408e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org          name = match.group(2)
3418e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org          snapshot_pos_to_name[pos] = name
3428e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    finally:
3438e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      log.close()
3448e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    return snapshot_pos_to_name
3454a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3464a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3478e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.orgclass LogReader(object):
3488e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  """V8 low-level (binary) log reader."""
3494a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3508e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  _ARCH_TO_POINTER_TYPE_MAP = {
3518e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    "ia32": ctypes.c_uint32,
3528e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    "arm": ctypes.c_uint32,
353c612e0211bdb8821cbd7886e15b0273ed82d2e9edanno@chromium.org    "mips": ctypes.c_uint32,
35408e7569a10f8edbb47b8fe70a6e160a4e0c9cd30machenbach@chromium.org    "x64": ctypes.c_uint64,
35508e7569a10f8edbb47b8fe70a6e160a4e0c9cd30machenbach@chromium.org    "arm64": ctypes.c_uint64
3568e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  }
3574a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3588e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  _CODE_CREATE_TAG = "C"
3598e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  _CODE_MOVE_TAG = "M"
3608e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  _CODE_DELETE_TAG = "D"
3618e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  _SNAPSHOT_POSITION_TAG = "P"
3628e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  _CODE_MOVING_GC_TAG = "G"
3634a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3648e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  def __init__(self, log_name, code_map, snapshot_pos_to_name):
3658e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    self.log_file = open(log_name, "r")
3668e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    self.log = mmap.mmap(self.log_file.fileno(), 0, mmap.MAP_PRIVATE)
3678e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    self.log_pos = 0
3684a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.code_map = code_map
3694a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.snapshot_pos_to_name = snapshot_pos_to_name
3704a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.address_to_snapshot_name = {}
3714a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
3728e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    self.arch = self.log[:self.log.find("\0")]
3738e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    self.log_pos += len(self.arch) + 1
3748e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    assert self.arch in LogReader._ARCH_TO_POINTER_TYPE_MAP, \
3758e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        "Unsupported architecture %s" % self.arch
3768e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    pointer_type = LogReader._ARCH_TO_POINTER_TYPE_MAP[self.arch]
3778e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org
3788e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    self.code_create_struct = LogReader._DefineStruct([
3798e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        ("name_size", ctypes.c_int32),
3808e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        ("code_address", pointer_type),
3818e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        ("code_size", ctypes.c_int32)])
3828e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org
3838e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    self.code_move_struct = LogReader._DefineStruct([
3848e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        ("from_address", pointer_type),
3858e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        ("to_address", pointer_type)])
3868e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org
3878e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    self.code_delete_struct = LogReader._DefineStruct([
3888e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        ("address", pointer_type)])
3898e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org
3908e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    self.snapshot_position_struct = LogReader._DefineStruct([
3918e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        ("address", pointer_type),
3928e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        ("position", ctypes.c_int32)])
3938e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org
3948e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  def ReadUpToGC(self):
3958e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    while self.log_pos < self.log.size():
3968e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      tag = self.log[self.log_pos]
3978e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      self.log_pos += 1
3988e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org
3998e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      if tag == LogReader._CODE_MOVING_GC_TAG:
4004a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        self.address_to_snapshot_name.clear()
4018e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        return
4024a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
4038e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      if tag == LogReader._CODE_CREATE_TAG:
4048e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        event = self.code_create_struct.from_buffer(self.log, self.log_pos)
4058e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        self.log_pos += ctypes.sizeof(event)
4068e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        start_address = event.code_address
4078e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        end_address = start_address + event.code_size
4084a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if start_address in self.address_to_snapshot_name:
4094a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          name = self.address_to_snapshot_name[start_address]
4104a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          origin = JS_SNAPSHOT_ORIGIN
4114a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        else:
4128e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org          name = self.log[self.log_pos:self.log_pos + event.name_size]
4134a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          origin = JS_ORIGIN
4148e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        self.log_pos += event.name_size
4158e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        origin_offset = self.log_pos
4168e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        self.log_pos += event.code_size
4174a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        code = Code(name, start_address, end_address, origin, origin_offset)
4184a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        conficting_code = self.code_map.Find(start_address)
4194a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if conficting_code:
420c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com          if not (conficting_code.start_address == code.start_address and
421c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com            conficting_code.end_address == code.end_address):
422c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com            self.code_map.Remove(conficting_code)
423c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com          else:
424c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com            LogReader._HandleCodeConflict(conficting_code, code)
425c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com            # TODO(vitalyr): this warning is too noisy because of our
426c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com            # attempts to reconstruct code log from the snapshot.
427c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com            # print >>sys.stderr, \
428c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com            #     "Warning: Skipping duplicate code log entry %s" % code
429c3b670ff19220959730d7886892bc4beb95d2ebaerik.corry@gmail.com            continue
4304a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        self.code_map.Add(code)
4314a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        continue
4324a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
4338e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      if tag == LogReader._CODE_MOVE_TAG:
4348e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        event = self.code_move_struct.from_buffer(self.log, self.log_pos)
4358e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        self.log_pos += ctypes.sizeof(event)
4368e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        old_start_address = event.from_address
4378e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        new_start_address = event.to_address
4384a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if old_start_address == new_start_address:
4394a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          # Skip useless code move entries.
4404a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          continue
4414a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        code = self.code_map.Find(old_start_address)
4424a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if not code:
4434a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          print >>sys.stderr, "Warning: Not found %x" % old_start_address
4444a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          continue
4454a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        assert code.start_address == old_start_address, \
4464a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            "Inexact move address %x for %s" % (old_start_address, code)
4474a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        self.code_map.Remove(code)
4484a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        size = code.end_address - code.start_address
4494a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        code.start_address = new_start_address
4504a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        code.end_address = new_start_address + size
4514a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        self.code_map.Add(code)
4524a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        continue
4534a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
4548e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      if tag == LogReader._CODE_DELETE_TAG:
4558e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        event = self.code_delete_struct.from_buffer(self.log, self.log_pos)
4568e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        self.log_pos += ctypes.sizeof(event)
4578e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        old_start_address = event.address
4584a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        code = self.code_map.Find(old_start_address)
4594a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if not code:
4604a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          print >>sys.stderr, "Warning: Not found %x" % old_start_address
4614a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          continue
4624a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        assert code.start_address == old_start_address, \
4634a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            "Inexact delete address %x for %s" % (old_start_address, code)
4644a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        self.code_map.Remove(code)
4654a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        continue
4664a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
4678e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      if tag == LogReader._SNAPSHOT_POSITION_TAG:
4688e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        event = self.snapshot_position_struct.from_buffer(self.log,
4698e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org                                                          self.log_pos)
4708e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        self.log_pos += ctypes.sizeof(event)
4718e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        start_address = event.address
4728e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        snapshot_pos = event.position
4738e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        if snapshot_pos in self.snapshot_pos_to_name:
4748e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org          self.address_to_snapshot_name[start_address] = \
4758e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org              self.snapshot_pos_to_name[snapshot_pos]
4768e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        continue
4778e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org
4788e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      assert False, "Unknown tag %s" % tag
4794a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
4804a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Dispose(self):
4814a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.log.close()
4828e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    self.log_file.close()
4838e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org
4848e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  @staticmethod
4858e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  def _DefineStruct(fields):
4868e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    class Struct(ctypes.Structure):
4878e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      _fields_ = fields
4888e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    return Struct
4894a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
4904a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  @staticmethod
4914a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def _HandleCodeConflict(old_code, new_code):
4924a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    assert (old_code.start_address == new_code.start_address and
4934a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            old_code.end_address == new_code.end_address), \
4944a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        "Conficting code log entries %s and %s" % (old_code, new_code)
4954a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if old_code.name == new_code.name:
4964a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return
4974a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # Code object may be shared by a few functions. Collect the full
4984a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # set of names.
4994a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    old_code.AddName(new_code.name)
5004a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5014a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5024a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgclass Descriptor(object):
5034a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  """Descriptor of a structure in the binary trace log."""
5044a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5054a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  CTYPE_MAP = {
5064a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    "u16": ctypes.c_uint16,
5074a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    "u32": ctypes.c_uint32,
5084a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    "u64": ctypes.c_uint64
5094a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  }
5104a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5114a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def __init__(self, fields):
5124a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    class TraceItem(ctypes.Structure):
5134a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      _fields_ = Descriptor.CtypesFields(fields)
5144a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5154a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      def __str__(self):
5164a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        return ", ".join("%s: %s" % (field, self.__getattribute__(field))
5174a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                         for field, _ in TraceItem._fields_)
5184a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5194a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.ctype = TraceItem
5204a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5214a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Read(self, trace, offset):
5224a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return self.ctype.from_buffer(trace, offset)
5234a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5244a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  @staticmethod
5254a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def CtypesFields(fields):
5264a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return [(field, Descriptor.CTYPE_MAP[format]) for (field, format) in fields]
5274a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5284a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5294a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# Please see http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=tree;f=tools/perf
5304a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# for the gory details.
5314a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5324a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5335323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org# Reference: struct perf_file_header in kernel/tools/perf/util/header.h
5344a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgTRACE_HEADER_DESC = Descriptor([
5354a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("magic", "u64"),
5364a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("size", "u64"),
5374a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("attr_size", "u64"),
5384a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("attrs_offset", "u64"),
5394a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("attrs_size", "u64"),
5404a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("data_offset", "u64"),
5414a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("data_size", "u64"),
5424a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("event_types_offset", "u64"),
5434a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("event_types_size", "u64")
5444a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org])
5454a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5464a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5475323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org# Reference: /usr/include/linux/perf_event.h
5484a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_EVENT_ATTR_DESC = Descriptor([
5494a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("type", "u32"),
5504a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("size", "u32"),
5514a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("config", "u64"),
5524a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("sample_period_or_freq", "u64"),
5534a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("sample_type", "u64"),
5544a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("read_format", "u64"),
5554a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("flags", "u64"),
5564a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("wakeup_events_or_watermark", "u32"),
5575323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  ("bp_type", "u32"),
5584a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("bp_addr", "u64"),
5595323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  ("bp_len", "u64")
5604a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org])
5614a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5624a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5635323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org# Reference: /usr/include/linux/perf_event.h
5644a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_EVENT_HEADER_DESC = Descriptor([
5654a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("type", "u32"),
5664a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("misc", "u16"),
5674a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("size", "u16")
5684a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org])
5694a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5704a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5715323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org# Reference: kernel/events/core.c
5724a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_MMAP_EVENT_BODY_DESC = Descriptor([
5734a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("pid", "u32"),
5744a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("tid", "u32"),
5754a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("addr", "u64"),
5764a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("len", "u64"),
5774a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("pgoff", "u64")
5784a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org])
5794a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5804a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5814a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# perf_event_attr.sample_type bits control the set of
5824a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org# perf_sample_event fields.
5834a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_IP = 1 << 0
5844a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_TID = 1 << 1
5854a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_TIME = 1 << 2
5864a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_ADDR = 1 << 3
5874a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_READ = 1 << 4
5884a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_CALLCHAIN = 1 << 5
5894a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_ID = 1 << 6
5904a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_CPU = 1 << 7
5914a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_PERIOD = 1 << 8
5924a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_STREAM_ID = 1 << 9
5934a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_RAW = 1 << 10
5944a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5954a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
5965323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org# Reference: /usr/include/perf_event.h, the comment for PERF_RECORD_SAMPLE.
5974a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_EVENT_BODY_FIELDS = [
5984a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("ip", "u64", PERF_SAMPLE_IP),
5994a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("pid", "u32", PERF_SAMPLE_TID),
6004a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("tid", "u32", PERF_SAMPLE_TID),
6014a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("time", "u64", PERF_SAMPLE_TIME),
6024a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("addr", "u64", PERF_SAMPLE_ADDR),
6034a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("id", "u64", PERF_SAMPLE_ID),
6044a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("stream_id", "u64", PERF_SAMPLE_STREAM_ID),
6054a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("cpu", "u32", PERF_SAMPLE_CPU),
6064a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("res", "u32", PERF_SAMPLE_CPU),
6074a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("period", "u64", PERF_SAMPLE_PERIOD),
6084a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # Don't want to handle read format that comes after the period and
6094a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # before the callchain and has variable size.
6104a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ("nr", "u64", PERF_SAMPLE_CALLCHAIN)
6114a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # Raw data follows the callchain and is ignored.
6124a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org]
6134a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6144a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6154a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_SAMPLE_EVENT_IP_FORMAT = "u64"
6164a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6174a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6184a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_RECORD_MMAP = 1
6194a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_RECORD_SAMPLE = 9
6204a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6214a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6224a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgclass TraceReader(object):
6234a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  """Perf (linux-2.6/tools/perf) trace file reader."""
6244a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6254a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  _TRACE_HEADER_MAGIC = 4993446653023372624
6264a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6274a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def __init__(self, trace_name):
6284a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.trace_file = open(trace_name, "r")
6294a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.trace = mmap.mmap(self.trace_file.fileno(), 0, mmap.MAP_PRIVATE)
6304a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.trace_header = TRACE_HEADER_DESC.Read(self.trace, 0)
6314a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if self.trace_header.magic != TraceReader._TRACE_HEADER_MAGIC:
6324a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print >>sys.stderr, "Warning: unsupported trace header magic"
6334a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.offset = self.trace_header.data_offset
6344a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.limit = self.trace_header.data_offset + self.trace_header.data_size
6354a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    assert self.limit <= self.trace.size(), \
6364a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        "Trace data limit exceeds trace file size"
6374a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.header_size = ctypes.sizeof(PERF_EVENT_HEADER_DESC.ctype)
6384a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    assert self.trace_header.attrs_size != 0, \
6394a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        "No perf event attributes found in the trace"
6404a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    perf_event_attr = PERF_EVENT_ATTR_DESC.Read(self.trace,
6414a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                                                self.trace_header.attrs_offset)
6424a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.sample_event_body_desc = self._SampleEventBodyDesc(
6434a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        perf_event_attr.sample_type)
6444a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.callchain_supported = \
6454a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        (perf_event_attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0
6464a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if self.callchain_supported:
6474a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      self.ip_struct = Descriptor.CTYPE_MAP[PERF_SAMPLE_EVENT_IP_FORMAT]
6484a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      self.ip_size = ctypes.sizeof(self.ip_struct)
6494a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6504a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def ReadEventHeader(self):
6514a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if self.offset >= self.limit:
6524a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return None, 0
6534a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    offset = self.offset
6544a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    header = PERF_EVENT_HEADER_DESC.Read(self.trace, self.offset)
6554a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.offset += header.size
6564a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return header, offset
6574a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6584a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def ReadMmap(self, header, offset):
6594a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    mmap_info = PERF_MMAP_EVENT_BODY_DESC.Read(self.trace,
6604a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                                               offset + self.header_size)
6614f693d6b99ffdbc05e5e211e08ed5039e13279d2ricow@chromium.org    # Read null-terminated filename.
6624a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info):
6634f693d6b99ffdbc05e5e211e08ed5039e13279d2ricow@chromium.org                          offset + header.size]
664de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org    mmap_info.filename = HOST_ROOT + filename[:filename.find(chr(0))]
6654a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return mmap_info
6664a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6674a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def ReadSample(self, header, offset):
6684a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    sample = self.sample_event_body_desc.Read(self.trace,
6694a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                                              offset + self.header_size)
6704a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if not self.callchain_supported:
6714a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return sample
6724a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    sample.ips = []
6734a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    offset += self.header_size + ctypes.sizeof(sample)
6744a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    for _ in xrange(sample.nr):
6754a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      sample.ips.append(
6764a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        self.ip_struct.from_buffer(self.trace, offset).value)
6774a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      offset += self.ip_size
6784a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return sample
6794a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6804a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Dispose(self):
6814a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.trace.close()
6824a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.trace_file.close()
6834a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6844a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def _SampleEventBodyDesc(self, sample_type):
6854a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    assert (sample_type & PERF_SAMPLE_READ) == 0, \
6864a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org           "Can't hande read format in samples"
6874a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    fields = [(field, format)
6884a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org              for (field, format, bit) in PERF_SAMPLE_EVENT_BODY_FIELDS
6894a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org              if (bit & sample_type) != 0]
6904a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return Descriptor(fields)
6914a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6924a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
6934a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgOBJDUMP_SECTION_HEADER_RE = re.compile(
6944a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  r"^\s*\d+\s(\.\S+)\s+[a-f0-9]")
6954a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgOBJDUMP_SYMBOL_LINE_RE = re.compile(
6964a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  r"^([a-f0-9]+)\s(.{7})\s(\S+)\s+([a-f0-9]+)\s+(?:\.hidden\s+)?(.*)$")
6974a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgOBJDUMP_DYNAMIC_SYMBOLS_START_RE = re.compile(
698f2038fb01417bcf7698b87a5dfaa4a861539618aerik.corry@gmail.com  r"^DYNAMIC SYMBOL TABLE")
699f2038fb01417bcf7698b87a5dfaa4a861539618aerik.corry@gmail.comOBJDUMP_SKIP_RE = re.compile(
700f2038fb01417bcf7698b87a5dfaa4a861539618aerik.corry@gmail.com  r"^.*ld\.so\.cache$")
7014a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgKERNEL_ALLSYMS_FILE = "/proc/kallsyms"
7024a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgPERF_KERNEL_ALLSYMS_RE = re.compile(
7034a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  r".*kallsyms.*")
7044a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgKERNEL_ALLSYMS_LINE_RE = re.compile(
7054a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  r"^([a-f0-9]+)\s(?:t|T)\s(\S+)$")
7064a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
7074a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
7084a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgclass LibraryRepo(object):
7094a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def __init__(self):
7104a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.infos = []
7114a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.names = set()
7124a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.ticks = {}
7134a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
7144a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Load(self, mmap_info, code_map, options):
7154a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # Skip kernel mmaps when requested using the fact that their tid
7164a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # is 0.
7174a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if mmap_info.tid == 0 and not options.kernel:
7184a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return True
719f2038fb01417bcf7698b87a5dfaa4a861539618aerik.corry@gmail.com    if OBJDUMP_SKIP_RE.match(mmap_info.filename):
720f2038fb01417bcf7698b87a5dfaa4a861539618aerik.corry@gmail.com      return True
7214a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if PERF_KERNEL_ALLSYMS_RE.match(mmap_info.filename):
7224a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return self._LoadKernelSymbols(code_map)
7234a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.infos.append(mmap_info)
7244a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    mmap_info.ticks = 0
7254a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    mmap_info.unique_name = self._UniqueMmapName(mmap_info)
7264a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if not os.path.exists(mmap_info.filename):
7274a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return True
7284a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # Request section headers (-h), symbols (-t), and dynamic symbols
7294a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # (-T) from objdump.
7304a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # Unfortunately, section headers span two lines, so we have to
7314a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # keep the just seen section name (from the first line in each
7324a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    # section header) in the after_section variable.
7335323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org    if mmap_info.filename.endswith(".ko"):
7345323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      dynamic_symbols = ""
7355323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org    else:
7365323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      dynamic_symbols = "-T"
7374a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    process = subprocess.Popen(
7385323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      "%s -h -t %s -C %s" % (OBJDUMP_BIN, dynamic_symbols, mmap_info.filename),
7394a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
7404a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    pipe = process.stdout
7414a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    after_section = None
7424a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    code_sections = set()
7434a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    reloc_sections = set()
7444a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    dynamic = False
7454a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    try:
7464a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      for line in pipe:
7474a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if after_section:
7484a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          if line.find("CODE") != -1:
7494a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            code_sections.add(after_section)
7504a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          if line.find("RELOC") != -1:
7514a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            reloc_sections.add(after_section)
7524a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          after_section = None
7534a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          continue
7544a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
7554a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        match = OBJDUMP_SECTION_HEADER_RE.match(line)
7564a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if match:
7574a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          after_section = match.group(1)
7584a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          continue
7594a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
7604a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if OBJDUMP_DYNAMIC_SYMBOLS_START_RE.match(line):
7614a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          dynamic = True
7624a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          continue
7634a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
7644a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        match = OBJDUMP_SYMBOL_LINE_RE.match(line)
7654a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if match:
7664a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          start_address = int(match.group(1), 16)
7674a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          origin_offset = start_address
7684a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          flags = match.group(2)
7694a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          section = match.group(3)
7704a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          if section in code_sections:
7714a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            if dynamic or section in reloc_sections:
7724a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org              start_address += mmap_info.addr
7734a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            size = int(match.group(4), 16)
7744a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            name = match.group(5)
7754a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            origin = mmap_info.filename
7764a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            code_map.Add(Code(name, start_address, start_address + size,
7774a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                              origin, origin_offset))
7784a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    finally:
7794a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      pipe.close()
7804a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    assert process.wait() == 0, "Failed to objdump %s" % mmap_info.filename
7814a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
7824a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def Tick(self, pc):
7834a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    for i, mmap_info in enumerate(self.infos):
7844a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if mmap_info.addr <= pc < (mmap_info.addr + mmap_info.len):
7854a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        mmap_info.ticks += 1
7864a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        self.infos[0], self.infos[i] = mmap_info, self.infos[0]
7874a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        return True
7884a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return False
7894a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
7904a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def _UniqueMmapName(self, mmap_info):
7914a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    name = mmap_info.filename
7924a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    index = 1
7934a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    while name in self.names:
7944a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      name = "%s-%d" % (mmap_info.filename, index)
7954a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      index += 1
7964a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    self.names.add(name)
7974a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return name
7984a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
7994a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  def _LoadKernelSymbols(self, code_map):
8004a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if not os.path.exists(KERNEL_ALLSYMS_FILE):
8014a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print >>sys.stderr, "Warning: %s not found" % KERNEL_ALLSYMS_FILE
8024a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      return False
8034a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    kallsyms = open(KERNEL_ALLSYMS_FILE, "r")
8044a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    code = None
8054a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    for line in kallsyms:
8064a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      match = KERNEL_ALLSYMS_LINE_RE.match(line)
8074a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if match:
8084a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        start_address = int(match.group(1), 16)
8094a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        end_address = start_address
8104a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        name = match.group(2)
8114a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        if code:
8124a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          code.end_address = start_address
8134a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          code_map.Add(code, 16)
8144a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        code = Code(name, start_address, end_address, "kernel", 0)
8154a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    return True
8164a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
8174a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
818ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.orgdef PrintReport(code_map, library_repo, arch, ticks, options):
8194a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  print "Ticks per symbol:"
8204a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  used_code = [code for code in code_map.UsedCode()]
8214a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  used_code.sort(key=lambda x: x.self_ticks, reverse=True)
8224a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  for i, code in enumerate(used_code):
823ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org    code_ticks = code.self_ticks
824ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org    print "%10d %5.1f%% %s [%s]" % (code_ticks, 100. * code_ticks / ticks,
825ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org                                    code.FullName(), code.origin)
8264a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if options.disasm_all or i < options.disasm_top:
8278e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      code.PrintAnnotated(arch, options)
8284a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  print
8294a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  print "Ticks per library:"
8305323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  mmap_infos = [m for m in library_repo.infos if m.ticks > 0]
8314a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  mmap_infos.sort(key=lambda m: m.ticks, reverse=True)
8324a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  for mmap_info in mmap_infos:
833ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org    mmap_ticks = mmap_info.ticks
834ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org    print "%10d %5.1f%% %s" % (mmap_ticks, 100. * mmap_ticks / ticks,
835ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org                               mmap_info.unique_name)
8364a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
8374a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
8384a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgdef PrintDot(code_map, options):
8394a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  print "digraph G {"
8404a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  for code in code_map.UsedCode():
8414a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if code.self_ticks < 10:
8424a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      continue
8434a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    print "n%d [shape=box,label=\"%s\"];" % (code.id, code.name)
8444a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if code.callee_ticks:
8454a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      for callee, ticks in code.callee_ticks.iteritems():
8464a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        print "n%d -> n%d [label=\"%d\"];" % (code.id, callee.id, ticks)
8474a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  print "}"
8484a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
8494a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
8504a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.orgif __name__ == "__main__":
8514a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  parser = optparse.OptionParser(USAGE)
8524a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  parser.add_option("--snapshot-log",
8534a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    default="obj/release/snapshot.log",
8544a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    help="V8 snapshot log file name [default: %default]")
8554a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  parser.add_option("--log",
8564a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    default="v8.log",
8574a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    help="V8 log file name [default: %default]")
8584a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  parser.add_option("--snapshot",
8594a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    default=False,
8604a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    action="store_true",
8614a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    help="process V8 snapshot log [default: %default]")
8624a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  parser.add_option("--trace",
8634a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    default="perf.data",
8644a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    help="perf trace file name [default: %default]")
8654a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  parser.add_option("--kernel",
8664a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    default=False,
8674a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    action="store_true",
8684a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    help="process kernel entries [default: %default]")
8694a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  parser.add_option("--disasm-top",
8704a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    default=0,
8714a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    type="int",
8724a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    help=("number of top symbols to disassemble and annotate "
8734a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                          "[default: %default]"))
8744a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  parser.add_option("--disasm-all",
8754a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    default=False,
8764a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    action="store_true",
8774a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    help=("disassemble and annotate all used symbols "
8784a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                          "[default: %default]"))
8794a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  parser.add_option("--dot",
8804a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    default=False,
8814a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    action="store_true",
8824a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    help="produce dot output (WIP) [default: %default]")
8834a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  parser.add_option("--quiet", "-q",
8844a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    default=False,
8854a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    action="store_true",
8864a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org                    help="no auxiliary messages [default: %default]")
887de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org  parser.add_option("--gc-fake-mmap",
888de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org                    default="/tmp/__v8_gc__",
889de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org                    help="gc fake mmap file [default: %default]")
890de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org  parser.add_option("--objdump",
891de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org                    default="/usr/bin/objdump",
892de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org                    help="objdump tool to use [default: %default]")
893de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org  parser.add_option("--host-root",
894de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org                    default="",
895de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org                    help="Path to the host root [default: %default]")
8964a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  options, args = parser.parse_args()
8974a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
8984a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  if not options.quiet:
8994a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if options.snapshot:
9008e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      print "V8 logs: %s, %s, %s.ll" % (options.snapshot_log,
9018e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org                                        options.log,
9028e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org                                        options.log)
9034a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    else:
9048e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org      print "V8 log: %s, %s.ll (no snapshot)" % (options.log, options.log)
9054a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    print "Perf trace file: %s" % options.trace
9064a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
907de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org  V8_GC_FAKE_MMAP = options.gc_fake_mmap
908de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org  HOST_ROOT = options.host_root
909de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org  if os.path.exists(options.objdump):
910de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org    disasm.OBJDUMP_BIN = options.objdump
911de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org    OBJDUMP_BIN = options.objdump
912de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org  else:
913de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org    print "Cannot find %s, falling back to default objdump" % options.objdump
914de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org
9154a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # Stats.
9164a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  events = 0
9174a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  ticks = 0
9184a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  missed_ticks = 0
9194a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  really_missed_ticks = 0
9205323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  optimized_ticks = 0
9215323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  generated_ticks = 0
9225323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org  v8_internal_ticks = 0
9234a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  mmap_time = 0
9244a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  sample_time = 0
9254a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
9268e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  # Process the snapshot log to fill the snapshot name map.
9274a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  snapshot_name_map = {}
9288e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  if options.snapshot:
9298e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    snapshot_log_reader = SnapshotLogReader(log_name=options.snapshot_log)
9308e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    snapshot_name_map = snapshot_log_reader.ReadNameMap()
9318e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org
9328e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  # Initialize the log reader.
9338e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  code_map = CodeMap()
9348e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  log_reader = LogReader(log_name=options.log + ".ll",
9358e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org                         code_map=code_map,
9368e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org                         snapshot_pos_to_name=snapshot_name_map)
9374a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  if not options.quiet:
9388e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org    print "Generated code architecture: %s" % log_reader.arch
9394a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    print
940ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org    sys.stdout.flush()
9414a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
9424a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  # Process the code and trace logs.
9434a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  library_repo = LibraryRepo()
9448e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org  log_reader.ReadUpToGC()
9454a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  trace_reader = TraceReader(options.trace)
9464a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  while True:
9474a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    header, offset = trace_reader.ReadEventHeader()
9484a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if not header:
9494a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      break
9504a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    events += 1
9514a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if header.type == PERF_RECORD_MMAP:
9524a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      start = time.time()
9534a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      mmap_info = trace_reader.ReadMmap(header, offset)
954de88679a78f9dae12fdf7955610969ac4c79b0bemstarzinger@chromium.org      if mmap_info.filename == HOST_ROOT + V8_GC_FAKE_MMAP:
9558e8294a88dc7d58f579aee0ba08c19fc8a616e2dsgjesse@chromium.org        log_reader.ReadUpToGC()
9564a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      else:
9574a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        library_repo.Load(mmap_info, code_map, options)
9584a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      mmap_time += time.time() - start
9594a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    elif header.type == PERF_RECORD_SAMPLE:
9604a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      ticks += 1
9614a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      start = time.time()
9624a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      sample = trace_reader.ReadSample(header, offset)
9634a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      code = code_map.Find(sample.ip)
9644a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if code:
9654a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        code.Tick(sample.ip)
9665323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org        if code.codetype == Code.OPTIMIZED:
9675323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org          optimized_ticks += 1
9685323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org        elif code.codetype == Code.FULL_CODEGEN:
9695323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org          generated_ticks += 1
9705323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org        elif code.codetype == Code.V8INTERNAL:
9715323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org          v8_internal_ticks += 1
9724a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      else:
9734a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        missed_ticks += 1
9744a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if not library_repo.Tick(sample.ip) and not code:
9754a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        really_missed_ticks += 1
9764a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      if trace_reader.callchain_supported:
9774a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org        for ip in sample.ips:
9784a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          caller_code = code_map.Find(ip)
9794a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org          if caller_code:
9804a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            if code:
9814a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org              caller_code.CalleeTick(code)
9824a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org            code = caller_code
9834a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      sample_time += time.time() - start
9844a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
9854a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  if options.dot:
9864a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    PrintDot(code_map, options)
9874a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  else:
988ea91cc579ade536e3a08498a8157921dd4f533d1ager@chromium.org    PrintReport(code_map, library_repo, log_reader.arch, ticks, options)
9894a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
9904a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org    if not options.quiet:
9915323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      def PrintTicks(number, total, description):
9925323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org        print("%10d %5.1f%% ticks in %s" %
9935323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org              (number, 100.0*number/total, description))
9944a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print
9954a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print "Stats:"
9964a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print "%10d total trace events" % events
9974a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print "%10d total ticks" % ticks
9984a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print "%10d ticks not in symbols" % missed_ticks
9995323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      unaccounted = "unaccounted ticks"
10005323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      if really_missed_ticks > 0:
10015323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org        unaccounted += " (probably in the kernel, try --kernel)"
10025323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      PrintTicks(really_missed_ticks, ticks, unaccounted)
10035323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      PrintTicks(optimized_ticks, ticks, "ticks in optimized code")
10045323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      PrintTicks(generated_ticks, ticks, "ticks in other lazily compiled code")
10055323a9c29497eb5a52821d396990c6d75a37baf7jkummerow@chromium.org      PrintTicks(v8_internal_ticks, ticks, "ticks in v8::internal::*")
10064a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print "%10d total symbols" % len([c for c in code_map.AllCode()])
10074a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print "%10d used symbols" % len([c for c in code_map.UsedCode()])
10084a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print "%9.2fs library processing time" % mmap_time
10094a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org      print "%9.2fs tick processing time" % sample_time
10104a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org
10114a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  log_reader.Dispose()
10124a5224e84636d192e82f288bfab0d308bdae5c37whesse@chromium.org  trace_reader.Dispose()
1013