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