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 p
= subprocess
.Popen(args
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.STDOUT
)
19 out
, err
= p
.communicate()
24 def FindNode(node
, component
):
25 for child
in node
['children']:
26 if child
['name'] == component
:
31 def InsertIntoTree(tree
, source_name
, size
):
32 components
= source_name
[3:].split('\\')
34 for index
, component
in enumerate(components
):
35 data
= FindNode(node
, component
)
37 data
= { 'name': source_name
, 'name': component
}
38 if index
== len(components
) - 1:
42 node
['children'].append(data
)
46 def FlattenTree(tree
):
47 result
= [['Path', 'Parent', 'Size', 'Value']]
48 def Flatten(node
, parent
):
50 if parent
and parent
!= '/':
51 name
= parent
+ '/' + name
52 if 'children' in node
:
53 result
.append([name
, parent
, -1, -1])
54 for c
in node
['children']:
57 result
.append([name
, parent
, node
['size'], node
['size']])
62 def GetAsset(filename
):
63 with
open(os
.path
.join(BASE_DIR
, filename
), 'rb') as f
:
67 def AppendAsScriptBlock(f
, value
, var
=None):
68 f
.write('<script type="text/javascript">\n')
70 f
.write('var ' + var
+ ' = ')
74 f
.write('</script>\n')
82 out_dir
= os
.path
.join(BASE_DIR
, '..', '..', '..', 'out', 'Release')
83 dlls
= [os
.path
.normpath(os
.path
.join(out_dir
, dll
))
84 for dll
in ('chrome.dll', 'chrome_child.dll')]
86 if os
.path
.exists(dll_path
):
87 print 'Tallying %s...' % dll_path
88 json_path
= dll_path
+ '.json'
89 Run(os
.path
.join(BASE_DIR
, '..', '..', '..', 'third_party', 'syzygy',
90 'binaries', 'exe', 'experimental', 'code_tally.exe'),
91 '--input-image=' + dll_path
,
92 '--input-pdb=' + dll_path
+ '.pdb',
93 '--output-file=' + json_path
)
94 jsons
.append(json_path
)
96 print 'Couldn\'t find dlls.'
97 print 'Pass fully qualified dll name(s) if you want to use something other '
98 print 'than out\\Release\\chrome.dll and chrome_child.dll.'
101 # Munge the code_tally json format into an easier-to-view format.
102 for json_name
in jsons
:
103 with
open(json_name
, 'r') as jsonf
:
104 all_data
= json
.load(jsonf
)
105 html_path
= os
.path
.splitext(json_name
)[0] + '.html'
106 print 'Generating %s... (standlone)' % html_path
110 for obj_name
, obj_data
in all_data
['objects'].iteritems():
111 for symbol
, symbol_data
in obj_data
.iteritems():
112 size
= int(symbol_data
['size'])
113 # Sometimes there's symbols with no source file, we just ignore those.
114 if 'contribs' in symbol_data
:
116 while i
< len(symbol_data
['contribs']):
117 src_index
= symbol_data
['contribs'][i
]
119 per_line
= symbol_data
['contribs'][i
]
121 source
= all_data
['sources'][int(src_index
)]
122 if source
not in by_source
:
123 by_source
[source
] = {'lines': {}, 'total_size': 0}
125 # per_line is [line, size, line, size, line, size, ...]
126 for j
in range(0, len(per_line
), 2):
127 line_number
= per_line
[j
]
128 size
+= per_line
[j
+ 1]
129 # Save some time/space in JS by using an array here. 0 == size,
131 by_source
[source
]['lines'].setdefault(line_number
, [0, []])
132 by_source
[source
]['lines'][line_number
][0] += per_line
[j
+ 1]
133 if symbol
in symbols_index
:
134 symindex
= symbols_index
[symbol
]
136 symbols
.append(symbol
)
137 symbols_index
[symbol
] = symindex
= len(symbols
) - 1
138 by_source
[source
]['lines'][line_number
][1].append(
140 by_source
[source
]['total_size'] += size
141 binary_name
= all_data
['executable']['name']
144 data
['children'] = []
147 for source
, file_data
in by_source
.iteritems():
148 InsertIntoTree(data
, source
, file_data
['total_size'])
150 store_as
= source
[3:].replace('\\', '/')
152 with codecs
.open(source
, 'rb', encoding
='latin1') as f
:
153 file_contents
[store_as
] = f
.read()
155 file_contents
[store_as
] = '// Unable to load source.'
157 line_data
[store_as
] = file_data
['lines']
158 # code_tally attempts to assign fractional bytes when code is shared
159 # across multiple symbols. Round off here for display after summing above.
160 for per_line
in line_data
[store_as
].values():
161 per_line
[0] = round(per_line
[0])
163 flattened
= FlattenTree(data
)
165 for i
in flattened
[1:]:
166 maxval
= max(i
[2], maxval
)
167 flattened_str
= json
.dumps(flattened
)
169 to_write
= GetAsset('template.html')
170 # Save all data and what would normally be external resources into the
171 # one html so that it's a standalone report.
172 with
open(html_path
, 'w') as f
:
174 # These aren't subbed in as a silly workaround for 32-bit python.
175 # The end result is only ~100M, but while substituting these into a
176 # template, it otherwise raises a MemoryError, I guess due to
177 # fragmentation. So instead, we just append them as variables to the file
178 # and then refer to the variables in the main script.
179 filedata_str
= json
.dumps(file_contents
).replace(
180 '</script>', '</scr"+"ipt>')
181 AppendAsScriptBlock(f
, filedata_str
, var
='g_file_contents')
182 AppendAsScriptBlock(f
, json
.dumps(line_data
), var
='g_line_data')
183 AppendAsScriptBlock(f
, json
.dumps(symbols
), var
='g_symbol_list')
184 favicon_str
= json
.dumps(base64
.b64encode(GetAsset('favicon.png')))
185 AppendAsScriptBlock(f
, favicon_str
, var
='g_favicon')
186 AppendAsScriptBlock(f
, flattened_str
, var
='g_raw_data')
187 AppendAsScriptBlock(f
, str(maxval
), var
='g_maxval')
188 dllname_str
= binary_name
+ ' ' + all_data
['executable']['version']
189 AppendAsScriptBlock(f
, json
.dumps(dllname_str
), var
='g_dllname')
190 AppendAsScriptBlock(f
, GetAsset('codemirror.js'))
191 AppendAsScriptBlock(f
, GetAsset('clike.js'))
192 AppendAsScriptBlock(f
, GetAsset('main.js'))
198 if __name__
== '__main__':