• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6import sys
7
8from lib.policy import PolicySet
9from lib.subcommand import SubCommand
10
11
12LOGGER = logging.getLogger('dmprof')
13
14
15class PProfCommand(SubCommand):
16  def __init__(self):
17    super(PProfCommand, self).__init__(
18        'Usage: %prog pprof [-c COMPONENT] <dump> <policy>')
19    self._parser.add_option('-c', '--component', type='string',
20                            dest='component',
21                            help='restrict to COMPONENT', metavar='COMPONENT')
22
23  def do(self, sys_argv):
24    options, args = self._parse_args(sys_argv, 2)
25
26    dump_path = args[1]
27    target_policy = args[2]
28    component = options.component
29
30    (bucket_set, dump) = SubCommand.load_basic_files(dump_path, False)
31    policy_set = PolicySet.load(SubCommand._parse_policy_list(target_policy))
32
33    with open(SubCommand._find_prefix(dump_path) + '.maps', 'r') as maps_f:
34      maps_lines = maps_f.readlines()
35    PProfCommand._output(
36        dump, policy_set[target_policy], bucket_set, maps_lines, component,
37        sys.stdout)
38
39    return 0
40
41  @staticmethod
42  def _output(dump, policy, bucket_set, maps_lines, component_name, out):
43    """Converts the heap profile dump so it can be processed by pprof.
44
45    Args:
46        dump: A Dump object.
47        policy: A Policy object.
48        bucket_set: A BucketSet object.
49        maps_lines: A list of strings containing /proc/.../maps.
50        component_name: A name of component for filtering.
51        out: An IO object to output.
52    """
53    out.write('heap profile: ')
54    com_committed, com_allocs = PProfCommand._accumulate(
55        dump, policy, bucket_set, component_name)
56
57    out.write('%6d: %8s [%6d: %8s] @ heapprofile\n' % (
58        com_allocs, com_committed, com_allocs, com_committed))
59
60    PProfCommand._output_stacktrace_lines(
61        dump, policy, bucket_set, component_name, out)
62
63    out.write('MAPPED_LIBRARIES:\n')
64    for line in maps_lines:
65      out.write(line)
66
67  @staticmethod
68  def _accumulate(dump, policy, bucket_set, component_name):
69    """Accumulates size of committed chunks and the number of allocated chunks.
70
71    Args:
72        dump: A Dump object.
73        policy: A Policy object.
74        bucket_set: A BucketSet object.
75        component_name: A name of component for filtering.
76
77    Returns:
78        Two integers which are the accumulated size of committed regions and the
79        number of allocated chunks, respectively.
80    """
81    com_committed = 0
82    com_allocs = 0
83
84    for _, region in dump.iter_map:
85      if region[0] != 'hooked':
86        continue
87      component_match, bucket = policy.find_mmap(region, bucket_set)
88
89      if (component_name and component_name != component_match) or (
90          region[1]['committed'] == 0):
91        continue
92
93      com_committed += region[1]['committed']
94      com_allocs += 1
95
96    for bucket_id, _, committed, allocs, frees in dump.iter_stacktrace:
97      bucket = bucket_set.get(bucket_id)
98      if not bucket or bucket.allocator_type == 'malloc':
99        component_match = policy.find_malloc(bucket)
100      elif bucket.allocator_type == 'mmap':
101        continue
102      else:
103        assert False
104      if (not bucket or
105          (component_name and component_name != component_match)):
106        continue
107
108      com_committed += committed
109      com_allocs += allocs - frees
110
111    return com_committed, com_allocs
112
113  @staticmethod
114  def _output_stacktrace_lines(dump, policy, bucket_set, component_name, out):
115    """Prints information of stacktrace lines for pprof.
116
117    Args:
118        dump: A Dump object.
119        policy: A Policy object.
120        bucket_set: A BucketSet object.
121        component_name: A name of component for filtering.
122        out: An IO object to output.
123    """
124    for _, region in dump.iter_map:
125      if region[0] != 'hooked':
126        continue
127      component_match, bucket = policy.find_mmap(region, bucket_set)
128
129      if (component_name and component_name != component_match) or (
130          region[1]['committed'] == 0):
131        continue
132
133      out.write('     1: %8s [     1: %8s] @' % (
134          region[1]['committed'], region[1]['committed']))
135      for address in bucket.stacktrace:
136        out.write(' 0x%016x' % address)
137      out.write('\n')
138
139    for bucket_id, _, committed, allocs, frees in dump.iter_stacktrace:
140      bucket = bucket_set.get(bucket_id)
141      if not bucket or bucket.allocator_type == 'malloc':
142        component_match = policy.find_malloc(bucket)
143      elif bucket.allocator_type == 'mmap':
144        continue
145      else:
146        assert False
147      if (not bucket or
148          (component_name and component_name != component_match)):
149        continue
150
151      out.write('%6d: %8s [%6d: %8s] @' % (
152          allocs - frees, str(committed), allocs - frees, str(committed)))
153      for address in bucket.stacktrace:
154        out.write(' 0x%016x' % address)
155      out.write('\n')
156