1f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch#!/usr/bin/env python 2f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# 33ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch# Copyright 2012 the V8 project authors. All rights reserved. 4f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# Redistribution and use in source and binary forms, with or without 5f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# modification, are permitted provided that the following conditions are 6f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# met: 7f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# 8f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# * Redistributions of source code must retain the above copyright 9f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# notice, this list of conditions and the following disclaimer. 10f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# * Redistributions in binary form must reproduce the above 11f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# copyright notice, this list of conditions and the following 12f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# disclaimer in the documentation and/or other materials provided 13f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# with the distribution. 14f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# * Neither the name of Google Inc. nor the names of its 15f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# contributors may be used to endorse or promote products derived 16f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# from this software without specific prior written permission. 17f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# 18f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 30f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport bisect 31f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport collections 32f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport ctypes 33e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdochimport disasm 34f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport mmap 35f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport optparse 36f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport os 37f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport re 38f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport subprocess 39f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport sys 40f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochimport time 41f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 42f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 43f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochUSAGE="""usage: %prog [OPTION]... 44f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 45f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochAnalyses V8 and perf logs to produce profiles. 46f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 47f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPerf logs can be collected using a command like: 48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch $ perf record -R -e cycles -c 10000 -f -i ./d8 bench.js --ll-prof 49f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # -R: collect all data 50f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # -e cycles: use cpu-cycles event (run "perf list" for details) 51f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # -c 10000: write a sample after each 10000 events 52f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # -f: force output file overwrite 53f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # -i: limit profiling to our process and the kernel 54f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # --ll-prof shell flag enables the right V8 logs 55f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochThis will produce a binary trace file (perf.data) that %prog can analyse. 56f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochIMPORTANT: 58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch The kernel has an internal maximum for events per second, it is 100K by 59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch default. That's not enough for "-c 10000". Set it to some higher value: 60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch $ echo 10000000 | sudo tee /proc/sys/kernel/perf_event_max_sample_rate 61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch You can also make the warning about kernel address maps go away: 62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch $ echo 0 | sudo tee /proc/sys/kernel/kptr_restrict 63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen MurdochWe have a convenience script that handles all of the above for you: 65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch $ tools/run-llprof.sh ./d8 bench.js 66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 67f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochExamples: 68f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Print flat profile with annotated disassembly for the 10 top 693b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch # symbols. Use default log names. 703b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch $ %prog --disasm-top=10 71f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 72f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Print flat profile with annotated disassembly for all used symbols. 73f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Use default log names and include kernel symbols into analysis. 74f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch $ %prog --disasm-all --kernel 75f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 76f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Print flat profile. Use custom log names. 773b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch $ %prog --log=foo.log --trace=foo.data 78f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch""" 79f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 80f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 81f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochJS_ORIGIN = "js" 823b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 83f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 84f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass Code(object): 85f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch """Code object.""" 86f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 87f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch _id = 0 88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch UNKNOWN = 0 89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch V8INTERNAL = 1 90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FULL_CODEGEN = 2 91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch OPTIMIZED = 3 92f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 93f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self, name, start_address, end_address, origin, origin_offset): 94f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.id = Code._id 95f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch Code._id += 1 96f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.name = name 97f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.other_names = None 98f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.start_address = start_address 99f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.end_address = end_address 100f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.origin = origin 101f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.origin_offset = origin_offset 102f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.self_ticks = 0 103f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.self_ticks_map = None 104f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.callee_ticks = None 105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if name.startswith("LazyCompile:*"): 106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.codetype = Code.OPTIMIZED 107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch elif name.startswith("LazyCompile:"): 108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.codetype = Code.FULL_CODEGEN 109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch elif name.startswith("v8::internal::"): 110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.codetype = Code.V8INTERNAL 111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch else: 112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch self.codetype = Code.UNKNOWN 113f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 114f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def AddName(self, name): 115f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert self.name != name 116f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.other_names is None: 117f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.other_names = [name] 118f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return 119f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not name in self.other_names: 120f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.other_names.append(name) 121f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 122f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def FullName(self): 123f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.other_names is None: 124f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return self.name 125f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.other_names.sort() 126f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return "%s (aka %s)" % (self.name, ", ".join(self.other_names)) 127f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 128f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def IsUsed(self): 129f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return self.self_ticks > 0 or self.callee_ticks is not None 130f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 131f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Tick(self, pc): 132f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.self_ticks += 1 133f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.self_ticks_map is None: 134f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.self_ticks_map = collections.defaultdict(lambda: 0) 135f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch offset = pc - self.start_address 136f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.self_ticks_map[offset] += 1 137f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 138f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def CalleeTick(self, callee): 139f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.callee_ticks is None: 140f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.callee_ticks = collections.defaultdict(lambda: 0) 141f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.callee_ticks[callee] += 1 142f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 143257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def PrintAnnotated(self, arch, options): 144f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.self_ticks_map is None: 145f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ticks_map = [] 146f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 147f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ticks_map = self.self_ticks_map.items() 148f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Convert the ticks map to offsets and counts arrays so that later 149f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # we can do binary search in the offsets array. 150f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ticks_map.sort(key=lambda t: t[0]) 151f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ticks_offsets = [t[0] for t in ticks_map] 152f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ticks_counts = [t[1] for t in ticks_map] 153f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Get a list of disassembled lines and their addresses. 154257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch lines = self._GetDisasmLines(arch, options) 155f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if len(lines) == 0: 156f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return 157f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Print annotated lines. 158f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch address = lines[0][0] 159f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch total_count = 0 160f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for i in xrange(len(lines)): 161f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch start_offset = lines[i][0] - address 162f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if i == len(lines) - 1: 163f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch end_offset = self.end_address - self.start_address 164f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 165f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch end_offset = lines[i + 1][0] - address 166f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Ticks (reported pc values) are not always precise, i.e. not 167f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # necessarily point at instruction starts. So we have to search 168f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # for ticks that touch the current instruction line. 169f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch j = bisect.bisect_left(ticks_offsets, end_offset) 170f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch count = 0 171f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for offset, cnt in reversed(zip(ticks_offsets[:j], ticks_counts[:j])): 172f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if offset < start_offset: 173f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch break 174f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch count += cnt 175f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch total_count += count 176109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch percent = 100.0 * count / self.self_ticks 177109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch offset = lines[i][0] 178109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch if percent >= 0.01: 179109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch # 5 spaces for tick count 180109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch # 1 space following 181109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch # 1 for '|' 182109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch # 1 space following 183109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch # 6 for the percentage number, incl. the '.' 184109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch # 1 for the '%' sign 185109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch # => 15 186109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch print "%5d | %6.2f%% %x(%d): %s" % (count, percent, offset, offset, lines[i][1]) 187f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 188109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch print "%s %x(%d): %s" % (" " * 15, offset, offset, lines[i][1]) 189f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print 190f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert total_count == self.self_ticks, \ 191f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Lost ticks (%d != %d) in %s" % (total_count, self.self_ticks, self) 192f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 193f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __str__(self): 194f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return "%s [0x%x, 0x%x) size: %d origin: %s" % ( 195f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.name, 196f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.start_address, 197f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.end_address, 198f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.end_address - self.start_address, 199f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.origin) 200f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 201257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def _GetDisasmLines(self, arch, options): 2023b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch if self.origin == JS_ORIGIN: 203e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch inplace = False 204257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch filename = options.log + ".ll" 205f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 206e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch inplace = True 207e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch filename = self.origin 208e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch return disasm.GetDisasmLines(filename, 209e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch self.origin_offset, 210e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch self.end_address - self.start_address, 211257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch arch, 212e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch inplace) 213f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 214f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 215f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodePage(object): 216f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch """Group of adjacent code objects.""" 217f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch SHIFT = 20 # 1M pages 219f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch SIZE = (1 << SHIFT) 220f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch MASK = ~(SIZE - 1) 221f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 222f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch @staticmethod 223f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def PageAddress(address): 224f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return address & CodePage.MASK 225f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 226f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch @staticmethod 227f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def PageId(address): 228f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return address >> CodePage.SHIFT 229f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 230f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch @staticmethod 231f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def PageAddressFromId(id): 232f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return id << CodePage.SHIFT 233f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 234f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self, address): 235f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.address = address 236f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_objects = [] 237f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 238f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Add(self, code): 239f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_objects.append(code) 240f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 241f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Remove(self, code): 242f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_objects.remove(code) 243f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 244f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Find(self, pc): 245f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_objects = self.code_objects 246f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for i, code in enumerate(code_objects): 247f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code.start_address <= pc < code.end_address: 248f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_objects[0], code_objects[i] = code, code_objects[0] 249f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return code 250f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return None 251f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 252f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __iter__(self): 253f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return self.code_objects.__iter__() 254f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 255f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 256f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodeMap(object): 257f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch """Code object map.""" 258f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 259f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self): 260f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.pages = {} 261f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.min_address = 1 << 64 262f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.max_address = -1 263f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 264f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Add(self, code, max_pages=-1): 265f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id = CodePage.PageId(code.start_address) 266f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1) 267f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch pages = 0 268f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch while page_id < limit_id: 269f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if max_pages >= 0 and pages > max_pages: 270f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print >>sys.stderr, \ 271f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Warning: page limit (%d) reached for %s [%s]" % ( 272f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch max_pages, code.name, code.origin) 273f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch break 274f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if page_id in self.pages: 275f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page = self.pages[page_id] 276f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 277f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page = CodePage(CodePage.PageAddressFromId(page_id)) 278f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.pages[page_id] = page 279f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page.Add(code) 280f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id += 1 281f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch pages += 1 282f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.min_address = min(self.min_address, code.start_address) 283f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.max_address = max(self.max_address, code.end_address) 284f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 285f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Remove(self, code): 286f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id = CodePage.PageId(code.start_address) 287f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1) 288f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch removed = False 289f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch while page_id < limit_id: 290f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if page_id not in self.pages: 291f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id += 1 292f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 293f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page = self.pages[page_id] 294f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page.Remove(code) 295f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch removed = True 296f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id += 1 297f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return removed 298f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 299f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def AllCode(self): 300f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for page in self.pages.itervalues(): 301f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for code in page: 302f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if CodePage.PageAddress(code.start_address) == page.address: 303f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch yield code 304f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 305f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def UsedCode(self): 306f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for code in self.AllCode(): 307f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code.IsUsed(): 308f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch yield code 309f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 310f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Print(self): 311f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for code in self.AllCode(): 312f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print code 313f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 314f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Find(self, pc): 315f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if pc < self.min_address or pc >= self.max_address: 316f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return None 317f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id = CodePage.PageId(pc) 318f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if page_id not in self.pages: 319f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return None 320f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return self.pages[page_id].Find(pc) 321f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 322f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 323f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodeInfo(object): 324f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch """Generic info about generated code objects.""" 325f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 326f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self, arch, header_size): 327f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.arch = arch 328f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.header_size = header_size 329f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 330f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochclass LogReader(object): 332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch """V8 low-level (binary) log reader.""" 333f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _ARCH_TO_POINTER_TYPE_MAP = { 335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch "ia32": ctypes.c_uint32, 336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch "arm": ctypes.c_uint32, 3373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch "mips": ctypes.c_uint32, 338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "x64": ctypes.c_uint64, 339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "arm64": ctypes.c_uint64 340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 341f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _CODE_CREATE_TAG = "C" 343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _CODE_MOVE_TAG = "M" 344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _CODE_MOVING_GC_TAG = "G" 345f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 3463b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch def __init__(self, log_name, code_map): 347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_file = open(log_name, "r") 348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log = mmap.mmap(self.log_file.fileno(), 0, mmap.MAP_PRIVATE) 349257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos = 0 350f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_map = code_map 351f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.arch = self.log[:self.log.find("\0")] 353257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += len(self.arch) + 1 354257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch assert self.arch in LogReader._ARCH_TO_POINTER_TYPE_MAP, \ 355257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch "Unsupported architecture %s" % self.arch 356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch pointer_type = LogReader._ARCH_TO_POINTER_TYPE_MAP[self.arch] 357257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.code_create_struct = LogReader._DefineStruct([ 359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("name_size", ctypes.c_int32), 360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("code_address", pointer_type), 361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("code_size", ctypes.c_int32)]) 362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 363257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.code_move_struct = LogReader._DefineStruct([ 364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("from_address", pointer_type), 365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("to_address", pointer_type)]) 366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.code_delete_struct = LogReader._DefineStruct([ 368257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("address", pointer_type)]) 369257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 370257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def ReadUpToGC(self): 371257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch while self.log_pos < self.log.size(): 372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch tag = self.log[self.log_pos] 373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += 1 374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if tag == LogReader._CODE_MOVING_GC_TAG: 376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch return 377f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if tag == LogReader._CODE_CREATE_TAG: 379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch event = self.code_create_struct.from_buffer(self.log, self.log_pos) 380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += ctypes.sizeof(event) 381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch start_address = event.code_address 382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch end_address = start_address + event.code_size 3833b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch name = self.log[self.log_pos:self.log_pos + event.name_size] 3843b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch origin = JS_ORIGIN 385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += event.name_size 386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch origin_offset = self.log_pos 387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += event.code_size 388f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = Code(name, start_address, end_address, origin, origin_offset) 389f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch conficting_code = self.code_map.Find(start_address) 390f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if conficting_code: 3913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if not (conficting_code.start_address == code.start_address and 3923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch conficting_code.end_address == code.end_address): 3933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch self.code_map.Remove(conficting_code) 3943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch else: 3953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch LogReader._HandleCodeConflict(conficting_code, code) 3963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch # TODO(vitalyr): this warning is too noisy because of our 3973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch # attempts to reconstruct code log from the snapshot. 3983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch # print >>sys.stderr, \ 3993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch # "Warning: Skipping duplicate code log entry %s" % code 4003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch continue 401f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_map.Add(code) 402f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 403f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if tag == LogReader._CODE_MOVE_TAG: 405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch event = self.code_move_struct.from_buffer(self.log, self.log_pos) 406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += ctypes.sizeof(event) 407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch old_start_address = event.from_address 408257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch new_start_address = event.to_address 409f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if old_start_address == new_start_address: 410f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Skip useless code move entries. 411f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 412f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = self.code_map.Find(old_start_address) 413f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not code: 414f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print >>sys.stderr, "Warning: Not found %x" % old_start_address 415f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 416f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert code.start_address == old_start_address, \ 417f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Inexact move address %x for %s" % (old_start_address, code) 418f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_map.Remove(code) 419f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch size = code.end_address - code.start_address 420f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code.start_address = new_start_address 421f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code.end_address = new_start_address + size 422f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_map.Add(code) 423f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 424f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 425257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch assert False, "Unknown tag %s" % tag 426f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 427f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Dispose(self): 428f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.log.close() 429257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_file.close() 430257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 431257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch @staticmethod 432257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def _DefineStruct(fields): 433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch class Struct(ctypes.Structure): 434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _fields_ = fields 435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch return Struct 436f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 437f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch @staticmethod 438f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def _HandleCodeConflict(old_code, new_code): 439f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert (old_code.start_address == new_code.start_address and 440f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch old_code.end_address == new_code.end_address), \ 441f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Conficting code log entries %s and %s" % (old_code, new_code) 442f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if old_code.name == new_code.name: 443f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return 444f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Code object may be shared by a few functions. Collect the full 445f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # set of names. 446f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch old_code.AddName(new_code.name) 447f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 448f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 449f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass Descriptor(object): 450f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch """Descriptor of a structure in the binary trace log.""" 451f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 452f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch CTYPE_MAP = { 453f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "u16": ctypes.c_uint16, 454f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "u32": ctypes.c_uint32, 455f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "u64": ctypes.c_uint64 456f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch } 457f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 458f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self, fields): 459f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch class TraceItem(ctypes.Structure): 460f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch _fields_ = Descriptor.CtypesFields(fields) 461f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 462f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __str__(self): 463f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return ", ".join("%s: %s" % (field, self.__getattribute__(field)) 464f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for field, _ in TraceItem._fields_) 465f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 466f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.ctype = TraceItem 467f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 468f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Read(self, trace, offset): 469f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return self.ctype.from_buffer(trace, offset) 470f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 471f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch @staticmethod 472f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def CtypesFields(fields): 473f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return [(field, Descriptor.CTYPE_MAP[format]) for (field, format) in fields] 474f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 475f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 476f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# Please see http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=tree;f=tools/perf 477f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# for the gory details. 478f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 479f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 480b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: struct perf_file_header in kernel/tools/perf/util/header.h 481f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochTRACE_HEADER_DESC = Descriptor([ 482f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("magic", "u64"), 483f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("size", "u64"), 484f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("attr_size", "u64"), 485f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("attrs_offset", "u64"), 486f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("attrs_size", "u64"), 487f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("data_offset", "u64"), 488f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("data_size", "u64"), 489f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("event_types_offset", "u64"), 490f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("event_types_size", "u64") 491f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch]) 492f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 493f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 494b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/linux/perf_event.h 495f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_EVENT_ATTR_DESC = Descriptor([ 496f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("type", "u32"), 497f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("size", "u32"), 498f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("config", "u64"), 499f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("sample_period_or_freq", "u64"), 500f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("sample_type", "u64"), 501f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("read_format", "u64"), 502f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("flags", "u64"), 503f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("wakeup_events_or_watermark", "u32"), 504b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ("bp_type", "u32"), 505f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("bp_addr", "u64"), 506b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ("bp_len", "u64") 507f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch]) 508f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 509f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 510b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/linux/perf_event.h 511f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_EVENT_HEADER_DESC = Descriptor([ 512f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("type", "u32"), 513f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("misc", "u16"), 514f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("size", "u16") 515f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch]) 516f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 517f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 518014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch# Reference: kernel/tools/perf/util/event.h 519f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_MMAP_EVENT_BODY_DESC = Descriptor([ 520f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("pid", "u32"), 521f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("tid", "u32"), 522f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("addr", "u64"), 523f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("len", "u64"), 524f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("pgoff", "u64") 525f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch]) 526f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 527014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch# Reference: kernel/tools/perf/util/event.h 528014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochPERF_MMAP2_EVENT_BODY_DESC = Descriptor([ 529014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ("pid", "u32"), 530014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ("tid", "u32"), 531014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ("addr", "u64"), 532014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ("len", "u64"), 533014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ("pgoff", "u64"), 534014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ("maj", "u32"), 535014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ("min", "u32"), 536014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ("ino", "u64"), 537014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ("ino_generation", "u64"), 538014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ("prot", "u32"), 539014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch ("flags","u32") 540014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch]) 541f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 542f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# perf_event_attr.sample_type bits control the set of 543f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# perf_sample_event fields. 544f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_IP = 1 << 0 545f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_TID = 1 << 1 546f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_TIME = 1 << 2 547f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_ADDR = 1 << 3 548f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_READ = 1 << 4 549f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_CALLCHAIN = 1 << 5 550f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_ID = 1 << 6 551f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_CPU = 1 << 7 552f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_PERIOD = 1 << 8 553f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_STREAM_ID = 1 << 9 554f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_RAW = 1 << 10 555f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 556f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 557b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/perf_event.h, the comment for PERF_RECORD_SAMPLE. 558f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_EVENT_BODY_FIELDS = [ 559f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("ip", "u64", PERF_SAMPLE_IP), 560f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("pid", "u32", PERF_SAMPLE_TID), 561f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("tid", "u32", PERF_SAMPLE_TID), 562f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("time", "u64", PERF_SAMPLE_TIME), 563f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("addr", "u64", PERF_SAMPLE_ADDR), 564f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("id", "u64", PERF_SAMPLE_ID), 565f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("stream_id", "u64", PERF_SAMPLE_STREAM_ID), 566f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("cpu", "u32", PERF_SAMPLE_CPU), 567f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("res", "u32", PERF_SAMPLE_CPU), 568f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("period", "u64", PERF_SAMPLE_PERIOD), 569f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Don't want to handle read format that comes after the period and 570f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # before the callchain and has variable size. 571f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("nr", "u64", PERF_SAMPLE_CALLCHAIN) 572f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Raw data follows the callchain and is ignored. 573f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch] 574f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 575f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 576f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_EVENT_IP_FORMAT = "u64" 577f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 578f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 579f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_RECORD_MMAP = 1 580014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben MurdochPERF_RECORD_MMAP2 = 10 581f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_RECORD_SAMPLE = 9 582f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 583f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 584f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass TraceReader(object): 585f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch """Perf (linux-2.6/tools/perf) trace file reader.""" 586f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 587f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch _TRACE_HEADER_MAGIC = 4993446653023372624 588f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 589f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self, trace_name): 590f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace_file = open(trace_name, "r") 591f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace = mmap.mmap(self.trace_file.fileno(), 0, mmap.MAP_PRIVATE) 592f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace_header = TRACE_HEADER_DESC.Read(self.trace, 0) 593f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.trace_header.magic != TraceReader._TRACE_HEADER_MAGIC: 594f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print >>sys.stderr, "Warning: unsupported trace header magic" 595f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.offset = self.trace_header.data_offset 596f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.limit = self.trace_header.data_offset + self.trace_header.data_size 597f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert self.limit <= self.trace.size(), \ 598f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Trace data limit exceeds trace file size" 599f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.header_size = ctypes.sizeof(PERF_EVENT_HEADER_DESC.ctype) 600f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert self.trace_header.attrs_size != 0, \ 601f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "No perf event attributes found in the trace" 602f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch perf_event_attr = PERF_EVENT_ATTR_DESC.Read(self.trace, 603f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace_header.attrs_offset) 604f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.sample_event_body_desc = self._SampleEventBodyDesc( 605f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch perf_event_attr.sample_type) 606f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.callchain_supported = \ 607f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch (perf_event_attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0 608f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.callchain_supported: 609f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.ip_struct = Descriptor.CTYPE_MAP[PERF_SAMPLE_EVENT_IP_FORMAT] 610f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.ip_size = ctypes.sizeof(self.ip_struct) 611f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 612f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def ReadEventHeader(self): 613f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.offset >= self.limit: 614f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return None, 0 615f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch offset = self.offset 616f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch header = PERF_EVENT_HEADER_DESC.Read(self.trace, self.offset) 617f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.offset += header.size 618f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return header, offset 619f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 620f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def ReadMmap(self, header, offset): 621f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_info = PERF_MMAP_EVENT_BODY_DESC.Read(self.trace, 622f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch offset + self.header_size) 6233fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch # Read null-terminated filename. 624f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info): 6253fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch offset + header.size] 626b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch mmap_info.filename = HOST_ROOT + filename[:filename.find(chr(0))] 627f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return mmap_info 628f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 629014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch def ReadMmap2(self, header, offset): 630014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch mmap_info = PERF_MMAP2_EVENT_BODY_DESC.Read(self.trace, 631014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch offset + self.header_size) 632014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch # Read null-terminated filename. 633014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info): 634014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch offset + header.size] 635014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch mmap_info.filename = HOST_ROOT + filename[:filename.find(chr(0))] 636014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return mmap_info 637014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 638f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def ReadSample(self, header, offset): 639f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample = self.sample_event_body_desc.Read(self.trace, 640f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch offset + self.header_size) 641f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not self.callchain_supported: 642f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return sample 643f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample.ips = [] 644f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch offset += self.header_size + ctypes.sizeof(sample) 645f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for _ in xrange(sample.nr): 646f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample.ips.append( 647f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.ip_struct.from_buffer(self.trace, offset).value) 648f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch offset += self.ip_size 649f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return sample 650f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 651f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Dispose(self): 652f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace.close() 653f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace_file.close() 654f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 655f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def _SampleEventBodyDesc(self, sample_type): 656f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert (sample_type & PERF_SAMPLE_READ) == 0, \ 657f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Can't hande read format in samples" 658f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch fields = [(field, format) 659f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for (field, format, bit) in PERF_SAMPLE_EVENT_BODY_FIELDS 660f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if (bit & sample_type) != 0] 661f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return Descriptor(fields) 662f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 663f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 664f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_SECTION_HEADER_RE = re.compile( 665f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch r"^\s*\d+\s(\.\S+)\s+[a-f0-9]") 666f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_SYMBOL_LINE_RE = re.compile( 667f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch r"^([a-f0-9]+)\s(.{7})\s(\S+)\s+([a-f0-9]+)\s+(?:\.hidden\s+)?(.*)$") 668f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_DYNAMIC_SYMBOLS_START_RE = re.compile( 6693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r"^DYNAMIC SYMBOL TABLE") 6703ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochOBJDUMP_SKIP_RE = re.compile( 6713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r"^.*ld\.so\.cache$") 672f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochKERNEL_ALLSYMS_FILE = "/proc/kallsyms" 673f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_KERNEL_ALLSYMS_RE = re.compile( 674f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch r".*kallsyms.*") 675f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochKERNEL_ALLSYMS_LINE_RE = re.compile( 676f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch r"^([a-f0-9]+)\s(?:t|T)\s(\S+)$") 677f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 678f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 679f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass LibraryRepo(object): 680f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self): 681f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.infos = [] 682f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.names = set() 683f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.ticks = {} 684f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 685014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 686014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch def HasDynamicSymbols(self, filename): 687014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if filename.endswith(".ko"): return False 688014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch process = subprocess.Popen( 689014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch "%s -h %s" % (OBJDUMP_BIN, filename), 690014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 691014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch pipe = process.stdout 692014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch try: 693014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch for line in pipe: 694014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch match = OBJDUMP_SECTION_HEADER_RE.match(line) 695014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if match and match.group(1) == 'dynsym': return True 696014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch finally: 697014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch pipe.close() 698014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch assert process.wait() == 0, "Failed to objdump -h %s" % filename 699014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch return False 700014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 701014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 702f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Load(self, mmap_info, code_map, options): 703f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Skip kernel mmaps when requested using the fact that their tid 704f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # is 0. 705f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if mmap_info.tid == 0 and not options.kernel: 706f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return True 7073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if OBJDUMP_SKIP_RE.match(mmap_info.filename): 7083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return True 709f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if PERF_KERNEL_ALLSYMS_RE.match(mmap_info.filename): 710f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return self._LoadKernelSymbols(code_map) 711f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.infos.append(mmap_info) 712f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_info.ticks = 0 713f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_info.unique_name = self._UniqueMmapName(mmap_info) 714f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not os.path.exists(mmap_info.filename): 715f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return True 716f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Request section headers (-h), symbols (-t), and dynamic symbols 717f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # (-T) from objdump. 718f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Unfortunately, section headers span two lines, so we have to 719f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # keep the just seen section name (from the first line in each 720f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # section header) in the after_section variable. 721014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if self.HasDynamicSymbols(mmap_info.filename): 722b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch dynamic_symbols = "-T" 723014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch else: 724014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch dynamic_symbols = "" 725f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch process = subprocess.Popen( 726b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "%s -h -t %s -C %s" % (OBJDUMP_BIN, dynamic_symbols, mmap_info.filename), 727f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 728f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch pipe = process.stdout 729f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch after_section = None 730f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_sections = set() 731f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch reloc_sections = set() 732f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch dynamic = False 733f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch try: 734f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for line in pipe: 735f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if after_section: 736f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if line.find("CODE") != -1: 737f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_sections.add(after_section) 738f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if line.find("RELOC") != -1: 739f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch reloc_sections.add(after_section) 740f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch after_section = None 741f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 742f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 743f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch match = OBJDUMP_SECTION_HEADER_RE.match(line) 744f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if match: 745f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch after_section = match.group(1) 746f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 747f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 748f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if OBJDUMP_DYNAMIC_SYMBOLS_START_RE.match(line): 749f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch dynamic = True 750f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 751f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 752f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch match = OBJDUMP_SYMBOL_LINE_RE.match(line) 753f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if match: 754f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch start_address = int(match.group(1), 16) 755f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch origin_offset = start_address 756f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch flags = match.group(2) 757f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch section = match.group(3) 758f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if section in code_sections: 759f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if dynamic or section in reloc_sections: 760f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch start_address += mmap_info.addr 761f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch size = int(match.group(4), 16) 762f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch name = match.group(5) 763f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch origin = mmap_info.filename 764f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_map.Add(Code(name, start_address, start_address + size, 765f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch origin, origin_offset)) 766f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch finally: 767f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch pipe.close() 768f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert process.wait() == 0, "Failed to objdump %s" % mmap_info.filename 769f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 770f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Tick(self, pc): 771f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for i, mmap_info in enumerate(self.infos): 772f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if mmap_info.addr <= pc < (mmap_info.addr + mmap_info.len): 773f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_info.ticks += 1 774f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.infos[0], self.infos[i] = mmap_info, self.infos[0] 775f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return True 776f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return False 777f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 778f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def _UniqueMmapName(self, mmap_info): 779f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch name = mmap_info.filename 780f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch index = 1 781f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch while name in self.names: 782f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch name = "%s-%d" % (mmap_info.filename, index) 783f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch index += 1 784f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.names.add(name) 785f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return name 786f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 787f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def _LoadKernelSymbols(self, code_map): 788f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not os.path.exists(KERNEL_ALLSYMS_FILE): 789f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print >>sys.stderr, "Warning: %s not found" % KERNEL_ALLSYMS_FILE 790f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return False 791f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch kallsyms = open(KERNEL_ALLSYMS_FILE, "r") 792f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = None 793f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for line in kallsyms: 794f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch match = KERNEL_ALLSYMS_LINE_RE.match(line) 795f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if match: 796f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch start_address = int(match.group(1), 16) 797f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch end_address = start_address 798f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch name = match.group(2) 799f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code: 800f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code.end_address = start_address 801f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_map.Add(code, 16) 802f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = Code(name, start_address, end_address, "kernel", 0) 803f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return True 804f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 805f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 806257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochdef PrintReport(code_map, library_repo, arch, ticks, options): 807f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "Ticks per symbol:" 808f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch used_code = [code for code in code_map.UsedCode()] 809f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch used_code.sort(key=lambda x: x.self_ticks, reverse=True) 810f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for i, code in enumerate(used_code): 811257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch code_ticks = code.self_ticks 812257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch print "%10d %5.1f%% %s [%s]" % (code_ticks, 100. * code_ticks / ticks, 813257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch code.FullName(), code.origin) 814f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if options.disasm_all or i < options.disasm_top: 815257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch code.PrintAnnotated(arch, options) 816f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print 817f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "Ticks per library:" 818b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch mmap_infos = [m for m in library_repo.infos if m.ticks > 0] 819f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_infos.sort(key=lambda m: m.ticks, reverse=True) 820f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for mmap_info in mmap_infos: 821257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch mmap_ticks = mmap_info.ticks 822257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch print "%10d %5.1f%% %s" % (mmap_ticks, 100. * mmap_ticks / ticks, 823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch mmap_info.unique_name) 824f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 825f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 826f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochdef PrintDot(code_map, options): 827f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "digraph G {" 828f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for code in code_map.UsedCode(): 829f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code.self_ticks < 10: 830f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 831f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "n%d [shape=box,label=\"%s\"];" % (code.id, code.name) 832f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code.callee_ticks: 833f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for callee, ticks in code.callee_ticks.iteritems(): 834f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "n%d -> n%d [label=\"%d\"];" % (code.id, callee.id, ticks) 835f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "}" 836f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 837f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 838f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochif __name__ == "__main__": 839f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser = optparse.OptionParser(USAGE) 840f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--log", 841f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default="v8.log", 842f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="V8 log file name [default: %default]") 843f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--trace", 844f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default="perf.data", 845f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="perf trace file name [default: %default]") 846f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--kernel", 847f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default=False, 848f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch action="store_true", 849f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="process kernel entries [default: %default]") 850f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--disasm-top", 851f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default=0, 852f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch type="int", 853f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help=("number of top symbols to disassemble and annotate " 854f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "[default: %default]")) 855f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--disasm-all", 856f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default=False, 857f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch action="store_true", 858f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help=("disassemble and annotate all used symbols " 859f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "[default: %default]")) 860f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--dot", 861f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default=False, 862f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch action="store_true", 863f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="produce dot output (WIP) [default: %default]") 864f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--quiet", "-q", 865f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default=False, 866f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch action="store_true", 867f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="no auxiliary messages [default: %default]") 868b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch parser.add_option("--gc-fake-mmap", 869b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch default="/tmp/__v8_gc__", 870b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch help="gc fake mmap file [default: %default]") 871b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch parser.add_option("--objdump", 872b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch default="/usr/bin/objdump", 873b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch help="objdump tool to use [default: %default]") 874b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch parser.add_option("--host-root", 875b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch default="", 876b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch help="Path to the host root [default: %default]") 877f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch options, args = parser.parse_args() 878f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 879f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not options.quiet: 8803b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch print "V8 log: %s, %s.ll" % (options.log, options.log) 881f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "Perf trace file: %s" % options.trace 882f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 883b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch V8_GC_FAKE_MMAP = options.gc_fake_mmap 884b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch HOST_ROOT = options.host_root 885b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if os.path.exists(options.objdump): 886b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch disasm.OBJDUMP_BIN = options.objdump 887b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch OBJDUMP_BIN = options.objdump 888b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch else: 889b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch print "Cannot find %s, falling back to default objdump" % options.objdump 890b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 891f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Stats. 892f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch events = 0 893f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ticks = 0 894f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch missed_ticks = 0 895f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch really_missed_ticks = 0 896b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch optimized_ticks = 0 897b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch generated_ticks = 0 898b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8_internal_ticks = 0 899f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_time = 0 900f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample_time = 0 901f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch # Initialize the log reader. 903257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch code_map = CodeMap() 904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch log_reader = LogReader(log_name=options.log + ".ll", 9053b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch code_map=code_map) 906f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not options.quiet: 907257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch print "Generated code architecture: %s" % log_reader.arch 908f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print 909257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch sys.stdout.flush() 910f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 911f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Process the code and trace logs. 912f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch library_repo = LibraryRepo() 913257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch log_reader.ReadUpToGC() 914f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch trace_reader = TraceReader(options.trace) 915f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch while True: 916f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch header, offset = trace_reader.ReadEventHeader() 917f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not header: 918f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch break 919f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch events += 1 920f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if header.type == PERF_RECORD_MMAP: 921f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch start = time.time() 922f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_info = trace_reader.ReadMmap(header, offset) 923b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if mmap_info.filename == HOST_ROOT + V8_GC_FAKE_MMAP: 924257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch log_reader.ReadUpToGC() 925f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 926f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch library_repo.Load(mmap_info, code_map, options) 927f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_time += time.time() - start 928014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch elif header.type == PERF_RECORD_MMAP2: 929014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch start = time.time() 930014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch mmap_info = trace_reader.ReadMmap2(header, offset) 931014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if mmap_info.filename == HOST_ROOT + V8_GC_FAKE_MMAP: 932014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch log_reader.ReadUpToGC() 933014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch else: 934014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch library_repo.Load(mmap_info, code_map, options) 935014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch mmap_time += time.time() - start 936f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch elif header.type == PERF_RECORD_SAMPLE: 937f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ticks += 1 938f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch start = time.time() 939f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample = trace_reader.ReadSample(header, offset) 940f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = code_map.Find(sample.ip) 941f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code: 942f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code.Tick(sample.ip) 943b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if code.codetype == Code.OPTIMIZED: 944b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch optimized_ticks += 1 945b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch elif code.codetype == Code.FULL_CODEGEN: 946b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch generated_ticks += 1 947b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch elif code.codetype == Code.V8INTERNAL: 948b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8_internal_ticks += 1 949f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 950f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch missed_ticks += 1 951f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not library_repo.Tick(sample.ip) and not code: 952f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch really_missed_ticks += 1 953f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if trace_reader.callchain_supported: 954f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for ip in sample.ips: 955f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch caller_code = code_map.Find(ip) 956f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if caller_code: 957f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code: 958f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch caller_code.CalleeTick(code) 959f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = caller_code 960f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample_time += time.time() - start 961f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 962f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if options.dot: 963f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch PrintDot(code_map, options) 964f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 965257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch PrintReport(code_map, library_repo, log_reader.arch, ticks, options) 966f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 967f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not options.quiet: 968b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def PrintTicks(number, total, description): 969b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch print("%10d %5.1f%% ticks in %s" % 970b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch (number, 100.0*number/total, description)) 971f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print 972f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "Stats:" 973f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%10d total trace events" % events 974f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%10d total ticks" % ticks 975f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%10d ticks not in symbols" % missed_ticks 976b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch unaccounted = "unaccounted ticks" 977b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if really_missed_ticks > 0: 978b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch unaccounted += " (probably in the kernel, try --kernel)" 979b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch PrintTicks(really_missed_ticks, ticks, unaccounted) 980b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch PrintTicks(optimized_ticks, ticks, "ticks in optimized code") 981b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch PrintTicks(generated_ticks, ticks, "ticks in other lazily compiled code") 982b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch PrintTicks(v8_internal_ticks, ticks, "ticks in v8::internal::*") 983f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%10d total symbols" % len([c for c in code_map.AllCode()]) 984f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%10d used symbols" % len([c for c in code_map.UsedCode()]) 985f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%9.2fs library processing time" % mmap_time 986f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%9.2fs tick processing time" % sample_time 987f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 988f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch log_reader.Dispose() 989f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch trace_reader.Dispose() 990