From 3adfa360a2b8d74a1112c77b6b66c223a67ce600 Mon Sep 17 00:00:00 2001 From: "mikhail.naganov@gmail.com" Date: Thu, 24 Feb 2011 08:23:37 +0000 Subject: [PATCH] Remove old Python version of tickprocessor git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6922 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- tools/linux-tick-processor.py | 78 ------ tools/splaytree.py | 226 ---------------- tools/tickprocessor.py | 571 ---------------------------------------- tools/windows-tick-processor.py | 137 ---------- 4 files changed, 1012 deletions(-) delete mode 100755 tools/linux-tick-processor.py delete mode 100644 tools/splaytree.py delete mode 100644 tools/tickprocessor.py delete mode 100755 tools/windows-tick-processor.py diff --git a/tools/linux-tick-processor.py b/tools/linux-tick-processor.py deleted file mode 100755 index 67c3b95..0000000 --- a/tools/linux-tick-processor.py +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008 the V8 project authors. All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# Usage: process-ticks.py -# Where is the log file name (eg, v8.log). - -import subprocess, re, sys, tickprocessor - -class LinuxTickProcessor(tickprocessor.TickProcessor): - - def ParseVMSymbols(self, filename, start, end): - """Extract symbols and add them to the cpp entries.""" - # Extra both dynamic and non-dynamic symbols. - command = 'nm -C -n "%s"; nm -C -n -D "%s"' % (filename, filename) - process = subprocess.Popen(command, shell=True, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - pipe = process.stdout - try: - for line in pipe: - row = re.match('^([0-9a-fA-F]{8}) . (.*)$', line) - if row: - addr = int(row.group(1), 16) - if addr < start and addr < end - start: - addr += start - self.cpp_entries.Insert(addr, tickprocessor.CodeEntry(addr, row.group(2))) - finally: - pipe.close() - - -class LinuxCmdLineProcessor(tickprocessor.CmdLineProcessor): - - def GetRequiredArgsNames(self): - return 'log_file' - - def ProcessRequiredArgs(self, args): - if len(args) != 1: - self.PrintUsageAndExit() - else: - self.log_file = args[0] - - -def Main(): - cmdline_processor = LinuxCmdLineProcessor() - cmdline_processor.ProcessArguments() - tick_processor = LinuxTickProcessor() - cmdline_processor.RunLogfileProcessing(tick_processor) - tick_processor.PrintResults() - - -if __name__ == '__main__': - Main() diff --git a/tools/splaytree.py b/tools/splaytree.py deleted file mode 100644 index 8c3c4fe..0000000 --- a/tools/splaytree.py +++ /dev/null @@ -1,226 +0,0 @@ -# Copyright 2008 the V8 project authors. All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -class Node(object): - """Nodes in the splay tree.""" - - def __init__(self, key, value): - self.key = key - self.value = value - self.left = None - self.right = None - - -class KeyNotFoundError(Exception): - """KeyNotFoundError is raised when removing a non-existing node.""" - - def __init__(self, key): - self.key = key - - -class SplayTree(object): - """The splay tree itself is just a reference to the root of the tree.""" - - def __init__(self): - """Create a new SplayTree.""" - self.root = None - - def IsEmpty(self): - """Is the SplayTree empty?""" - return not self.root - - def Insert(self, key, value): - """Insert a new node in the SplayTree.""" - # If the tree is empty, insert the new node. - if self.IsEmpty(): - self.root = Node(key, value) - return - # Splay on the key to move the last node on the search path for - # the key to the root of the tree. - self.Splay(key) - # Ignore repeated insertions with the same key. - if self.root.key == key: - return - # Insert the new node. - node = Node(key, value) - if key > self.root.key: - node.left = self.root - node.right = self.root.right - self.root.right = None - else: - node.right = self.root - node.left = self.root.left - self.root.left = None - self.root = node - - def Remove(self, key): - """Remove the node with the given key from the SplayTree.""" - # Raise exception for key that is not found if the tree is empty. - if self.IsEmpty(): - raise KeyNotFoundError(key) - # Splay on the key to move the node with the given key to the top. - self.Splay(key) - # Raise exception for key that is not found. - if self.root.key != key: - raise KeyNotFoundError(key) - removed = self.root - # Link out the root node. - if not self.root.left: - # No left child, so the new tree is just the right child. - self.root = self.root.right - else: - # Left child exists. - right = self.root.right - # Make the original left child the new root. - self.root = self.root.left - # Splay to make sure that the new root has an empty right child. - self.Splay(key) - # Insert the original right child as the right child of the new - # root. - self.root.right = right - return removed - - def Find(self, key): - """Returns the node with the given key or None if no such node exists.""" - if self.IsEmpty(): - return None - self.Splay(key) - if self.root.key == key: - return self.root - return None - - def FindMax(self): - """Returns the node with the largest key value.""" - if self.IsEmpty(): - return None - current = self.root - while current.right != None: - current = current.right - return current - - # Returns the node with the smallest key value. - def FindMin(self): - if self.IsEmpty(): - return None - current = self.root - while current.left != None: - current = current.left - return current - - def FindGreatestsLessThan(self, key): - """Returns node with greatest key less than or equal to the given key.""" - if self.IsEmpty(): - return None - # Splay on the key to move the node with the given key or the last - # node on the search path to the top of the tree. - self.Splay(key) - # Now the result is either the root node or the greatest node in - # the left subtree. - if self.root.key <= key: - return self.root - else: - tmp = self.root - self.root = self.root.left - result = self.FindMax() - self.root = tmp - return result - - def ExportValueList(self): - """Returns a list containing all the values of the nodes in the tree.""" - result = [] - nodes_to_visit = [self.root] - while len(nodes_to_visit) > 0: - node = nodes_to_visit.pop() - if not node: - continue - result.append(node.value) - nodes_to_visit.append(node.left) - nodes_to_visit.append(node.right) - return result - - def Splay(self, key): - """Perform splay operation. - - Perform the splay operation for the given key. Moves the node with - the given key to the top of the tree. If no node has the given - key, the last node on the search path is moved to the top of the - tree. - - This uses the simplified top-down splaying algorithm from: - - "Self-adjusting Binary Search Trees" by Sleator and Tarjan - - """ - if self.IsEmpty(): - return - # Create a dummy node. The use of the dummy node is a bit - # counter-intuitive: The right child of the dummy node will hold - # the L tree of the algorithm. The left child of the dummy node - # will hold the R tree of the algorithm. Using a dummy node, left - # and right will always be nodes and we avoid special cases. - dummy = left = right = Node(None, None) - current = self.root - while True: - if key < current.key: - if not current.left: - break - if key < current.left.key: - # Rotate right. - tmp = current.left - current.left = tmp.right - tmp.right = current - current = tmp - if not current.left: - break - # Link right. - right.left = current - right = current - current = current.left - elif key > current.key: - if not current.right: - break - if key > current.right.key: - # Rotate left. - tmp = current.right - current.right = tmp.left - tmp.left = current - current = tmp - if not current.right: - break - # Link left. - left.right = current - left = current - current = current.right - else: - break - # Assemble. - left.right = current.left - right.left = current.right - current.left = dummy.right - current.right = dummy.left - self.root = current diff --git a/tools/tickprocessor.py b/tools/tickprocessor.py deleted file mode 100644 index c932e3f..0000000 --- a/tools/tickprocessor.py +++ /dev/null @@ -1,571 +0,0 @@ -# Copyright 2008 the V8 project authors. All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -import csv, splaytree, sys, re -from operator import itemgetter -import getopt, os, string - -class CodeEntry(object): - - def __init__(self, start_addr, name): - self.start_addr = start_addr - self.tick_count = 0 - self.name = name - self.stacks = {} - - def Tick(self, pc, stack): - self.tick_count += 1 - if len(stack) > 0: - stack.insert(0, self.ToString()) - stack_key = tuple(stack) - self.stacks[stack_key] = self.stacks.setdefault(stack_key, 0) + 1 - - def RegionTicks(self): - return None - - def SetStartAddress(self, start_addr): - self.start_addr = start_addr - - def ToString(self): - return self.name - - def IsSharedLibraryEntry(self): - return False - - def IsICEntry(self): - return False - - def IsJSFunction(self): - return False - -class SharedLibraryEntry(CodeEntry): - - def __init__(self, start_addr, name): - CodeEntry.__init__(self, start_addr, name) - - def IsSharedLibraryEntry(self): - return True - - -class JSCodeEntry(CodeEntry): - - def __init__(self, start_addr, name, type, size, assembler): - CodeEntry.__init__(self, start_addr, name) - self.type = type - self.size = size - self.assembler = assembler - self.region_ticks = None - self.builtin_ic_re = re.compile('^(Keyed)?(Call|Load|Store)IC_') - - def Tick(self, pc, stack): - super(JSCodeEntry, self).Tick(pc, stack) - if not pc is None: - offset = pc - self.start_addr - seen = [] - narrowest = None - narrowest_width = None - for region in self.Regions(): - if region.Contains(offset): - if (not region.name in seen): - seen.append(region.name) - if narrowest is None or region.Width() < narrowest.Width(): - narrowest = region - if len(seen) == 0: - return - if self.region_ticks is None: - self.region_ticks = {} - for name in seen: - if not name in self.region_ticks: - self.region_ticks[name] = [0, 0] - self.region_ticks[name][0] += 1 - if name == narrowest.name: - self.region_ticks[name][1] += 1 - - def RegionTicks(self): - return self.region_ticks - - def Regions(self): - if self.assembler: - return self.assembler.regions - else: - return [] - - def ToString(self): - name = self.name - if name == '': - name = '' - elif name.startswith(' '): - name = '' + name - return self.type + ': ' + name - - def IsICEntry(self): - return self.type in ('CallIC', 'LoadIC', 'StoreIC') or \ - (self.type == 'Builtin' and self.builtin_ic_re.match(self.name)) - - def IsJSFunction(self): - return self.type in ('Function', 'LazyCompile', 'Script') - -class CodeRegion(object): - - def __init__(self, start_offset, name): - self.start_offset = start_offset - self.name = name - self.end_offset = None - - def Contains(self, pc): - return (self.start_offset <= pc) and (pc <= self.end_offset) - - def Width(self): - return self.end_offset - self.start_offset - - -class Assembler(object): - - def __init__(self): - # Mapping from region ids to open regions - self.pending_regions = {} - self.regions = [] - - -class FunctionEnumerator(object): - - def __init__(self): - self.known_funcs = {} - self.next_func_id = 0 - - def GetFunctionId(self, name): - if not self.known_funcs.has_key(name): - self.known_funcs[name] = self.next_func_id - self.next_func_id += 1 - return self.known_funcs[name] - - def GetKnownFunctions(self): - known_funcs_items = self.known_funcs.items(); - known_funcs_items.sort(key = itemgetter(1)) - result = [] - for func, id_not_used in known_funcs_items: - result.append(func) - return result - - -VMStates = { 'JS': 0, 'GC': 1, 'COMPILER': 2, 'OTHER': 3, 'EXTERNAL' : 4 } - - -class TickProcessor(object): - - def __init__(self): - self.log_file = '' - self.deleted_code = [] - self.vm_extent = {} - # Map from assembler ids to the pending assembler objects - self.pending_assemblers = {} - # Map from code addresses the have been allocated but not yet officially - # created to their assemblers. - self.assemblers = {} - self.js_entries = splaytree.SplayTree() - self.cpp_entries = splaytree.SplayTree() - self.total_number_of_ticks = 0 - self.number_of_library_ticks = 0 - self.unaccounted_number_of_ticks = 0 - self.excluded_number_of_ticks = 0 - self.number_of_gc_ticks = 0 - # Flag indicating whether to ignore unaccounted ticks in the report - self.ignore_unknown = False - self.func_enum = FunctionEnumerator() - self.packed_stacks = [] - - def ProcessLogfile(self, filename, included_state = None, ignore_unknown = False, separate_ic = False, call_graph_json = False): - self.log_file = filename - self.included_state = included_state - self.ignore_unknown = ignore_unknown - self.separate_ic = separate_ic - self.call_graph_json = call_graph_json - - try: - logfile = open(filename, 'rb') - except IOError: - sys.exit("Could not open logfile: " + filename) - try: - try: - logreader = csv.reader(logfile) - row_num = 1 - for row in logreader: - row_num += 1 - if row[0] == 'tick': - self.ProcessTick(int(row[1], 16), int(row[2], 16), int(row[3], 16), int(row[4]), self.PreprocessStack(row[5:])) - elif row[0] == 'code-creation': - self.ProcessCodeCreation(row[1], int(row[2], 16), int(row[3]), row[4]) - elif row[0] == 'code-move': - self.ProcessCodeMove(int(row[1], 16), int(row[2], 16)) - elif row[0] == 'code-delete': - self.ProcessCodeDelete(int(row[1], 16)) - elif row[0] == 'function-creation': - self.ProcessFunctionCreation(int(row[1], 16), int(row[2], 16)) - elif row[0] == 'function-move': - self.ProcessFunctionMove(int(row[1], 16), int(row[2], 16)) - elif row[0] == 'function-delete': - self.ProcessFunctionDelete(int(row[1], 16)) - elif row[0] == 'shared-library': - self.AddSharedLibraryEntry(row[1], int(row[2], 16), int(row[3], 16)) - self.ParseVMSymbols(row[1], int(row[2], 16), int(row[3], 16)) - elif row[0] == 'begin-code-region': - self.ProcessBeginCodeRegion(int(row[1], 16), int(row[2], 16), int(row[3], 16), row[4]) - elif row[0] == 'end-code-region': - self.ProcessEndCodeRegion(int(row[1], 16), int(row[2], 16), int(row[3], 16)) - elif row[0] == 'code-allocate': - self.ProcessCodeAllocate(int(row[1], 16), int(row[2], 16)) - except csv.Error: - print("parse error in line " + str(row_num)) - raise - finally: - logfile.close() - - def AddSharedLibraryEntry(self, filename, start, end): - # Mark the pages used by this library. - i = start - while i < end: - page = i >> 12 - self.vm_extent[page] = 1 - i += 4096 - # Add the library to the entries so that ticks for which we do not - # have symbol information is reported as belonging to the library. - self.cpp_entries.Insert(start, SharedLibraryEntry(start, filename)) - - def ParseVMSymbols(self, filename, start, end): - return - - def ProcessCodeAllocate(self, addr, assem): - if assem in self.pending_assemblers: - assembler = self.pending_assemblers.pop(assem) - self.assemblers[addr] = assembler - - def ProcessCodeCreation(self, type, addr, size, name): - if addr in self.assemblers: - assembler = self.assemblers.pop(addr) - else: - assembler = None - self.js_entries.Insert(addr, JSCodeEntry(addr, name, type, size, assembler)) - - def ProcessCodeMove(self, from_addr, to_addr): - try: - removed_node = self.js_entries.Remove(from_addr) - removed_node.value.SetStartAddress(to_addr); - self.js_entries.Insert(to_addr, removed_node.value) - except splaytree.KeyNotFoundError: - print('Code move event for unknown code: 0x%x' % from_addr) - - def ProcessCodeDelete(self, from_addr): - try: - removed_node = self.js_entries.Remove(from_addr) - self.deleted_code.append(removed_node.value) - except splaytree.KeyNotFoundError: - print('Code delete event for unknown code: 0x%x' % from_addr) - - def ProcessFunctionCreation(self, func_addr, code_addr): - js_entry_node = self.js_entries.Find(code_addr) - if js_entry_node: - js_entry = js_entry_node.value - self.js_entries.Insert(func_addr, JSCodeEntry(func_addr, js_entry.name, js_entry.type, 1, None)) - - def ProcessFunctionMove(self, from_addr, to_addr): - try: - removed_node = self.js_entries.Remove(from_addr) - removed_node.value.SetStartAddress(to_addr); - self.js_entries.Insert(to_addr, removed_node.value) - except splaytree.KeyNotFoundError: - return - - def ProcessFunctionDelete(self, from_addr): - try: - removed_node = self.js_entries.Remove(from_addr) - self.deleted_code.append(removed_node.value) - except splaytree.KeyNotFoundError: - return - - def ProcessBeginCodeRegion(self, id, assm, start, name): - if not assm in self.pending_assemblers: - self.pending_assemblers[assm] = Assembler() - assembler = self.pending_assemblers[assm] - assembler.pending_regions[id] = CodeRegion(start, name) - - def ProcessEndCodeRegion(self, id, assm, end): - assm = self.pending_assemblers[assm] - region = assm.pending_regions.pop(id) - region.end_offset = end - assm.regions.append(region) - - def IncludeTick(self, pc, sp, state): - return (self.included_state is None) or (self.included_state == state) - - def FindEntry(self, pc): - page = pc >> 12 - if page in self.vm_extent: - entry = self.cpp_entries.FindGreatestsLessThan(pc) - if entry != None: - return entry.value - else: - return entry - max = self.js_entries.FindMax() - min = self.js_entries.FindMin() - if max != None and pc < (max.key + max.value.size) and pc > min.key: - return self.js_entries.FindGreatestsLessThan(pc).value - return None - - def PreprocessStack(self, stack): - # remove all non-addresses (e.g. 'overflow') and convert to int - result = [] - for frame in stack: - if frame.startswith('0x'): - result.append(int(frame, 16)) - return result - - def ProcessStack(self, stack): - result = [] - for frame in stack: - entry = self.FindEntry(frame) - if entry != None: - result.append(entry.ToString()) - return result - - def ProcessTick(self, pc, sp, func, state, stack): - if state == VMStates['GC']: - self.number_of_gc_ticks += 1 - if not self.IncludeTick(pc, sp, state): - self.excluded_number_of_ticks += 1; - return - self.total_number_of_ticks += 1 - entry = self.FindEntry(pc) - if entry == None: - self.unaccounted_number_of_ticks += 1 - return - if entry.IsSharedLibraryEntry(): - self.number_of_library_ticks += 1 - if entry.IsICEntry() and not self.separate_ic: - if len(stack) > 0: - caller_pc = stack.pop(0) - self.total_number_of_ticks -= 1 - self.ProcessTick(caller_pc, sp, func, state, stack) - else: - self.unaccounted_number_of_ticks += 1 - else: - processed_stack = self.ProcessStack(stack) - if not entry.IsSharedLibraryEntry() and not entry.IsJSFunction(): - func_entry_node = self.js_entries.Find(func) - if func_entry_node and func_entry_node.value.IsJSFunction(): - processed_stack.insert(0, func_entry_node.value.ToString()) - entry.Tick(pc, processed_stack) - if self.call_graph_json: - self.AddToPackedStacks(pc, stack) - - def AddToPackedStacks(self, pc, stack): - full_stack = stack - full_stack.insert(0, pc) - func_names = self.ProcessStack(full_stack) - func_ids = [] - for func in func_names: - func_ids.append(self.func_enum.GetFunctionId(func)) - self.packed_stacks.append(func_ids) - - def PrintResults(self): - if not self.call_graph_json: - self.PrintStatistics() - else: - self.PrintCallGraphJSON() - - def PrintStatistics(self): - print('Statistical profiling result from %s, (%d ticks, %d unaccounted, %d excluded).' % - (self.log_file, - self.total_number_of_ticks, - self.unaccounted_number_of_ticks, - self.excluded_number_of_ticks)) - if self.total_number_of_ticks > 0: - js_entries = self.js_entries.ExportValueList() - js_entries.extend(self.deleted_code) - cpp_entries = self.cpp_entries.ExportValueList() - # Print the unknown ticks percentage if they are not ignored. - if not self.ignore_unknown and self.unaccounted_number_of_ticks > 0: - self.PrintHeader('Unknown') - self.PrintCounter(self.unaccounted_number_of_ticks) - # Print the library ticks. - self.PrintHeader('Shared libraries') - self.PrintEntries(cpp_entries, lambda e:e.IsSharedLibraryEntry()) - # Print the JavaScript ticks. - self.PrintHeader('JavaScript') - self.PrintEntries(js_entries, lambda e:not e.IsSharedLibraryEntry()) - # Print the C++ ticks. - self.PrintHeader('C++') - self.PrintEntries(cpp_entries, lambda e:not e.IsSharedLibraryEntry()) - # Print the GC ticks. - self.PrintHeader('GC') - self.PrintCounter(self.number_of_gc_ticks) - # Print call profile. - print('\n [Call profile]:') - print(' total call path') - js_entries.extend(cpp_entries) - self.PrintCallProfile(js_entries) - - def PrintHeader(self, header_title): - print('\n [%s]:' % header_title) - print(' ticks total nonlib name') - - def PrintCounter(self, ticks_count): - percentage = ticks_count * 100.0 / self.total_number_of_ticks - print(' %(ticks)5d %(total)5.1f%%' % { - 'ticks' : ticks_count, - 'total' : percentage, - }) - - def PrintEntries(self, entries, condition): - # If ignoring unaccounted ticks don't include these in percentage - # calculations - number_of_accounted_ticks = self.total_number_of_ticks - if self.ignore_unknown: - number_of_accounted_ticks -= self.unaccounted_number_of_ticks - - number_of_non_library_ticks = number_of_accounted_ticks - self.number_of_library_ticks - entries.sort(key=lambda e: (e.tick_count, e.ToString()), reverse=True) - for entry in entries: - if entry.tick_count > 0 and condition(entry): - total_percentage = entry.tick_count * 100.0 / number_of_accounted_ticks - if entry.IsSharedLibraryEntry(): - non_library_percentage = 0 - else: - non_library_percentage = entry.tick_count * 100.0 / number_of_non_library_ticks - print(' %(ticks)5d %(total)5.1f%% %(nonlib)6.1f%% %(name)s' % { - 'ticks' : entry.tick_count, - 'total' : total_percentage, - 'nonlib' : non_library_percentage, - 'name' : entry.ToString() - }) - region_ticks = entry.RegionTicks() - if not region_ticks is None: - items = region_ticks.items() - items.sort(key=lambda e: e[1][1], reverse=True) - for (name, ticks) in items: - print(' flat cum') - print(' %(flat)5.1f%% %(accum)5.1f%% %(name)s' % { - 'flat' : ticks[1] * 100.0 / entry.tick_count, - 'accum' : ticks[0] * 100.0 / entry.tick_count, - 'name': name - }) - - def PrintCallProfile(self, entries): - all_stacks = {} - total_stacks = 0 - for entry in entries: - all_stacks.update(entry.stacks) - for count in entry.stacks.itervalues(): - total_stacks += count - all_stacks_items = all_stacks.items(); - all_stacks_items.sort(key = itemgetter(1), reverse=True) - missing_percentage = (self.total_number_of_ticks - total_stacks) * 100.0 / self.total_number_of_ticks - print(' %(ticks)5d %(total)5.1f%% ' % { - 'ticks' : self.total_number_of_ticks - total_stacks, - 'total' : missing_percentage - }) - for stack, count in all_stacks_items: - total_percentage = count * 100.0 / self.total_number_of_ticks - print(' %(ticks)5d %(total)5.1f%% %(call_path)s' % { - 'ticks' : count, - 'total' : total_percentage, - 'call_path' : stack[0] + ' <- ' + stack[1] - }) - - def PrintCallGraphJSON(self): - print('\nvar __profile_funcs = ["' + - '",\n"'.join(self.func_enum.GetKnownFunctions()) + - '"];') - print('var __profile_ticks = [') - str_packed_stacks = [] - for stack in self.packed_stacks: - str_packed_stacks.append('[' + ','.join(map(str, stack)) + ']') - print(',\n'.join(str_packed_stacks)) - print('];') - -class CmdLineProcessor(object): - - def __init__(self): - self.options = ["js", - "gc", - "compiler", - "other", - "external", - "ignore-unknown", - "separate-ic", - "call-graph-json"] - # default values - self.state = None - self.ignore_unknown = False - self.log_file = None - self.separate_ic = False - self.call_graph_json = False - - def ProcessArguments(self): - try: - opts, args = getopt.getopt(sys.argv[1:], "jgcoe", self.options) - except getopt.GetoptError: - self.PrintUsageAndExit() - for key, value in opts: - if key in ("-j", "--js"): - self.state = VMStates['JS'] - if key in ("-g", "--gc"): - self.state = VMStates['GC'] - if key in ("-c", "--compiler"): - self.state = VMStates['COMPILER'] - if key in ("-o", "--other"): - self.state = VMStates['OTHER'] - if key in ("-e", "--external"): - self.state = VMStates['EXTERNAL'] - if key in ("--ignore-unknown"): - self.ignore_unknown = True - if key in ("--separate-ic"): - self.separate_ic = True - if key in ("--call-graph-json"): - self.call_graph_json = True - self.ProcessRequiredArgs(args) - - def ProcessRequiredArgs(self, args): - return - - def GetRequiredArgsNames(self): - return - - def PrintUsageAndExit(self): - print('Usage: %(script_name)s --{%(opts)s} %(req_opts)s' % { - 'script_name': os.path.basename(sys.argv[0]), - 'opts': string.join(self.options, ','), - 'req_opts': self.GetRequiredArgsNames() - }) - sys.exit(2) - - def RunLogfileProcessing(self, tick_processor): - tick_processor.ProcessLogfile(self.log_file, self.state, self.ignore_unknown, - self.separate_ic, self.call_graph_json) - - -if __name__ == '__main__': - sys.exit('You probably want to run windows-tick-processor.py or linux-tick-processor.py.') diff --git a/tools/windows-tick-processor.py b/tools/windows-tick-processor.py deleted file mode 100755 index ade2bf2..0000000 --- a/tools/windows-tick-processor.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2008 the V8 project authors. All rights reserved. -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials provided -# with the distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived -# from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -# Usage: process-ticks.py -# -# Where is the binary program name (eg, v8_shell.exe) and -# is the log file name (eg, v8.log). -# -# This tick processor expects to find a map file for the binary named -# binary.map if the binary is named binary.exe. The tick processor -# only works for statically linked executables - no information about -# shared libraries is logged from v8 on Windows. - -import os, re, sys, tickprocessor - -class WindowsTickProcessor(tickprocessor.TickProcessor): - - def Unmangle(self, name): - """Performs very simple unmangling of C++ names. - - Does not handle arguments and template arguments. The mangled names have - the form: - - ?LookupInDescriptor@JSObject@internal@v8@@...arguments info... - - """ - # Name is mangled if it starts with a question mark. - is_mangled = re.match("^\?(.*)", name) - if is_mangled: - substrings = is_mangled.group(1).split('@') - try: - # The function name is terminated by two @s in a row. Find the - # substrings that are part of the function name. - index = substrings.index('') - substrings = substrings[0:index] - except ValueError: - # If we did not find two @s in a row, the mangled name is not in - # the format we expect and we give up. - return name - substrings.reverse() - function_name = "::".join(substrings) - return function_name - return name - - - def ParseMapFile(self, filename): - """Parse map file and add symbol information to the cpp entries.""" - # Locate map file. - has_dot = re.match('^([a-zA-F0-9_-]*)[\.]?.*$', filename) - if has_dot: - map_file_name = has_dot.group(1) + '.map' - try: - map_file = open(map_file_name, 'rb') - except IOError: - sys.exit("Could not open map file: " + map_file_name) - else: - sys.exit("Could not find map file for executable: " + filename) - try: - max_addr = 0 - min_addr = 2**30 - # Process map file and search for function entries. - row_regexp = re.compile(' 0001:[0-9a-fA-F]{8}\s*([_\?@$0-9a-zA-Z]*)\s*([0-9a-fA-F]{8}).*') - for line in map_file: - row = re.match(row_regexp, line) - if row: - addr = int(row.group(2), 16) - if addr > max_addr: - max_addr = addr - if addr < min_addr: - min_addr = addr - mangled_name = row.group(1) - name = self.Unmangle(mangled_name) - self.cpp_entries.Insert(addr, tickprocessor.CodeEntry(addr, name)); - i = min_addr - # Mark the pages for which there are functions in the map file. - while i < max_addr: - page = i >> 12 - self.vm_extent[page] = 1 - i += 4096 - finally: - map_file.close() - - -class WindowsCmdLineProcessor(tickprocessor.CmdLineProcessor): - - def __init__(self): - super(WindowsCmdLineProcessor, self).__init__() - self.binary_file = None - - def GetRequiredArgsNames(self): - return 'binary log_file' - - def ProcessRequiredArgs(self, args): - if len(args) != 2: - self.PrintUsageAndExit() - else: - self.binary_file = args[0] - self.log_file = args[1] - - -def Main(): - cmdline_processor = WindowsCmdLineProcessor() - cmdline_processor.ProcessArguments() - tickprocessor = WindowsTickProcessor() - tickprocessor.ParseMapFile(cmdline_processor.binary_file) - cmdline_processor.RunLogfileProcessing(tickprocessor) - tickprocessor.PrintResults() - -if __name__ == '__main__': - Main() -- 2.7.4