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