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