| Index: tools/win/sizeviewer/sizeviewer.py
|
| diff --git a/tools/win/sizeviewer/sizeviewer.py b/tools/win/sizeviewer/sizeviewer.py
|
| index defb00a4b85a5d9cdb60eb2aaf116013eba119b5..3e6d92d03a3956d84e934d382a52bb61f925a396 100644
|
| --- a/tools/win/sizeviewer/sizeviewer.py
|
| +++ b/tools/win/sizeviewer/sizeviewer.py
|
| @@ -2,6 +2,8 @@
|
| # Use of this source code is governed by a BSD-style license that can be
|
| # found in the LICENSE file.
|
|
|
| +import base64
|
| +import codecs
|
| import json
|
| import os
|
| import string
|
| @@ -25,12 +27,12 @@ def FindNode(node, component):
|
|
|
|
|
| def InsertIntoTree(tree, source_name, size):
|
| - components = source_name.replace(':', '').split('\\')
|
| + components = source_name[3:].split('\\')
|
| node = tree
|
| for index, component in enumerate(components):
|
| data = FindNode(node, component)
|
| if not data:
|
| - data = { 'name': component }
|
| + data = { 'name': source_name, 'name': component }
|
| if index == len(components) - 1:
|
| data['size'] = size
|
| else:
|
| @@ -39,6 +41,37 @@ def InsertIntoTree(tree, source_name, size):
|
| node = data
|
|
|
|
|
| +def FlattenTree(tree):
|
| + result = [['Path', 'Parent', 'Size', 'Value']]
|
| + def Flatten(node, parent):
|
| + name = node['name']
|
| + if parent and parent != '/':
|
| + name = parent + '/' + name
|
| + if 'children' in node:
|
| + result.append([name, parent, -1, -1])
|
| + for c in node['children']:
|
| + Flatten(c, name)
|
| + else:
|
| + result.append([name, parent, node['size'], node['size']])
|
| + Flatten(tree, '')
|
| + return result
|
| +
|
| +
|
| +def GetAsset(filename):
|
| + with open(os.path.join(BASE_DIR, filename), 'rb') as f:
|
| + return f.read()
|
| +
|
| +
|
| +def AppendAsScriptBlock(f, value, var=None):
|
| + f.write('<script type="text/javascript">\n')
|
| + if var:
|
| + f.write('var ' + var + ' = ')
|
| + f.write(value)
|
| + if var:
|
| + f.write(';\n')
|
| + f.write('</script>\n')
|
| +
|
| +
|
| def main():
|
| out_dir = os.path.join(BASE_DIR, '..', '..', '..', 'out', 'Release')
|
| jsons = []
|
| @@ -56,37 +89,99 @@ def main():
|
| print 'Couldn\'t find binaries, looking in', out_dir
|
| return 1
|
|
|
| + # Munge the code_tally json format into an easier-to-view format.
|
| for json_name in jsons:
|
| with open(json_name, 'r') as jsonf:
|
| all_data = json.load(jsonf)
|
| html_path = os.path.splitext(json_name)[0] + '.html'
|
| - print 'Generating %s...' % html_path
|
| + print 'Generating %s... (standlone)' % html_path
|
| by_source = {}
|
| + symbols_index = {}
|
| + symbols = []
|
| for obj_name, obj_data in all_data['objects'].iteritems():
|
| for symbol, symbol_data in obj_data.iteritems():
|
| size = int(symbol_data['size'])
|
| # Sometimes there's symbols with no source file, we just ignore those.
|
| if 'contribs' in symbol_data:
|
| - # There may be more than one file in the list, we just assign to the
|
| - # first source file that contains the symbol, rather than try to
|
| - # split or duplicate info.
|
| - src_index = symbol_data['contribs'][0]
|
| - source = all_data['sources'][int(src_index)]
|
| - if source not in by_source:
|
| - by_source[source] = []
|
| - by_source[source].append(size)
|
| + i = 0
|
| + while i < len(symbol_data['contribs']):
|
| + src_index = symbol_data['contribs'][i]
|
| + i += 1
|
| + per_line = symbol_data['contribs'][i]
|
| + i += 1
|
| + source = all_data['sources'][int(src_index)]
|
| + if source not in by_source:
|
| + by_source[source] = {'lines': {}, 'total_size': 0}
|
| + size = 0
|
| + # per_line is [line, size, line, size, line, size, ...]
|
| + for j in range(0, len(per_line), 2):
|
| + line_number = per_line[j]
|
| + size += per_line[j + 1]
|
| + # Save some time/space in JS by using an array here. 0 == size,
|
| + # 1 == symbol list.
|
| + by_source[source]['lines'].setdefault(line_number, [0, []])
|
| + by_source[source]['lines'][line_number][0] += per_line[j + 1]
|
| + if symbol in symbols_index:
|
| + symindex = symbols_index[symbol]
|
| + else:
|
| + symbols.append(symbol)
|
| + symbols_index[symbol] = symindex = len(symbols) - 1
|
| + by_source[source]['lines'][line_number][1].append(
|
| + symindex)
|
| + by_source[source]['total_size'] += size
|
| binary_name = all_data['executable']['name']
|
| data = {}
|
| - data['name'] = binary_name
|
| + data['name'] = '/'
|
| data['children'] = []
|
| - for source, sizes in by_source.iteritems():
|
| - InsertIntoTree(data, source, sum(sizes))
|
| + file_contents = {}
|
| + line_data = {}
|
| + for source, file_data in by_source.iteritems():
|
| + InsertIntoTree(data, source, file_data['total_size'])
|
| +
|
| + store_as = source[3:].replace('\\', '/')
|
| + try:
|
| + with codecs.open(source, 'rb', encoding='latin1') as f:
|
| + file_contents[store_as] = f.read()
|
| + except IOError:
|
| + file_contents[store_as] = '// Unable to load source.'
|
| +
|
| + line_data[store_as] = file_data['lines']
|
| + # code_tally attempts to assign fractional bytes when code is shared
|
| + # across multiple symbols. Round off here for display after summing above.
|
| + for per_line in line_data[store_as].values():
|
| + per_line[0] = round(per_line[0])
|
| +
|
| + flattened = FlattenTree(data)
|
| + maxval = 0
|
| + for i in flattened[1:]:
|
| + maxval = max(i[2], maxval)
|
| + flattened_str = json.dumps(flattened)
|
| +
|
| + to_write = GetAsset('template.html')
|
| + # Save all data and what would normally be external resources into the
|
| + # one html so that it's a standalone report.
|
| with open(html_path, 'w') as f:
|
| - with open(os.path.join(BASE_DIR, 'template.html'), 'r') as templatef:
|
| - template = templatef.read()
|
| - f.write(string.Template(template).substitute(
|
| - {'data': json.dumps(data, indent=2),
|
| - 'dllname': binary_name + ' ' + all_data['executable']['version']}))
|
| + f.write(to_write)
|
| + # These aren't subbed in as a silly workaround for 32-bit python.
|
| + # The end result is only ~100M, but while substituting these into a
|
| + # template, it otherwise raises a MemoryError, I guess due to
|
| + # fragmentation. So instead, we just append them as variables to the file
|
| + # and then refer to the variables in the main script.
|
| + filedata_str = json.dumps(file_contents).replace(
|
| + '</script>', '</scr"+"ipt>')
|
| + AppendAsScriptBlock(f, filedata_str, var='g_file_contents')
|
| + AppendAsScriptBlock(f, json.dumps(line_data), var='g_line_data')
|
| + AppendAsScriptBlock(f, json.dumps(symbols), var='g_symbol_list')
|
| + favicon_str = json.dumps(base64.b64encode(GetAsset('favicon.png')))
|
| + AppendAsScriptBlock(f, favicon_str, var='g_favicon')
|
| + AppendAsScriptBlock(f, flattened_str, var='g_raw_data')
|
| + AppendAsScriptBlock(f, str(maxval), var='g_maxval')
|
| + dllname_str = binary_name + ' ' + all_data['executable']['version']
|
| + AppendAsScriptBlock(f, json.dumps(dllname_str), var='g_dllname')
|
| + AppendAsScriptBlock(f, GetAsset('codemirror.js'))
|
| + AppendAsScriptBlock(f, GetAsset('clike.js'))
|
| + AppendAsScriptBlock(f, GetAsset('main.js'))
|
| + f.write('</html>')
|
|
|
| return 0
|
|
|
|
|