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

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

Issue 397593007: Handle shared memory symbols better in the binarysize tool. (Closed)
Patch Set: Removed extra output in unittest. Created 5 years, 10 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
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2014 The Chromium Authors. All rights reserved. 2 # Copyright 2014 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Describe the size difference of two binaries. 6 """Describe the size difference of two binaries.
7 7
8 Generates a description of the size difference of two binaries based 8 Generates a description of the size difference of two binaries based
9 on the difference of the size of various symbols. 9 on the difference of the size of various symbols.
10 10
(...skipping 20 matching lines...) Expand all
31 --nm-out /tmp/nm2.dump 31 --nm-out /tmp/nm2.dump
32 32
33 # cleanup useless files 33 # cleanup useless files
34 rm -r /tmp/throwaway 34 rm -r /tmp/throwaway
35 35
36 # run this tool 36 # run this tool
37 explain_binary_size_delta.py --nm1 /tmp/nm1.dump --nm2 /tmp/nm2.dump 37 explain_binary_size_delta.py --nm1 /tmp/nm1.dump --nm2 /tmp/nm2.dump
38 """ 38 """
39 39
40 import collections 40 import collections
41 from collections import Counter
42 from math import ceil
41 import operator 43 import operator
42 import optparse 44 import optparse
43 import os 45 import os
44 import sys 46 import sys
45 47
46 import binary_size_utils 48 import binary_size_utils
47 49
48 50
51 def CalculateSharedAddresses(symbols):
52 """Checks how many symbols share the same memory space. This returns a
53 Counter result where result[address] will tell you how many times address was
54 used by symbols."""
55 count = Counter()
56 for _, _, _, _, address in symbols:
57 count[address] += 1
58
59 return count
60
61
62 def CalculateEffectiveSize(share_count, address, symbol_size):
63 """Given a raw symbol_size and an address, this method returns the
64 size we should blame on this symbol considering it might share the
65 machine code/data with other symbols. Using the raw symbol_size for
66 each symbol would in those cases over estimate the true cost of that
67 block.
68
69 """
70 shared_count = share_count[address]
71 if shared_count == 1:
72 return symbol_size
73
74 assert shared_count > 1
75 return int(ceil(symbol_size / float(shared_count)))
76
77 class SymbolDelta(object):
78 """Stores old size, new size and some metadata."""
79 def __init__(self, shared):
80 self.old_size = None
81 self.new_size = None
82 self.shares_space_with_other_symbols = shared
83
84 def __eq__(self, other):
85 return (self.old_size == other.old_size and
86 self.new_size == other.new_size and
87 self.shares_space_with_other_symbols ==
88 other.shares_space_with_other_symbols)
89
90 def __ne__(self, other):
91 return not self.__eq__(other)
92
93 def copy_symbol_delta(self):
94 symbol_delta = SymbolDelta(self.shares_space_with_other_symbols)
95 symbol_delta.old_size = self.old_size
96 symbol_delta.new_size = self.new_size
97 return symbol_delta
98
99 class DeltaInfo(SymbolDelta):
100 """Summary of a the change for one symbol between two instances."""
101 def __init__(self, file_path, symbol_type, symbol_name, shared):
102 SymbolDelta.__init__(self, shared)
103 self.file_path = file_path
104 self.symbol_type = symbol_type
105 self.symbol_name = symbol_name
106
107 def __eq__(self, other):
108 return (self.file_path == other.file_path and
109 self.symbol_type == other.symbol_type and
110 self.symbol_name == other.symbol_name and
111 SymbolDelta.__eq__(self, other))
112
113 def __ne__(self, other):
114 return not self.__eq__(other)
115
116 def ExtractSymbolDelta(self):
117 """Returns a copy of the SymbolDelta for this DeltaInfo."""
118 return SymbolDelta.copy_symbol_delta(self)
119
49 def Compare(symbols1, symbols2): 120 def Compare(symbols1, symbols2):
50 """Executes a comparison of the symbols in symbols1 and symbols2. 121 """Executes a comparison of the symbols in symbols1 and symbols2.
51 122
52 Returns: 123 Returns:
53 tuple of lists: (added_symbols, removed_symbols, changed_symbols, others) 124 tuple of lists: (added_symbols, removed_symbols, changed_symbols, others)
125 where each list contains DeltaInfo objects.
54 """ 126 """
55 added = [] # tuples 127 added = [] # tuples
56 removed = [] # tuples 128 removed = [] # tuples
57 changed = [] # tuples 129 changed = [] # tuples
58 unchanged = [] # tuples 130 unchanged = [] # tuples
59 131
60 cache1 = {} 132 cache1 = {}
61 cache2 = {} 133 cache2 = {}
62 # Make a map of (file, symbol_type) : (symbol_name, symbol_size) 134 # Make a map of (file, symbol_type) : (symbol_name, effective_symbol_size)
63 for cache, symbols in ((cache1, symbols1), (cache2, symbols2)): 135 share_count1 = CalculateSharedAddresses(symbols1)
64 for symbol_name, symbol_type, symbol_size, file_path in symbols: 136 share_count2 = CalculateSharedAddresses(symbols2)
137 for cache, symbols, share_count in ((cache1, symbols1, share_count1),
138 (cache2, symbols2, share_count2)):
139 for symbol_name, symbol_type, symbol_size, file_path, address in symbols:
65 if 'vtable for ' in symbol_name: 140 if 'vtable for ' in symbol_name:
66 symbol_type = '@' # hack to categorize these separately 141 symbol_type = '@' # hack to categorize these separately
67 if file_path: 142 if file_path:
68 file_path = os.path.normpath(file_path) 143 file_path = os.path.normpath(file_path)
69 if sys.platform.startswith('win'): 144 if sys.platform.startswith('win'):
70 file_path = file_path.replace('\\', '/') 145 file_path = file_path.replace('\\', '/')
71 else: 146 else:
72 file_path = '(No Path)' 147 file_path = '(No Path)'
148 # Take into consideration that multiple symbols might share the same
149 # block of code.
150 effective_symbol_size = CalculateEffectiveSize(share_count, address,
151 symbol_size)
73 key = (file_path, symbol_type) 152 key = (file_path, symbol_type)
74 bucket = cache.setdefault(key, {}) 153 bucket = cache.setdefault(key, {})
75 size_list = bucket.setdefault(symbol_name, []) 154 size_list = bucket.setdefault(symbol_name, [])
76 size_list.append(symbol_size) 155 size_list.append((effective_symbol_size,
156 effective_symbol_size != symbol_size))
77 157
78 # Now diff them. We iterate over the elements in cache1. For each symbol 158 # Now diff them. We iterate over the elements in cache1. For each symbol
79 # that we find in cache2, we record whether it was deleted, changed, or 159 # that we find in cache2, we record whether it was deleted, changed, or
80 # unchanged. We then remove it from cache2; all the symbols that remain 160 # unchanged. We then remove it from cache2; all the symbols that remain
81 # in cache2 at the end of the iteration over cache1 are the 'new' symbols. 161 # in cache2 at the end of the iteration over cache1 are the 'new' symbols.
82 for key, bucket1 in cache1.items(): 162 for key, bucket1 in cache1.items():
83 bucket2 = cache2.get(key) 163 bucket2 = cache2.get(key)
164 file_path, symbol_type = key;
84 if not bucket2: 165 if not bucket2:
85 # A file was removed. Everything in bucket1 is dead. 166 # A file was removed. Everything in bucket1 is dead.
86 for symbol_name, symbol_size_list in bucket1.items(): 167 for symbol_name, symbol_size_list in bucket1.items():
87 for symbol_size in symbol_size_list: 168 for (symbol_size, shared) in symbol_size_list:
88 removed.append((key[0], key[1], symbol_name, symbol_size, None)) 169 delta_info = DeltaInfo(file_path, symbol_type, symbol_name, shared)
170 delta_info.old_size = symbol_size
171 removed.append(delta_info)
89 else: 172 else:
90 # File still exists, look for changes within. 173 # File still exists, look for changes within.
91 for symbol_name, symbol_size_list in bucket1.items(): 174 for symbol_name, symbol_size_list in bucket1.items():
92 size_list2 = bucket2.get(symbol_name) 175 size_list2 = bucket2.get(symbol_name)
93 if size_list2 is None: 176 if size_list2 is None:
94 # Symbol no longer exists in bucket2. 177 # Symbol no longer exists in bucket2.
95 for symbol_size in symbol_size_list: 178 for (symbol_size, shared) in symbol_size_list:
96 removed.append((key[0], key[1], symbol_name, symbol_size, None)) 179 delta_info = DeltaInfo(file_path, symbol_type, symbol_name, shared)
180 delta_info.old_size = symbol_size
181 removed.append(delta_info)
97 else: 182 else:
98 del bucket2[symbol_name] # Symbol is not new, delete from cache2. 183 del bucket2[symbol_name] # Symbol is not new, delete from cache2.
99 if len(symbol_size_list) == 1 and len(size_list2) == 1: 184 if len(symbol_size_list) == 1 and len(size_list2) == 1:
100 symbol_size = symbol_size_list[0] 185 symbol_size, shared1 = symbol_size_list[0]
101 size2 = size_list2[0] 186 size2, shared2 = size_list2[0]
187 delta_info = DeltaInfo(file_path, symbol_type, symbol_name,
188 shared1 or shared2)
189 delta_info.old_size = symbol_size
190 delta_info.new_size = size2
102 if symbol_size != size2: 191 if symbol_size != size2:
103 # Symbol has change size in bucket. 192 # Symbol has change size in bucket.
104 changed.append((key[0], key[1], symbol_name, symbol_size, size2)) 193 changed.append(delta_info)
105 else: 194 else:
106 # Symbol is unchanged. 195 # Symbol is unchanged.
107 unchanged.append((key[0], key[1], symbol_name, symbol_size, 196 unchanged.append(delta_info)
108 size2))
109 else: 197 else:
110 # Complex comparison for when a symbol exists multiple times 198 # Complex comparison for when a symbol exists multiple times
111 # in the same file (where file can be "unknown file"). 199 # in the same file (where file can be "unknown file").
112 symbol_size_counter = collections.Counter(symbol_size_list) 200 symbol_size_counter = collections.Counter(symbol_size_list)
113 delta_counter = collections.Counter(symbol_size_list) 201 delta_counter = collections.Counter(symbol_size_list)
114 delta_counter.subtract(size_list2) 202 delta_counter.subtract(size_list2)
115 for symbol_size in sorted(delta_counter.keys()): 203 for delta_counter_key in sorted(delta_counter.keys()):
116 delta = delta_counter[symbol_size] 204 delta = delta_counter[delta_counter_key]
117 unchanged_count = symbol_size_counter[symbol_size] 205 unchanged_count = symbol_size_counter[delta_counter_key]
206 (symbol_size, shared) = delta_counter_key
118 if delta > 0: 207 if delta > 0:
119 unchanged_count -= delta 208 unchanged_count -= delta
120 for _ in range(unchanged_count): 209 for _ in range(unchanged_count):
121 unchanged.append((key[0], key[1], symbol_name, symbol_size, 210 delta_info = DeltaInfo(file_path, symbol_type,
122 symbol_size)) 211 symbol_name, shared)
212 delta_info.old_size = symbol_size
213 delta_info.new_size = symbol_size
214 unchanged.append(delta_info)
123 if delta > 0: # Used to be more of these than there is now. 215 if delta > 0: # Used to be more of these than there is now.
124 for _ in range(delta): 216 for _ in range(delta):
125 removed.append((key[0], key[1], symbol_name, symbol_size, 217 delta_info = DeltaInfo(file_path, symbol_type,
126 None)) 218 symbol_name, shared)
219 delta_info.old_size = symbol_size
220 removed.append(delta_info)
127 elif delta < 0: # More of this (symbol,size) now. 221 elif delta < 0: # More of this (symbol,size) now.
128 for _ in range(-delta): 222 for _ in range(-delta):
129 added.append((key[0], key[1], symbol_name, None, symbol_size)) 223 delta_info = DeltaInfo(file_path, symbol_type,
224 symbol_name, shared)
225 delta_info.new_size = symbol_size
226 added.append(delta_info)
130 227
131 if len(bucket2) == 0: 228 if len(bucket2) == 0:
132 del cache1[key] # Entire bucket is empty, delete from cache2 229 del cache1[key] # Entire bucket is empty, delete from cache2
133 230
134 # We have now analyzed all symbols that are in cache1 and removed all of 231 # We have now analyzed all symbols that are in cache1 and removed all of
135 # the encountered symbols from cache2. What's left in cache2 is the new 232 # the encountered symbols from cache2. What's left in cache2 is the new
136 # symbols. 233 # symbols.
137 for key, bucket2 in cache2.iteritems(): 234 for key, bucket2 in cache2.iteritems():
235 file_path, symbol_type = key;
138 for symbol_name, symbol_size_list in bucket2.items(): 236 for symbol_name, symbol_size_list in bucket2.items():
139 for symbol_size in symbol_size_list: 237 for (symbol_size, shared) in symbol_size_list:
140 added.append((key[0], key[1], symbol_name, None, symbol_size)) 238 delta_info = DeltaInfo(file_path, symbol_type, symbol_name, shared)
239 delta_info.new_size = symbol_size
240 added.append(delta_info)
141 return (added, removed, changed, unchanged) 241 return (added, removed, changed, unchanged)
142 242
243
143 def DeltaStr(number): 244 def DeltaStr(number):
144 """Returns the number as a string with a '+' prefix if it's > 0 and 245 """Returns the number as a string with a '+' prefix if it's > 0 and
145 a '-' prefix if it's < 0.""" 246 a '-' prefix if it's < 0."""
146 result = str(number) 247 result = str(number)
147 if number > 0: 248 if number > 0:
148 result = '+' + result 249 result = '+' + result
149 return result 250 return result
150 251
151 252
253 def SharedInfoStr(symbol_info):
254 """Returns a string (prefixed by space) explaining that numbers are
255 adjusted because of shared space between symbols, or an empty string
256 if space had not been shared."""
257
258 if symbol_info.shares_space_with_other_symbols:
259 return " (adjusted sizes because of memory sharing)"
260
261 return ""
262
152 class CrunchStatsData(object): 263 class CrunchStatsData(object):
153 """Stores a summary of data of a certain kind.""" 264 """Stores a summary of data of a certain kind."""
154 def __init__(self, symbols): 265 def __init__(self, symbols):
155 self.symbols = symbols 266 self.symbols = symbols
156 self.sources = set() 267 self.sources = set()
157 self.before_size = 0 268 self.before_size = 0
158 self.after_size = 0 269 self.after_size = 0
159 self.symbols_by_path = {} 270 self.symbols_by_path = {}
160 271
161 272
162 def CrunchStats(added, removed, changed, unchanged, showsources, showsymbols): 273 def CrunchStats(added, removed, changed, unchanged, showsources, showsymbols):
163 """Outputs to stdout a summary of changes based on the symbol lists.""" 274 """Outputs to stdout a summary of changes based on the symbol lists."""
164 # Split changed into grown and shrunk because that is easier to 275 # Split changed into grown and shrunk because that is easier to
165 # discuss. 276 # discuss.
166 grown = [] 277 grown = []
167 shrunk = [] 278 shrunk = []
168 for item in changed: 279 for item in changed:
169 file_path, symbol_type, symbol_name, size1, size2 = item 280 if item.old_size < item.new_size:
170 if size1 < size2:
171 grown.append(item) 281 grown.append(item)
172 else: 282 else:
173 shrunk.append(item) 283 shrunk.append(item)
174 284
175 new_symbols = CrunchStatsData(added) 285 new_symbols = CrunchStatsData(added)
176 removed_symbols = CrunchStatsData(removed) 286 removed_symbols = CrunchStatsData(removed)
177 grown_symbols = CrunchStatsData(grown) 287 grown_symbols = CrunchStatsData(grown)
178 shrunk_symbols = CrunchStatsData(shrunk) 288 shrunk_symbols = CrunchStatsData(shrunk)
179 sections = [new_symbols, removed_symbols, grown_symbols, shrunk_symbols] 289 sections = [new_symbols, removed_symbols, grown_symbols, shrunk_symbols]
180 for section in sections: 290 for section in sections:
181 for file_path, symbol_type, symbol_name, size1, size2 in section.symbols: 291 for item in section.symbols:
182 section.sources.add(file_path) 292 section.sources.add(item.file_path)
183 if size1 is not None: 293 if item.old_size is not None:
184 section.before_size += size1 294 section.before_size += item.old_size
185 if size2 is not None: 295 if item.new_size is not None:
186 section.after_size += size2 296 section.after_size += item.new_size
187 bucket = section.symbols_by_path.setdefault(file_path, []) 297 bucket = section.symbols_by_path.setdefault(item.file_path, [])
188 bucket.append((symbol_name, symbol_type, size1, size2)) 298 bucket.append((item.symbol_name, item.symbol_type,
299 item.ExtractSymbolDelta()))
189 300
190 total_change = sum(s.after_size - s.before_size for s in sections) 301 total_change = sum(s.after_size - s.before_size for s in sections)
191 summary = 'Total change: %s bytes' % DeltaStr(total_change) 302 summary = 'Total change: %s bytes' % DeltaStr(total_change)
192 print(summary) 303 print(summary)
193 print('=' * len(summary)) 304 print('=' * len(summary))
194 for section in sections: 305 for section in sections:
195 if not section.symbols: 306 if not section.symbols:
196 continue 307 continue
197 if section.before_size == 0: 308 if section.before_size == 0:
198 description = ('added, totalling %s bytes' % DeltaStr(section.after_size)) 309 description = ('added, totalling %s bytes' % DeltaStr(section.after_size))
199 elif section.after_size == 0: 310 elif section.after_size == 0:
200 description = ('removed, totalling %s bytes' % 311 description = ('removed, totalling %s bytes' %
201 DeltaStr(-section.before_size)) 312 DeltaStr(-section.before_size))
202 else: 313 else:
203 if section.after_size > section.before_size: 314 if section.after_size > section.before_size:
204 type_str = 'grown' 315 type_str = 'grown'
205 else: 316 else:
206 type_str = 'shrunk' 317 type_str = 'shrunk'
207 description = ('%s, for a net change of %s bytes ' 318 description = ('%s, for a net change of %s bytes '
208 '(%d bytes before, %d bytes after)' % 319 '(%d bytes before, %d bytes after)' %
209 (type_str, DeltaStr(section.after_size - section.before_size), 320 (type_str, DeltaStr(section.after_size - section.before_size),
210 section.before_size, section.after_size)) 321 section.before_size, section.after_size))
211 print(' %d %s across %d sources' % 322 print(' %d %s across %d sources' %
212 (len(section.symbols), description, len(section.sources))) 323 (len(section.symbols), description, len(section.sources)))
213 324
214 maybe_unchanged_sources = set() 325 maybe_unchanged_sources = set()
215 unchanged_symbols_size = 0 326 unchanged_symbols_size = 0
216 for file_path, symbol_type, symbol_name, size1, size2 in unchanged: 327 for item in unchanged:
217 maybe_unchanged_sources.add(file_path) 328 maybe_unchanged_sources.add(item.file_path)
218 unchanged_symbols_size += size1 # == size2 329 unchanged_symbols_size += item.old_size # == item.new_size
219 print(' %d unchanged, totalling %d bytes' % 330 print(' %d unchanged, totalling %d bytes' %
220 (len(unchanged), unchanged_symbols_size)) 331 (len(unchanged), unchanged_symbols_size))
221 332
222 # High level analysis, always output. 333 # High level analysis, always output.
223 unchanged_sources = maybe_unchanged_sources 334 unchanged_sources = maybe_unchanged_sources
224 for section in sections: 335 for section in sections:
225 unchanged_sources = unchanged_sources - section.sources 336 unchanged_sources = unchanged_sources - section.sources
226 new_sources = (new_symbols.sources - 337 new_sources = (new_symbols.sources -
227 maybe_unchanged_sources - 338 maybe_unchanged_sources -
228 removed_symbols.sources) 339 removed_symbols.sources)
(...skipping 20 matching lines...) Expand all
249 if not showsources: 360 if not showsources:
250 return # Per-source analysis, only if requested 361 return # Per-source analysis, only if requested
251 print 'Per-source Analysis:' 362 print 'Per-source Analysis:'
252 delta_by_path = {} 363 delta_by_path = {}
253 for section in sections: 364 for section in sections:
254 for path in section.symbols_by_path: 365 for path in section.symbols_by_path:
255 entry = delta_by_path.get(path) 366 entry = delta_by_path.get(path)
256 if not entry: 367 if not entry:
257 entry = {'plus': 0, 'minus': 0} 368 entry = {'plus': 0, 'minus': 0}
258 delta_by_path[path] = entry 369 delta_by_path[path] = entry
259 for symbol_name, symbol_type, size1, size2 in \ 370 for symbol_name, symbol_type, symbol_delta in \
260 section.symbols_by_path[path]: 371 section.symbols_by_path[path]:
261 if size1 is None: 372 if symbol_delta.old_size is None:
262 delta = size2 373 delta = symbol_delta.new_size
263 elif size2 is None: 374 elif symbol_delta.new_size is None:
264 delta = -size1 375 delta = -symbol_delta.old_size
265 else: 376 else:
266 delta = size2 - size1 377 delta = symbol_delta.new_size - symbol_delta.old_size
267 378
268 if delta > 0: 379 if delta > 0:
269 entry['plus'] += delta 380 entry['plus'] += delta
270 else: 381 else:
271 entry['minus'] += (-1 * delta) 382 entry['minus'] += (-1 * delta)
272 383
273 def delta_sort_key(item): 384 def delta_sort_key(item):
274 _path, size_data = item 385 _path, size_data = item
275 growth = size_data['plus'] - size_data['minus'] 386 growth = size_data['plus'] - size_data['minus']
276 return growth 387 return growth
277 388
278 for path, size_data in sorted(delta_by_path.iteritems(), key=delta_sort_key, 389 for path, size_data in sorted(delta_by_path.iteritems(), key=delta_sort_key,
279 reverse=True): 390 reverse=True):
280 gain = size_data['plus'] 391 gain = size_data['plus']
281 loss = size_data['minus'] 392 loss = size_data['minus']
282 delta = size_data['plus'] - size_data['minus'] 393 delta = size_data['plus'] - size_data['minus']
283 header = ' %s - Source: %s - (gained %d, lost %d)' % (DeltaStr(delta), 394 header = ' %s - Source: %s - (gained %d, lost %d)' % (DeltaStr(delta),
284 path, gain, loss) 395 path, gain, loss)
285 divider = '-' * len(header) 396 divider = '-' * len(header)
286 print '' 397 print ''
287 print divider 398 print divider
288 print header 399 print header
289 print divider 400 print divider
290 if showsymbols: 401 if showsymbols:
402 def ExtractNewSize(tup):
403 symbol_delta = tup[2]
404 return symbol_delta.new_size
405 def ExtractOldSize(tup):
406 symbol_delta = tup[2]
407 return symbol_delta.old_size
291 if path in new_symbols.symbols_by_path: 408 if path in new_symbols.symbols_by_path:
292 print ' New symbols:' 409 print ' New symbols:'
293 for symbol_name, symbol_type, size1, size2 in \ 410 for symbol_name, symbol_type, symbol_delta in \
294 sorted(new_symbols.symbols_by_path[path], 411 sorted(new_symbols.symbols_by_path[path],
295 key=operator.itemgetter(3), 412 key=ExtractNewSize,
296 reverse=True): 413 reverse=True):
297 print (' %8s: %s type=%s, size=%d bytes' % 414 print (' %8s: %s type=%s, size=%d bytes%s' %
298 (DeltaStr(size2), symbol_name, symbol_type, size2)) 415 (DeltaStr(symbol_delta.new_size), symbol_name, symbol_type,
416 symbol_delta.new_size, SharedInfoStr(symbol_delta)))
299 if path in removed_symbols.symbols_by_path: 417 if path in removed_symbols.symbols_by_path:
300 print ' Removed symbols:' 418 print ' Removed symbols:'
301 for symbol_name, symbol_type, size1, size2 in \ 419 for symbol_name, symbol_type, symbol_delta in \
302 sorted(removed_symbols.symbols_by_path[path], 420 sorted(removed_symbols.symbols_by_path[path],
303 key=operator.itemgetter(2)): 421 key=ExtractOldSize):
304 print (' %8s: %s type=%s, size=%d bytes' % 422 print (' %8s: %s type=%s, size=%d bytes%s' %
305 (DeltaStr(-size1), symbol_name, symbol_type, size1)) 423 (DeltaStr(-symbol_delta.old_size), symbol_name, symbol_type,
424 symbol_delta.old_size,
425 SharedInfoStr(symbol_delta)))
306 for (changed_symbols_by_path, type_str) in [ 426 for (changed_symbols_by_path, type_str) in [
307 (grown_symbols.symbols_by_path, "Grown"), 427 (grown_symbols.symbols_by_path, "Grown"),
308 (shrunk_symbols.symbols_by_path, "Shrunk")]: 428 (shrunk_symbols.symbols_by_path, "Shrunk")]:
309 if path in changed_symbols_by_path: 429 if path in changed_symbols_by_path:
310 print ' %s symbols:' % type_str 430 print ' %s symbols:' % type_str
311 def changed_symbol_sortkey(item): 431 def changed_symbol_sortkey(item):
312 symbol_name, _symbol_type, size1, size2 = item 432 symbol_name, _symbol_type, symbol_delta = item
313 return (size1 - size2, symbol_name) 433 return (symbol_delta.old_size - symbol_delta.new_size, symbol_name)
314 for symbol_name, symbol_type, size1, size2 in \ 434 for symbol_name, symbol_type, symbol_delta in \
315 sorted(changed_symbols_by_path[path], key=changed_symbol_sortkey): 435 sorted(changed_symbols_by_path[path], key=changed_symbol_sortkey):
316 print (' %8s: %s type=%s, (was %d bytes, now %d bytes)' 436 print (' %8s: %s type=%s, (was %d bytes, now %d bytes)%s'
317 % (DeltaStr(size2 - size1), symbol_name, 437 % (DeltaStr(symbol_delta.new_size - symbol_delta.old_size),
318 symbol_type, size1, size2)) 438 symbol_name, symbol_type,
439 symbol_delta.old_size, symbol_delta.new_size,
440 SharedInfoStr(symbol_delta)))
319 441
320 442
321 def main(): 443 def main():
322 usage = """%prog [options] 444 usage = """%prog [options]
323 445
324 Analyzes the symbolic differences between two binary files 446 Analyzes the symbolic differences between two binary files
325 (typically, not necessarily, two different builds of the same 447 (typically, not necessarily, two different builds of the same
326 library) and produces a detailed description of symbols that have 448 library) and produces a detailed description of symbols that have
327 been added, removed, or whose size has changed. 449 been added, removed, or whose size has changed.
328 450
(...skipping 24 matching lines...) Expand all
353 with file(path, 'r') as nm_input: 475 with file(path, 'r') as nm_input:
354 if opts.verbose: 476 if opts.verbose:
355 print 'parsing ' + path + '...' 477 print 'parsing ' + path + '...'
356 symbols.append(list(binary_size_utils.ParseNm(nm_input))) 478 symbols.append(list(binary_size_utils.ParseNm(nm_input)))
357 (added, removed, changed, unchanged) = Compare(symbols[0], symbols[1]) 479 (added, removed, changed, unchanged) = Compare(symbols[0], symbols[1])
358 CrunchStats(added, removed, changed, unchanged, 480 CrunchStats(added, removed, changed, unchanged,
359 opts.showsources | opts.showsymbols, opts.showsymbols) 481 opts.showsources | opts.showsymbols, opts.showsymbols)
360 482
361 if __name__ == '__main__': 483 if __name__ == '__main__':
362 sys.exit(main()) 484 sys.exit(main())
OLDNEW
« no previous file with comments | « tools/binary_size/binary_size_utils.py ('k') | tools/binary_size/explain_binary_size_delta_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698