288def CrunchStats(added, removed, changed, unchanged, showsources, showsymbols):
289 """Outputs to stdout a summary of changes based on the symbol lists."""
290
291
292 grown = []
293 shrunk = []
294 for item in changed:
295 if item.old_size < item.new_size:
296 grown.append(item)
297 else:
298 shrunk.append(item)
299
300 new_symbols = CrunchStatsData(added)
301 removed_symbols = CrunchStatsData(removed)
302 grown_symbols = CrunchStatsData(grown)
303 shrunk_symbols = CrunchStatsData(shrunk)
304 sections = [new_symbols, removed_symbols, grown_symbols, shrunk_symbols]
305 for section in sections:
306 for item in section.symbols:
307 section.sources.add(item.file_path)
308 if item.old_size is not None:
309 section.before_size += item.old_size
310 if item.new_size is not None:
311 section.after_size += item.new_size
312 bucket = section.symbols_by_path.setdefault(item.file_path, [])
313 bucket.append((item.symbol_name, item.symbol_type,
314 item.ExtractSymbolDelta()))
315
316 total_change = sum(s.after_size - s.before_size for s in sections)
317 summary = 'Total change: %s bytes' % DeltaStr(total_change)
319 print(
'=' * len(summary))
320 for section in sections:
321 if not section.symbols:
322 continue
323 if section.before_size == 0:
324 description = (
325 'added, totalling %s bytes' % DeltaStr(section.after_size))
326 elif section.after_size == 0:
327 description = (
328 'removed, totalling %s bytes' % DeltaStr(-section.before_size))
329 else:
330 if section.after_size > section.before_size:
331 type_str = 'grown'
332 else:
333 type_str = 'shrunk'
334 description = (
335 '%s, for a net change of %s bytes '
336 '(%d bytes before, %d bytes after)' %
337 (type_str, DeltaStr(section.after_size - section.before_size),
338 section.before_size, section.after_size))
339 print(
' %d %s across %d sources' % (len(section.symbols), description,
340 len(section.sources)))
341
342 maybe_unchanged_sources = set()
343 unchanged_symbols_size = 0
344 for item in unchanged:
345 maybe_unchanged_sources.add(item.file_path)
346 unchanged_symbols_size += item.old_size
347 print(
' %d unchanged, totalling %d bytes' % (len(unchanged),
348 unchanged_symbols_size))
349
350
351 unchanged_sources = maybe_unchanged_sources
352 for section in sections:
353 unchanged_sources = unchanged_sources - section.sources
354 new_sources = (
355 new_symbols.sources - maybe_unchanged_sources - removed_symbols.sources)
356 removed_sources = (
357 removed_symbols.sources - maybe_unchanged_sources - new_symbols.sources)
358 partially_changed_sources = (
359 grown_symbols.sources | shrunk_symbols.sources | new_symbols.sources |
360 removed_symbols.sources) - removed_sources - new_sources
361 allFiles = set()
362 for section in sections:
363 allFiles = allFiles | section.sources
364 allFiles = allFiles | maybe_unchanged_sources
365 print(
'Source stats:')
366 print(
' %d sources encountered.' % len(allFiles))
367 print(
' %d completely new.' % len(new_sources))
368 print(
' %d removed completely.' % len(removed_sources))
369 print(
' %d partially changed.' % len(partially_changed_sources))
370 print(
' %d completely unchanged.' % len(unchanged_sources))
371 remainder = (allFiles - new_sources - removed_sources -
372 partially_changed_sources - unchanged_sources)
373 assert len(remainder) == 0
374
375 if not showsources:
376 return
377 print(
'Per-source Analysis:')
378 delta_by_path = {}
379 for section in sections:
380 for path in section.symbols_by_path:
381 entry = delta_by_path.get(path)
382 if not entry:
383 entry = {'plus': 0, 'minus': 0}
384 delta_by_path[path] = entry
385 for symbol_name, symbol_type, symbol_delta in \
386 section.symbols_by_path[path]:
387 if symbol_delta.old_size is None:
388 delta = symbol_delta.new_size
389 elif symbol_delta.new_size is None:
390 delta = -symbol_delta.old_size
391 else:
392 delta = symbol_delta.new_size - symbol_delta.old_size
393
394 if delta > 0:
395 entry['plus'] += delta
396 else:
397 entry['minus'] += (-1 * delta)
398
399 def delta_sort_key(item):
400 _path, size_data = item
401 growth = size_data['plus'] - size_data['minus']
402 return growth
403
404 for path, size_data in sorted(delta_by_path.items(),
405 key=delta_sort_key,
406 reverse=True):
407 gain = size_data['plus']
408 loss = size_data['minus']
409 delta = size_data['plus'] - size_data['minus']
410 header = ' %s - Source: %s - (gained %d, lost %d)' % (DeltaStr(delta),
411 path, gain, loss)
412 divider = '-' * len(header)
417 if showsymbols:
418
419 def ExtractNewSize(tup):
420 symbol_delta = tup[2]
421 return symbol_delta.new_size
422
423 def ExtractOldSize(tup):
424 symbol_delta = tup[2]
425 return symbol_delta.old_size
426
427 if path in new_symbols.symbols_by_path:
428 print(
' New symbols:')
429 for symbol_name, symbol_type, symbol_delta in \
430 sorted(new_symbols.symbols_by_path[path],
431 key=ExtractNewSize,
432 reverse=True):
433 print(
' %8s: %s type=%s, size=%d bytes%s' %
434 (DeltaStr(symbol_delta.new_size), symbol_name,
435 symbol_type, symbol_delta.new_size,
436 SharedInfoStr(symbol_delta)))
437 if path in removed_symbols.symbols_by_path:
438 print(
' Removed symbols:')
439 for symbol_name, symbol_type, symbol_delta in \
440 sorted(removed_symbols.symbols_by_path[path],
441 key=ExtractOldSize):
442 print(
' %8s: %s type=%s, size=%d bytes%s' %
443 (DeltaStr(-symbol_delta.old_size), symbol_name,
444 symbol_type, symbol_delta.old_size,
445 SharedInfoStr(symbol_delta)))
446 for (changed_symbols_by_path,
447 type_str) in [(grown_symbols.symbols_by_path, "Grown"),
448 (shrunk_symbols.symbols_by_path, "Shrunk")]:
449 if path in changed_symbols_by_path:
450 print(
' %s symbols:' % type_str)
451
452 def changed_symbol_sortkey(item):
453 symbol_name, _symbol_type, symbol_delta = item
454 return (symbol_delta.old_size - symbol_delta.new_size,
455 symbol_name)
456
457 for symbol_name, symbol_type, symbol_delta in \
458 sorted(changed_symbols_by_path[path], key=changed_symbol_sortkey):
460 ' %8s: %s type=%s, (was %d bytes, now %d bytes)%s'
461 % (DeltaStr(symbol_delta.new_size -
462 symbol_delta.old_size), symbol_name,
463 symbol_type,
464 symbol_delta.old_size, symbol_delta.new_size,
465 SharedInfoStr(symbol_delta)))
466
467