Commit b1adcbd2 authored by scottmg's avatar scottmg Committed by Commit bot

binary_size: Remove legacy path, keep / as / for unittests on windows

Starting on a port to Windows. As the non-legacy path was added 8 months
ago, is it ok to remove the legacy one now?

R=bratell@opera.com, andrewhayden@chromium.org
BUG=441867

Review URL: https://codereview.chromium.org/797363002

Cr-Commit-Position: refs/heads/master@{#308395}
parent a055ad28
...@@ -66,6 +66,8 @@ def Compare(symbols1, symbols2): ...@@ -66,6 +66,8 @@ def Compare(symbols1, symbols2):
symbol_type = '@' # hack to categorize these separately symbol_type = '@' # hack to categorize these separately
if file_path: if file_path:
file_path = os.path.normpath(file_path) file_path = os.path.normpath(file_path)
if sys.platform.startswith('win'):
file_path = file_path.replace('\\', '/')
else: else:
file_path = '(No Path)' file_path = '(No Path)'
key = (file_path, symbol_type) key = (file_path, symbol_type)
......
<!DOCTYPE html>
<!--
Copyright 2014 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<html>
<head>
<title>Binary Size Analysis</title>
<link rel='stylesheet' href='webtreemap/webtreemap.css'>
<style>
body { font-family: sans-serif; }
tt, pre { font-family: WebKitWorkaround, monospace; }
#map {
margin: 0 auto;
position: relative;
cursor: pointer;
-webkit-user-select: none;
}
#table {
border: 1px solid black;
}
.treemaplegend {
margin: 0 auto;
position: relative;
}
.webtreemap-symbol-vtable {
background: #FFFFAA;
}
.webtreemap-node:hover {
border-color: red;
background: linear-gradient(rgb(240,240,200), rgb(180,180,200));
}
</style>
<script src='webtreemap/webtreemap.js'></script>
<script src='treemap-dump.js'></script>
<script src='largest-symbols.js'></script>
<script src='largest-sources.js'></script>
<script src='largest-vtables.js'></script>
</head>
<body onload='show_report_treemap()'>
<div style='text-align: center; margin-bottom: 2em;'>
<h1>Binary Size Analysis</h1>
<a href='#' onclick='show_report_treemap()'>Spatial Treemap</a>
~
<a href='#' onclick='show_report_largest_sources()'>Largest Sources</a>
~
<a href='#' onclick='show_report_largest_symbols()'>Largest Symbols</a>
~
<a href='#' onclick='show_report_largest_vtables()'>Largest VTables</a>
</div>
<div id='report'></div>
<script>
function escape(str) {
return str.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
var treemap_width = 800;
var treemap_height = 450;
function show_report_treemap() {
console.log('displaying treemap')
var div = document.getElementById('report');
var w = window.treemap_width;
var h = window.treemap_height;
div.innerHTML = '<div style=\'text-align: center;\'>' +
'<button onclick=\'zoomInTreemap()\'>Bigger (More Detail)</button>' +
', <button onclick=\'zoomOutTreemap()\'>Smaller (Less Detail)</button>' +
' or resize to: ' +
'<input type=text size=5 id=treemap_width value=' + w + '>x' +
'<input type=text size=5 id=treemap_height value=' + h + '>' +
'<button onclick=\'resizeTreemap()\'>Go</button>' +
'<br><em>Click on a box to zoom in and reveal more detail. ' +
'Click on the outermost box to zoom out.</em>' +
'<br>Legend: <table border=1 class=\'treemaplegend\' cellborder=1><tr>' +
'<td class=\'webtreemap-symbol-bss\'>BSS</td>' +
'<td class=\'webtreemap-symbol-data\'>Data</td>' +
'<td class=\'webtreemap-symbol-code\'>Code</td>' +
'<td class=\'webtreemap-symbol-read-only_data\'>RO Data</td>' +
'<td class=\'webtreemap-symbol-weak_symbol\'>Weak</td>' +
'<td class=\'webtreemap-symbol-vtable\'>VTable</td>' +
'</tr></table>' +
'<br>' +
'<div id=\'map\' ' +
'style=\'width: ' + w + 'px; height: ' + h + 'px;\'>' +
'</div></div>';
var map = document.getElementById('map');
appendTreemap(map, kTree);
}
function zoomInTreemap() {
window.treemap_width = Math.round(window.treemap_width * 1.25);
window.treemap_height = Math.round(window.treemap_height * 1.25);
show_report_treemap();
}
function zoomOutTreemap() {
window.treemap_width = Math.round(window.treemap_width / 1.25);
window.treemap_height = Math.round(window.treemap_height / 1.25);
show_report_treemap();
}
function resizeTreemap() {
window.treemap_width = document.getElementById('treemap_width').value;
window.treemap_height = document.getElementById('treemap_height').value;
show_report_treemap();
}
function show_report_largest_symbols() {
console.log('displaying largest-symbols report')
var div = document.getElementById('report');
div.innerHTML = '<div><table id=\'list\' border=1><tr>' +
'<th>Rank</th><th>Size</th><th>Type</th><th>Source</th>' +
'</tr></table>';
var list = document.getElementById('list');
for (var i = 0; i < largestSymbols.length; i++) {
var record = largestSymbols[i];
var link;
if (record.location.indexOf('out') == 0) {
link = record.location;
} else {
link = '<a href="https://code.google.com/p/chromium/codesearch#chromium/src/'
+ record.location + '">' + escape(record.location) + '</a>';
}
list.innerHTML += '<tr>'
+ '<td>' + (i+1) + '</td>'
+ '<td>' + escape(record.size) + '</td>'
+ '<td style=\'white-space: nowrap;\'>' + escape(record.type) + '</td>'
+ '<td>' + link + ':<br>'
+ escape(record.symbol) + '</td>'
+ '</tr>';
}
}
function show_report_largest_sources() {
console.log('displaying largest-sources report')
var div = document.getElementById('report');
div.innerHTML = '<div><table id=\'list\' border=1><tr>' +
'<th>Rank</th><th>Size</th><th>Symbol Count</th><th>Source</th>' +
'</tr></table>';
var list = document.getElementById('list');
for (var i = 0; i < largestSources.length; i++) {
var record = largestSources[i];
var link;
if (record.location.indexOf('out') == 0) {
link = record.location;
} else {
link = '<a href="https://code.google.com/p/chromium/codesearch#chromium/src/'
+ record.location + '">' + escape(record.location) + '</a>';
}
list.innerHTML += '<tr>'
+ '<td>' + (i+1) + '</td>'
+ '<td>' + escape(record.size) + '</td>'
+ '<td>' + escape(record.symbol_count) + '</td>'
+ '<td>' + link + '</td>'
+ '</tr>';
}
}
function show_report_largest_vtables() {
console.log('displaying largest-vtables report')
var div = document.getElementById('report');
div.innerHTML = '<div><table id=\'list\' border=1><tr>' +
'<th>Rank</th><th>Size</th><th>Symbol</th><th>Source</th>' +
'</tr></table>';
var list = document.getElementById('list');
for (var i = 0; i < largestVTables.length; i++) {
var record = largestVTables[i];
var link;
if (record.location.indexOf('out') == 0) {
link = record.location;
} else {
link = '<a href="https://code.google.com/p/chromium/codesearch#chromium/src/'
+ record.location + '">' + escape(record.location) + '</a>';
}
list.innerHTML += '<tr>'
+ '<td>' + (i+1) + '</td>'
+ '<td>' + escape(record.size) + '</td>'
+ '<td>' + escape(record.symbol) + '</td>'
+ '<td>' + link + '</td>'
+ '</tr>';
}
}
</script>
</body>
</html>
\ No newline at end of file
...@@ -26,7 +26,7 @@ import time ...@@ -26,7 +26,7 @@ import time
import binary_size_utils import binary_size_utils
# This path changee is not beautiful. Temporary (I hope) measure until # This path change is not beautiful. Temporary (I hope) measure until
# the chromium project has figured out a proper way to organize the # the chromium project has figured out a proper way to organize the
# library of python tools. http://crbug.com/375725 # library of python tools. http://crbug.com/375725
elf_symbolizer_path = os.path.abspath(os.path.join( elf_symbolizer_path = os.path.abspath(os.path.join(
...@@ -220,140 +220,6 @@ def MakeCompactTree(symbols, symbol_path_origin_dir): ...@@ -220,140 +220,6 @@ def MakeCompactTree(symbols, symbol_path_origin_dir):
return result return result
# TODO(andrewhayden): Only used for legacy reports. Delete.
def TreeifySymbols(symbols):
"""Convert symbols into a path-based tree, calculating size information
along the way.
The result is a dictionary that contains two kinds of nodes:
1. Leaf nodes, representing source code locations (e.g., c++ files)
These nodes have the following dictionary entries:
sizes: a dictionary whose keys are categories (such as code, data,
vtable, etceteras) and whose values are the size, in bytes, of
those categories;
size: the total size, in bytes, of all the entries in the sizes dict
2. Non-leaf nodes, representing directories
These nodes have the following dictionary entries:
children: a dictionary whose keys are names (path entries; either
directory or file names) and whose values are other nodes;
size: the total size, in bytes, of all the leaf nodes that are
contained within the children dict (recursively expanded)
The result object is itself a dictionary that represents the common ancestor
of all child nodes, e.g. a path to which all other nodes beneath it are
relative. The 'size' attribute of this dict yields the sum of the size of all
leaf nodes within the data structure.
"""
dirs = {'children': {}, 'size': 0}
for sym, symbol_type, size, path in symbols:
dirs['size'] += size
if path:
path = os.path.normpath(path)
if path.startswith('/'):
path = path[1:]
parts = None
if path:
parts = path.split('/')
if parts:
assert path
file_key = parts.pop()
tree = dirs
try:
# Traverse the tree to the parent of the file node, creating as needed
for part in parts:
assert part != ''
if part not in tree['children']:
tree['children'][part] = {'children': {}, 'size': 0}
tree = tree['children'][part]
tree['size'] += size
# Get (creating if necessary) the node for the file
# This node doesn't have a 'children' attribute
if file_key not in tree['children']:
tree['children'][file_key] = {'sizes': collections.defaultdict(int),
'size': 0}
tree = tree['children'][file_key]
tree['size'] += size
# Accumulate size into a bucket within the file
symbol_type = symbol_type.lower()
if 'vtable for ' in sym:
tree['sizes']['[vtable]'] += size
elif 'r' == symbol_type:
tree['sizes']['[rodata]'] += size
elif 'd' == symbol_type:
tree['sizes']['[data]'] += size
elif 'b' == symbol_type:
tree['sizes']['[bss]'] += size
elif 't' == symbol_type:
# 'text' in binary parlance means 'code'.
tree['sizes']['[code]'] += size
elif 'w' == symbol_type:
tree['sizes']['[weak]'] += size
else:
tree['sizes']['[other]'] += size
except:
print >> sys.stderr, sym, parts, file_key
raise
else:
key = 'symbols without paths'
if key not in dirs['children']:
dirs['children'][key] = {'sizes': collections.defaultdict(int),
'size': 0}
tree = dirs['children'][key]
subkey = 'misc'
if (sym.endswith('::__FUNCTION__') or
sym.endswith('::__PRETTY_FUNCTION__')):
subkey = '__FUNCTION__'
elif sym.startswith('CSWTCH.'):
subkey = 'CSWTCH'
elif '::' in sym:
subkey = sym[0:sym.find('::') + 2]
tree['sizes'][subkey] = tree['sizes'].get(subkey, 0) + size
tree['size'] += size
return dirs
# TODO(andrewhayden): Only used for legacy reports. Delete.
def JsonifyTree(tree, name):
"""Convert TreeifySymbols output to a JSON treemap.
The format is very similar, with the notable exceptions being
lists of children instead of maps and some different attribute names."""
children = []
css_class_map = {
'[vtable]': 'vtable',
'[rodata]': 'read-only_data',
'[data]': 'data',
'[bss]': 'bss',
'[code]': 'code',
'[weak]': 'weak_symbol'
}
if 'children' in tree:
# Non-leaf node. Recurse.
for child_name, child in tree['children'].iteritems():
children.append(JsonifyTree(child, child_name))
else:
# Leaf node; dump per-file stats as entries in the treemap
for kind, size in tree['sizes'].iteritems():
child_json = {'name': kind + ' (' + FormatBytes(size) + ')',
'data': { '$area': size }}
css_class = css_class_map.get(kind)
if css_class is not None:
child_json['data']['$symbol'] = css_class
children.append(child_json)
# Sort children by size, largest to smallest.
children.sort(key=lambda child: -child['data']['$area'])
# For leaf nodes, the 'size' attribute is the size of the leaf;
# Non-leaf nodes don't really have a size, but their 'size' attribute is
# the sum of the sizes of all their children.
return {'name': name + ' (' + FormatBytes(tree['size']) + ')',
'data': { '$area': tree['size'] },
'children': children }
def DumpCompactTree(symbols, symbol_path_origin_dir, outfile): def DumpCompactTree(symbols, symbol_path_origin_dir, outfile):
tree_root = MakeCompactTree(symbols, symbol_path_origin_dir) tree_root = MakeCompactTree(symbols, symbol_path_origin_dir)
with open(outfile, 'w') as out: with open(outfile, 'w') as out:
...@@ -363,45 +229,6 @@ def DumpCompactTree(symbols, symbol_path_origin_dir, outfile): ...@@ -363,45 +229,6 @@ def DumpCompactTree(symbols, symbol_path_origin_dir, outfile):
print('Writing %d bytes json' % os.path.getsize(outfile)) print('Writing %d bytes json' % os.path.getsize(outfile))
# TODO(andrewhayden): Only used for legacy reports. Delete.
def DumpTreemap(symbols, outfile):
dirs = TreeifySymbols(symbols)
out = open(outfile, 'w')
try:
out.write('var kTree = ' + json.dumps(JsonifyTree(dirs, '/')))
finally:
out.flush()
out.close()
# TODO(andrewhayden): Only used for legacy reports. Delete.
def DumpLargestSymbols(symbols, outfile, n):
# a list of (sym, symbol_type, size, path); sort by size.
symbols = sorted(symbols, key=lambda x: -x[2])
dumped = 0
out = open(outfile, 'w')
try:
out.write('var largestSymbols = [\n')
for sym, symbol_type, size, path in symbols:
if symbol_type in ('b', 'w'):
continue # skip bss and weak symbols
if path is None:
path = ''
entry = {'size': FormatBytes(size),
'symbol': sym,
'type': SymbolTypeToHuman(symbol_type),
'location': path }
out.write(json.dumps(entry))
out.write(',\n')
dumped += 1
if dumped >= n:
return
finally:
out.write('];\n')
out.flush()
out.close()
def MakeSourceMap(symbols): def MakeSourceMap(symbols):
sources = {} sources = {}
for _sym, _symbol_type, size, path in symbols: for _sym, _symbol_type, size, path in symbols:
...@@ -418,55 +245,6 @@ def MakeSourceMap(symbols): ...@@ -418,55 +245,6 @@ def MakeSourceMap(symbols):
return sources return sources
# TODO(andrewhayden): Only used for legacy reports. Delete.
def DumpLargestSources(symbols, outfile, n):
source_map = MakeSourceMap(symbols)
sources = sorted(source_map.values(), key=lambda x: -x['size'])
dumped = 0
out = open(outfile, 'w')
try:
out.write('var largestSources = [\n')
for record in sources:
entry = {'size': FormatBytes(record['size']),
'symbol_count': str(record['symbol_count']),
'location': record['path']}
out.write(json.dumps(entry))
out.write(',\n')
dumped += 1
if dumped >= n:
return
finally:
out.write('];\n')
out.flush()
out.close()
# TODO(andrewhayden): Only used for legacy reports. Delete.
def DumpLargestVTables(symbols, outfile, n):
vtables = []
for symbol, _type, size, path in symbols:
if 'vtable for ' in symbol:
vtables.append({'symbol': symbol, 'path': path, 'size': size})
vtables = sorted(vtables, key=lambda x: -x['size'])
dumped = 0
out = open(outfile, 'w')
try:
out.write('var largestVTables = [\n')
for record in vtables:
entry = {'size': FormatBytes(record['size']),
'symbol': record['symbol'],
'location': record['path']}
out.write(json.dumps(entry))
out.write(',\n')
dumped += 1
if dumped >= n:
return
finally:
out.write('];\n')
out.flush()
out.close()
# Regex for parsing "nm" output. A sample line looks like this: # Regex for parsing "nm" output. A sample line looks like this:
# 0167b39c 00000018 t ACCESS_DESCRIPTION_free /path/file.c:95 # 0167b39c 00000018 t ACCESS_DESCRIPTION_free /path/file.c:95
# #
...@@ -886,44 +664,26 @@ def main(): ...@@ -886,44 +664,26 @@ def main():
os.makedirs(opts.destdir, 0755) os.makedirs(opts.destdir, 0755)
if opts.legacy: # legacy report if opts.library:
DumpTreemap(symbols, os.path.join(opts.destdir, 'treemap-dump.js')) symbol_path_origin_dir = os.path.dirname(os.path.abspath(opts.library))
DumpLargestSymbols(symbols, else:
os.path.join(opts.destdir, 'largest-symbols.js'), 100) # Just a guess. Hopefully all paths in the input file are absolute.
DumpLargestSources(symbols, symbol_path_origin_dir = os.path.abspath(os.getcwd())
os.path.join(opts.destdir, 'largest-sources.js'), 100) data_js_file_name = os.path.join(opts.destdir, 'data.js')
DumpLargestVTables(symbols, DumpCompactTree(symbols, symbol_path_origin_dir, data_js_file_name)
os.path.join(opts.destdir, 'largest-vtables.js'), 100) d3_out = os.path.join(opts.destdir, 'd3')
treemap_out = os.path.join(opts.destdir, 'webtreemap') if not os.path.exists(d3_out):
if not os.path.exists(treemap_out): os.makedirs(d3_out, 0755)
os.makedirs(treemap_out, 0755) d3_src = os.path.join(os.path.dirname(__file__),
treemap_src = os.path.join('third_party', 'webtreemap', 'src') '..',
shutil.copy(os.path.join(treemap_src, 'COPYING'), treemap_out) '..',
shutil.copy(os.path.join(treemap_src, 'webtreemap.js'), treemap_out) 'third_party', 'd3', 'src')
shutil.copy(os.path.join(treemap_src, 'webtreemap.css'), treemap_out) template_src = os.path.join(os.path.dirname(__file__),
shutil.copy(os.path.join('tools', 'binary_size', 'legacy_template', 'template')
'index.html'), opts.destdir) shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out)
else: # modern report shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out)
if opts.library: shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir)
symbol_path_origin_dir = os.path.dirname(os.path.abspath(opts.library)) shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir)
else:
# Just a guess. Hopefully all paths in the input file are absolute.
symbol_path_origin_dir = os.path.abspath(os.getcwd())
data_js_file_name = os.path.join(opts.destdir, 'data.js')
DumpCompactTree(symbols, symbol_path_origin_dir, data_js_file_name)
d3_out = os.path.join(opts.destdir, 'd3')
if not os.path.exists(d3_out):
os.makedirs(d3_out, 0755)
d3_src = os.path.join(os.path.dirname(__file__),
'..',
'..',
'third_party', 'd3', 'src')
template_src = os.path.join(os.path.dirname(__file__),
'template')
shutil.copy(os.path.join(d3_src, 'LICENSE'), d3_out)
shutil.copy(os.path.join(d3_src, 'd3.js'), d3_out)
shutil.copy(os.path.join(template_src, 'index.html'), opts.destdir)
shutil.copy(os.path.join(template_src, 'D3SymbolTreeMap.js'), opts.destdir)
print 'Report saved to ' + opts.destdir + '/index.html' print 'Report saved to ' + opts.destdir + '/index.html'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment