[Cronet] Delay StartNetLog and StopNetLog until native request context is initialized
[chromium-blink-merge.git] / tools / win / sizeviewer / sizeviewer.py
blob95078f1ac706a7e494c4d795fd6195e55c8126ec
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, '..', '..', '..', 'third_party', 'syzygy',
84 'binaries', 'exe', 'experimental', 'code_tally.exe'),
85 '--input-image=' + dll_path,
86 '--input-pdb=' + dll_path + '.pdb',
87 '--output-file=' + json_path)
88 jsons.append(json_path)
89 if not jsons:
90 print 'Couldn\'t find binaries, looking in', out_dir
91 return 1
93 # Munge the code_tally json format into an easier-to-view format.
94 for json_name in jsons:
95 with open(json_name, 'r') as jsonf:
96 all_data = json.load(jsonf)
97 html_path = os.path.splitext(json_name)[0] + '.html'
98 print 'Generating %s... (standlone)' % html_path
99 by_source = {}
100 symbols_index = {}
101 symbols = []
102 for obj_name, obj_data in all_data['objects'].iteritems():
103 for symbol, symbol_data in obj_data.iteritems():
104 size = int(symbol_data['size'])
105 # Sometimes there's symbols with no source file, we just ignore those.
106 if 'contribs' in symbol_data:
107 i = 0
108 while i < len(symbol_data['contribs']):
109 src_index = symbol_data['contribs'][i]
110 i += 1
111 per_line = symbol_data['contribs'][i]
112 i += 1
113 source = all_data['sources'][int(src_index)]
114 if source not in by_source:
115 by_source[source] = {'lines': {}, 'total_size': 0}
116 size = 0
117 # per_line is [line, size, line, size, line, size, ...]
118 for j in range(0, len(per_line), 2):
119 line_number = per_line[j]
120 size += per_line[j + 1]
121 # Save some time/space in JS by using an array here. 0 == size,
122 # 1 == symbol list.
123 by_source[source]['lines'].setdefault(line_number, [0, []])
124 by_source[source]['lines'][line_number][0] += per_line[j + 1]
125 if symbol in symbols_index:
126 symindex = symbols_index[symbol]
127 else:
128 symbols.append(symbol)
129 symbols_index[symbol] = symindex = len(symbols) - 1
130 by_source[source]['lines'][line_number][1].append(
131 symindex)
132 by_source[source]['total_size'] += size
133 binary_name = all_data['executable']['name']
134 data = {}
135 data['name'] = '/'
136 data['children'] = []
137 file_contents = {}
138 line_data = {}
139 for source, file_data in by_source.iteritems():
140 InsertIntoTree(data, source, file_data['total_size'])
142 store_as = source[3:].replace('\\', '/')
143 try:
144 with codecs.open(source, 'rb', encoding='latin1') as f:
145 file_contents[store_as] = f.read()
146 except IOError:
147 file_contents[store_as] = '// Unable to load source.'
149 line_data[store_as] = file_data['lines']
150 # code_tally attempts to assign fractional bytes when code is shared
151 # across multiple symbols. Round off here for display after summing above.
152 for per_line in line_data[store_as].values():
153 per_line[0] = round(per_line[0])
155 flattened = FlattenTree(data)
156 maxval = 0
157 for i in flattened[1:]:
158 maxval = max(i[2], maxval)
159 flattened_str = json.dumps(flattened)
161 to_write = GetAsset('template.html')
162 # Save all data and what would normally be external resources into the
163 # one html so that it's a standalone report.
164 with open(html_path, 'w') as f:
165 f.write(to_write)
166 # These aren't subbed in as a silly workaround for 32-bit python.
167 # The end result is only ~100M, but while substituting these into a
168 # template, it otherwise raises a MemoryError, I guess due to
169 # fragmentation. So instead, we just append them as variables to the file
170 # and then refer to the variables in the main script.
171 filedata_str = json.dumps(file_contents).replace(
172 '</script>', '</scr"+"ipt>')
173 AppendAsScriptBlock(f, filedata_str, var='g_file_contents')
174 AppendAsScriptBlock(f, json.dumps(line_data), var='g_line_data')
175 AppendAsScriptBlock(f, json.dumps(symbols), var='g_symbol_list')
176 favicon_str = json.dumps(base64.b64encode(GetAsset('favicon.png')))
177 AppendAsScriptBlock(f, favicon_str, var='g_favicon')
178 AppendAsScriptBlock(f, flattened_str, var='g_raw_data')
179 AppendAsScriptBlock(f, str(maxval), var='g_maxval')
180 dllname_str = binary_name + ' ' + all_data['executable']['version']
181 AppendAsScriptBlock(f, json.dumps(dllname_str), var='g_dllname')
182 AppendAsScriptBlock(f, GetAsset('codemirror.js'))
183 AppendAsScriptBlock(f, GetAsset('clike.js'))
184 AppendAsScriptBlock(f, GetAsset('main.js'))
185 f.write('</html>')
187 return 0
190 if __name__ == '__main__':
191 sys.exit(main())