11cb0ef41Sopenharmony_ci#!/usr/bin/env python
21cb0ef41Sopenharmony_ci#
31cb0ef41Sopenharmony_ci# Copyright 2012 the V8 project authors. All rights reserved.
41cb0ef41Sopenharmony_ci# Redistribution and use in source and binary forms, with or without
51cb0ef41Sopenharmony_ci# modification, are permitted provided that the following conditions are
61cb0ef41Sopenharmony_ci# met:
71cb0ef41Sopenharmony_ci#
81cb0ef41Sopenharmony_ci#     * Redistributions of source code must retain the above copyright
91cb0ef41Sopenharmony_ci#       notice, this list of conditions and the following disclaimer.
101cb0ef41Sopenharmony_ci#     * Redistributions in binary form must reproduce the above
111cb0ef41Sopenharmony_ci#       copyright notice, this list of conditions and the following
121cb0ef41Sopenharmony_ci#       disclaimer in the documentation and/or other materials provided
131cb0ef41Sopenharmony_ci#       with the distribution.
141cb0ef41Sopenharmony_ci#     * Neither the name of Google Inc. nor the names of its
151cb0ef41Sopenharmony_ci#       contributors may be used to endorse or promote products derived
161cb0ef41Sopenharmony_ci#       from this software without specific prior written permission.
171cb0ef41Sopenharmony_ci#
181cb0ef41Sopenharmony_ci# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
191cb0ef41Sopenharmony_ci# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
201cb0ef41Sopenharmony_ci# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
211cb0ef41Sopenharmony_ci# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
221cb0ef41Sopenharmony_ci# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
231cb0ef41Sopenharmony_ci# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
241cb0ef41Sopenharmony_ci# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
251cb0ef41Sopenharmony_ci# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
261cb0ef41Sopenharmony_ci# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
271cb0ef41Sopenharmony_ci# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
281cb0ef41Sopenharmony_ci# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci# for py2/py3 compatibility
321cb0ef41Sopenharmony_cifrom __future__ import print_function
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ciimport bisect
351cb0ef41Sopenharmony_ciimport collections
361cb0ef41Sopenharmony_ciimport ctypes
371cb0ef41Sopenharmony_ciimport disasm
381cb0ef41Sopenharmony_ciimport mmap
391cb0ef41Sopenharmony_ciimport optparse
401cb0ef41Sopenharmony_ciimport os
411cb0ef41Sopenharmony_ciimport re
421cb0ef41Sopenharmony_ciimport subprocess
431cb0ef41Sopenharmony_ciimport sys
441cb0ef41Sopenharmony_ciimport time
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ciUSAGE="""usage: %prog [OPTION]...
481cb0ef41Sopenharmony_ci
491cb0ef41Sopenharmony_ciAnalyses V8 and perf logs to produce profiles.
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_ciPerf logs can be collected using a command like:
521cb0ef41Sopenharmony_ci  $ perf record -R -e cycles -c 10000 -f -i ./d8 bench.js --ll-prof
531cb0ef41Sopenharmony_ci  # -R: collect all data
541cb0ef41Sopenharmony_ci  # -e cycles: use cpu-cycles event (run "perf list" for details)
551cb0ef41Sopenharmony_ci  # -c 10000: write a sample after each 10000 events
561cb0ef41Sopenharmony_ci  # -f: force output file overwrite
571cb0ef41Sopenharmony_ci  # -i: limit profiling to our process and the kernel
581cb0ef41Sopenharmony_ci  # --ll-prof shell flag enables the right V8 logs
591cb0ef41Sopenharmony_ciThis will produce a binary trace file (perf.data) that %prog can analyse.
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ciIMPORTANT:
621cb0ef41Sopenharmony_ci  The kernel has an internal maximum for events per second, it is 100K by
631cb0ef41Sopenharmony_ci  default. That's not enough for "-c 10000". Set it to some higher value:
641cb0ef41Sopenharmony_ci  $ echo 10000000 | sudo tee /proc/sys/kernel/perf_event_max_sample_rate
651cb0ef41Sopenharmony_ci  You can also make the warning about kernel address maps go away:
661cb0ef41Sopenharmony_ci  $ echo 0 | sudo tee /proc/sys/kernel/kptr_restrict
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ciWe have a convenience script that handles all of the above for you:
691cb0ef41Sopenharmony_ci  $ tools/run-llprof.sh ./d8 bench.js
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ciExamples:
721cb0ef41Sopenharmony_ci  # Print flat profile with annotated disassembly for the 10 top
731cb0ef41Sopenharmony_ci  # symbols. Use default log names.
741cb0ef41Sopenharmony_ci  $ %prog --disasm-top=10
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci  # Print flat profile with annotated disassembly for all used symbols.
771cb0ef41Sopenharmony_ci  # Use default log names and include kernel symbols into analysis.
781cb0ef41Sopenharmony_ci  $ %prog --disasm-all --kernel
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci  # Print flat profile. Use custom log names.
811cb0ef41Sopenharmony_ci  $ %prog --log=foo.log --trace=foo.data
821cb0ef41Sopenharmony_ci"""
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ciJS_ORIGIN = "js"
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ciclass Code(object):
891cb0ef41Sopenharmony_ci  """Code object."""
901cb0ef41Sopenharmony_ci
911cb0ef41Sopenharmony_ci  _id = 0
921cb0ef41Sopenharmony_ci  UNKNOWN = 0
931cb0ef41Sopenharmony_ci  V8INTERNAL = 1
941cb0ef41Sopenharmony_ci  FULL_CODEGEN = 2
951cb0ef41Sopenharmony_ci  OPTIMIZED = 3
961cb0ef41Sopenharmony_ci
971cb0ef41Sopenharmony_ci  def __init__(self, name, start_address, end_address, origin, origin_offset):
981cb0ef41Sopenharmony_ci    self.id = Code._id
991cb0ef41Sopenharmony_ci    Code._id += 1
1001cb0ef41Sopenharmony_ci    self.name = name
1011cb0ef41Sopenharmony_ci    self.other_names = None
1021cb0ef41Sopenharmony_ci    self.start_address = start_address
1031cb0ef41Sopenharmony_ci    self.end_address = end_address
1041cb0ef41Sopenharmony_ci    self.origin = origin
1051cb0ef41Sopenharmony_ci    self.origin_offset = origin_offset
1061cb0ef41Sopenharmony_ci    self.self_ticks = 0
1071cb0ef41Sopenharmony_ci    self.self_ticks_map = None
1081cb0ef41Sopenharmony_ci    self.callee_ticks = None
1091cb0ef41Sopenharmony_ci    if name.startswith("LazyCompile:*"):
1101cb0ef41Sopenharmony_ci      self.codetype = Code.OPTIMIZED
1111cb0ef41Sopenharmony_ci    elif name.startswith("LazyCompile:"):
1121cb0ef41Sopenharmony_ci      self.codetype = Code.FULL_CODEGEN
1131cb0ef41Sopenharmony_ci    elif name.startswith("v8::internal::"):
1141cb0ef41Sopenharmony_ci      self.codetype = Code.V8INTERNAL
1151cb0ef41Sopenharmony_ci    else:
1161cb0ef41Sopenharmony_ci      self.codetype = Code.UNKNOWN
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  def AddName(self, name):
1191cb0ef41Sopenharmony_ci    assert self.name != name
1201cb0ef41Sopenharmony_ci    if self.other_names is None:
1211cb0ef41Sopenharmony_ci      self.other_names = [name]
1221cb0ef41Sopenharmony_ci      return
1231cb0ef41Sopenharmony_ci    if not name in self.other_names:
1241cb0ef41Sopenharmony_ci      self.other_names.append(name)
1251cb0ef41Sopenharmony_ci
1261cb0ef41Sopenharmony_ci  def FullName(self):
1271cb0ef41Sopenharmony_ci    if self.other_names is None:
1281cb0ef41Sopenharmony_ci      return self.name
1291cb0ef41Sopenharmony_ci    self.other_names.sort()
1301cb0ef41Sopenharmony_ci    return "%s (aka %s)" % (self.name, ", ".join(self.other_names))
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci  def IsUsed(self):
1331cb0ef41Sopenharmony_ci    return self.self_ticks > 0 or self.callee_ticks is not None
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci  def Tick(self, pc):
1361cb0ef41Sopenharmony_ci    self.self_ticks += 1
1371cb0ef41Sopenharmony_ci    if self.self_ticks_map is None:
1381cb0ef41Sopenharmony_ci      self.self_ticks_map = collections.defaultdict(lambda: 0)
1391cb0ef41Sopenharmony_ci    offset = pc - self.start_address
1401cb0ef41Sopenharmony_ci    self.self_ticks_map[offset] += 1
1411cb0ef41Sopenharmony_ci
1421cb0ef41Sopenharmony_ci  def CalleeTick(self, callee):
1431cb0ef41Sopenharmony_ci    if self.callee_ticks is None:
1441cb0ef41Sopenharmony_ci      self.callee_ticks = collections.defaultdict(lambda: 0)
1451cb0ef41Sopenharmony_ci    self.callee_ticks[callee] += 1
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  def PrintAnnotated(self, arch, options):
1481cb0ef41Sopenharmony_ci    if self.self_ticks_map is None:
1491cb0ef41Sopenharmony_ci      ticks_map = []
1501cb0ef41Sopenharmony_ci    else:
1511cb0ef41Sopenharmony_ci      ticks_map = self.self_ticks_map.items()
1521cb0ef41Sopenharmony_ci    # Convert the ticks map to offsets and counts arrays so that later
1531cb0ef41Sopenharmony_ci    # we can do binary search in the offsets array.
1541cb0ef41Sopenharmony_ci    ticks_map.sort(key=lambda t: t[0])
1551cb0ef41Sopenharmony_ci    ticks_offsets = [t[0] for t in ticks_map]
1561cb0ef41Sopenharmony_ci    ticks_counts = [t[1] for t in ticks_map]
1571cb0ef41Sopenharmony_ci    # Get a list of disassembled lines and their addresses.
1581cb0ef41Sopenharmony_ci    lines = self._GetDisasmLines(arch, options)
1591cb0ef41Sopenharmony_ci    if len(lines) == 0:
1601cb0ef41Sopenharmony_ci      return
1611cb0ef41Sopenharmony_ci    # Print annotated lines.
1621cb0ef41Sopenharmony_ci    address = lines[0][0]
1631cb0ef41Sopenharmony_ci    total_count = 0
1641cb0ef41Sopenharmony_ci    for i in range(len(lines)):
1651cb0ef41Sopenharmony_ci      start_offset = lines[i][0] - address
1661cb0ef41Sopenharmony_ci      if i == len(lines) - 1:
1671cb0ef41Sopenharmony_ci        end_offset = self.end_address - self.start_address
1681cb0ef41Sopenharmony_ci      else:
1691cb0ef41Sopenharmony_ci        end_offset = lines[i + 1][0] - address
1701cb0ef41Sopenharmony_ci      # Ticks (reported pc values) are not always precise, i.e. not
1711cb0ef41Sopenharmony_ci      # necessarily point at instruction starts. So we have to search
1721cb0ef41Sopenharmony_ci      # for ticks that touch the current instruction line.
1731cb0ef41Sopenharmony_ci      j = bisect.bisect_left(ticks_offsets, end_offset)
1741cb0ef41Sopenharmony_ci      count = 0
1751cb0ef41Sopenharmony_ci      for offset, cnt in reversed(zip(ticks_offsets[:j], ticks_counts[:j])):
1761cb0ef41Sopenharmony_ci        if offset < start_offset:
1771cb0ef41Sopenharmony_ci          break
1781cb0ef41Sopenharmony_ci        count += cnt
1791cb0ef41Sopenharmony_ci      total_count += count
1801cb0ef41Sopenharmony_ci      percent = 100.0 * count / self.self_ticks
1811cb0ef41Sopenharmony_ci      offset = lines[i][0]
1821cb0ef41Sopenharmony_ci      if percent >= 0.01:
1831cb0ef41Sopenharmony_ci        # 5 spaces for tick count
1841cb0ef41Sopenharmony_ci        # 1 space following
1851cb0ef41Sopenharmony_ci        # 1 for '|'
1861cb0ef41Sopenharmony_ci        # 1 space following
1871cb0ef41Sopenharmony_ci        # 6 for the percentage number, incl. the '.'
1881cb0ef41Sopenharmony_ci        # 1 for the '%' sign
1891cb0ef41Sopenharmony_ci        # => 15
1901cb0ef41Sopenharmony_ci        print("%5d | %6.2f%% %x(%d): %s" % (count, percent, offset, offset, lines[i][1]))
1911cb0ef41Sopenharmony_ci      else:
1921cb0ef41Sopenharmony_ci        print("%s %x(%d): %s" % (" " * 15, offset, offset, lines[i][1]))
1931cb0ef41Sopenharmony_ci    print()
1941cb0ef41Sopenharmony_ci    assert total_count == self.self_ticks, \
1951cb0ef41Sopenharmony_ci        "Lost ticks (%d != %d) in %s" % (total_count, self.self_ticks, self)
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci  def __str__(self):
1981cb0ef41Sopenharmony_ci    return "%s [0x%x, 0x%x) size: %d origin: %s" % (
1991cb0ef41Sopenharmony_ci      self.name,
2001cb0ef41Sopenharmony_ci      self.start_address,
2011cb0ef41Sopenharmony_ci      self.end_address,
2021cb0ef41Sopenharmony_ci      self.end_address - self.start_address,
2031cb0ef41Sopenharmony_ci      self.origin)
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_ci  def _GetDisasmLines(self, arch, options):
2061cb0ef41Sopenharmony_ci    if self.origin == JS_ORIGIN:
2071cb0ef41Sopenharmony_ci      inplace = False
2081cb0ef41Sopenharmony_ci      filename = options.log + ".ll"
2091cb0ef41Sopenharmony_ci    else:
2101cb0ef41Sopenharmony_ci      inplace = True
2111cb0ef41Sopenharmony_ci      filename = self.origin
2121cb0ef41Sopenharmony_ci    return disasm.GetDisasmLines(filename,
2131cb0ef41Sopenharmony_ci                                 self.origin_offset,
2141cb0ef41Sopenharmony_ci                                 self.end_address - self.start_address,
2151cb0ef41Sopenharmony_ci                                 arch,
2161cb0ef41Sopenharmony_ci                                 inplace)
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci
2191cb0ef41Sopenharmony_ciclass CodePage(object):
2201cb0ef41Sopenharmony_ci  """Group of adjacent code objects."""
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci  SHIFT = 20  # 1M pages
2231cb0ef41Sopenharmony_ci  SIZE = (1 << SHIFT)
2241cb0ef41Sopenharmony_ci  MASK = ~(SIZE - 1)
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci  @staticmethod
2271cb0ef41Sopenharmony_ci  def PageAddress(address):
2281cb0ef41Sopenharmony_ci    return address & CodePage.MASK
2291cb0ef41Sopenharmony_ci
2301cb0ef41Sopenharmony_ci  @staticmethod
2311cb0ef41Sopenharmony_ci  def PageId(address):
2321cb0ef41Sopenharmony_ci    return address >> CodePage.SHIFT
2331cb0ef41Sopenharmony_ci
2341cb0ef41Sopenharmony_ci  @staticmethod
2351cb0ef41Sopenharmony_ci  def PageAddressFromId(id):
2361cb0ef41Sopenharmony_ci    return id << CodePage.SHIFT
2371cb0ef41Sopenharmony_ci
2381cb0ef41Sopenharmony_ci  def __init__(self, address):
2391cb0ef41Sopenharmony_ci    self.address = address
2401cb0ef41Sopenharmony_ci    self.code_objects = []
2411cb0ef41Sopenharmony_ci
2421cb0ef41Sopenharmony_ci  def Add(self, code):
2431cb0ef41Sopenharmony_ci    self.code_objects.append(code)
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci  def Remove(self, code):
2461cb0ef41Sopenharmony_ci    self.code_objects.remove(code)
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci  def Find(self, pc):
2491cb0ef41Sopenharmony_ci    code_objects = self.code_objects
2501cb0ef41Sopenharmony_ci    for i, code in enumerate(code_objects):
2511cb0ef41Sopenharmony_ci      if code.start_address <= pc < code.end_address:
2521cb0ef41Sopenharmony_ci        code_objects[0], code_objects[i] = code, code_objects[0]
2531cb0ef41Sopenharmony_ci        return code
2541cb0ef41Sopenharmony_ci    return None
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ci  def __iter__(self):
2571cb0ef41Sopenharmony_ci    return self.code_objects.__iter__()
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ci
2601cb0ef41Sopenharmony_ciclass CodeMap(object):
2611cb0ef41Sopenharmony_ci  """Code object map."""
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  def __init__(self):
2641cb0ef41Sopenharmony_ci    self.pages = {}
2651cb0ef41Sopenharmony_ci    self.min_address = 1 << 64
2661cb0ef41Sopenharmony_ci    self.max_address = -1
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci  def Add(self, code, max_pages=-1):
2691cb0ef41Sopenharmony_ci    page_id = CodePage.PageId(code.start_address)
2701cb0ef41Sopenharmony_ci    limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1)
2711cb0ef41Sopenharmony_ci    pages = 0
2721cb0ef41Sopenharmony_ci    while page_id < limit_id:
2731cb0ef41Sopenharmony_ci      if max_pages >= 0 and pages > max_pages:
2741cb0ef41Sopenharmony_ci        print("Warning: page limit (%d) reached for %s [%s]" % (
2751cb0ef41Sopenharmony_ci            max_pages, code.name, code.origin), file=sys.stderr)
2761cb0ef41Sopenharmony_ci        break
2771cb0ef41Sopenharmony_ci      if page_id in self.pages:
2781cb0ef41Sopenharmony_ci        page = self.pages[page_id]
2791cb0ef41Sopenharmony_ci      else:
2801cb0ef41Sopenharmony_ci        page = CodePage(CodePage.PageAddressFromId(page_id))
2811cb0ef41Sopenharmony_ci        self.pages[page_id] = page
2821cb0ef41Sopenharmony_ci      page.Add(code)
2831cb0ef41Sopenharmony_ci      page_id += 1
2841cb0ef41Sopenharmony_ci      pages += 1
2851cb0ef41Sopenharmony_ci    self.min_address = min(self.min_address, code.start_address)
2861cb0ef41Sopenharmony_ci    self.max_address = max(self.max_address, code.end_address)
2871cb0ef41Sopenharmony_ci
2881cb0ef41Sopenharmony_ci  def Remove(self, code):
2891cb0ef41Sopenharmony_ci    page_id = CodePage.PageId(code.start_address)
2901cb0ef41Sopenharmony_ci    limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1)
2911cb0ef41Sopenharmony_ci    removed = False
2921cb0ef41Sopenharmony_ci    while page_id < limit_id:
2931cb0ef41Sopenharmony_ci      if page_id not in self.pages:
2941cb0ef41Sopenharmony_ci        page_id += 1
2951cb0ef41Sopenharmony_ci        continue
2961cb0ef41Sopenharmony_ci      page = self.pages[page_id]
2971cb0ef41Sopenharmony_ci      page.Remove(code)
2981cb0ef41Sopenharmony_ci      removed = True
2991cb0ef41Sopenharmony_ci      page_id += 1
3001cb0ef41Sopenharmony_ci    return removed
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_ci  def AllCode(self):
3031cb0ef41Sopenharmony_ci    for page in self.pages.itervalues():
3041cb0ef41Sopenharmony_ci      for code in page:
3051cb0ef41Sopenharmony_ci        if CodePage.PageAddress(code.start_address) == page.address:
3061cb0ef41Sopenharmony_ci          yield code
3071cb0ef41Sopenharmony_ci
3081cb0ef41Sopenharmony_ci  def UsedCode(self):
3091cb0ef41Sopenharmony_ci    for code in self.AllCode():
3101cb0ef41Sopenharmony_ci      if code.IsUsed():
3111cb0ef41Sopenharmony_ci        yield code
3121cb0ef41Sopenharmony_ci
3131cb0ef41Sopenharmony_ci  def Print(self):
3141cb0ef41Sopenharmony_ci    for code in self.AllCode():
3151cb0ef41Sopenharmony_ci      print(code)
3161cb0ef41Sopenharmony_ci
3171cb0ef41Sopenharmony_ci  def Find(self, pc):
3181cb0ef41Sopenharmony_ci    if pc < self.min_address or pc >= self.max_address:
3191cb0ef41Sopenharmony_ci      return None
3201cb0ef41Sopenharmony_ci    page_id = CodePage.PageId(pc)
3211cb0ef41Sopenharmony_ci    if page_id not in self.pages:
3221cb0ef41Sopenharmony_ci      return None
3231cb0ef41Sopenharmony_ci    return self.pages[page_id].Find(pc)
3241cb0ef41Sopenharmony_ci
3251cb0ef41Sopenharmony_ci
3261cb0ef41Sopenharmony_ciclass CodeInfo(object):
3271cb0ef41Sopenharmony_ci  """Generic info about generated code objects."""
3281cb0ef41Sopenharmony_ci
3291cb0ef41Sopenharmony_ci  def __init__(self, arch, header_size):
3301cb0ef41Sopenharmony_ci    self.arch = arch
3311cb0ef41Sopenharmony_ci    self.header_size = header_size
3321cb0ef41Sopenharmony_ci
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ciclass LogReader(object):
3351cb0ef41Sopenharmony_ci  """V8 low-level (binary) log reader."""
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci  _ARCH_TO_POINTER_TYPE_MAP = {
3381cb0ef41Sopenharmony_ci    "ia32": ctypes.c_uint32,
3391cb0ef41Sopenharmony_ci    "arm": ctypes.c_uint32,
3401cb0ef41Sopenharmony_ci    "mips": ctypes.c_uint32,
3411cb0ef41Sopenharmony_ci    "x64": ctypes.c_uint64,
3421cb0ef41Sopenharmony_ci    "arm64": ctypes.c_uint64
3431cb0ef41Sopenharmony_ci  }
3441cb0ef41Sopenharmony_ci
3451cb0ef41Sopenharmony_ci  _CODE_CREATE_TAG = "C"
3461cb0ef41Sopenharmony_ci  _CODE_MOVE_TAG = "M"
3471cb0ef41Sopenharmony_ci  _CODE_MOVING_GC_TAG = "G"
3481cb0ef41Sopenharmony_ci
3491cb0ef41Sopenharmony_ci  def __init__(self, log_name, code_map):
3501cb0ef41Sopenharmony_ci    self.log_file = open(log_name, "r")
3511cb0ef41Sopenharmony_ci    self.log = mmap.mmap(self.log_file.fileno(), 0, mmap.MAP_PRIVATE)
3521cb0ef41Sopenharmony_ci    self.log_pos = 0
3531cb0ef41Sopenharmony_ci    self.code_map = code_map
3541cb0ef41Sopenharmony_ci
3551cb0ef41Sopenharmony_ci    self.arch = self.log[:self.log.find("\0")]
3561cb0ef41Sopenharmony_ci    self.log_pos += len(self.arch) + 1
3571cb0ef41Sopenharmony_ci    assert self.arch in LogReader._ARCH_TO_POINTER_TYPE_MAP, \
3581cb0ef41Sopenharmony_ci        "Unsupported architecture %s" % self.arch
3591cb0ef41Sopenharmony_ci    pointer_type = LogReader._ARCH_TO_POINTER_TYPE_MAP[self.arch]
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ci    self.code_create_struct = LogReader._DefineStruct([
3621cb0ef41Sopenharmony_ci        ("name_size", ctypes.c_int32),
3631cb0ef41Sopenharmony_ci        ("code_address", pointer_type),
3641cb0ef41Sopenharmony_ci        ("code_size", ctypes.c_int32)])
3651cb0ef41Sopenharmony_ci
3661cb0ef41Sopenharmony_ci    self.code_move_struct = LogReader._DefineStruct([
3671cb0ef41Sopenharmony_ci        ("from_address", pointer_type),
3681cb0ef41Sopenharmony_ci        ("to_address", pointer_type)])
3691cb0ef41Sopenharmony_ci
3701cb0ef41Sopenharmony_ci    self.code_delete_struct = LogReader._DefineStruct([
3711cb0ef41Sopenharmony_ci        ("address", pointer_type)])
3721cb0ef41Sopenharmony_ci
3731cb0ef41Sopenharmony_ci  def ReadUpToGC(self):
3741cb0ef41Sopenharmony_ci    while self.log_pos < self.log.size():
3751cb0ef41Sopenharmony_ci      tag = self.log[self.log_pos]
3761cb0ef41Sopenharmony_ci      self.log_pos += 1
3771cb0ef41Sopenharmony_ci
3781cb0ef41Sopenharmony_ci      if tag == LogReader._CODE_MOVING_GC_TAG:
3791cb0ef41Sopenharmony_ci        return
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci      if tag == LogReader._CODE_CREATE_TAG:
3821cb0ef41Sopenharmony_ci        event = self.code_create_struct.from_buffer(self.log, self.log_pos)
3831cb0ef41Sopenharmony_ci        self.log_pos += ctypes.sizeof(event)
3841cb0ef41Sopenharmony_ci        start_address = event.code_address
3851cb0ef41Sopenharmony_ci        end_address = start_address + event.code_size
3861cb0ef41Sopenharmony_ci        name = self.log[self.log_pos:self.log_pos + event.name_size]
3871cb0ef41Sopenharmony_ci        origin = JS_ORIGIN
3881cb0ef41Sopenharmony_ci        self.log_pos += event.name_size
3891cb0ef41Sopenharmony_ci        origin_offset = self.log_pos
3901cb0ef41Sopenharmony_ci        self.log_pos += event.code_size
3911cb0ef41Sopenharmony_ci        code = Code(name, start_address, end_address, origin, origin_offset)
3921cb0ef41Sopenharmony_ci        conficting_code = self.code_map.Find(start_address)
3931cb0ef41Sopenharmony_ci        if conficting_code:
3941cb0ef41Sopenharmony_ci          if not (conficting_code.start_address == code.start_address and
3951cb0ef41Sopenharmony_ci            conficting_code.end_address == code.end_address):
3961cb0ef41Sopenharmony_ci            self.code_map.Remove(conficting_code)
3971cb0ef41Sopenharmony_ci          else:
3981cb0ef41Sopenharmony_ci            LogReader._HandleCodeConflict(conficting_code, code)
3991cb0ef41Sopenharmony_ci            # TODO(vitalyr): this warning is too noisy because of our
4001cb0ef41Sopenharmony_ci            # attempts to reconstruct code log from the snapshot.
4011cb0ef41Sopenharmony_ci            # print >>sys.stderr, \
4021cb0ef41Sopenharmony_ci            #     "Warning: Skipping duplicate code log entry %s" % code
4031cb0ef41Sopenharmony_ci            continue
4041cb0ef41Sopenharmony_ci        self.code_map.Add(code)
4051cb0ef41Sopenharmony_ci        continue
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ci      if tag == LogReader._CODE_MOVE_TAG:
4081cb0ef41Sopenharmony_ci        event = self.code_move_struct.from_buffer(self.log, self.log_pos)
4091cb0ef41Sopenharmony_ci        self.log_pos += ctypes.sizeof(event)
4101cb0ef41Sopenharmony_ci        old_start_address = event.from_address
4111cb0ef41Sopenharmony_ci        new_start_address = event.to_address
4121cb0ef41Sopenharmony_ci        if old_start_address == new_start_address:
4131cb0ef41Sopenharmony_ci          # Skip useless code move entries.
4141cb0ef41Sopenharmony_ci          continue
4151cb0ef41Sopenharmony_ci        code = self.code_map.Find(old_start_address)
4161cb0ef41Sopenharmony_ci        if not code:
4171cb0ef41Sopenharmony_ci          print("Warning: Not found %x" % old_start_address, file=sys.stderr)
4181cb0ef41Sopenharmony_ci          continue
4191cb0ef41Sopenharmony_ci        assert code.start_address == old_start_address, \
4201cb0ef41Sopenharmony_ci            "Inexact move address %x for %s" % (old_start_address, code)
4211cb0ef41Sopenharmony_ci        self.code_map.Remove(code)
4221cb0ef41Sopenharmony_ci        size = code.end_address - code.start_address
4231cb0ef41Sopenharmony_ci        code.start_address = new_start_address
4241cb0ef41Sopenharmony_ci        code.end_address = new_start_address + size
4251cb0ef41Sopenharmony_ci        self.code_map.Add(code)
4261cb0ef41Sopenharmony_ci        continue
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_ci      assert False, "Unknown tag %s" % tag
4291cb0ef41Sopenharmony_ci
4301cb0ef41Sopenharmony_ci  def Dispose(self):
4311cb0ef41Sopenharmony_ci    self.log.close()
4321cb0ef41Sopenharmony_ci    self.log_file.close()
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ci  @staticmethod
4351cb0ef41Sopenharmony_ci  def _DefineStruct(fields):
4361cb0ef41Sopenharmony_ci    class Struct(ctypes.Structure):
4371cb0ef41Sopenharmony_ci      _fields_ = fields
4381cb0ef41Sopenharmony_ci    return Struct
4391cb0ef41Sopenharmony_ci
4401cb0ef41Sopenharmony_ci  @staticmethod
4411cb0ef41Sopenharmony_ci  def _HandleCodeConflict(old_code, new_code):
4421cb0ef41Sopenharmony_ci    assert (old_code.start_address == new_code.start_address and
4431cb0ef41Sopenharmony_ci            old_code.end_address == new_code.end_address), \
4441cb0ef41Sopenharmony_ci        "Conficting code log entries %s and %s" % (old_code, new_code)
4451cb0ef41Sopenharmony_ci    if old_code.name == new_code.name:
4461cb0ef41Sopenharmony_ci      return
4471cb0ef41Sopenharmony_ci    # Code object may be shared by a few functions. Collect the full
4481cb0ef41Sopenharmony_ci    # set of names.
4491cb0ef41Sopenharmony_ci    old_code.AddName(new_code.name)
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_ci
4521cb0ef41Sopenharmony_ciclass Descriptor(object):
4531cb0ef41Sopenharmony_ci  """Descriptor of a structure in the binary trace log."""
4541cb0ef41Sopenharmony_ci
4551cb0ef41Sopenharmony_ci  CTYPE_MAP = {
4561cb0ef41Sopenharmony_ci    "u16": ctypes.c_uint16,
4571cb0ef41Sopenharmony_ci    "u32": ctypes.c_uint32,
4581cb0ef41Sopenharmony_ci    "u64": ctypes.c_uint64
4591cb0ef41Sopenharmony_ci  }
4601cb0ef41Sopenharmony_ci
4611cb0ef41Sopenharmony_ci  def __init__(self, fields):
4621cb0ef41Sopenharmony_ci    class TraceItem(ctypes.Structure):
4631cb0ef41Sopenharmony_ci      _fields_ = Descriptor.CtypesFields(fields)
4641cb0ef41Sopenharmony_ci
4651cb0ef41Sopenharmony_ci      def __str__(self):
4661cb0ef41Sopenharmony_ci        return ", ".join("%s: %s" % (field, self.__getattribute__(field))
4671cb0ef41Sopenharmony_ci                         for field, _ in TraceItem._fields_)
4681cb0ef41Sopenharmony_ci
4691cb0ef41Sopenharmony_ci    self.ctype = TraceItem
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_ci  def Read(self, trace, offset):
4721cb0ef41Sopenharmony_ci    return self.ctype.from_buffer(trace, offset)
4731cb0ef41Sopenharmony_ci
4741cb0ef41Sopenharmony_ci  @staticmethod
4751cb0ef41Sopenharmony_ci  def CtypesFields(fields):
4761cb0ef41Sopenharmony_ci    return [(field, Descriptor.CTYPE_MAP[format]) for (field, format) in fields]
4771cb0ef41Sopenharmony_ci
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci# Please see http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=tree;f=tools/perf
4801cb0ef41Sopenharmony_ci# for the gory details.
4811cb0ef41Sopenharmony_ci
4821cb0ef41Sopenharmony_ci
4831cb0ef41Sopenharmony_ci# Reference: struct perf_file_header in kernel/tools/perf/util/header.h
4841cb0ef41Sopenharmony_ciTRACE_HEADER_DESC = Descriptor([
4851cb0ef41Sopenharmony_ci  ("magic", "u64"),
4861cb0ef41Sopenharmony_ci  ("size", "u64"),
4871cb0ef41Sopenharmony_ci  ("attr_size", "u64"),
4881cb0ef41Sopenharmony_ci  ("attrs_offset", "u64"),
4891cb0ef41Sopenharmony_ci  ("attrs_size", "u64"),
4901cb0ef41Sopenharmony_ci  ("data_offset", "u64"),
4911cb0ef41Sopenharmony_ci  ("data_size", "u64"),
4921cb0ef41Sopenharmony_ci  ("event_types_offset", "u64"),
4931cb0ef41Sopenharmony_ci  ("event_types_size", "u64")
4941cb0ef41Sopenharmony_ci])
4951cb0ef41Sopenharmony_ci
4961cb0ef41Sopenharmony_ci
4971cb0ef41Sopenharmony_ci# Reference: /usr/include/linux/perf_event.h
4981cb0ef41Sopenharmony_ciPERF_EVENT_ATTR_DESC = Descriptor([
4991cb0ef41Sopenharmony_ci  ("type", "u32"),
5001cb0ef41Sopenharmony_ci  ("size", "u32"),
5011cb0ef41Sopenharmony_ci  ("config", "u64"),
5021cb0ef41Sopenharmony_ci  ("sample_period_or_freq", "u64"),
5031cb0ef41Sopenharmony_ci  ("sample_type", "u64"),
5041cb0ef41Sopenharmony_ci  ("read_format", "u64"),
5051cb0ef41Sopenharmony_ci  ("flags", "u64"),
5061cb0ef41Sopenharmony_ci  ("wakeup_events_or_watermark", "u32"),
5071cb0ef41Sopenharmony_ci  ("bp_type", "u32"),
5081cb0ef41Sopenharmony_ci  ("bp_addr", "u64"),
5091cb0ef41Sopenharmony_ci  ("bp_len", "u64")
5101cb0ef41Sopenharmony_ci])
5111cb0ef41Sopenharmony_ci
5121cb0ef41Sopenharmony_ci
5131cb0ef41Sopenharmony_ci# Reference: /usr/include/linux/perf_event.h
5141cb0ef41Sopenharmony_ciPERF_EVENT_HEADER_DESC = Descriptor([
5151cb0ef41Sopenharmony_ci  ("type", "u32"),
5161cb0ef41Sopenharmony_ci  ("misc", "u16"),
5171cb0ef41Sopenharmony_ci  ("size", "u16")
5181cb0ef41Sopenharmony_ci])
5191cb0ef41Sopenharmony_ci
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_ci# Reference: kernel/tools/perf/util/event.h
5221cb0ef41Sopenharmony_ciPERF_MMAP_EVENT_BODY_DESC = Descriptor([
5231cb0ef41Sopenharmony_ci  ("pid", "u32"),
5241cb0ef41Sopenharmony_ci  ("tid", "u32"),
5251cb0ef41Sopenharmony_ci  ("addr", "u64"),
5261cb0ef41Sopenharmony_ci  ("len", "u64"),
5271cb0ef41Sopenharmony_ci  ("pgoff", "u64")
5281cb0ef41Sopenharmony_ci])
5291cb0ef41Sopenharmony_ci
5301cb0ef41Sopenharmony_ci# Reference: kernel/tools/perf/util/event.h
5311cb0ef41Sopenharmony_ciPERF_MMAP2_EVENT_BODY_DESC = Descriptor([
5321cb0ef41Sopenharmony_ci  ("pid", "u32"),
5331cb0ef41Sopenharmony_ci  ("tid", "u32"),
5341cb0ef41Sopenharmony_ci  ("addr", "u64"),
5351cb0ef41Sopenharmony_ci  ("len", "u64"),
5361cb0ef41Sopenharmony_ci  ("pgoff", "u64"),
5371cb0ef41Sopenharmony_ci  ("maj", "u32"),
5381cb0ef41Sopenharmony_ci  ("min", "u32"),
5391cb0ef41Sopenharmony_ci  ("ino", "u64"),
5401cb0ef41Sopenharmony_ci  ("ino_generation", "u64"),
5411cb0ef41Sopenharmony_ci  ("prot", "u32"),
5421cb0ef41Sopenharmony_ci  ("flags","u32")
5431cb0ef41Sopenharmony_ci])
5441cb0ef41Sopenharmony_ci
5451cb0ef41Sopenharmony_ci# perf_event_attr.sample_type bits control the set of
5461cb0ef41Sopenharmony_ci# perf_sample_event fields.
5471cb0ef41Sopenharmony_ciPERF_SAMPLE_IP = 1 << 0
5481cb0ef41Sopenharmony_ciPERF_SAMPLE_TID = 1 << 1
5491cb0ef41Sopenharmony_ciPERF_SAMPLE_TIME = 1 << 2
5501cb0ef41Sopenharmony_ciPERF_SAMPLE_ADDR = 1 << 3
5511cb0ef41Sopenharmony_ciPERF_SAMPLE_READ = 1 << 4
5521cb0ef41Sopenharmony_ciPERF_SAMPLE_CALLCHAIN = 1 << 5
5531cb0ef41Sopenharmony_ciPERF_SAMPLE_ID = 1 << 6
5541cb0ef41Sopenharmony_ciPERF_SAMPLE_CPU = 1 << 7
5551cb0ef41Sopenharmony_ciPERF_SAMPLE_PERIOD = 1 << 8
5561cb0ef41Sopenharmony_ciPERF_SAMPLE_STREAM_ID = 1 << 9
5571cb0ef41Sopenharmony_ciPERF_SAMPLE_RAW = 1 << 10
5581cb0ef41Sopenharmony_ci
5591cb0ef41Sopenharmony_ci
5601cb0ef41Sopenharmony_ci# Reference: /usr/include/perf_event.h, the comment for PERF_RECORD_SAMPLE.
5611cb0ef41Sopenharmony_ciPERF_SAMPLE_EVENT_BODY_FIELDS = [
5621cb0ef41Sopenharmony_ci  ("ip", "u64", PERF_SAMPLE_IP),
5631cb0ef41Sopenharmony_ci  ("pid", "u32", PERF_SAMPLE_TID),
5641cb0ef41Sopenharmony_ci  ("tid", "u32", PERF_SAMPLE_TID),
5651cb0ef41Sopenharmony_ci  ("time", "u64", PERF_SAMPLE_TIME),
5661cb0ef41Sopenharmony_ci  ("addr", "u64", PERF_SAMPLE_ADDR),
5671cb0ef41Sopenharmony_ci  ("id", "u64", PERF_SAMPLE_ID),
5681cb0ef41Sopenharmony_ci  ("stream_id", "u64", PERF_SAMPLE_STREAM_ID),
5691cb0ef41Sopenharmony_ci  ("cpu", "u32", PERF_SAMPLE_CPU),
5701cb0ef41Sopenharmony_ci  ("res", "u32", PERF_SAMPLE_CPU),
5711cb0ef41Sopenharmony_ci  ("period", "u64", PERF_SAMPLE_PERIOD),
5721cb0ef41Sopenharmony_ci  # Don't want to handle read format that comes after the period and
5731cb0ef41Sopenharmony_ci  # before the callchain and has variable size.
5741cb0ef41Sopenharmony_ci  ("nr", "u64", PERF_SAMPLE_CALLCHAIN)
5751cb0ef41Sopenharmony_ci  # Raw data follows the callchain and is ignored.
5761cb0ef41Sopenharmony_ci]
5771cb0ef41Sopenharmony_ci
5781cb0ef41Sopenharmony_ci
5791cb0ef41Sopenharmony_ciPERF_SAMPLE_EVENT_IP_FORMAT = "u64"
5801cb0ef41Sopenharmony_ci
5811cb0ef41Sopenharmony_ci
5821cb0ef41Sopenharmony_ciPERF_RECORD_MMAP = 1
5831cb0ef41Sopenharmony_ciPERF_RECORD_MMAP2 = 10
5841cb0ef41Sopenharmony_ciPERF_RECORD_SAMPLE = 9
5851cb0ef41Sopenharmony_ci
5861cb0ef41Sopenharmony_ci
5871cb0ef41Sopenharmony_ciclass TraceReader(object):
5881cb0ef41Sopenharmony_ci  """Perf (linux-2.6/tools/perf) trace file reader."""
5891cb0ef41Sopenharmony_ci
5901cb0ef41Sopenharmony_ci  _TRACE_HEADER_MAGIC = 4993446653023372624
5911cb0ef41Sopenharmony_ci
5921cb0ef41Sopenharmony_ci  def __init__(self, trace_name):
5931cb0ef41Sopenharmony_ci    self.trace_file = open(trace_name, "r")
5941cb0ef41Sopenharmony_ci    self.trace = mmap.mmap(self.trace_file.fileno(), 0, mmap.MAP_PRIVATE)
5951cb0ef41Sopenharmony_ci    self.trace_header = TRACE_HEADER_DESC.Read(self.trace, 0)
5961cb0ef41Sopenharmony_ci    if self.trace_header.magic != TraceReader._TRACE_HEADER_MAGIC:
5971cb0ef41Sopenharmony_ci      print("Warning: unsupported trace header magic", file=sys.stderr)
5981cb0ef41Sopenharmony_ci    self.offset = self.trace_header.data_offset
5991cb0ef41Sopenharmony_ci    self.limit = self.trace_header.data_offset + self.trace_header.data_size
6001cb0ef41Sopenharmony_ci    assert self.limit <= self.trace.size(), \
6011cb0ef41Sopenharmony_ci        "Trace data limit exceeds trace file size"
6021cb0ef41Sopenharmony_ci    self.header_size = ctypes.sizeof(PERF_EVENT_HEADER_DESC.ctype)
6031cb0ef41Sopenharmony_ci    assert self.trace_header.attrs_size != 0, \
6041cb0ef41Sopenharmony_ci        "No perf event attributes found in the trace"
6051cb0ef41Sopenharmony_ci    perf_event_attr = PERF_EVENT_ATTR_DESC.Read(self.trace,
6061cb0ef41Sopenharmony_ci                                                self.trace_header.attrs_offset)
6071cb0ef41Sopenharmony_ci    self.sample_event_body_desc = self._SampleEventBodyDesc(
6081cb0ef41Sopenharmony_ci        perf_event_attr.sample_type)
6091cb0ef41Sopenharmony_ci    self.callchain_supported = \
6101cb0ef41Sopenharmony_ci        (perf_event_attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0
6111cb0ef41Sopenharmony_ci    if self.callchain_supported:
6121cb0ef41Sopenharmony_ci      self.ip_struct = Descriptor.CTYPE_MAP[PERF_SAMPLE_EVENT_IP_FORMAT]
6131cb0ef41Sopenharmony_ci      self.ip_size = ctypes.sizeof(self.ip_struct)
6141cb0ef41Sopenharmony_ci
6151cb0ef41Sopenharmony_ci  def ReadEventHeader(self):
6161cb0ef41Sopenharmony_ci    if self.offset >= self.limit:
6171cb0ef41Sopenharmony_ci      return None, 0
6181cb0ef41Sopenharmony_ci    offset = self.offset
6191cb0ef41Sopenharmony_ci    header = PERF_EVENT_HEADER_DESC.Read(self.trace, self.offset)
6201cb0ef41Sopenharmony_ci    self.offset += header.size
6211cb0ef41Sopenharmony_ci    return header, offset
6221cb0ef41Sopenharmony_ci
6231cb0ef41Sopenharmony_ci  def ReadMmap(self, header, offset):
6241cb0ef41Sopenharmony_ci    mmap_info = PERF_MMAP_EVENT_BODY_DESC.Read(self.trace,
6251cb0ef41Sopenharmony_ci                                               offset + self.header_size)
6261cb0ef41Sopenharmony_ci    # Read null-terminated filename.
6271cb0ef41Sopenharmony_ci    filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info):
6281cb0ef41Sopenharmony_ci                          offset + header.size]
6291cb0ef41Sopenharmony_ci    mmap_info.filename = HOST_ROOT + filename[:filename.find(chr(0))]
6301cb0ef41Sopenharmony_ci    return mmap_info
6311cb0ef41Sopenharmony_ci
6321cb0ef41Sopenharmony_ci  def ReadMmap2(self, header, offset):
6331cb0ef41Sopenharmony_ci    mmap_info = PERF_MMAP2_EVENT_BODY_DESC.Read(self.trace,
6341cb0ef41Sopenharmony_ci                                                offset + self.header_size)
6351cb0ef41Sopenharmony_ci    # Read null-terminated filename.
6361cb0ef41Sopenharmony_ci    filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info):
6371cb0ef41Sopenharmony_ci                          offset + header.size]
6381cb0ef41Sopenharmony_ci    mmap_info.filename = HOST_ROOT + filename[:filename.find(chr(0))]
6391cb0ef41Sopenharmony_ci    return mmap_info
6401cb0ef41Sopenharmony_ci
6411cb0ef41Sopenharmony_ci  def ReadSample(self, header, offset):
6421cb0ef41Sopenharmony_ci    sample = self.sample_event_body_desc.Read(self.trace,
6431cb0ef41Sopenharmony_ci                                              offset + self.header_size)
6441cb0ef41Sopenharmony_ci    if not self.callchain_supported:
6451cb0ef41Sopenharmony_ci      return sample
6461cb0ef41Sopenharmony_ci    sample.ips = []
6471cb0ef41Sopenharmony_ci    offset += self.header_size + ctypes.sizeof(sample)
6481cb0ef41Sopenharmony_ci    for _ in range(sample.nr):
6491cb0ef41Sopenharmony_ci      sample.ips.append(
6501cb0ef41Sopenharmony_ci        self.ip_struct.from_buffer(self.trace, offset).value)
6511cb0ef41Sopenharmony_ci      offset += self.ip_size
6521cb0ef41Sopenharmony_ci    return sample
6531cb0ef41Sopenharmony_ci
6541cb0ef41Sopenharmony_ci  def Dispose(self):
6551cb0ef41Sopenharmony_ci    self.trace.close()
6561cb0ef41Sopenharmony_ci    self.trace_file.close()
6571cb0ef41Sopenharmony_ci
6581cb0ef41Sopenharmony_ci  def _SampleEventBodyDesc(self, sample_type):
6591cb0ef41Sopenharmony_ci    assert (sample_type & PERF_SAMPLE_READ) == 0, \
6601cb0ef41Sopenharmony_ci           "Can't hande read format in samples"
6611cb0ef41Sopenharmony_ci    fields = [(field, format)
6621cb0ef41Sopenharmony_ci              for (field, format, bit) in PERF_SAMPLE_EVENT_BODY_FIELDS
6631cb0ef41Sopenharmony_ci              if (bit & sample_type) != 0]
6641cb0ef41Sopenharmony_ci    return Descriptor(fields)
6651cb0ef41Sopenharmony_ci
6661cb0ef41Sopenharmony_ci
6671cb0ef41Sopenharmony_ciOBJDUMP_SECTION_HEADER_RE = re.compile(
6681cb0ef41Sopenharmony_ci  r"^\s*\d+\s(\.\S+)\s+[a-f0-9]")
6691cb0ef41Sopenharmony_ciOBJDUMP_SYMBOL_LINE_RE = re.compile(
6701cb0ef41Sopenharmony_ci  r"^([a-f0-9]+)\s(.{7})\s(\S+)\s+([a-f0-9]+)\s+(?:\.hidden\s+)?(.*)$")
6711cb0ef41Sopenharmony_ciOBJDUMP_DYNAMIC_SYMBOLS_START_RE = re.compile(
6721cb0ef41Sopenharmony_ci  r"^DYNAMIC SYMBOL TABLE")
6731cb0ef41Sopenharmony_ciOBJDUMP_SKIP_RE = re.compile(
6741cb0ef41Sopenharmony_ci  r"^.*ld\.so\.cache$")
6751cb0ef41Sopenharmony_ciKERNEL_ALLSYMS_FILE = "/proc/kallsyms"
6761cb0ef41Sopenharmony_ciPERF_KERNEL_ALLSYMS_RE = re.compile(
6771cb0ef41Sopenharmony_ci  r".*kallsyms.*")
6781cb0ef41Sopenharmony_ciKERNEL_ALLSYMS_LINE_RE = re.compile(
6791cb0ef41Sopenharmony_ci  r"^([a-f0-9]+)\s(?:t|T)\s(\S+)$")
6801cb0ef41Sopenharmony_ci
6811cb0ef41Sopenharmony_ci
6821cb0ef41Sopenharmony_ciclass LibraryRepo(object):
6831cb0ef41Sopenharmony_ci  def __init__(self):
6841cb0ef41Sopenharmony_ci    self.infos = []
6851cb0ef41Sopenharmony_ci    self.names = set()
6861cb0ef41Sopenharmony_ci    self.ticks = {}
6871cb0ef41Sopenharmony_ci
6881cb0ef41Sopenharmony_ci
6891cb0ef41Sopenharmony_ci  def HasDynamicSymbols(self, filename):
6901cb0ef41Sopenharmony_ci    if filename.endswith(".ko"): return False
6911cb0ef41Sopenharmony_ci    process = subprocess.Popen(
6921cb0ef41Sopenharmony_ci      "%s -h %s" % (OBJDUMP_BIN, filename),
6931cb0ef41Sopenharmony_ci      shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
6941cb0ef41Sopenharmony_ci    pipe = process.stdout
6951cb0ef41Sopenharmony_ci    try:
6961cb0ef41Sopenharmony_ci      for line in pipe:
6971cb0ef41Sopenharmony_ci        match = OBJDUMP_SECTION_HEADER_RE.match(line)
6981cb0ef41Sopenharmony_ci        if match and match.group(1) == 'dynsym': return True
6991cb0ef41Sopenharmony_ci    finally:
7001cb0ef41Sopenharmony_ci      pipe.close()
7011cb0ef41Sopenharmony_ci    assert process.wait() == 0, "Failed to objdump -h %s" % filename
7021cb0ef41Sopenharmony_ci    return False
7031cb0ef41Sopenharmony_ci
7041cb0ef41Sopenharmony_ci
7051cb0ef41Sopenharmony_ci  def Load(self, mmap_info, code_map, options):
7061cb0ef41Sopenharmony_ci    # Skip kernel mmaps when requested using the fact that their tid
7071cb0ef41Sopenharmony_ci    # is 0.
7081cb0ef41Sopenharmony_ci    if mmap_info.tid == 0 and not options.kernel:
7091cb0ef41Sopenharmony_ci      return True
7101cb0ef41Sopenharmony_ci    if OBJDUMP_SKIP_RE.match(mmap_info.filename):
7111cb0ef41Sopenharmony_ci      return True
7121cb0ef41Sopenharmony_ci    if PERF_KERNEL_ALLSYMS_RE.match(mmap_info.filename):
7131cb0ef41Sopenharmony_ci      return self._LoadKernelSymbols(code_map)
7141cb0ef41Sopenharmony_ci    self.infos.append(mmap_info)
7151cb0ef41Sopenharmony_ci    mmap_info.ticks = 0
7161cb0ef41Sopenharmony_ci    mmap_info.unique_name = self._UniqueMmapName(mmap_info)
7171cb0ef41Sopenharmony_ci    if not os.path.exists(mmap_info.filename):
7181cb0ef41Sopenharmony_ci      return True
7191cb0ef41Sopenharmony_ci    # Request section headers (-h), symbols (-t), and dynamic symbols
7201cb0ef41Sopenharmony_ci    # (-T) from objdump.
7211cb0ef41Sopenharmony_ci    # Unfortunately, section headers span two lines, so we have to
7221cb0ef41Sopenharmony_ci    # keep the just seen section name (from the first line in each
7231cb0ef41Sopenharmony_ci    # section header) in the after_section variable.
7241cb0ef41Sopenharmony_ci    if self.HasDynamicSymbols(mmap_info.filename):
7251cb0ef41Sopenharmony_ci      dynamic_symbols = "-T"
7261cb0ef41Sopenharmony_ci    else:
7271cb0ef41Sopenharmony_ci      dynamic_symbols = ""
7281cb0ef41Sopenharmony_ci    process = subprocess.Popen(
7291cb0ef41Sopenharmony_ci      "%s -h -t %s -C %s" % (OBJDUMP_BIN, dynamic_symbols, mmap_info.filename),
7301cb0ef41Sopenharmony_ci      shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
7311cb0ef41Sopenharmony_ci    pipe = process.stdout
7321cb0ef41Sopenharmony_ci    after_section = None
7331cb0ef41Sopenharmony_ci    code_sections = set()
7341cb0ef41Sopenharmony_ci    reloc_sections = set()
7351cb0ef41Sopenharmony_ci    dynamic = False
7361cb0ef41Sopenharmony_ci    try:
7371cb0ef41Sopenharmony_ci      for line in pipe:
7381cb0ef41Sopenharmony_ci        if after_section:
7391cb0ef41Sopenharmony_ci          if line.find("CODE") != -1:
7401cb0ef41Sopenharmony_ci            code_sections.add(after_section)
7411cb0ef41Sopenharmony_ci          if line.find("RELOC") != -1:
7421cb0ef41Sopenharmony_ci            reloc_sections.add(after_section)
7431cb0ef41Sopenharmony_ci          after_section = None
7441cb0ef41Sopenharmony_ci          continue
7451cb0ef41Sopenharmony_ci
7461cb0ef41Sopenharmony_ci        match = OBJDUMP_SECTION_HEADER_RE.match(line)
7471cb0ef41Sopenharmony_ci        if match:
7481cb0ef41Sopenharmony_ci          after_section = match.group(1)
7491cb0ef41Sopenharmony_ci          continue
7501cb0ef41Sopenharmony_ci
7511cb0ef41Sopenharmony_ci        if OBJDUMP_DYNAMIC_SYMBOLS_START_RE.match(line):
7521cb0ef41Sopenharmony_ci          dynamic = True
7531cb0ef41Sopenharmony_ci          continue
7541cb0ef41Sopenharmony_ci
7551cb0ef41Sopenharmony_ci        match = OBJDUMP_SYMBOL_LINE_RE.match(line)
7561cb0ef41Sopenharmony_ci        if match:
7571cb0ef41Sopenharmony_ci          start_address = int(match.group(1), 16)
7581cb0ef41Sopenharmony_ci          origin_offset = start_address
7591cb0ef41Sopenharmony_ci          flags = match.group(2)
7601cb0ef41Sopenharmony_ci          section = match.group(3)
7611cb0ef41Sopenharmony_ci          if section in code_sections:
7621cb0ef41Sopenharmony_ci            if dynamic or section in reloc_sections:
7631cb0ef41Sopenharmony_ci              start_address += mmap_info.addr
7641cb0ef41Sopenharmony_ci            size = int(match.group(4), 16)
7651cb0ef41Sopenharmony_ci            name = match.group(5)
7661cb0ef41Sopenharmony_ci            origin = mmap_info.filename
7671cb0ef41Sopenharmony_ci            code_map.Add(Code(name, start_address, start_address + size,
7681cb0ef41Sopenharmony_ci                              origin, origin_offset))
7691cb0ef41Sopenharmony_ci    finally:
7701cb0ef41Sopenharmony_ci      pipe.close()
7711cb0ef41Sopenharmony_ci    assert process.wait() == 0, "Failed to objdump %s" % mmap_info.filename
7721cb0ef41Sopenharmony_ci
7731cb0ef41Sopenharmony_ci  def Tick(self, pc):
7741cb0ef41Sopenharmony_ci    for i, mmap_info in enumerate(self.infos):
7751cb0ef41Sopenharmony_ci      if mmap_info.addr <= pc < (mmap_info.addr + mmap_info.len):
7761cb0ef41Sopenharmony_ci        mmap_info.ticks += 1
7771cb0ef41Sopenharmony_ci        self.infos[0], self.infos[i] = mmap_info, self.infos[0]
7781cb0ef41Sopenharmony_ci        return True
7791cb0ef41Sopenharmony_ci    return False
7801cb0ef41Sopenharmony_ci
7811cb0ef41Sopenharmony_ci  def _UniqueMmapName(self, mmap_info):
7821cb0ef41Sopenharmony_ci    name = mmap_info.filename
7831cb0ef41Sopenharmony_ci    index = 1
7841cb0ef41Sopenharmony_ci    while name in self.names:
7851cb0ef41Sopenharmony_ci      name = "%s-%d" % (mmap_info.filename, index)
7861cb0ef41Sopenharmony_ci      index += 1
7871cb0ef41Sopenharmony_ci    self.names.add(name)
7881cb0ef41Sopenharmony_ci    return name
7891cb0ef41Sopenharmony_ci
7901cb0ef41Sopenharmony_ci  def _LoadKernelSymbols(self, code_map):
7911cb0ef41Sopenharmony_ci    if not os.path.exists(KERNEL_ALLSYMS_FILE):
7921cb0ef41Sopenharmony_ci      print("Warning: %s not found" % KERNEL_ALLSYMS_FILE, file=sys.stderr)
7931cb0ef41Sopenharmony_ci      return False
7941cb0ef41Sopenharmony_ci    kallsyms = open(KERNEL_ALLSYMS_FILE, "r")
7951cb0ef41Sopenharmony_ci    code = None
7961cb0ef41Sopenharmony_ci    for line in kallsyms:
7971cb0ef41Sopenharmony_ci      match = KERNEL_ALLSYMS_LINE_RE.match(line)
7981cb0ef41Sopenharmony_ci      if match:
7991cb0ef41Sopenharmony_ci        start_address = int(match.group(1), 16)
8001cb0ef41Sopenharmony_ci        end_address = start_address
8011cb0ef41Sopenharmony_ci        name = match.group(2)
8021cb0ef41Sopenharmony_ci        if code:
8031cb0ef41Sopenharmony_ci          code.end_address = start_address
8041cb0ef41Sopenharmony_ci          code_map.Add(code, 16)
8051cb0ef41Sopenharmony_ci        code = Code(name, start_address, end_address, "kernel", 0)
8061cb0ef41Sopenharmony_ci    return True
8071cb0ef41Sopenharmony_ci
8081cb0ef41Sopenharmony_ci
8091cb0ef41Sopenharmony_cidef PrintReport(code_map, library_repo, arch, ticks, options):
8101cb0ef41Sopenharmony_ci  print("Ticks per symbol:")
8111cb0ef41Sopenharmony_ci  used_code = [code for code in code_map.UsedCode()]
8121cb0ef41Sopenharmony_ci  used_code.sort(key=lambda x: x.self_ticks, reverse=True)
8131cb0ef41Sopenharmony_ci  for i, code in enumerate(used_code):
8141cb0ef41Sopenharmony_ci    code_ticks = code.self_ticks
8151cb0ef41Sopenharmony_ci    print("%10d %5.1f%% %s [%s]" % (code_ticks, 100. * code_ticks / ticks,
8161cb0ef41Sopenharmony_ci                                    code.FullName(), code.origin))
8171cb0ef41Sopenharmony_ci    if options.disasm_all or i < options.disasm_top:
8181cb0ef41Sopenharmony_ci      code.PrintAnnotated(arch, options)
8191cb0ef41Sopenharmony_ci  print()
8201cb0ef41Sopenharmony_ci  print("Ticks per library:")
8211cb0ef41Sopenharmony_ci  mmap_infos = [m for m in library_repo.infos if m.ticks > 0]
8221cb0ef41Sopenharmony_ci  mmap_infos.sort(key=lambda m: m.ticks, reverse=True)
8231cb0ef41Sopenharmony_ci  for mmap_info in mmap_infos:
8241cb0ef41Sopenharmony_ci    mmap_ticks = mmap_info.ticks
8251cb0ef41Sopenharmony_ci    print("%10d %5.1f%% %s" % (mmap_ticks, 100. * mmap_ticks / ticks,
8261cb0ef41Sopenharmony_ci                               mmap_info.unique_name))
8271cb0ef41Sopenharmony_ci
8281cb0ef41Sopenharmony_ci
8291cb0ef41Sopenharmony_cidef PrintDot(code_map, options):
8301cb0ef41Sopenharmony_ci  print("digraph G {")
8311cb0ef41Sopenharmony_ci  for code in code_map.UsedCode():
8321cb0ef41Sopenharmony_ci    if code.self_ticks < 10:
8331cb0ef41Sopenharmony_ci      continue
8341cb0ef41Sopenharmony_ci    print("n%d [shape=box,label=\"%s\"];" % (code.id, code.name))
8351cb0ef41Sopenharmony_ci    if code.callee_ticks:
8361cb0ef41Sopenharmony_ci      for callee, ticks in code.callee_ticks.iteritems():
8371cb0ef41Sopenharmony_ci        print("n%d -> n%d [label=\"%d\"];" % (code.id, callee.id, ticks))
8381cb0ef41Sopenharmony_ci  print("}")
8391cb0ef41Sopenharmony_ci
8401cb0ef41Sopenharmony_ci
8411cb0ef41Sopenharmony_ciif __name__ == "__main__":
8421cb0ef41Sopenharmony_ci  parser = optparse.OptionParser(USAGE)
8431cb0ef41Sopenharmony_ci  parser.add_option("--log",
8441cb0ef41Sopenharmony_ci                    default="v8.log",
8451cb0ef41Sopenharmony_ci                    help="V8 log file name [default: %default]")
8461cb0ef41Sopenharmony_ci  parser.add_option("--trace",
8471cb0ef41Sopenharmony_ci                    default="perf.data",
8481cb0ef41Sopenharmony_ci                    help="perf trace file name [default: %default]")
8491cb0ef41Sopenharmony_ci  parser.add_option("--kernel",
8501cb0ef41Sopenharmony_ci                    default=False,
8511cb0ef41Sopenharmony_ci                    action="store_true",
8521cb0ef41Sopenharmony_ci                    help="process kernel entries [default: %default]")
8531cb0ef41Sopenharmony_ci  parser.add_option("--disasm-top",
8541cb0ef41Sopenharmony_ci                    default=0,
8551cb0ef41Sopenharmony_ci                    type="int",
8561cb0ef41Sopenharmony_ci                    help=("number of top symbols to disassemble and annotate "
8571cb0ef41Sopenharmony_ci                          "[default: %default]"))
8581cb0ef41Sopenharmony_ci  parser.add_option("--disasm-all",
8591cb0ef41Sopenharmony_ci                    default=False,
8601cb0ef41Sopenharmony_ci                    action="store_true",
8611cb0ef41Sopenharmony_ci                    help=("disassemble and annotate all used symbols "
8621cb0ef41Sopenharmony_ci                          "[default: %default]"))
8631cb0ef41Sopenharmony_ci  parser.add_option("--dot",
8641cb0ef41Sopenharmony_ci                    default=False,
8651cb0ef41Sopenharmony_ci                    action="store_true",
8661cb0ef41Sopenharmony_ci                    help="produce dot output (WIP) [default: %default]")
8671cb0ef41Sopenharmony_ci  parser.add_option("--quiet", "-q",
8681cb0ef41Sopenharmony_ci                    default=False,
8691cb0ef41Sopenharmony_ci                    action="store_true",
8701cb0ef41Sopenharmony_ci                    help="no auxiliary messages [default: %default]")
8711cb0ef41Sopenharmony_ci  parser.add_option("--gc-fake-mmap",
8721cb0ef41Sopenharmony_ci                    default="/tmp/__v8_gc__",
8731cb0ef41Sopenharmony_ci                    help="gc fake mmap file [default: %default]")
8741cb0ef41Sopenharmony_ci  parser.add_option("--objdump",
8751cb0ef41Sopenharmony_ci                    default="/usr/bin/objdump",
8761cb0ef41Sopenharmony_ci                    help="objdump tool to use [default: %default]")
8771cb0ef41Sopenharmony_ci  parser.add_option("--host-root",
8781cb0ef41Sopenharmony_ci                    default="",
8791cb0ef41Sopenharmony_ci                    help="Path to the host root [default: %default]")
8801cb0ef41Sopenharmony_ci  options, args = parser.parse_args()
8811cb0ef41Sopenharmony_ci
8821cb0ef41Sopenharmony_ci  if not options.quiet:
8831cb0ef41Sopenharmony_ci    print("V8 log: %s, %s.ll" % (options.log, options.log))
8841cb0ef41Sopenharmony_ci    print("Perf trace file: %s" % options.trace)
8851cb0ef41Sopenharmony_ci
8861cb0ef41Sopenharmony_ci  V8_GC_FAKE_MMAP = options.gc_fake_mmap
8871cb0ef41Sopenharmony_ci  HOST_ROOT = options.host_root
8881cb0ef41Sopenharmony_ci  if os.path.exists(options.objdump):
8891cb0ef41Sopenharmony_ci    disasm.OBJDUMP_BIN = options.objdump
8901cb0ef41Sopenharmony_ci    OBJDUMP_BIN = options.objdump
8911cb0ef41Sopenharmony_ci  else:
8921cb0ef41Sopenharmony_ci    print("Cannot find %s, falling back to default objdump" % options.objdump)
8931cb0ef41Sopenharmony_ci
8941cb0ef41Sopenharmony_ci  # Stats.
8951cb0ef41Sopenharmony_ci  events = 0
8961cb0ef41Sopenharmony_ci  ticks = 0
8971cb0ef41Sopenharmony_ci  missed_ticks = 0
8981cb0ef41Sopenharmony_ci  really_missed_ticks = 0
8991cb0ef41Sopenharmony_ci  optimized_ticks = 0
9001cb0ef41Sopenharmony_ci  generated_ticks = 0
9011cb0ef41Sopenharmony_ci  v8_internal_ticks = 0
9021cb0ef41Sopenharmony_ci  mmap_time = 0
9031cb0ef41Sopenharmony_ci  sample_time = 0
9041cb0ef41Sopenharmony_ci
9051cb0ef41Sopenharmony_ci  # Initialize the log reader.
9061cb0ef41Sopenharmony_ci  code_map = CodeMap()
9071cb0ef41Sopenharmony_ci  log_reader = LogReader(log_name=options.log + ".ll",
9081cb0ef41Sopenharmony_ci                         code_map=code_map)
9091cb0ef41Sopenharmony_ci  if not options.quiet:
9101cb0ef41Sopenharmony_ci    print("Generated code architecture: %s" % log_reader.arch)
9111cb0ef41Sopenharmony_ci    print()
9121cb0ef41Sopenharmony_ci    sys.stdout.flush()
9131cb0ef41Sopenharmony_ci
9141cb0ef41Sopenharmony_ci  # Process the code and trace logs.
9151cb0ef41Sopenharmony_ci  library_repo = LibraryRepo()
9161cb0ef41Sopenharmony_ci  log_reader.ReadUpToGC()
9171cb0ef41Sopenharmony_ci  trace_reader = TraceReader(options.trace)
9181cb0ef41Sopenharmony_ci  while True:
9191cb0ef41Sopenharmony_ci    header, offset = trace_reader.ReadEventHeader()
9201cb0ef41Sopenharmony_ci    if not header:
9211cb0ef41Sopenharmony_ci      break
9221cb0ef41Sopenharmony_ci    events += 1
9231cb0ef41Sopenharmony_ci    if header.type == PERF_RECORD_MMAP:
9241cb0ef41Sopenharmony_ci      start = time.time()
9251cb0ef41Sopenharmony_ci      mmap_info = trace_reader.ReadMmap(header, offset)
9261cb0ef41Sopenharmony_ci      if mmap_info.filename == HOST_ROOT + V8_GC_FAKE_MMAP:
9271cb0ef41Sopenharmony_ci        log_reader.ReadUpToGC()
9281cb0ef41Sopenharmony_ci      else:
9291cb0ef41Sopenharmony_ci        library_repo.Load(mmap_info, code_map, options)
9301cb0ef41Sopenharmony_ci      mmap_time += time.time() - start
9311cb0ef41Sopenharmony_ci    elif header.type == PERF_RECORD_MMAP2:
9321cb0ef41Sopenharmony_ci      start = time.time()
9331cb0ef41Sopenharmony_ci      mmap_info = trace_reader.ReadMmap2(header, offset)
9341cb0ef41Sopenharmony_ci      if mmap_info.filename == HOST_ROOT + V8_GC_FAKE_MMAP:
9351cb0ef41Sopenharmony_ci        log_reader.ReadUpToGC()
9361cb0ef41Sopenharmony_ci      else:
9371cb0ef41Sopenharmony_ci        library_repo.Load(mmap_info, code_map, options)
9381cb0ef41Sopenharmony_ci      mmap_time += time.time() - start
9391cb0ef41Sopenharmony_ci    elif header.type == PERF_RECORD_SAMPLE:
9401cb0ef41Sopenharmony_ci      ticks += 1
9411cb0ef41Sopenharmony_ci      start = time.time()
9421cb0ef41Sopenharmony_ci      sample = trace_reader.ReadSample(header, offset)
9431cb0ef41Sopenharmony_ci      code = code_map.Find(sample.ip)
9441cb0ef41Sopenharmony_ci      if code:
9451cb0ef41Sopenharmony_ci        code.Tick(sample.ip)
9461cb0ef41Sopenharmony_ci        if code.codetype == Code.OPTIMIZED:
9471cb0ef41Sopenharmony_ci          optimized_ticks += 1
9481cb0ef41Sopenharmony_ci        elif code.codetype == Code.FULL_CODEGEN:
9491cb0ef41Sopenharmony_ci          generated_ticks += 1
9501cb0ef41Sopenharmony_ci        elif code.codetype == Code.V8INTERNAL:
9511cb0ef41Sopenharmony_ci          v8_internal_ticks += 1
9521cb0ef41Sopenharmony_ci      else:
9531cb0ef41Sopenharmony_ci        missed_ticks += 1
9541cb0ef41Sopenharmony_ci      if not library_repo.Tick(sample.ip) and not code:
9551cb0ef41Sopenharmony_ci        really_missed_ticks += 1
9561cb0ef41Sopenharmony_ci      if trace_reader.callchain_supported:
9571cb0ef41Sopenharmony_ci        for ip in sample.ips:
9581cb0ef41Sopenharmony_ci          caller_code = code_map.Find(ip)
9591cb0ef41Sopenharmony_ci          if caller_code:
9601cb0ef41Sopenharmony_ci            if code:
9611cb0ef41Sopenharmony_ci              caller_code.CalleeTick(code)
9621cb0ef41Sopenharmony_ci            code = caller_code
9631cb0ef41Sopenharmony_ci      sample_time += time.time() - start
9641cb0ef41Sopenharmony_ci
9651cb0ef41Sopenharmony_ci  if options.dot:
9661cb0ef41Sopenharmony_ci    PrintDot(code_map, options)
9671cb0ef41Sopenharmony_ci  else:
9681cb0ef41Sopenharmony_ci    PrintReport(code_map, library_repo, log_reader.arch, ticks, options)
9691cb0ef41Sopenharmony_ci
9701cb0ef41Sopenharmony_ci    if not options.quiet:
9711cb0ef41Sopenharmony_ci      def PrintTicks(number, total, description):
9721cb0ef41Sopenharmony_ci        print("%10d %5.1f%% ticks in %s" %
9731cb0ef41Sopenharmony_ci              (number, 100.0*number/total, description))
9741cb0ef41Sopenharmony_ci      print()
9751cb0ef41Sopenharmony_ci      print("Stats:")
9761cb0ef41Sopenharmony_ci      print("%10d total trace events" % events)
9771cb0ef41Sopenharmony_ci      print("%10d total ticks" % ticks)
9781cb0ef41Sopenharmony_ci      print("%10d ticks not in symbols" % missed_ticks)
9791cb0ef41Sopenharmony_ci      unaccounted = "unaccounted ticks"
9801cb0ef41Sopenharmony_ci      if really_missed_ticks > 0:
9811cb0ef41Sopenharmony_ci        unaccounted += " (probably in the kernel, try --kernel)"
9821cb0ef41Sopenharmony_ci      PrintTicks(really_missed_ticks, ticks, unaccounted)
9831cb0ef41Sopenharmony_ci      PrintTicks(optimized_ticks, ticks, "ticks in optimized code")
9841cb0ef41Sopenharmony_ci      PrintTicks(generated_ticks, ticks, "ticks in other lazily compiled code")
9851cb0ef41Sopenharmony_ci      PrintTicks(v8_internal_ticks, ticks, "ticks in v8::internal::*")
9861cb0ef41Sopenharmony_ci      print("%10d total symbols" % len([c for c in code_map.AllCode()]))
9871cb0ef41Sopenharmony_ci      print("%10d used symbols" % len([c for c in code_map.UsedCode()]))
9881cb0ef41Sopenharmony_ci      print("%9.2fs library processing time" % mmap_time)
9891cb0ef41Sopenharmony_ci      print("%9.2fs tick processing time" % sample_time)
9901cb0ef41Sopenharmony_ci
9911cb0ef41Sopenharmony_ci  log_reader.Dispose()
9921cb0ef41Sopenharmony_ci  trace_reader.Dispose()
993