OLD | NEW |
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 """Generate a spatial analysis against an arbitrary library. | 6 """Generate a spatial analysis against an arbitrary library. |
7 | 7 |
8 To use, build the 'binary_size_tool' target. Then run this tool, passing | 8 To use, build the 'binary_size_tool' target. Then run this tool, passing |
9 in the location of the library to be analyzed along with any other options | 9 in the location of the library to be analyzed along with any other options |
10 you desire. | 10 you desire. |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 return 2 # Depth of the added subtree. | 162 return 2 # Depth of the added subtree. |
163 | 163 |
164 | 164 |
165 def MakeCompactTree(symbols, symbol_path_origin_dir): | 165 def MakeCompactTree(symbols, symbol_path_origin_dir): |
166 result = {NODE_NAME_KEY: '/', | 166 result = {NODE_NAME_KEY: '/', |
167 NODE_CHILDREN_KEY: {}, | 167 NODE_CHILDREN_KEY: {}, |
168 NODE_TYPE_KEY: 'p', | 168 NODE_TYPE_KEY: 'p', |
169 NODE_MAX_DEPTH_KEY: 0} | 169 NODE_MAX_DEPTH_KEY: 0} |
170 seen_symbol_with_path = False | 170 seen_symbol_with_path = False |
171 cwd = os.path.abspath(os.getcwd()) | 171 cwd = os.path.abspath(os.getcwd()) |
172 for symbol_name, symbol_type, symbol_size, file_path in symbols: | 172 for symbol_name, symbol_type, symbol_size, file_path, _address in symbols: |
173 | 173 |
174 if 'vtable for ' in symbol_name: | 174 if 'vtable for ' in symbol_name: |
175 symbol_type = '@' # hack to categorize these separately | 175 symbol_type = '@' # hack to categorize these separately |
176 # Take path like '/foo/bar/baz', convert to ['foo', 'bar', 'baz'] | 176 # Take path like '/foo/bar/baz', convert to ['foo', 'bar', 'baz'] |
177 if file_path and file_path != "??": | 177 if file_path and file_path != "??": |
178 file_path = os.path.abspath(os.path.join(symbol_path_origin_dir, | 178 file_path = os.path.abspath(os.path.join(symbol_path_origin_dir, |
179 file_path)) | 179 file_path)) |
180 # Let the output structure be relative to $CWD if inside $CWD, | 180 # Let the output structure be relative to $CWD if inside $CWD, |
181 # otherwise relative to the disk root. This is to avoid | 181 # otherwise relative to the disk root. This is to avoid |
182 # unnecessary click-through levels in the output. | 182 # unnecessary click-through levels in the output. |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
238 directory or file names) and whose values are other nodes; | 238 directory or file names) and whose values are other nodes; |
239 size: the total size, in bytes, of all the leaf nodes that are | 239 size: the total size, in bytes, of all the leaf nodes that are |
240 contained within the children dict (recursively expanded) | 240 contained within the children dict (recursively expanded) |
241 | 241 |
242 The result object is itself a dictionary that represents the common ancestor | 242 The result object is itself a dictionary that represents the common ancestor |
243 of all child nodes, e.g. a path to which all other nodes beneath it are | 243 of all child nodes, e.g. a path to which all other nodes beneath it are |
244 relative. The 'size' attribute of this dict yields the sum of the size of all | 244 relative. The 'size' attribute of this dict yields the sum of the size of all |
245 leaf nodes within the data structure. | 245 leaf nodes within the data structure. |
246 """ | 246 """ |
247 dirs = {'children': {}, 'size': 0} | 247 dirs = {'children': {}, 'size': 0} |
248 for sym, symbol_type, size, path in symbols: | 248 for sym, symbol_type, size, path, _address in symbols: |
249 dirs['size'] += size | 249 dirs['size'] += size |
250 if path: | 250 if path: |
251 path = os.path.normpath(path) | 251 path = os.path.normpath(path) |
252 if path.startswith('/'): | 252 if path.startswith('/'): |
253 path = path[1:] | 253 path = path[1:] |
254 | 254 |
255 parts = None | 255 parts = None |
256 if path: | 256 if path: |
257 parts = path.split('/') | 257 parts = path.split('/') |
258 | 258 |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 | 375 |
376 | 376 |
377 # TODO(andrewhayden): Only used for legacy reports. Delete. | 377 # TODO(andrewhayden): Only used for legacy reports. Delete. |
378 def DumpLargestSymbols(symbols, outfile, n): | 378 def DumpLargestSymbols(symbols, outfile, n): |
379 # a list of (sym, symbol_type, size, path); sort by size. | 379 # a list of (sym, symbol_type, size, path); sort by size. |
380 symbols = sorted(symbols, key=lambda x: -x[2]) | 380 symbols = sorted(symbols, key=lambda x: -x[2]) |
381 dumped = 0 | 381 dumped = 0 |
382 out = open(outfile, 'w') | 382 out = open(outfile, 'w') |
383 try: | 383 try: |
384 out.write('var largestSymbols = [\n') | 384 out.write('var largestSymbols = [\n') |
385 for sym, symbol_type, size, path in symbols: | 385 for sym, symbol_type, size, path, _address in symbols: |
386 if symbol_type in ('b', 'w'): | 386 if symbol_type in ('b', 'w'): |
387 continue # skip bss and weak symbols | 387 continue # skip bss and weak symbols |
388 if path is None: | 388 if path is None: |
389 path = '' | 389 path = '' |
390 entry = {'size': FormatBytes(size), | 390 entry = {'size': FormatBytes(size), |
391 'symbol': sym, | 391 'symbol': sym, |
392 'type': SymbolTypeToHuman(symbol_type), | 392 'type': SymbolTypeToHuman(symbol_type), |
393 'location': path } | 393 'location': path } |
394 out.write(json.dumps(entry)) | 394 out.write(json.dumps(entry)) |
395 out.write(',\n') | 395 out.write(',\n') |
396 dumped += 1 | 396 dumped += 1 |
397 if dumped >= n: | 397 if dumped >= n: |
398 return | 398 return |
399 finally: | 399 finally: |
400 out.write('];\n') | 400 out.write('];\n') |
401 out.flush() | 401 out.flush() |
402 out.close() | 402 out.close() |
403 | 403 |
404 | 404 |
405 def MakeSourceMap(symbols): | 405 def MakeSourceMap(symbols): |
406 sources = {} | 406 sources = {} |
407 for _sym, _symbol_type, size, path in symbols: | 407 for _sym, _symbol_type, size, path, _address in symbols: |
408 key = None | 408 key = None |
409 if path: | 409 if path: |
410 key = os.path.normpath(path) | 410 key = os.path.normpath(path) |
411 else: | 411 else: |
412 key = '[no path]' | 412 key = '[no path]' |
413 if key not in sources: | 413 if key not in sources: |
414 sources[key] = {'path': path, 'symbol_count': 0, 'size': 0} | 414 sources[key] = {'path': path, 'symbol_count': 0, 'size': 0} |
415 record = sources[key] | 415 record = sources[key] |
416 record['size'] += size | 416 record['size'] += size |
417 record['symbol_count'] += 1 | 417 record['symbol_count'] += 1 |
(...skipping 19 matching lines...) Expand all Loading... |
437 return | 437 return |
438 finally: | 438 finally: |
439 out.write('];\n') | 439 out.write('];\n') |
440 out.flush() | 440 out.flush() |
441 out.close() | 441 out.close() |
442 | 442 |
443 | 443 |
444 # TODO(andrewhayden): Only used for legacy reports. Delete. | 444 # TODO(andrewhayden): Only used for legacy reports. Delete. |
445 def DumpLargestVTables(symbols, outfile, n): | 445 def DumpLargestVTables(symbols, outfile, n): |
446 vtables = [] | 446 vtables = [] |
447 for symbol, _type, size, path in symbols: | 447 for symbol, _type, size, path, _address in symbols: |
448 if 'vtable for ' in symbol: | 448 if 'vtable for ' in symbol: |
449 vtables.append({'symbol': symbol, 'path': path, 'size': size}) | 449 vtables.append({'symbol': symbol, 'path': path, 'size': size}) |
450 vtables = sorted(vtables, key=lambda x: -x['size']) | 450 vtables = sorted(vtables, key=lambda x: -x['size']) |
451 dumped = 0 | 451 dumped = 0 |
452 out = open(outfile, 'w') | 452 out = open(outfile, 'w') |
453 try: | 453 try: |
454 out.write('var largestVTables = [\n') | 454 out.write('var largestVTables = [\n') |
455 for record in vtables: | 455 for record in vtables: |
456 entry = {'size': FormatBytes(record['size']), | 456 entry = {'size': FormatBytes(record['size']), |
457 'symbol': record['symbol'], | 457 'symbol': record['symbol'], |
(...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
923 shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out) | 923 shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out) |
924 shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out) | 924 shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out) |
925 shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir) | 925 shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir) |
926 shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir) | 926 shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir) |
927 | 927 |
928 print 'Report saved to ' + opts.destdir + '/index.html' | 928 print 'Report saved to ' + opts.destdir + '/index.html' |
929 | 929 |
930 | 930 |
931 if __name__ == '__main__': | 931 if __name__ == '__main__': |
932 sys.exit(main()) | 932 sys.exit(main()) |
OLD | NEW |