1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#!/usr/bin/env python 2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# 3a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# Copyright 2009 the V8 project authors. All rights reserved. 4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# Redistribution and use in source and binary forms, with or without 5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# modification, are permitted provided that the following conditions are 6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# met: 7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# 8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# * Redistributions of source code must retain the above copyright 9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# notice, this list of conditions and the following disclaimer. 10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# * Redistributions in binary form must reproduce the above 11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# copyright notice, this list of conditions and the following 12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# disclaimer in the documentation and/or other materials provided 13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# with the distribution. 14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# * Neither the name of Google Inc. nor the names of its 15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# contributors may be used to endorse or promote products derived 16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# from this software without specific prior written permission. 17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# 18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# This is an utility for converting V8 heap logs into .hp files that can 31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# be further processed using 'hp2ps' tool (bundled with GHC and Valgrind) 32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# to produce heap usage histograms. 33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# Sample usage: 35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# $ ./shell --log-gc script.js 36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# $ tools/process-heap-prof.py v8.log | hp2ps -c > script-heap-graph.ps 37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# ('-c' enables color, see hp2ps manual page for more options) 38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# or 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# $ tools/process-heap-prof.py --js-cons-profile v8.log | hp2ps -c > script-heap-graph.ps 40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# to get JS constructor profile 41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 43d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockimport csv, sys, time, optparse 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 45d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockdef ProcessLogFile(filename, options): 46d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if options.js_cons_profile: 47d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block itemname = 'heap-js-cons-item' 48d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block else: 49d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block itemname = 'heap-sample-item' 50589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block first_call_time = None 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sample_time = 0.0 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sampling = False 54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block try: 55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block logfile = open(filename, 'rb') 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block try: 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block logreader = csv.reader(logfile) 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block print('JOB "v8"') 60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block print('DATE "%s"' % time.asctime(time.localtime())) 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block print('SAMPLE_UNIT "seconds"') 62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block print('VALUE_UNIT "bytes"') 63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for row in logreader: 65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if row[0] == 'heap-sample-begin' and row[1] == 'Heap': 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sample_time = float(row[3])/1000.0 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if first_call_time == None: 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block first_call_time = sample_time 69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sample_time -= first_call_time 70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block print('BEGIN_SAMPLE %.2f' % sample_time) 71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sampling = True 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block elif row[0] == 'heap-sample-end' and row[1] == 'Heap': 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block print('END_SAMPLE %.2f' % sample_time) 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sampling = False 75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block elif row[0] == itemname and sampling: 76d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block print(row[1]), 77d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if options.count: 78d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block print('%d' % (int(row[2]))), 79d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if options.size: 80d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block print('%d' % (int(row[3]))), 81d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block print 82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block finally: 83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block logfile.close() 84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block except: 85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sys.exit('can\'t open %s' % filename) 86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 87d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 88d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockdef BuildOptions(): 89d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block result = optparse.OptionParser() 90d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block result.add_option("--js_cons_profile", help="Constructor profile", 91d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block default=False, action="store_true") 92d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block result.add_option("--size", help="Report object size", 93d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block default=False, action="store_true") 94d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block result.add_option("--count", help="Report object count", 95d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block default=False, action="store_true") 96d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block return result 97d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 98d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 99d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockdef ProcessOptions(options): 100d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if not options.size and not options.count: 101d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block options.size = True 102d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block return True 103d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 104d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 105d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockdef Main(): 106d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block parser = BuildOptions() 107d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block (options, args) = parser.parse_args() 108d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if not ProcessOptions(options): 109d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block parser.print_help() 110d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block sys.exit(); 111589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 112d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if not args: 113d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block print "Missing logfile" 114d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block sys.exit(); 115589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 116d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block ProcessLogFile(args[0], options) 117d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 118d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 119d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockif __name__ == '__main__': 120d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block sys.exit(Main()) 121