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 69f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # symbols. Use default log names and include the snapshot log. 70f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch $ %prog --snapshot --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. 77f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch $ %prog --log=foo.log --snapshot-log=snap-foo.log --trace=foo.data --snapshot 78f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch""" 79f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 80f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 81f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochJS_ORIGIN = "js" 82f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochJS_SNAPSHOT_ORIGIN = "js-snapshot" 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 176f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch count = 100.0 * count / self.self_ticks 177f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if count >= 0.01: 178e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch print "%15.2f %x: %s" % (count, lines[i][0], lines[i][1]) 179f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 180e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch print "%s %x: %s" % (" " * 15, lines[i][0], lines[i][1]) 181f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print 182f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert total_count == self.self_ticks, \ 183f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Lost ticks (%d != %d) in %s" % (total_count, self.self_ticks, self) 184f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 185f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __str__(self): 186f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return "%s [0x%x, 0x%x) size: %d origin: %s" % ( 187f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.name, 188f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.start_address, 189f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.end_address, 190f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.end_address - self.start_address, 191f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.origin) 192f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 193257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def _GetDisasmLines(self, arch, options): 194f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.origin == JS_ORIGIN or self.origin == JS_SNAPSHOT_ORIGIN: 195e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch inplace = False 196257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch filename = options.log + ".ll" 197f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 198e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch inplace = True 199e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch filename = self.origin 200e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch return disasm.GetDisasmLines(filename, 201e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch self.origin_offset, 202e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch self.end_address - self.start_address, 203257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch arch, 204e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch inplace) 205f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 206f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 207f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodePage(object): 208f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch """Group of adjacent code objects.""" 209f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch SHIFT = 20 # 1M pages 211f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch SIZE = (1 << SHIFT) 212f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch MASK = ~(SIZE - 1) 213f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 214f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch @staticmethod 215f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def PageAddress(address): 216f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return address & CodePage.MASK 217f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 218f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch @staticmethod 219f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def PageId(address): 220f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return address >> CodePage.SHIFT 221f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 222f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch @staticmethod 223f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def PageAddressFromId(id): 224f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return id << CodePage.SHIFT 225f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 226f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self, address): 227f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.address = address 228f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_objects = [] 229f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 230f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Add(self, code): 231f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_objects.append(code) 232f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 233f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Remove(self, code): 234f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_objects.remove(code) 235f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 236f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Find(self, pc): 237f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_objects = self.code_objects 238f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for i, code in enumerate(code_objects): 239f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code.start_address <= pc < code.end_address: 240f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_objects[0], code_objects[i] = code, code_objects[0] 241f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return code 242f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return None 243f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 244f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __iter__(self): 245f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return self.code_objects.__iter__() 246f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 247f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 248f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodeMap(object): 249f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch """Code object map.""" 250f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 251f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self): 252f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.pages = {} 253f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.min_address = 1 << 64 254f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.max_address = -1 255f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 256f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Add(self, code, max_pages=-1): 257f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id = CodePage.PageId(code.start_address) 258f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1) 259f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch pages = 0 260f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch while page_id < limit_id: 261f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if max_pages >= 0 and pages > max_pages: 262f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print >>sys.stderr, \ 263f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Warning: page limit (%d) reached for %s [%s]" % ( 264f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch max_pages, code.name, code.origin) 265f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch break 266f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if page_id in self.pages: 267f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page = self.pages[page_id] 268f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 269f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page = CodePage(CodePage.PageAddressFromId(page_id)) 270f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.pages[page_id] = page 271f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page.Add(code) 272f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id += 1 273f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch pages += 1 274f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.min_address = min(self.min_address, code.start_address) 275f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.max_address = max(self.max_address, code.end_address) 276f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 277f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Remove(self, code): 278f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id = CodePage.PageId(code.start_address) 279f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch limit_id = CodePage.PageId(code.end_address + CodePage.SIZE - 1) 280f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch removed = False 281f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch while page_id < limit_id: 282f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if page_id not in self.pages: 283f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id += 1 284f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 285f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page = self.pages[page_id] 286f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page.Remove(code) 287f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch removed = True 288f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id += 1 289f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return removed 290f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 291f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def AllCode(self): 292f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for page in self.pages.itervalues(): 293f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for code in page: 294f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if CodePage.PageAddress(code.start_address) == page.address: 295f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch yield code 296f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 297f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def UsedCode(self): 298f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for code in self.AllCode(): 299f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code.IsUsed(): 300f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch yield code 301f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 302f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Print(self): 303f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for code in self.AllCode(): 304f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print code 305f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 306f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Find(self, pc): 307f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if pc < self.min_address or pc >= self.max_address: 308f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return None 309f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch page_id = CodePage.PageId(pc) 310f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if page_id not in self.pages: 311f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return None 312f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return self.pages[page_id].Find(pc) 313f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 314f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 315f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass CodeInfo(object): 316f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch """Generic info about generated code objects.""" 317f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 318f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self, arch, header_size): 319f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.arch = arch 320f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.header_size = header_size 321f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 322f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochclass SnapshotLogReader(object): 324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch """V8 snapshot log reader.""" 325f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _SNAPSHOT_CODE_NAME_RE = re.compile( 327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch r"snapshot-code-name,(\d+),\"(.*)\"") 328f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 329257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def __init__(self, log_name): 330257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_name = log_name 331257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 332257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def ReadNameMap(self): 333257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch log = open(self.log_name, "r") 334257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch try: 335257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch snapshot_pos_to_name = {} 336257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch for line in log: 337257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch match = SnapshotLogReader._SNAPSHOT_CODE_NAME_RE.match(line) 338257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if match: 339257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch pos = int(match.group(1)) 340257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch name = match.group(2) 341257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch snapshot_pos_to_name[pos] = name 342257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch finally: 343257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch log.close() 344257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch return snapshot_pos_to_name 345f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 346f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 347257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochclass LogReader(object): 348257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch """V8 low-level (binary) log reader.""" 349f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 350257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _ARCH_TO_POINTER_TYPE_MAP = { 351257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch "ia32": ctypes.c_uint32, 352257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch "arm": ctypes.c_uint32, 3533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch "mips": ctypes.c_uint32, 354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "x64": ctypes.c_uint64, 355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "arm64": ctypes.c_uint64 356257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch } 357f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 358257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _CODE_CREATE_TAG = "C" 359257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _CODE_MOVE_TAG = "M" 360257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _CODE_DELETE_TAG = "D" 361257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _SNAPSHOT_POSITION_TAG = "P" 362257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _CODE_MOVING_GC_TAG = "G" 363f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 364257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def __init__(self, log_name, code_map, snapshot_pos_to_name): 365257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_file = open(log_name, "r") 366257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log = mmap.mmap(self.log_file.fileno(), 0, mmap.MAP_PRIVATE) 367257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos = 0 368f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_map = code_map 369f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.snapshot_pos_to_name = snapshot_pos_to_name 370f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.address_to_snapshot_name = {} 371f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 372257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.arch = self.log[:self.log.find("\0")] 373257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += len(self.arch) + 1 374257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch assert self.arch in LogReader._ARCH_TO_POINTER_TYPE_MAP, \ 375257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch "Unsupported architecture %s" % self.arch 376257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch pointer_type = LogReader._ARCH_TO_POINTER_TYPE_MAP[self.arch] 377257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 378257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.code_create_struct = LogReader._DefineStruct([ 379257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("name_size", ctypes.c_int32), 380257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("code_address", pointer_type), 381257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("code_size", ctypes.c_int32)]) 382257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 383257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.code_move_struct = LogReader._DefineStruct([ 384257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("from_address", pointer_type), 385257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("to_address", pointer_type)]) 386257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 387257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.code_delete_struct = LogReader._DefineStruct([ 388257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("address", pointer_type)]) 389257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.snapshot_position_struct = LogReader._DefineStruct([ 391257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("address", pointer_type), 392257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch ("position", ctypes.c_int32)]) 393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def ReadUpToGC(self): 395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch while self.log_pos < self.log.size(): 396257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch tag = self.log[self.log_pos] 397257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += 1 398257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 399257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if tag == LogReader._CODE_MOVING_GC_TAG: 400f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.address_to_snapshot_name.clear() 401257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch return 402f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 403257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if tag == LogReader._CODE_CREATE_TAG: 404257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch event = self.code_create_struct.from_buffer(self.log, self.log_pos) 405257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += ctypes.sizeof(event) 406257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch start_address = event.code_address 407257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch end_address = start_address + event.code_size 408f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if start_address in self.address_to_snapshot_name: 409f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch name = self.address_to_snapshot_name[start_address] 410f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch origin = JS_SNAPSHOT_ORIGIN 411f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 412257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch name = self.log[self.log_pos:self.log_pos + event.name_size] 413f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch origin = JS_ORIGIN 414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += event.name_size 415257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch origin_offset = self.log_pos 416257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += event.code_size 417f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = Code(name, start_address, end_address, origin, origin_offset) 418f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch conficting_code = self.code_map.Find(start_address) 419f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if conficting_code: 4203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if not (conficting_code.start_address == code.start_address and 4213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch conficting_code.end_address == code.end_address): 4223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch self.code_map.Remove(conficting_code) 4233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch else: 4243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch LogReader._HandleCodeConflict(conficting_code, code) 4253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch # TODO(vitalyr): this warning is too noisy because of our 4263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch # attempts to reconstruct code log from the snapshot. 4273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch # print >>sys.stderr, \ 4283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch # "Warning: Skipping duplicate code log entry %s" % code 4293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch continue 430f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_map.Add(code) 431f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 432f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 433257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if tag == LogReader._CODE_MOVE_TAG: 434257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch event = self.code_move_struct.from_buffer(self.log, self.log_pos) 435257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += ctypes.sizeof(event) 436257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch old_start_address = event.from_address 437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch new_start_address = event.to_address 438f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if old_start_address == new_start_address: 439f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Skip useless code move entries. 440f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 441f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = self.code_map.Find(old_start_address) 442f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not code: 443f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print >>sys.stderr, "Warning: Not found %x" % old_start_address 444f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 445f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert code.start_address == old_start_address, \ 446f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Inexact move address %x for %s" % (old_start_address, code) 447f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_map.Remove(code) 448f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch size = code.end_address - code.start_address 449f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code.start_address = new_start_address 450f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code.end_address = new_start_address + size 451f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_map.Add(code) 452f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 453f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 454257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if tag == LogReader._CODE_DELETE_TAG: 455257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch event = self.code_delete_struct.from_buffer(self.log, self.log_pos) 456257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += ctypes.sizeof(event) 457257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch old_start_address = event.address 458f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = self.code_map.Find(old_start_address) 459f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not code: 460f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print >>sys.stderr, "Warning: Not found %x" % old_start_address 461f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 462f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert code.start_address == old_start_address, \ 463f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Inexact delete address %x for %s" % (old_start_address, code) 464f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.code_map.Remove(code) 465f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 466f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 467257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if tag == LogReader._SNAPSHOT_POSITION_TAG: 468257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch event = self.snapshot_position_struct.from_buffer(self.log, 469257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos) 470257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_pos += ctypes.sizeof(event) 471257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch start_address = event.address 472257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch snapshot_pos = event.position 473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if snapshot_pos in self.snapshot_pos_to_name: 474257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.address_to_snapshot_name[start_address] = \ 475257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.snapshot_pos_to_name[snapshot_pos] 476257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch continue 477257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 478257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch assert False, "Unknown tag %s" % tag 479f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 480f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Dispose(self): 481f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.log.close() 482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch self.log_file.close() 483257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 484257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch @staticmethod 485257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch def _DefineStruct(fields): 486257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch class Struct(ctypes.Structure): 487257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch _fields_ = fields 488257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch return Struct 489f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 490f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch @staticmethod 491f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def _HandleCodeConflict(old_code, new_code): 492f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert (old_code.start_address == new_code.start_address and 493f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch old_code.end_address == new_code.end_address), \ 494f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Conficting code log entries %s and %s" % (old_code, new_code) 495f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if old_code.name == new_code.name: 496f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return 497f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Code object may be shared by a few functions. Collect the full 498f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # set of names. 499f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch old_code.AddName(new_code.name) 500f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 501f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 502f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass Descriptor(object): 503f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch """Descriptor of a structure in the binary trace log.""" 504f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 505f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch CTYPE_MAP = { 506f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "u16": ctypes.c_uint16, 507f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "u32": ctypes.c_uint32, 508f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "u64": ctypes.c_uint64 509f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch } 510f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 511f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self, fields): 512f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch class TraceItem(ctypes.Structure): 513f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch _fields_ = Descriptor.CtypesFields(fields) 514f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 515f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __str__(self): 516f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return ", ".join("%s: %s" % (field, self.__getattribute__(field)) 517f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for field, _ in TraceItem._fields_) 518f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 519f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.ctype = TraceItem 520f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 521f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Read(self, trace, offset): 522f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return self.ctype.from_buffer(trace, offset) 523f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 524f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch @staticmethod 525f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def CtypesFields(fields): 526f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return [(field, Descriptor.CTYPE_MAP[format]) for (field, format) in fields] 527f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 528f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 529f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# Please see http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=tree;f=tools/perf 530f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# for the gory details. 531f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 532f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 533b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: struct perf_file_header in kernel/tools/perf/util/header.h 534f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochTRACE_HEADER_DESC = Descriptor([ 535f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("magic", "u64"), 536f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("size", "u64"), 537f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("attr_size", "u64"), 538f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("attrs_offset", "u64"), 539f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("attrs_size", "u64"), 540f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("data_offset", "u64"), 541f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("data_size", "u64"), 542f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("event_types_offset", "u64"), 543f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("event_types_size", "u64") 544f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch]) 545f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 546f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 547b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/linux/perf_event.h 548f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_EVENT_ATTR_DESC = Descriptor([ 549f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("type", "u32"), 550f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("size", "u32"), 551f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("config", "u64"), 552f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("sample_period_or_freq", "u64"), 553f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("sample_type", "u64"), 554f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("read_format", "u64"), 555f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("flags", "u64"), 556f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("wakeup_events_or_watermark", "u32"), 557b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ("bp_type", "u32"), 558f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("bp_addr", "u64"), 559b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ("bp_len", "u64") 560f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch]) 561f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 562f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 563b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/linux/perf_event.h 564f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_EVENT_HEADER_DESC = Descriptor([ 565f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("type", "u32"), 566f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("misc", "u16"), 567f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("size", "u16") 568f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch]) 569f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 570f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 571b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: kernel/events/core.c 572f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_MMAP_EVENT_BODY_DESC = Descriptor([ 573f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("pid", "u32"), 574f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("tid", "u32"), 575f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("addr", "u64"), 576f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("len", "u64"), 577f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("pgoff", "u64") 578f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch]) 579f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 580f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 581f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# perf_event_attr.sample_type bits control the set of 582f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch# perf_sample_event fields. 583f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_IP = 1 << 0 584f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_TID = 1 << 1 585f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_TIME = 1 << 2 586f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_ADDR = 1 << 3 587f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_READ = 1 << 4 588f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_CALLCHAIN = 1 << 5 589f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_ID = 1 << 6 590f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_CPU = 1 << 7 591f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_PERIOD = 1 << 8 592f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_STREAM_ID = 1 << 9 593f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_RAW = 1 << 10 594f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 595f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 596b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch# Reference: /usr/include/perf_event.h, the comment for PERF_RECORD_SAMPLE. 597f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_EVENT_BODY_FIELDS = [ 598f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("ip", "u64", PERF_SAMPLE_IP), 599f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("pid", "u32", PERF_SAMPLE_TID), 600f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("tid", "u32", PERF_SAMPLE_TID), 601f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("time", "u64", PERF_SAMPLE_TIME), 602f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("addr", "u64", PERF_SAMPLE_ADDR), 603f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("id", "u64", PERF_SAMPLE_ID), 604f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("stream_id", "u64", PERF_SAMPLE_STREAM_ID), 605f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("cpu", "u32", PERF_SAMPLE_CPU), 606f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("res", "u32", PERF_SAMPLE_CPU), 607f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("period", "u64", PERF_SAMPLE_PERIOD), 608f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Don't want to handle read format that comes after the period and 609f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # before the callchain and has variable size. 610f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ("nr", "u64", PERF_SAMPLE_CALLCHAIN) 611f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Raw data follows the callchain and is ignored. 612f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch] 613f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 614f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 615f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_SAMPLE_EVENT_IP_FORMAT = "u64" 616f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 617f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 618f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_RECORD_MMAP = 1 619f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_RECORD_SAMPLE = 9 620f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 621f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 622f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass TraceReader(object): 623f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch """Perf (linux-2.6/tools/perf) trace file reader.""" 624f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 625f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch _TRACE_HEADER_MAGIC = 4993446653023372624 626f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 627f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self, trace_name): 628f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace_file = open(trace_name, "r") 629f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace = mmap.mmap(self.trace_file.fileno(), 0, mmap.MAP_PRIVATE) 630f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace_header = TRACE_HEADER_DESC.Read(self.trace, 0) 631f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.trace_header.magic != TraceReader._TRACE_HEADER_MAGIC: 632f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print >>sys.stderr, "Warning: unsupported trace header magic" 633f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.offset = self.trace_header.data_offset 634f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.limit = self.trace_header.data_offset + self.trace_header.data_size 635f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert self.limit <= self.trace.size(), \ 636f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Trace data limit exceeds trace file size" 637f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.header_size = ctypes.sizeof(PERF_EVENT_HEADER_DESC.ctype) 638f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert self.trace_header.attrs_size != 0, \ 639f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "No perf event attributes found in the trace" 640f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch perf_event_attr = PERF_EVENT_ATTR_DESC.Read(self.trace, 641f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace_header.attrs_offset) 642f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.sample_event_body_desc = self._SampleEventBodyDesc( 643f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch perf_event_attr.sample_type) 644f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.callchain_supported = \ 645f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch (perf_event_attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0 646f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.callchain_supported: 647f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.ip_struct = Descriptor.CTYPE_MAP[PERF_SAMPLE_EVENT_IP_FORMAT] 648f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.ip_size = ctypes.sizeof(self.ip_struct) 649f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 650f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def ReadEventHeader(self): 651f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if self.offset >= self.limit: 652f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return None, 0 653f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch offset = self.offset 654f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch header = PERF_EVENT_HEADER_DESC.Read(self.trace, self.offset) 655f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.offset += header.size 656f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return header, offset 657f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 658f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def ReadMmap(self, header, offset): 659f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_info = PERF_MMAP_EVENT_BODY_DESC.Read(self.trace, 660f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch offset + self.header_size) 6613fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch # Read null-terminated filename. 662f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch filename = self.trace[offset + self.header_size + ctypes.sizeof(mmap_info): 6633fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch offset + header.size] 664b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch mmap_info.filename = HOST_ROOT + filename[:filename.find(chr(0))] 665f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return mmap_info 666f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 667f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def ReadSample(self, header, offset): 668f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample = self.sample_event_body_desc.Read(self.trace, 669f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch offset + self.header_size) 670f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not self.callchain_supported: 671f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return sample 672f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample.ips = [] 673f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch offset += self.header_size + ctypes.sizeof(sample) 674f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for _ in xrange(sample.nr): 675f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample.ips.append( 676f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.ip_struct.from_buffer(self.trace, offset).value) 677f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch offset += self.ip_size 678f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return sample 679f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 680f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Dispose(self): 681f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace.close() 682f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.trace_file.close() 683f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 684f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def _SampleEventBodyDesc(self, sample_type): 685f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert (sample_type & PERF_SAMPLE_READ) == 0, \ 686f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "Can't hande read format in samples" 687f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch fields = [(field, format) 688f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for (field, format, bit) in PERF_SAMPLE_EVENT_BODY_FIELDS 689f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if (bit & sample_type) != 0] 690f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return Descriptor(fields) 691f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 692f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 693f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_SECTION_HEADER_RE = re.compile( 694f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch r"^\s*\d+\s(\.\S+)\s+[a-f0-9]") 695f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_SYMBOL_LINE_RE = re.compile( 696f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch r"^([a-f0-9]+)\s(.{7})\s(\S+)\s+([a-f0-9]+)\s+(?:\.hidden\s+)?(.*)$") 697f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochOBJDUMP_DYNAMIC_SYMBOLS_START_RE = re.compile( 6983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r"^DYNAMIC SYMBOL TABLE") 6993ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochOBJDUMP_SKIP_RE = re.compile( 7003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch r"^.*ld\.so\.cache$") 701f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochKERNEL_ALLSYMS_FILE = "/proc/kallsyms" 702f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochPERF_KERNEL_ALLSYMS_RE = re.compile( 703f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch r".*kallsyms.*") 704f87a203d89e1bbb6708282e0b64dbd13d59b723dBen MurdochKERNEL_ALLSYMS_LINE_RE = re.compile( 705f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch r"^([a-f0-9]+)\s(?:t|T)\s(\S+)$") 706f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 707f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 708f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochclass LibraryRepo(object): 709f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def __init__(self): 710f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.infos = [] 711f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.names = set() 712f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.ticks = {} 713f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 714f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Load(self, mmap_info, code_map, options): 715f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Skip kernel mmaps when requested using the fact that their tid 716f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # is 0. 717f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if mmap_info.tid == 0 and not options.kernel: 718f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return True 7193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if OBJDUMP_SKIP_RE.match(mmap_info.filename): 7203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return True 721f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if PERF_KERNEL_ALLSYMS_RE.match(mmap_info.filename): 722f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return self._LoadKernelSymbols(code_map) 723f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.infos.append(mmap_info) 724f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_info.ticks = 0 725f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_info.unique_name = self._UniqueMmapName(mmap_info) 726f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not os.path.exists(mmap_info.filename): 727f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return True 728f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Request section headers (-h), symbols (-t), and dynamic symbols 729f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # (-T) from objdump. 730f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Unfortunately, section headers span two lines, so we have to 731f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # keep the just seen section name (from the first line in each 732f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # section header) in the after_section variable. 733b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if mmap_info.filename.endswith(".ko"): 734b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch dynamic_symbols = "" 735b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch else: 736b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch dynamic_symbols = "-T" 737f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch process = subprocess.Popen( 738b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch "%s -h -t %s -C %s" % (OBJDUMP_BIN, dynamic_symbols, mmap_info.filename), 739f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 740f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch pipe = process.stdout 741f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch after_section = None 742f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_sections = set() 743f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch reloc_sections = set() 744f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch dynamic = False 745f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch try: 746f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for line in pipe: 747f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if after_section: 748f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if line.find("CODE") != -1: 749f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_sections.add(after_section) 750f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if line.find("RELOC") != -1: 751f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch reloc_sections.add(after_section) 752f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch after_section = None 753f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 754f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 755f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch match = OBJDUMP_SECTION_HEADER_RE.match(line) 756f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if match: 757f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch after_section = match.group(1) 758f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 759f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 760f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if OBJDUMP_DYNAMIC_SYMBOLS_START_RE.match(line): 761f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch dynamic = True 762f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 763f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 764f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch match = OBJDUMP_SYMBOL_LINE_RE.match(line) 765f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if match: 766f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch start_address = int(match.group(1), 16) 767f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch origin_offset = start_address 768f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch flags = match.group(2) 769f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch section = match.group(3) 770f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if section in code_sections: 771f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if dynamic or section in reloc_sections: 772f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch start_address += mmap_info.addr 773f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch size = int(match.group(4), 16) 774f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch name = match.group(5) 775f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch origin = mmap_info.filename 776f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_map.Add(Code(name, start_address, start_address + size, 777f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch origin, origin_offset)) 778f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch finally: 779f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch pipe.close() 780f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch assert process.wait() == 0, "Failed to objdump %s" % mmap_info.filename 781f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 782f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def Tick(self, pc): 783f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for i, mmap_info in enumerate(self.infos): 784f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if mmap_info.addr <= pc < (mmap_info.addr + mmap_info.len): 785f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_info.ticks += 1 786f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.infos[0], self.infos[i] = mmap_info, self.infos[0] 787f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return True 788f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return False 789f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 790f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def _UniqueMmapName(self, mmap_info): 791f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch name = mmap_info.filename 792f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch index = 1 793f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch while name in self.names: 794f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch name = "%s-%d" % (mmap_info.filename, index) 795f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch index += 1 796f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch self.names.add(name) 797f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return name 798f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 799f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch def _LoadKernelSymbols(self, code_map): 800f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not os.path.exists(KERNEL_ALLSYMS_FILE): 801f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print >>sys.stderr, "Warning: %s not found" % KERNEL_ALLSYMS_FILE 802f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return False 803f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch kallsyms = open(KERNEL_ALLSYMS_FILE, "r") 804f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = None 805f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for line in kallsyms: 806f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch match = KERNEL_ALLSYMS_LINE_RE.match(line) 807f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if match: 808f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch start_address = int(match.group(1), 16) 809f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch end_address = start_address 810f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch name = match.group(2) 811f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code: 812f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code.end_address = start_address 813f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code_map.Add(code, 16) 814f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = Code(name, start_address, end_address, "kernel", 0) 815f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch return True 816f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 817f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 818257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochdef PrintReport(code_map, library_repo, arch, ticks, options): 819f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "Ticks per symbol:" 820f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch used_code = [code for code in code_map.UsedCode()] 821f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch used_code.sort(key=lambda x: x.self_ticks, reverse=True) 822f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for i, code in enumerate(used_code): 823257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch code_ticks = code.self_ticks 824257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch print "%10d %5.1f%% %s [%s]" % (code_ticks, 100. * code_ticks / ticks, 825257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch code.FullName(), code.origin) 826f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if options.disasm_all or i < options.disasm_top: 827257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch code.PrintAnnotated(arch, options) 828f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print 829f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "Ticks per library:" 830b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch mmap_infos = [m for m in library_repo.infos if m.ticks > 0] 831f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_infos.sort(key=lambda m: m.ticks, reverse=True) 832f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for mmap_info in mmap_infos: 833257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch mmap_ticks = mmap_info.ticks 834257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch print "%10d %5.1f%% %s" % (mmap_ticks, 100. * mmap_ticks / ticks, 835257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch mmap_info.unique_name) 836f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 837f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 838f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochdef PrintDot(code_map, options): 839f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "digraph G {" 840f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for code in code_map.UsedCode(): 841f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code.self_ticks < 10: 842f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch continue 843f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "n%d [shape=box,label=\"%s\"];" % (code.id, code.name) 844f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code.callee_ticks: 845f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for callee, ticks in code.callee_ticks.iteritems(): 846f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "n%d -> n%d [label=\"%d\"];" % (code.id, callee.id, ticks) 847f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "}" 848f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 849f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 850f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdochif __name__ == "__main__": 851f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser = optparse.OptionParser(USAGE) 852f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--snapshot-log", 853f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default="obj/release/snapshot.log", 854f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="V8 snapshot log file name [default: %default]") 855f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--log", 856f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default="v8.log", 857f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="V8 log file name [default: %default]") 858f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--snapshot", 859f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default=False, 860f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch action="store_true", 861f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="process V8 snapshot log [default: %default]") 862f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--trace", 863f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default="perf.data", 864f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="perf trace file name [default: %default]") 865f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--kernel", 866f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default=False, 867f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch action="store_true", 868f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="process kernel entries [default: %default]") 869f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--disasm-top", 870f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default=0, 871f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch type="int", 872f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help=("number of top symbols to disassemble and annotate " 873f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "[default: %default]")) 874f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--disasm-all", 875f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default=False, 876f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch action="store_true", 877f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help=("disassemble and annotate all used symbols " 878f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch "[default: %default]")) 879f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--dot", 880f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default=False, 881f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch action="store_true", 882f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="produce dot output (WIP) [default: %default]") 883f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch parser.add_option("--quiet", "-q", 884f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch default=False, 885f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch action="store_true", 886f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch help="no auxiliary messages [default: %default]") 887b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch parser.add_option("--gc-fake-mmap", 888b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch default="/tmp/__v8_gc__", 889b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch help="gc fake mmap file [default: %default]") 890b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch parser.add_option("--objdump", 891b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch default="/usr/bin/objdump", 892b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch help="objdump tool to use [default: %default]") 893b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch parser.add_option("--host-root", 894b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch default="", 895b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch help="Path to the host root [default: %default]") 896f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch options, args = parser.parse_args() 897f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 898f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not options.quiet: 899f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if options.snapshot: 900257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch print "V8 logs: %s, %s, %s.ll" % (options.snapshot_log, 901257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch options.log, 902257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch options.log) 903f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 904257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch print "V8 log: %s, %s.ll (no snapshot)" % (options.log, options.log) 905f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "Perf trace file: %s" % options.trace 906f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 907b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch V8_GC_FAKE_MMAP = options.gc_fake_mmap 908b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch HOST_ROOT = options.host_root 909b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if os.path.exists(options.objdump): 910b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch disasm.OBJDUMP_BIN = options.objdump 911b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch OBJDUMP_BIN = options.objdump 912b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch else: 913b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch print "Cannot find %s, falling back to default objdump" % options.objdump 914b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 915f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Stats. 916f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch events = 0 917f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ticks = 0 918f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch missed_ticks = 0 919f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch really_missed_ticks = 0 920b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch optimized_ticks = 0 921b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch generated_ticks = 0 922b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8_internal_ticks = 0 923f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_time = 0 924f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample_time = 0 925f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 926257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch # Process the snapshot log to fill the snapshot name map. 927f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch snapshot_name_map = {} 928257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch if options.snapshot: 929257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch snapshot_log_reader = SnapshotLogReader(log_name=options.snapshot_log) 930257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch snapshot_name_map = snapshot_log_reader.ReadNameMap() 931257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch 932257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch # Initialize the log reader. 933257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch code_map = CodeMap() 934257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch log_reader = LogReader(log_name=options.log + ".ll", 935257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch code_map=code_map, 936257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch snapshot_pos_to_name=snapshot_name_map) 937f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not options.quiet: 938257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch print "Generated code architecture: %s" % log_reader.arch 939f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print 940257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch sys.stdout.flush() 941f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 942f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch # Process the code and trace logs. 943f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch library_repo = LibraryRepo() 944257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch log_reader.ReadUpToGC() 945f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch trace_reader = TraceReader(options.trace) 946f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch while True: 947f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch header, offset = trace_reader.ReadEventHeader() 948f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not header: 949f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch break 950f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch events += 1 951f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if header.type == PERF_RECORD_MMAP: 952f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch start = time.time() 953f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_info = trace_reader.ReadMmap(header, offset) 954b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if mmap_info.filename == HOST_ROOT + V8_GC_FAKE_MMAP: 955257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch log_reader.ReadUpToGC() 956f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 957f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch library_repo.Load(mmap_info, code_map, options) 958f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch mmap_time += time.time() - start 959f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch elif header.type == PERF_RECORD_SAMPLE: 960f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch ticks += 1 961f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch start = time.time() 962f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample = trace_reader.ReadSample(header, offset) 963f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = code_map.Find(sample.ip) 964f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code: 965f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code.Tick(sample.ip) 966b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if code.codetype == Code.OPTIMIZED: 967b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch optimized_ticks += 1 968b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch elif code.codetype == Code.FULL_CODEGEN: 969b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch generated_ticks += 1 970b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch elif code.codetype == Code.V8INTERNAL: 971b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch v8_internal_ticks += 1 972f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 973f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch missed_ticks += 1 974f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not library_repo.Tick(sample.ip) and not code: 975f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch really_missed_ticks += 1 976f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if trace_reader.callchain_supported: 977f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch for ip in sample.ips: 978f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch caller_code = code_map.Find(ip) 979f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if caller_code: 980f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if code: 981f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch caller_code.CalleeTick(code) 982f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch code = caller_code 983f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch sample_time += time.time() - start 984f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 985f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if options.dot: 986f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch PrintDot(code_map, options) 987f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch else: 988257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch PrintReport(code_map, library_repo, log_reader.arch, ticks, options) 989f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 990f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch if not options.quiet: 991b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch def PrintTicks(number, total, description): 992b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch print("%10d %5.1f%% ticks in %s" % 993b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch (number, 100.0*number/total, description)) 994f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print 995f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "Stats:" 996f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%10d total trace events" % events 997f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%10d total ticks" % ticks 998f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%10d ticks not in symbols" % missed_ticks 999b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch unaccounted = "unaccounted ticks" 1000b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if really_missed_ticks > 0: 1001b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch unaccounted += " (probably in the kernel, try --kernel)" 1002b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch PrintTicks(really_missed_ticks, ticks, unaccounted) 1003b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch PrintTicks(optimized_ticks, ticks, "ticks in optimized code") 1004b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch PrintTicks(generated_ticks, ticks, "ticks in other lazily compiled code") 1005b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch PrintTicks(v8_internal_ticks, ticks, "ticks in v8::internal::*") 1006f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%10d total symbols" % len([c for c in code_map.AllCode()]) 1007f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%10d used symbols" % len([c for c in code_map.UsedCode()]) 1008f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%9.2fs library processing time" % mmap_time 1009f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch print "%9.2fs tick processing time" % sample_time 1010f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch 1011f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch log_reader.Dispose() 1012f87a203d89e1bbb6708282e0b64dbd13d59b723dBen Murdoch trace_reader.Dispose() 1013