Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(522)

Side by Side Diff: tools/win/sizeviewer/sizeviewer.py

Issue 801123002: Improve sizeviewer for Windows (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/win/sizeviewer/main.js ('k') | tools/win/sizeviewer/template.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import base64
6 import codecs
5 import json 7 import json
6 import os 8 import os
7 import string 9 import string
8 import subprocess 10 import subprocess
9 import sys 11 import sys
10 12
11 13
12 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 14 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
13 15
14 16
15 def Run(*args): 17 def Run(*args):
16 with open(os.devnull, 'w') as null: 18 with open(os.devnull, 'w') as null:
17 subprocess.check_call(args, stdout=null, stderr=null) 19 subprocess.check_call(args, stdout=null, stderr=null)
18 20
19 21
20 def FindNode(node, component): 22 def FindNode(node, component):
21 for child in node['children']: 23 for child in node['children']:
22 if child['name'] == component: 24 if child['name'] == component:
23 return child 25 return child
24 return None 26 return None
25 27
26 28
27 def InsertIntoTree(tree, source_name, size): 29 def InsertIntoTree(tree, source_name, size):
28 components = source_name.replace(':', '').split('\\') 30 components = source_name[3:].split('\\')
29 node = tree 31 node = tree
30 for index, component in enumerate(components): 32 for index, component in enumerate(components):
31 data = FindNode(node, component) 33 data = FindNode(node, component)
32 if not data: 34 if not data:
33 data = { 'name': component } 35 data = { 'name': source_name, 'name': component }
34 if index == len(components) - 1: 36 if index == len(components) - 1:
35 data['size'] = size 37 data['size'] = size
36 else: 38 else:
37 data['children'] = [] 39 data['children'] = []
38 node['children'].append(data) 40 node['children'].append(data)
39 node = data 41 node = data
40 42
41 43
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
58
59
60 def GetAsset(filename):
61 with open(os.path.join(BASE_DIR, filename), 'rb') as f:
62 return f.read()
63
64
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')
73
74
42 def main(): 75 def main():
43 out_dir = os.path.join(BASE_DIR, '..', '..', '..', 'out', 'Release') 76 out_dir = os.path.join(BASE_DIR, '..', '..', '..', 'out', 'Release')
44 jsons = [] 77 jsons = []
45 for dll in ('chrome.dll', 'chrome_child.dll'): 78 for dll in ('chrome.dll', 'chrome_child.dll'):
46 dll_path = os.path.normpath(os.path.join(out_dir, dll)) 79 dll_path = os.path.normpath(os.path.join(out_dir, dll))
47 if os.path.exists(dll_path): 80 if os.path.exists(dll_path):
48 print 'Tallying %s...' % dll_path 81 print 'Tallying %s...' % dll_path
49 json_path = dll_path + '.json' 82 json_path = dll_path + '.json'
50 Run(os.path.join(BASE_DIR, 'code_tally.exe'), 83 Run(os.path.join(BASE_DIR, 'code_tally.exe'),
51 '--input-image=' + dll_path, 84 '--input-image=' + dll_path,
52 '--input-pdb=' + dll_path + '.pdb', 85 '--input-pdb=' + dll_path + '.pdb',
53 '--output-file=' + json_path) 86 '--output-file=' + json_path)
54 jsons.append(json_path) 87 jsons.append(json_path)
55 if not jsons: 88 if not jsons:
56 print 'Couldn\'t find binaries, looking in', out_dir 89 print 'Couldn\'t find binaries, looking in', out_dir
57 return 1 90 return 1
58 91
92 # Munge the code_tally json format into an easier-to-view format.
59 for json_name in jsons: 93 for json_name in jsons:
60 with open(json_name, 'r') as jsonf: 94 with open(json_name, 'r') as jsonf:
61 all_data = json.load(jsonf) 95 all_data = json.load(jsonf)
62 html_path = os.path.splitext(json_name)[0] + '.html' 96 html_path = os.path.splitext(json_name)[0] + '.html'
63 print 'Generating %s...' % html_path 97 print 'Generating %s... (standlone)' % html_path
64 by_source = {} 98 by_source = {}
99 symbols_index = {}
100 symbols = []
65 for obj_name, obj_data in all_data['objects'].iteritems(): 101 for obj_name, obj_data in all_data['objects'].iteritems():
66 for symbol, symbol_data in obj_data.iteritems(): 102 for symbol, symbol_data in obj_data.iteritems():
67 size = int(symbol_data['size']) 103 size = int(symbol_data['size'])
68 # Sometimes there's symbols with no source file, we just ignore those. 104 # Sometimes there's symbols with no source file, we just ignore those.
69 if 'contribs' in symbol_data: 105 if 'contribs' in symbol_data:
70 # There may be more than one file in the list, we just assign to the 106 i = 0
71 # first source file that contains the symbol, rather than try to 107 while i < len(symbol_data['contribs']):
72 # split or duplicate info. 108 src_index = symbol_data['contribs'][i]
73 src_index = symbol_data['contribs'][0] 109 i += 1
74 source = all_data['sources'][int(src_index)] 110 per_line = symbol_data['contribs'][i]
75 if source not in by_source: 111 i += 1
76 by_source[source] = [] 112 source = all_data['sources'][int(src_index)]
77 by_source[source].append(size) 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
78 binary_name = all_data['executable']['name'] 132 binary_name = all_data['executable']['name']
79 data = {} 133 data = {}
80 data['name'] = binary_name 134 data['name'] = '/'
81 data['children'] = [] 135 data['children'] = []
82 for source, sizes in by_source.iteritems(): 136 file_contents = {}
83 InsertIntoTree(data, source, sum(sizes)) 137 line_data = {}
138 for source, file_data in by_source.iteritems():
139 InsertIntoTree(data, source, file_data['total_size'])
140
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.'
147
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])
153
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)
159
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.
84 with open(html_path, 'w') as f: 163 with open(html_path, 'w') as f:
85 with open(os.path.join(BASE_DIR, 'template.html'), 'r') as templatef: 164 f.write(to_write)
86 template = templatef.read() 165 # These aren't subbed in as a silly workaround for 32-bit python.
87 f.write(string.Template(template).substitute( 166 # The end result is only ~100M, but while substituting these into a
88 {'data': json.dumps(data, indent=2), 167 # template, it otherwise raises a MemoryError, I guess due to
89 'dllname': binary_name + ' ' + all_data['executable']['version']})) 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>')
90 185
91 return 0 186 return 0
92 187
93 188
94 if __name__ == '__main__': 189 if __name__ == '__main__':
95 sys.exit(main()) 190 sys.exit(main())
OLDNEW
« no previous file with comments | « tools/win/sizeviewer/main.js ('k') | tools/win/sizeviewer/template.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698