Revert 264226 "Reduce dependency of TiclInvalidationService on P..."
[chromium-blink-merge.git] / tools / deep_memory_profiler / subcommands / cat.py
blob5430ce102c3579af8ca4073b18a262ad99d0fe93
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.
5 import json
6 import logging
7 import sys
9 from lib.bucket import BUCKET_ID, COMMITTED, ALLOC_COUNT, FREE_COUNT
10 from lib.ordered_dict import OrderedDict
11 from lib.subcommand import SubCommand
12 from lib.sorter import MallocUnit, MMapUnit, SorterSet, UnhookedUnit, UnitSet
15 LOGGER = logging.getLogger('dmprof')
18 class CatCommand(SubCommand):
19 def __init__(self):
20 super(CatCommand, self).__init__('Usage: %prog cat <first-dump>')
21 self._parser.add_option('--alternative-dirs', dest='alternative_dirs',
22 metavar='/path/on/target@/path/on/host[:...]',
23 help='Read files in /path/on/host/ instead of '
24 'files in /path/on/target/.')
25 self._parser.add_option('--indent', dest='indent', action='store_true',
26 help='Indent the output.')
28 def do(self, sys_argv):
29 options, args = self._parse_args(sys_argv, 1)
30 dump_path = args[1]
31 # TODO(dmikurube): Support shared memory.
32 alternative_dirs_dict = {}
33 if options.alternative_dirs:
34 for alternative_dir_pair in options.alternative_dirs.split(':'):
35 target_path, host_path = alternative_dir_pair.split('@', 1)
36 alternative_dirs_dict[target_path] = host_path
37 (bucket_set, dumps) = SubCommand.load_basic_files(
38 dump_path, True, alternative_dirs=alternative_dirs_dict)
40 # Load all sorters.
41 sorters = SorterSet()
43 json_root = OrderedDict()
44 json_root['version'] = 1
45 json_root['run_id'] = None
46 json_root['roots'] = []
47 for sorter in sorters:
48 if sorter.root:
49 json_root['roots'].append([sorter.world, sorter.name])
50 json_root['default_template'] = 'l2'
51 json_root['templates'] = sorters.templates.as_dict()
53 orders = OrderedDict()
54 orders['worlds'] = OrderedDict()
55 for world in ['vm', 'malloc']:
56 orders['worlds'][world] = OrderedDict()
57 orders['worlds'][world]['breakdown'] = OrderedDict()
58 for sorter in sorters.iter_world(world):
59 order = []
60 for rule in sorter.iter_rule():
61 if rule.name not in order:
62 order.append(rule.name)
63 orders['worlds'][world]['breakdown'][sorter.name] = order
64 json_root['orders'] = orders
66 json_root['snapshots'] = []
68 for dump in dumps:
69 if json_root['run_id'] and json_root['run_id'] != dump.run_id:
70 LOGGER.error('Inconsistent heap profile dumps.')
71 json_root['run_id'] = ''
72 else:
73 json_root['run_id'] = dump.run_id
75 LOGGER.info('Sorting a dump %s...' % dump.path)
76 json_root['snapshots'].append(
77 self._fill_snapshot(dump, bucket_set, sorters))
79 if options.indent:
80 json.dump(json_root, sys.stdout, indent=2)
81 else:
82 json.dump(json_root, sys.stdout)
83 print ''
85 @staticmethod
86 def _fill_snapshot(dump, bucket_set, sorters):
87 root = OrderedDict()
88 root['time'] = dump.time
89 root['worlds'] = OrderedDict()
90 root['worlds']['vm'] = CatCommand._fill_world(
91 dump, bucket_set, sorters, 'vm')
92 root['worlds']['malloc'] = CatCommand._fill_world(
93 dump, bucket_set, sorters, 'malloc')
94 return root
96 @staticmethod
97 def _fill_world(dump, bucket_set, sorters, world):
98 root = OrderedDict()
100 root['name'] = world
101 if world == 'vm':
102 root['unit_fields'] = ['size', 'reserved']
103 elif world == 'malloc':
104 root['unit_fields'] = ['size', 'alloc_count', 'free_count']
106 # Make { vm | malloc } units with their sizes.
107 root['units'] = OrderedDict()
108 unit_set = UnitSet(world)
109 if world == 'vm':
110 for unit in CatCommand._iterate_vm_unit(dump, None, bucket_set):
111 unit_set.append(unit)
112 for unit in unit_set:
113 root['units'][unit.unit_id] = [unit.committed, unit.reserved]
114 elif world == 'malloc':
115 for unit in CatCommand._iterate_malloc_unit(dump, bucket_set):
116 unit_set.append(unit)
117 for unit in unit_set:
118 root['units'][unit.unit_id] = [
119 unit.size, unit.alloc_count, unit.free_count]
121 # Iterate for { vm | malloc } sorters.
122 root['breakdown'] = OrderedDict()
123 for sorter in sorters.iter_world(world):
124 LOGGER.info(' Sorting with %s:%s.' % (sorter.world, sorter.name))
125 breakdown = OrderedDict()
126 for rule in sorter.iter_rule():
127 category = OrderedDict()
128 category['name'] = rule.name
129 subs = []
130 for sub_world, sub_breakdown in rule.iter_subs():
131 subs.append([sub_world, sub_breakdown])
132 if subs:
133 category['subs'] = subs
134 if rule.hidden:
135 category['hidden'] = True
136 category['units'] = []
137 breakdown[rule.name] = category
138 for unit in unit_set:
139 found = sorter.find(unit)
140 if found:
141 # Note that a bucket which doesn't match any rule is just dropped.
142 breakdown[found.name]['units'].append(unit.unit_id)
143 root['breakdown'][sorter.name] = breakdown
145 return root
147 @staticmethod
148 def _iterate_vm_unit(dump, pfn_dict, bucket_set):
149 unit_id = 0
150 for _, region in dump.iter_map:
151 unit_id += 1
152 if region[0] == 'unhooked':
153 if pfn_dict and dump.pageframe_length:
154 for pageframe in region[1]['pageframe']:
155 yield UnhookedUnit(unit_id, pageframe.size, pageframe.size,
156 region, pageframe, pfn_dict)
157 else:
158 yield UnhookedUnit(unit_id,
159 int(region[1]['committed']),
160 int(region[1]['reserved']),
161 region)
162 elif region[0] == 'hooked':
163 if pfn_dict and dump.pageframe_length:
164 for pageframe in region[1]['pageframe']:
165 yield MMapUnit(unit_id,
166 pageframe.size,
167 pageframe.size,
168 region, bucket_set, pageframe, pfn_dict)
169 else:
170 yield MMapUnit(unit_id,
171 int(region[1]['committed']),
172 int(region[1]['reserved']),
173 region,
174 bucket_set)
175 else:
176 LOGGER.error('Unrecognized mapping status: %s' % region[0])
178 @staticmethod
179 def _iterate_malloc_unit(dump, bucket_set):
180 for line in dump.iter_stacktrace:
181 words = line.split()
182 bucket = bucket_set.get(int(words[BUCKET_ID]))
183 if bucket and bucket.allocator_type == 'malloc':
184 yield MallocUnit(int(words[BUCKET_ID]),
185 int(words[COMMITTED]),
186 int(words[ALLOC_COUNT]),
187 int(words[FREE_COUNT]),
188 bucket)
189 elif not bucket:
190 # 'Not-found' buckets are all assumed as malloc buckets.
191 yield MallocUnit(int(words[BUCKET_ID]),
192 int(words[COMMITTED]),
193 int(words[ALLOC_COUNT]),
194 int(words[FREE_COUNT]),
195 None)