1558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch# Copyright 2013 The Chromium Authors. All rights reserved.
2558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch# Use of this source code is governed by a BSD-style license that can be
3558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch# found in the LICENSE file.
4558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
5558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochimport json
6558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochimport os
7558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochimport string
8558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochimport subprocess
9558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochimport sys
10558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
11558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
12558790d6acca3451cf3a6b497803a5f07d0bec58Ben MurdochBASE_DIR = os.path.dirname(os.path.abspath(__file__))
13558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
14558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
15558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochdef Run(*args):
16558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  with open(os.devnull, 'w') as null:
17558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    subprocess.check_call(args, stdout=null, stderr=null)
18558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
19558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
20558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochdef FindNode(node, component):
21558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  for child in node['children']:
22558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if child['name'] == component:
23558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      return child
24558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return None
25558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
26558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
27558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochdef InsertIntoTree(tree, source_name, size):
28558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  components = source_name.replace(':', '').split('\\')
29558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  node = tree
30558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  for index, component in enumerate(components):
31558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    data = FindNode(node, component)
32558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if not data:
33558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      data = { 'name': component }
34558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      if index == len(components) - 1:
35558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        data['size'] = size
36558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      else:
37558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        data['children'] = []
38558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      node['children'].append(data)
39558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    node = data
40558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
41558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
42558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochdef main():
43558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  out_dir = os.path.join(BASE_DIR, '..', '..', '..', 'out', 'Release')
44558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  jsons = []
45558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  for dll in ('chrome.dll', 'chrome_child.dll'):
46558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    dll_path = os.path.normpath(os.path.join(out_dir, dll))
47558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    if os.path.exists(dll_path):
48558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      print 'Tallying %s...' % dll_path
49558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      json_path = dll_path + '.json'
50558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      Run(os.path.join(BASE_DIR, 'code_tally.exe'),
51558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          '--input-image=' + dll_path,
52558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          '--input-pdb=' + dll_path + '.pdb',
53558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          '--output-file=' + json_path)
54558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      jsons.append(json_path)
55558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if not jsons:
56558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    print 'Couldn\'t find binaries, looking in', out_dir
57558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    return 1
58558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
59558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  for json_name in jsons:
60558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    with open(json_name, 'r') as jsonf:
61558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      all_data = json.load(jsonf)
62558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    html_path = os.path.splitext(json_name)[0] + '.html'
63558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    print 'Generating %s...' % html_path
64558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    by_source = {}
65558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    for obj_name, obj_data in all_data['objects'].iteritems():
66558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      for symbol, symbol_data in obj_data.iteritems():
67558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        size = int(symbol_data['size'])
68558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        # Sometimes there's symbols with no source file, we just ignore those.
69558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        if 'contribs' in symbol_data:
70558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          # There may be more than one file in the list, we just assign to the
71558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          # first source file that contains the symbol, rather than try to
72558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          # split or duplicate info.
73558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          src_index = symbol_data['contribs'][0]
74558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          source = all_data['sources'][int(src_index)]
75558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          if source not in by_source:
76558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch            by_source[source] = []
77558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          by_source[source].append(size)
78558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    binary_name = all_data['executable']['name']
79558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    data = {}
80558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    data['name'] = binary_name
81558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    data['children'] = []
82558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    for source, sizes in by_source.iteritems():
83558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      InsertIntoTree(data, source, sum(sizes))
84558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    with open(html_path, 'w') as f:
85558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      with open(os.path.join(BASE_DIR, 'template.html'), 'r') as templatef:
86558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch        template = templatef.read()
87558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch      f.write(string.Template(template).substitute(
88558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch          {'data': json.dumps(data, indent=2),
89558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch           'dllname': binary_name + ' ' + all_data['executable']['version']}))
90558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
91558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  return 0
92558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
93558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch
94558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochif __name__ == '__main__':
95558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  sys.exit(main())
96