Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Side by Side Diff: tools/binary_size/create_html_breakdown.py

Issue 2785483002: Reland of V2 of //tools/binary_size rewrite (diffs). (Closed)
Patch Set: add missing name= Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/binary_size/console.py ('k') | tools/binary_size/describe.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved. 2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Creates an html report that allows you to view binary size by component.""" 6 """Creates an html report that allows you to view binary size by component."""
7 7
8 import argparse 8 import argparse
9 import json 9 import json
10 import logging 10 import logging
11 import os 11 import os
12 import shutil 12 import shutil
13 import sys 13 import sys
14 14
15 import analyze
16 import helpers 15 import helpers
16 import map2size
17 17
18 18
19 # Node dictionary keys. These are output in json read by the webapp so 19 # Node dictionary keys. These are output in json read by the webapp so
20 # keep them short to save file size. 20 # keep them short to save file size.
21 # Note: If these change, the webapp must also change. 21 # Note: If these change, the webapp must also change.
22 _NODE_TYPE_KEY = 'k' 22 _NODE_TYPE_KEY = 'k'
23 _NODE_TYPE_BUCKET = 'b' 23 _NODE_TYPE_BUCKET = 'b'
24 _NODE_TYPE_PATH = 'p' 24 _NODE_TYPE_PATH = 'p'
25 _NODE_TYPE_SYMBOL = 's' 25 _NODE_TYPE_SYMBOL = 's'
26 _NODE_NAME_KEY = 'n' 26 _NODE_NAME_KEY = 'n'
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 node_name = symbol_name or '[Anonymous]' 106 node_name = symbol_name or '[Anonymous]'
107 elif symbol_name.startswith('*'): 107 elif symbol_name.startswith('*'):
108 node_name = symbol_name 108 node_name = symbol_name
109 else: 109 else:
110 node_name = symbol_type 110 node_name = symbol_type
111 node = _GetOrMakeChildNode(node, _NODE_TYPE_SYMBOL, node_name) 111 node = _GetOrMakeChildNode(node, _NODE_TYPE_SYMBOL, node_name)
112 node[_NODE_SYMBOL_SIZE_KEY] = node.get(_NODE_SYMBOL_SIZE_KEY, 0) + symbol_size 112 node[_NODE_SYMBOL_SIZE_KEY] = node.get(_NODE_SYMBOL_SIZE_KEY, 0) + symbol_size
113 node[_NODE_SYMBOL_TYPE_KEY] = symbol_type 113 node[_NODE_SYMBOL_TYPE_KEY] = symbol_type
114 114
115 115
116 def _MakeCompactTree(root_group, include_symbols): 116 def _MakeCompactTree(symbols, include_symbols):
117 result = { 117 result = {
118 _NODE_NAME_KEY: '/', 118 _NODE_NAME_KEY: '/',
119 _NODE_CHILDREN_KEY: {}, 119 _NODE_CHILDREN_KEY: {},
120 _NODE_TYPE_KEY: 'p', 120 _NODE_TYPE_KEY: 'p',
121 _NODE_MAX_DEPTH_KEY: 0, 121 _NODE_MAX_DEPTH_KEY: 0,
122 } 122 }
123 for symbol in root_group: 123 for symbol in symbols:
124 file_path = symbol.path or _NAME_NO_PATH_BUCKET 124 file_path = symbol.path or _NAME_NO_PATH_BUCKET
125 node = result 125 node = result
126 depth = 0 126 depth = 0
127 for path_part in file_path.split(os.path.sep): 127 for path_part in file_path.split(os.path.sep):
128 if not path_part: 128 if not path_part:
129 continue 129 continue
130 depth += 1 130 depth += 1
131 node = _GetOrMakeChildNode(node, _NODE_TYPE_PATH, path_part) 131 node = _GetOrMakeChildNode(node, _NODE_TYPE_PATH, path_part)
132 132
133 symbol_type = symbol.section 133 symbol_type = symbol.section
134 if symbol.name: 134 if symbol.name.endswith('[vtable]'):
135 if symbol.name.endswith('[vtable]'): 135 symbol_type = _NODE_SYMBOL_TYPE_VTABLE
136 symbol_type = _NODE_SYMBOL_TYPE_VTABLE 136 elif symbol.name.endswith(']'):
137 elif symbol.name.endswith(']'): 137 symbol_type = _NODE_SYMBOL_TYPE_GENERATED
138 symbol_type = _NODE_SYMBOL_TYPE_GENERATED
139 _AddSymbolIntoFileNode(node, symbol_type, symbol.name, symbol.size, 138 _AddSymbolIntoFileNode(node, symbol_type, symbol.name, symbol.size,
140 include_symbols) 139 include_symbols)
141 depth += 2 140 depth += 2
142 result[_NODE_MAX_DEPTH_KEY] = max(result[_NODE_MAX_DEPTH_KEY], depth) 141 result[_NODE_MAX_DEPTH_KEY] = max(result[_NODE_MAX_DEPTH_KEY], depth)
143 142
144 # The (no path) bucket can be extremely large if we failed to get 143 # The (no path) bucket can be extremely large if we failed to get
145 # path information. Split it into subgroups if needed. 144 # path information. Split it into subgroups if needed.
146 no_path_bucket = result[_NODE_CHILDREN_KEY].get(_NAME_NO_PATH_BUCKET) 145 no_path_bucket = result[_NODE_CHILDREN_KEY].get(_NAME_NO_PATH_BUCKET)
147 if no_path_bucket and include_symbols: 146 if no_path_bucket and include_symbols:
148 _SplitLargeBucket(no_path_bucket) 147 _SplitLargeBucket(no_path_bucket)
149 148
150 _MakeChildrenDictsIntoLists(result) 149 _MakeChildrenDictsIntoLists(result)
151 150
152 return result 151 return result
153 152
154 153
155 def _CopyTemplateFiles(dest_dir): 154 def _CopyTemplateFiles(dest_dir):
156 d3_out = os.path.join(dest_dir, 'd3') 155 d3_out = os.path.join(dest_dir, 'd3')
157 if not os.path.exists(d3_out): 156 if not os.path.exists(d3_out):
158 os.makedirs(d3_out, 0755) 157 os.makedirs(d3_out, 0755)
159 d3_src = os.path.join(helpers.SRC_ROOT, 'third_party', 'd3', 'src') 158 d3_src = os.path.join(helpers.SRC_ROOT, 'third_party', 'd3', 'src')
160 template_src = os.path.join(os.path.dirname(__file__), 'template') 159 template_src = os.path.join(os.path.dirname(__file__), 'template')
161 shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out) 160 shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out)
162 shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out) 161 shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out)
163 shutil.copy(os.path.join(template_src, 'index.html'), dest_dir) 162 shutil.copy(os.path.join(template_src, 'index.html'), dest_dir)
164 shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), dest_dir) 163 shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), dest_dir)
165 164
166 165
167 def main(): 166 def main(argv):
168 parser = argparse.ArgumentParser() 167 parser = argparse.ArgumentParser()
168 parser.add_argument('input_file',
169 help='Path to input file. Can be a linker .map file, or '
170 'a .size file.')
169 parser.add_argument('--report-dir', metavar='PATH', required=True, 171 parser.add_argument('--report-dir', metavar='PATH', required=True,
170 help='Write output to the specified directory. An HTML ' 172 help='Write output to the specified directory. An HTML '
171 'report is generated here.') 173 'report is generated here.')
172 parser.add_argument('--include-bss', action='store_true', 174 parser.add_argument('--include-bss', action='store_true',
173 help='Include symbols from .bss (which consume no real ' 175 help='Include symbols from .bss (which consume no real '
174 'space)') 176 'space)')
175 parser.add_argument('--include-symbols', action='store_true', 177 parser.add_argument('--include-symbols', action='store_true',
176 help='Use per-symbol granularity rather than per-file.') 178 help='Use per-symbol granularity rather than per-file.')
177 analyze.AddOptions(parser) 179 map2size.AddOptions(parser)
178 args = helpers.AddCommonOptionsAndParseArgs(parser) 180 args = helpers.AddCommonOptionsAndParseArgs(parser, argv)
179 181
180 result = analyze.AnalyzeWithArgs(args) 182 size_info = map2size.AnalyzeWithArgs(args, args.input_file)
181 root_group = result.symbol_group 183 symbols = size_info.symbols
182 if not args.include_bss: 184 if not args.include_bss:
183 root_group = root_group.WhereInSection('b').Inverted() 185 symbols = size_info.WhereInSection('b').Inverted()
184 root_group = root_group.WhereBiggerThan(0) 186 symbols = symbols.WhereBiggerThan(0)
185 187
186 # Copy report boilerplate into output directory. This also proves that the 188 # Copy report boilerplate into output directory. This also proves that the
187 # output directory is safe for writing, so there should be no problems writing 189 # output directory is safe for writing, so there should be no problems writing
188 # the nm.out file later. 190 # the nm.out file later.
189 _CopyTemplateFiles(args.report_dir) 191 _CopyTemplateFiles(args.report_dir)
190 192
191 logging.info('Creating JSON objects') 193 logging.info('Creating JSON objects')
192 tree_root = _MakeCompactTree(root_group, args.include_symbols) 194 tree_root = _MakeCompactTree(symbols, args.include_symbols)
193 195
194 logging.info('Serializing') 196 logging.info('Serializing')
195 with open(os.path.join(args.report_dir, 'data.js'), 'w') as out_file: 197 with open(os.path.join(args.report_dir, 'data.js'), 'w') as out_file:
196 out_file.write('var tree_data=') 198 out_file.write('var tree_data=')
197 # Use separators without whitespace to get a smaller file. 199 # Use separators without whitespace to get a smaller file.
198 json.dump(tree_root, out_file, ensure_ascii=False, check_circular=False, 200 json.dump(tree_root, out_file, ensure_ascii=False, check_circular=False,
199 separators=(',', ':')) 201 separators=(',', ':'))
200 202
201 print 'Report saved to ' + args.report_dir + '/index.html' 203 print 'Report saved to ' + args.report_dir + '/index.html'
202 204
205
203 if __name__ == '__main__': 206 if __name__ == '__main__':
204 sys.exit(main()) 207 sys.exit(main(sys.argv))
OLDNEW
« no previous file with comments | « tools/binary_size/console.py ('k') | tools/binary_size/describe.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698