Workaround for xkbcommon dead keys.
[chromium-blink-merge.git] / tools / win / sizeviewer / sizeviewer.py
blob3e6d92d03a3956d84e934d382a52bb61f925a396
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 base64
6 import codecs
7 import json
8 import os
9 import string
10 import subprocess
11 import sys
14 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
17 def Run(*args):
18 with open(os.devnull, 'w') as null:
19 subprocess.check_call(args, stdout=null, stderr=null)
22 def FindNode(node, component):
23 for child in node['children']:
24 if child['name'] == component:
25 return child
26 return None
29 def InsertIntoTree(tree, source_name, size):
30 components = source_name[3:].split('\\')
31 node = tree
32 for index, component in enumerate(components):
33 data = FindNode(node, component)
34 if not data:
35 data = { 'name': source_name, 'name': component }
36 if index == len(components) - 1:
37 data['size'] = size
38 else:
39 data['children'] = []
40 node['children'].append(data)
41 node = data
44 def FlattenTree(tree):
45 result = [['Path', 'Parent', 'Size', 'Value']]
46 def Flatten(node, parent):
47 name = node['name']
48 if parent and parent != '/':
49 name = parent + '/' + name
50 if 'children' in node:
51 result.append([name, parent, -1, -1])
52 for c in node['children']:
53 Flatten(c, name)
54 else:
55 result.append([name, parent, node['size'], node['size']])
56 Flatten(tree, '')
57 return result
60 def GetAsset(filename):
61 with open(os.path.join(BASE_DIR, filename), 'rb') as f:
62 return f.read()
65 def AppendAsScriptBlock(f, value, var=None):
66 f.write('<script type="text/javascript">\n')
67 if var:
68 f.write('var ' + var + ' = ')
69 f.write(value)
70 if var:
71 f.write(';\n')
72 f.write('</script>\n')
75 def main():
76 out_dir = os.path.join(BASE_DIR, '..', '..', '..', 'out', 'Release')
77 jsons = []
78 for dll in ('chrome.dll', 'chrome_child.dll'):
79 dll_path = os.path.normpath(os.path.join(out_dir, dll))
80 if os.path.exists(dll_path):
81 print 'Tallying %s...' % dll_path
82 json_path = dll_path + '.json'
83 Run(os.path.join(BASE_DIR, 'code_tally.exe'),
84 '--input-image=' + dll_path,
85 '--input-pdb=' + dll_path + '.pdb',
86 '--output-file=' + json_path)
87 jsons.append(json_path)
88 if not jsons:
89 print 'Couldn\'t find binaries, looking in', out_dir
90 return 1
92 # Munge the code_tally json format into an easier-to-view format.
93 for json_name in jsons:
94 with open(json_name, 'r') as jsonf:
95 all_data = json.load(jsonf)
96 html_path = os.path.splitext(json_name)[0] + '.html'
97 print 'Generating %s... (standlone)' % html_path
98 by_source = {}
99 symbols_index = {}
100 symbols = []
101 for obj_name, obj_data in all_data['objects'].iteritems():
102 for symbol, symbol_data in obj_data.iteritems():
103 size = int(symbol_data['size'])
104 # Sometimes there's symbols with no source file, we just ignore those.
105 if 'contribs' in symbol_data:
106 i = 0
107 while i < len(symbol_data['contribs']):
108 src_index = symbol_data['contribs'][i]
109 i += 1
110 per_line = symbol_data['contribs'][i]
111 i += 1
112 source = all_data['sources'][int(src_index)]
113 if source not in by_source:
114 by_source[source] = {'lines': {}, 'total_size': 0}
115 size = 0
116 # per_line is [line, size, line, size, line, size, ...]
117 for j in range(0, len(per_line), 2):
118 line_number = per_line[j]
119 size += per_line[j + 1]
120 # Save some time/space in JS by using an array here. 0 == size,
121 # 1 == symbol list.
122 by_source[source]['lines'].setdefault(line_number, [0, []])
123 by_source[source]['lines'][line_number][0] += per_line[j + 1]
124 if symbol in symbols_index:
125 symindex = symbols_index[symbol]
126 else:
127 symbols.append(symbol)
128 symbols_index[symbol] = symindex = len(symbols) - 1
129 by_source[source]['lines'][line_number][1].append(
130 symindex)
131 by_source[source]['total_size'] += size
132 binary_name = all_data['executable']['name']
133 data = {}
134 data['name'] = '/'
135 data['children'] = []
136 file_contents = {}
137 line_data = {}
138 for source, file_data in by_source.iteritems():
139 InsertIntoTree(data, source, file_data['total_size'])
141 store_as = source[3:].replace('\\', '/')
142 try:
143 with codecs.open(source, 'rb', encoding='latin1') as f:
144 file_contents[store_as] = f.read()
145 except IOError:
146 file_contents[store_as] = '// Unable to load source.'
148 line_data[store_as] = file_data['lines']
149 # code_tally attempts to assign fractional bytes when code is shared
150 # across multiple symbols. Round off here for display after summing above.
151 for per_line in line_data[store_as].values():
152 per_line[0] = round(per_line[0])
154 flattened = FlattenTree(data)
155 maxval = 0
156 for i in flattened[1:]:
157 maxval = max(i[2], maxval)
158 flattened_str = json.dumps(flattened)
160 to_write = GetAsset('template.html')
161 # Save all data and what would normally be external resources into the
162 # one html so that it's a standalone report.
163 with open(html_path, 'w') as f:
164 f.write(to_write)
165 # These aren't subbed in as a silly workaround for 32-bit python.
166 # The end result is only ~100M, but while substituting these into a
167 # template, it otherwise raises a MemoryError, I guess due to
168 # fragmentation. So instead, we just append them as variables to the file
169 # and then refer to the variables in the main script.
170 filedata_str = json.dumps(file_contents).replace(
171 '</script>', '</scr"+"ipt>')
172 AppendAsScriptBlock(f, filedata_str, var='g_file_contents')
173 AppendAsScriptBlock(f, json.dumps(line_data), var='g_line_data')
174 AppendAsScriptBlock(f, json.dumps(symbols), var='g_symbol_list')
175 favicon_str = json.dumps(base64.b64encode(GetAsset('favicon.png')))
176 AppendAsScriptBlock(f, favicon_str, var='g_favicon')
177 AppendAsScriptBlock(f, flattened_str, var='g_raw_data')
178 AppendAsScriptBlock(f, str(maxval), var='g_maxval')
179 dllname_str = binary_name + ' ' + all_data['executable']['version']
180 AppendAsScriptBlock(f, json.dumps(dllname_str), var='g_dllname')
181 AppendAsScriptBlock(f, GetAsset('codemirror.js'))
182 AppendAsScriptBlock(f, GetAsset('clike.js'))
183 AppendAsScriptBlock(f, GetAsset('main.js'))
184 f.write('</html>')
186 return 0
189 if __name__ == '__main__':
190 sys.exit(main())