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

Side by Side Diff: tools/binary_size/file_format.py

Issue 2775173005: FREEZE.unindexed (Closed)
Patch Set: ps2 Created 3 years, 8 months 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/binary_size/describe.py ('k') | tools/binary_size/integration_test.py » ('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 2017 The Chromium Authors. All rights reserved. 1 # Copyright 2017 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 """Deals with loading & saving .size files.""" 5 """Deals with loading & saving .size files."""
6 6
7 import ast 7 import collections
8 import gzip 8 import gzip
9 import models 9 import models
10 import logging
11 import os
10 12
11 13
12 # File format version for .size files. 14 # File format version for .size files.
13 _SERIALIZATION_VERSION = 1 15 _SERIALIZATION_VERSION = 'Size File Format v1'
14 16
15 17
16 def EndsWithMaybeGz(path, suffix): 18 def _LogSize(file_obj, desc):
17 return path.endswith(suffix) or path.endswith(suffix + '.gz') 19 if not logging.getLogger().isEnabledFor(logging.DEBUG):
20 return
21 file_obj.flush()
22 size = os.fstat(file_obj.fileno()).st_size
23 logging.debug('File size with %s: %d' % (desc, size))
18 24
19 25
20 def OpenMaybeGz(path, mode=None): 26 def _SaveSizeInfoToFile(size_info, file_obj):
21 """Calls `gzip.open()` if |path| ends in ".gz", otherwise calls `open()`.""" 27 file_obj.write('%s\n' % _SERIALIZATION_VERSION)
22 if path.endswith('.gz'): 28 file_obj.write('# Created by //tools/binary_size\n')
23 if mode and 'w' in mode: 29 file_obj.write('%s\n' % '\t'.join(size_info.section_sizes))
24 return gzip.GzipFile(path, mode, 1) 30 file_obj.write('%s\n' % '\t'.join(
25 return gzip.open(path, mode) 31 str(v) for v in size_info.section_sizes.itervalues()))
26 return open(path, mode or 'r') 32 _LogSize(file_obj, 'header') # For libchrome: 450 bytes.
33
34 # Store a single copy of all paths and have them referenced by index.
35 # Using an OrderedDict makes the indices more repetitive (better compression).
36 path_tuples = collections.OrderedDict.fromkeys(
37 (s.object_path, s.source_path) for s in size_info.symbols)
38 for i, key in enumerate(path_tuples):
39 path_tuples[key] = i
40 file_obj.write('%d\n' % len(path_tuples))
41 file_obj.writelines('%s\t%s\n' % pair for pair in path_tuples)
42 _LogSize(file_obj, 'paths') # For libchrome, adds 200kb.
43
44 # Symbol counts by section.
45 by_section = size_info.symbols.GroupBySectionName().SortedByName()
46 file_obj.write('%s\n' % '\t'.join(g.name for g in by_section))
47 file_obj.write('%s\n' % '\t'.join(str(len(g)) for g in by_section))
48
49 def write_numeric(func, delta=False):
50 for group in by_section:
51 prev_value = 0
52 last_sym = group[-1]
53 for symbol in group:
54 value = func(symbol)
55 if delta:
56 value, prev_value = value - prev_value, value
57 file_obj.write(str(value))
58 if symbol is not last_sym:
59 file_obj.write(' ')
60 file_obj.write('\n')
61
62 write_numeric(lambda s: s.address, delta=True)
63 _LogSize(file_obj, 'addresses') # For libchrome, adds 300kb.
64 # Do not write padding, it will be recalcualted from addresses on load.
65 write_numeric(lambda s: s.size_without_padding)
66 _LogSize(file_obj, 'sizes') # For libchrome, adds 300kb
67 write_numeric(lambda s: path_tuples[(s.object_path, s.source_path)],
68 delta=True)
69 _LogSize(file_obj, 'path indices') # For libchrome: adds 125kb.
70
71 for group in by_section:
72 for symbol in group:
73 # Do not write name when full_name exists. It will be derived on load.
74 file_obj.write(symbol.full_name or symbol.name)
75 if symbol.is_anonymous:
76 file_obj.write('\t1')
77 file_obj.write('\n')
78 _LogSize(file_obj, 'names (final)') # For libchrome: adds 3.5mb.
27 79
28 80
29 def _SaveSizeInfoToFile(result, file_obj): 81 def _LoadSizeInfoFromFile(lines):
30 """Saves the result to the given file object.""" 82 """Loads a size_info from the given file."""
31 # Store one bucket per line. 83 actual_version = next(lines)[:-1]
32 file_obj.write('%d\n' % _SERIALIZATION_VERSION) 84 assert actual_version == _SERIALIZATION_VERSION, (
33 file_obj.write('%r\n' % result.section_sizes) 85 'Version mismatch. Need to write some upgrade code.')
34 file_obj.write('%d\n' % len(result.symbols)) 86 # Comment line.
35 prev_section_name = None 87 next(lines)
36 # Store symbol fields as tab-separated. 88 section_names = next(lines)[:-1].split('\t')
37 # Store only non-derived fields. 89 section_values = next(lines)[:-1].split('\t')
38 for symbol in result.symbols: 90 section_sizes = {k: int(v) for k, v in zip(section_names, section_values)}
39 if symbol.section_name != prev_section_name: 91
40 file_obj.write('%s\n' % symbol.section_name) 92 num_path_tuples = int(next(lines))
41 prev_section_name = symbol.section_name 93 path_tuples = [None] * num_path_tuples
42 # Don't write padding nor name since these are derived values. 94 for i in xrange(num_path_tuples):
43 file_obj.write('%x\t%x\t%s\t%s\n' % ( 95 path_tuples[i] = next(lines)[:-1].split('\t')
44 symbol.address, symbol.size_without_padding, 96
45 symbol.function_signature or symbol.name, symbol.path)) 97 section_names = next(lines)[:-1].split('\t')
98 section_counts = [int(c) for c in next(lines)[:-1].split('\t')]
99
100 def read_numeric(delta=False):
101 ret = []
102 delta_multiplier = int(delta)
103 for _ in section_counts:
104 value = 0
105 fields = next(lines).split(' ')
106 for i, f in enumerate(fields):
107 value = value * delta_multiplier + int(f)
108 fields[i] = value
109 ret.append(fields)
110 return ret
111
112 addresses = read_numeric(delta=True)
113 sizes = read_numeric(delta=False)
114 path_indices = read_numeric(delta=True)
115
116 symbol_list = [None] * sum(section_counts)
117 symbol_idx = 0
118 for section_index, cur_section_name in enumerate(section_names):
119 for i in xrange(section_counts[section_index]):
120 line = next(lines)[:-1]
121 is_anonymous = line.endswith('\t1')
122 name = line[:-2] if is_anonymous else line
123
124 new_sym = models.Symbol.__new__(models.Symbol)
125 new_sym.section_name = cur_section_name
126 new_sym.address = addresses[section_index][i]
127 new_sym.size = sizes[section_index][i]
128 new_sym.name = name
129 paths = path_tuples[path_indices[section_index][i]]
130 new_sym.object_path = paths[0]
131 new_sym.source_path = paths[1]
132 new_sym.is_anonymous = is_anonymous
133 new_sym.padding = 0 # Derived
134 new_sym.full_name = None # Derived
135 symbol_list[symbol_idx] = new_sym
136 symbol_idx += 1
137
138 symbols = models.SymbolGroup(symbol_list)
139 return models.SizeInfo(symbols, section_sizes)
46 140
47 141
48 def _LoadSizeInfoFromFile(file_obj): 142 def SaveSizeInfo(size_info, path):
49 """Loads a result from the given file.""" 143 """Saves |size_info| to |path}."""
50 lines = iter(file_obj) 144 with gzip.open(path, 'wb') as f:
51 actual_version = int(next(lines)) 145 _SaveSizeInfoToFile(size_info, f)
52 assert actual_version == _SERIALIZATION_VERSION, (
53 'Version mismatch. Need to write some upgrade code.')
54
55 section_sizes = ast.literal_eval(next(lines))
56 num_syms = int(next(lines))
57 symbol_list = [None] * num_syms
58 section_name = None
59 for i in xrange(num_syms):
60 line = next(lines)[:-1]
61 if '\t' not in line:
62 section_name = line
63 line = next(lines)[:-1]
64 new_sym = models.Symbol.__new__(models.Symbol)
65 parts = line.split('\t')
66 new_sym.section_name = section_name
67 new_sym.address = int(parts[0], 16)
68 new_sym.size = int(parts[1], 16)
69 new_sym.name = parts[2]
70 new_sym.path = parts[3]
71 new_sym.padding = 0 # Derived
72 new_sym.function_signature = None # Derived
73 symbol_list[i] = new_sym
74
75 return models.SizeInfo(models.SymbolGroup(symbol_list), section_sizes)
76
77
78 def SaveSizeInfo(result, path):
79 with OpenMaybeGz(path, 'wb') as f:
80 _SaveSizeInfoToFile(result, f)
81 146
82 147
83 def LoadSizeInfo(path): 148 def LoadSizeInfo(path):
84 with OpenMaybeGz(path) as f: 149 """Returns a SizeInfo loaded from |path|."""
85 return _LoadSizeInfoFromFile(f) 150 with gzip.open(path) as f:
151 return _LoadSizeInfoFromFile(iter(f))
OLDNEW
« no previous file with comments | « tools/binary_size/describe.py ('k') | tools/binary_size/integration_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698