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.
14 BASE_DIR
= os
.path
.dirname(os
.path
.abspath(__file__
))
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
:
29 def InsertIntoTree(tree
, source_name
, size
):
30 components
= source_name
[3:].split('\\')
32 for index
, component
in enumerate(components
):
33 data
= FindNode(node
, component
)
35 data
= { 'name': source_name
, 'name': component
}
36 if index
== len(components
) - 1:
40 node
['children'].append(data
)
44 def FlattenTree(tree
):
45 result
= [['Path', 'Parent', 'Size', 'Value']]
46 def Flatten(node
, parent
):
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']:
55 result
.append([name
, parent
, node
['size'], node
['size']])
60 def GetAsset(filename
):
61 with
open(os
.path
.join(BASE_DIR
, filename
), 'rb') as f
:
65 def AppendAsScriptBlock(f
, value
, var
=None):
66 f
.write('<script type="text/javascript">\n')
68 f
.write('var ' + var
+ ' = ')
72 f
.write('</script>\n')
76 out_dir
= os
.path
.join(BASE_DIR
, '..', '..', '..', 'out', 'Release')
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
)
90 print 'Couldn\'t find binaries, looking in', out_dir
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
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
:
108 while i
< len(symbol_data
['contribs']):
109 src_index
= symbol_data
['contribs'][i
]
111 per_line
= symbol_data
['contribs'][i
]
113 source
= all_data
['sources'][int(src_index
)]
114 if source
not in by_source
:
115 by_source
[source
] = {'lines': {}, 'total_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,
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
]
128 symbols
.append(symbol
)
129 symbols_index
[symbol
] = symindex
= len(symbols
) - 1
130 by_source
[source
]['lines'][line_number
][1].append(
132 by_source
[source
]['total_size'] += size
133 binary_name
= all_data
['executable']['name']
136 data
['children'] = []
139 for source
, file_data
in by_source
.iteritems():
140 InsertIntoTree(data
, source
, file_data
['total_size'])
142 store_as
= source
[3:].replace('\\', '/')
144 with codecs
.open(source
, 'rb', encoding
='latin1') as f
:
145 file_contents
[store_as
] = f
.read()
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
)
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
:
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'))
190 if __name__
== '__main__':