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