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

Side by Side Diff: tools/binary_size/libsupersize/models.py

Issue 2870743003: supersize: Add symbol.template_name, and strip <>s from symbol.name (Closed)
Patch Set: review comments Created 3 years, 7 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 # 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 """Classes that comprise the data model for binary size analysis. 4 """Classes that comprise the data model for binary size analysis.
5 5
6 The primary classes are Symbol, and SymbolGroup. 6 The primary classes are Symbol, and SymbolGroup.
7 7
8 Description of common properties: 8 Description of common properties:
9 * address: The start address of the symbol. 9 * address: The start address of the symbol.
10 May be 0 (e.g. for .bss or for SymbolGroups). 10 May be 0 (e.g. for .bss or for SymbolGroups).
11 * size: The number of bytes this symbol takes up, including padding that comes 11 * size: The number of bytes this symbol takes up, including padding that comes
12 before |address|. 12 before |address|.
13 * num_aliases: The number of symbols with the same address (including self). 13 * num_aliases: The number of symbols with the same address (including self).
14 * pss: size / num_aliases. 14 * pss: size / num_aliases.
15 * padding: The number of bytes of padding before |address| due to this symbol. 15 * padding: The number of bytes of padding before |address| due to this symbol.
16 * name: Symbol names with parameter list removed. 16 * name: Names with templates and parameter list removed.
17 Never None, but will be '' for anonymous symbols. 17 Never None, but will be '' for anonymous symbols.
18 * full_name: Symbols names with parameter list left in. 18 * template_name: Name with parameter list removed (but templates left in).
19 Never None, but will be '' for anonymous symbols, and for symbols that do 19 Never None, but will be '' for anonymous symbols.
20 not contain a parameter list. 20 * full_name: Name with template and parameter list left in.
21 Never None, but will be '' for anonymous symbols.
21 * is_anonymous: True when the symbol exists in an anonymous namespace (which 22 * is_anonymous: True when the symbol exists in an anonymous namespace (which
22 are removed from both full_name and name during normalization). 23 are removed from both full_name and name during normalization).
23 * section_name: E.g. ".text", ".rodata", ".data.rel.local" 24 * section_name: E.g. ".text", ".rodata", ".data.rel.local"
24 * section: The second character of |section_name|. E.g. "t", "r", "d". 25 * section: The second character of |section_name|. E.g. "t", "r", "d".
25 """ 26 """
26 27
27 import collections 28 import collections
28 import logging 29 import logging
29 import os 30 import os
30 import re 31 import re
31 32
32 import cluster_symbols 33 import cluster_symbols
(...skipping 23 matching lines...) Expand all
56 FLAG_REL = 8 57 FLAG_REL = 8
57 FLAG_REL_LOCAL = 16 58 FLAG_REL_LOCAL = 16
58 FLAG_GENERATED_SOURCE = 32 59 FLAG_GENERATED_SOURCE = 32
59 60
60 61
61 class SizeInfo(object): 62 class SizeInfo(object):
62 """Represents all size information for a single binary. 63 """Represents all size information for a single binary.
63 64
64 Fields: 65 Fields:
65 section_sizes: A dict of section_name -> size. 66 section_sizes: A dict of section_name -> size.
66 symbols: A SymbolGroup containing all symbols, sorted by address. 67 raw_symbols: A list of all symbols, sorted by address.
68 symbols: A SymbolGroup containing all symbols. By default, these are the
69 same as raw_symbols, but may contain custom groupings when it is
70 desirable to convey the result of a query along with section_sizes and
71 metadata.
67 metadata: A dict. 72 metadata: A dict.
68 """ 73 """
69 __slots__ = ( 74 __slots__ = (
70 'section_sizes', 75 'section_sizes',
76 'raw_symbols',
71 'symbols', 77 'symbols',
72 'metadata', 78 'metadata',
73 ) 79 )
74 80
75 """Root size information.""" 81 """Root size information."""
76 def __init__(self, section_sizes, symbols, metadata=None): 82 def __init__(self, section_sizes, raw_symbols, metadata=None, symbols=None):
77 self.section_sizes = section_sizes # E.g. {'.text': 0} 83 self.section_sizes = section_sizes # E.g. {'.text': 0}
78 self.symbols = symbols 84 self.raw_symbols = raw_symbols
85 self.symbols = symbols or SymbolGroup(raw_symbols)
79 self.metadata = metadata or {} 86 self.metadata = metadata or {}
80 87
81 def Cluster(self): 88 def Clustered(self):
82 """Returns a new SizeInfo with some symbols moved into subgroups. 89 """Returns a new SizeInfo with some symbols moved into subgroups.
83 90
84 See SymbolGroup.Cluster() for more details. 91 See SymbolGroup.Clustered() for more details.
85 """ 92 """
86 return SizeInfo(self.section_sizes, self.symbols.Cluster(), self.metadata) 93 return SizeInfo(self.section_sizes, self.raw_symbols, self.metadata,
94 symbols=self.symbols.Clustered())
87 95
88 96
89 class SizeInfoDiff(object): 97 class SizeInfoDiff(object):
90 """What you get when you Diff() two SizeInfo objects. 98 """What you get when you Diff() two SizeInfo objects.
91 99
92 Fields: 100 Fields:
93 section_sizes: A dict of section_name -> size delta. 101 section_sizes: A dict of section_name -> size delta.
94 symbols: A SymbolDiff with all symbols in it. 102 symbols: A SymbolDiff with all symbols in it.
95 before_metadata: metadata of the "before" SizeInfo. 103 before_metadata: metadata of the "before" SizeInfo.
96 after_metadata: metadata of the "after" SizeInfo. 104 after_metadata: metadata of the "after" SizeInfo.
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 195
188 class Symbol(BaseSymbol): 196 class Symbol(BaseSymbol):
189 """Represents a single symbol within a binary. 197 """Represents a single symbol within a binary.
190 198
191 Refer to module docs for field descriptions. 199 Refer to module docs for field descriptions.
192 """ 200 """
193 201
194 __slots__ = ( 202 __slots__ = (
195 'address', 203 'address',
196 'full_name', 204 'full_name',
205 'template_name',
206 'name',
197 'flags', 207 'flags',
198 'object_path', 208 'object_path',
199 'name',
200 'aliases', 209 'aliases',
201 'padding', 210 'padding',
202 'section_name', 211 'section_name',
203 'source_path', 212 'source_path',
204 'size', 213 'size',
205 ) 214 )
206 215
207 def __init__(self, section_name, size_without_padding, address=None, 216 def __init__(self, section_name, size_without_padding, address=None,
208 name=None, source_path=None, object_path=None, full_name=None, 217 full_name=None, template_name=None, name=None, source_path=None,
209 flags=0, aliases=None): 218 object_path=None, flags=0, aliases=None):
210 self.section_name = section_name 219 self.section_name = section_name
211 self.address = address or 0 220 self.address = address or 0
221 self.full_name = full_name or ''
222 self.template_name = template_name or ''
212 self.name = name or '' 223 self.name = name or ''
213 self.full_name = full_name or ''
214 self.source_path = source_path or '' 224 self.source_path = source_path or ''
215 self.object_path = object_path or '' 225 self.object_path = object_path or ''
216 self.size = size_without_padding 226 self.size = size_without_padding
217 self.flags = flags 227 self.flags = flags
218 self.aliases = aliases 228 self.aliases = aliases
219 self.padding = 0 229 self.padding = 0
220 230
221 def __repr__(self): 231 def __repr__(self):
222 template = ('{}@{:x}(size_without_padding={},padding={},name={},' 232 template = ('{}@{:x}(size_without_padding={},padding={},name={},'
223 'object_path={},source_path={},flags={})') 233 'object_path={},source_path={},flags={})')
(...skipping 26 matching lines...) Expand all
250 * unioned = group1 + group2 260 * unioned = group1 + group2
251 """ 261 """
252 262
253 __slots__ = ( 263 __slots__ = (
254 '_padding', 264 '_padding',
255 '_size', 265 '_size',
256 '_pss', 266 '_pss',
257 '_symbols', 267 '_symbols',
258 '_filtered_symbols', 268 '_filtered_symbols',
259 'full_name', 269 'full_name',
270 'template_name',
260 'name', 271 'name',
261 'section_name', 272 'section_name',
262 'is_sorted', 273 'is_sorted',
263 ) 274 )
264 275
265 def __init__(self, symbols, filtered_symbols=None, name=None, 276 # template_name and full_name are useful when clustering symbol clones.
266 full_name=None, section_name=None, is_sorted=False): 277 def __init__(self, symbols, filtered_symbols=None, full_name=None,
278 template_name=None, name='', section_name=None, is_sorted=False):
267 self._padding = None 279 self._padding = None
268 self._size = None 280 self._size = None
269 self._pss = None 281 self._pss = None
270 self._symbols = symbols 282 self._symbols = symbols
271 self._filtered_symbols = filtered_symbols or [] 283 self._filtered_symbols = filtered_symbols or []
284 self.full_name = full_name if full_name is not None else name
285 self.template_name = template_name if template_name is not None else name
272 self.name = name or '' 286 self.name = name or ''
273 self.full_name = full_name
274 self.section_name = section_name or '.*' 287 self.section_name = section_name or '.*'
275 self.is_sorted = is_sorted 288 self.is_sorted = is_sorted
276 289
277 def __repr__(self): 290 def __repr__(self):
278 return 'Group(name=%s,count=%d,size=%d)' % ( 291 return 'Group(name=%s,count=%d,size=%d)' % (
279 self.name, len(self), self.size) 292 self.name, len(self), self.size)
280 293
281 def __iter__(self): 294 def __iter__(self):
282 return iter(self._symbols) 295 return iter(self._symbols)
283 296
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 for s in self: 392 for s in self:
380 if s.IsGroup(): 393 if s.IsGroup():
381 for x in s.IterLeafSymbols(): 394 for x in s.IterLeafSymbols():
382 yield x 395 yield x
383 else: 396 else:
384 yield s 397 yield s
385 398
386 def CountUniqueSymbols(self): 399 def CountUniqueSymbols(self):
387 return sum(1 for s in self.IterUniqueSymbols()) 400 return sum(1 for s in self.IterUniqueSymbols())
388 401
389 def _CreateTransformed(self, symbols, filtered_symbols=None, name=None, 402 def _CreateTransformed(self, symbols, filtered_symbols=None, full_name=None,
390 full_name=None, section_name=None, is_sorted=None): 403 template_name=None, name=None, section_name=None,
404 is_sorted=None):
391 if is_sorted is None: 405 if is_sorted is None:
392 is_sorted = self.is_sorted 406 is_sorted = self.is_sorted
393 return SymbolGroup(symbols, filtered_symbols=filtered_symbols, name=name, 407 return SymbolGroup(symbols, filtered_symbols=filtered_symbols,
394 full_name=full_name, section_name=section_name, 408 full_name=full_name, template_name=template_name,
409 name=name, section_name=section_name,
395 is_sorted=is_sorted) 410 is_sorted=is_sorted)
396 411
397 def Cluster(self): 412 def Clustered(self):
398 """Returns a new SymbolGroup with some symbols moved into subgroups. 413 """Returns a new SymbolGroup with some symbols moved into subgroups.
399 414
400 Subgroups include: 415 Subgroups include:
401 * Symbols that have [clone] in their name (created during inlining). 416 * Symbols that have [clone] in their name (created during inlining).
402 * Star symbols (such as "** merge strings", and "** symbol gap") 417 * Star symbols (such as "** merge strings", and "** symbol gap")
403 418
404 To view created groups: 419 To view created groups:
405 Print(clustered.Filter(lambda s: s.IsGroup()), recursive=True) 420 Print(clustered.Filter(lambda s: s.IsGroup()), recursive=True)
406 """ 421 """
407 return self._CreateTransformed(cluster_symbols.ClusterSymbols(self)) 422 return self._CreateTransformed(cluster_symbols.ClusterSymbols(self))
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 461
447 def WhereInSection(self, section): 462 def WhereInSection(self, section):
448 if len(section) == 1: 463 if len(section) == 1:
449 ret = self.Filter(lambda s: s.section == section) 464 ret = self.Filter(lambda s: s.section == section)
450 ret.section_name = SECTION_TO_SECTION_NAME[section] 465 ret.section_name = SECTION_TO_SECTION_NAME[section]
451 else: 466 else:
452 ret = self.Filter(lambda s: s.section_name == section) 467 ret = self.Filter(lambda s: s.section_name == section)
453 ret.section_name = section 468 ret.section_name = section
454 return ret 469 return ret
455 470
471 def WhereIsTemplate(self):
472 return self.Filter(lambda s: s.template_name is not s.name)
473
456 def WhereSourceIsGenerated(self): 474 def WhereSourceIsGenerated(self):
457 return self.Filter(lambda s: s.generated_source) 475 return self.Filter(lambda s: s.generated_source)
458 476
459 def WhereGeneratedByToolchain(self): 477 def WhereGeneratedByToolchain(self):
460 return self.Filter(lambda s: s.IsGeneratedByToolchain()) 478 return self.Filter(lambda s: s.IsGeneratedByToolchain())
461 479
480 def WhereFullNameMatches(self, pattern):
481 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern))
482 return self.Filter(lambda s: regex.search(s.full_name))
483
484 def WhereTemplateNameMatches(self, pattern):
485 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern))
486 return self.Filter(lambda s: regex.search(s.template_name))
487
462 def WhereNameMatches(self, pattern): 488 def WhereNameMatches(self, pattern):
463 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern)) 489 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern))
464 return self.Filter(lambda s: regex.search(s.name)) 490 return self.Filter(lambda s: regex.search(s.name))
465 491
466 def WhereFullNameMatches(self, pattern):
467 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern))
468 return self.Filter(lambda s: regex.search(s.full_name or s.name))
469
470 def WhereObjectPathMatches(self, pattern): 492 def WhereObjectPathMatches(self, pattern):
471 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern)) 493 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern))
472 return self.Filter(lambda s: regex.search(s.object_path)) 494 return self.Filter(lambda s: regex.search(s.object_path))
473 495
474 def WhereSourcePathMatches(self, pattern): 496 def WhereSourcePathMatches(self, pattern):
475 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern)) 497 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern))
476 return self.Filter(lambda s: regex.search(s.source_path)) 498 return self.Filter(lambda s: regex.search(s.source_path))
477 499
478 def WherePathMatches(self, pattern): 500 def WherePathMatches(self, pattern):
479 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern)) 501 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern))
480 return self.Filter(lambda s: (regex.search(s.source_path) or 502 return self.Filter(lambda s: (regex.search(s.source_path) or
481 regex.search(s.object_path))) 503 regex.search(s.object_path)))
482 504
483 def WhereMatches(self, pattern): 505 def WhereMatches(self, pattern):
484 """Looks for |pattern| within all paths & names.""" 506 """Looks for |pattern| within all paths & names."""
485 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern)) 507 regex = re.compile(match_util.ExpandRegexIdentifierPlaceholder(pattern))
486 return self.Filter(lambda s: (regex.search(s.source_path) or 508 return self.Filter(lambda s: (
487 regex.search(s.object_path) or 509 regex.search(s.source_path) or
488 regex.search(s.full_name or '') or 510 regex.search(s.object_path) or
489 regex.search(s.name))) 511 regex.search(s.full_name) or
512 s.full_name is not s.template_name and regex.search(s.template_name) or
513 s.full_name is not s.name and regex.search(s.name)))
490 514
491 def WhereAddressInRange(self, start, end=None): 515 def WhereAddressInRange(self, start, end=None):
492 """Searches for addesses within [start, end). 516 """Searches for addesses within [start, end).
493 517
494 Args may be ints or hex strings. Default value for |end| is |start| + 1. 518 Args may be ints or hex strings. Default value for |end| is |start| + 1.
495 """ 519 """
496 if isinstance(start, basestring): 520 if isinstance(start, basestring):
497 start = int(start, 16) 521 start = int(start, 16)
498 if end is None: 522 if end is None:
499 end = start + 1 523 end = start + 1
500 return self.Filter(lambda s: s.address >= start and s.address < end) 524 return self.Filter(lambda s: s.address >= start and s.address < end)
501 525
502 def WhereHasPath(self): 526 def WhereHasPath(self):
503 return self.Filter(lambda s: s.source_path or s.object_path) 527 return self.Filter(lambda s: s.source_path or s.object_path)
504 528
505 def WhereHasAnyAttribution(self): 529 def WhereHasAnyAttribution(self):
506 return self.Filter(lambda s: s.name or s.source_path or s.object_path) 530 return self.Filter(lambda s: s.full_name or s.source_path or s.object_path)
507 531
508 def Inverted(self): 532 def Inverted(self):
509 """Returns the symbols that were filtered out by the previous filter. 533 """Returns the symbols that were filtered out by the previous filter.
510 534
511 Applies only when the previous call was a filter. 535 Applies only when the previous call was a filter.
512 536
513 Example: 537 Example:
514 # Symbols that do not have "third_party" in their path. 538 # Symbols that do not have "third_party" in their path.
515 symbols.WherePathMatches(r'third_party').Inverted() 539 symbols.WherePathMatches(r'third_party').Inverted()
516 # Symbols within third_party that do not contain the string "foo". 540 # Symbols within third_party that do not contain the string "foo".
517 symbols.WherePathMatches(r'third_party').WhereMatches('foo').Inverted() 541 symbols.WherePathMatches(r'third_party').WhereMatches('foo').Inverted()
518 """ 542 """
519 return self._CreateTransformed( 543 return self._CreateTransformed(
520 self._filtered_symbols, filtered_symbols=self._symbols, is_sorted=False) 544 self._filtered_symbols, filtered_symbols=self._symbols, is_sorted=False)
521 545
522 def GroupBy(self, func, min_count=0): 546 def GroupedBy(self, func, min_count=0):
523 """Returns a SymbolGroup of SymbolGroups, indexed by |func|. 547 """Returns a SymbolGroup of SymbolGroups, indexed by |func|.
524 548
525 Symbols within each subgroup maintain their relative ordering. 549 Symbols within each subgroup maintain their relative ordering.
526 550
527 Args: 551 Args:
528 func: Grouping function. Passed a symbol and returns a string for the 552 func: Grouping function. Passed a symbol and returns a string for the
529 name of the subgroup to put the symbol in. If None is returned, the 553 name of the subgroup to put the symbol in. If None is returned, the
530 symbol is omitted. 554 symbol is omitted.
531 min_count: Miniumum number of symbols for a group. If fewer than this many 555 min_count: Miniumum number of symbols for a group. If fewer than this many
532 symbols end up in a group, they will not be put within a group. 556 symbols end up in a group, they will not be put within a group.
(...skipping 19 matching lines...) Expand all
552 is_sorted=False)) 576 is_sorted=False))
553 elif include_singles: 577 elif include_singles:
554 after_syms.extend(symbols) 578 after_syms.extend(symbols)
555 else: 579 else:
556 filtered_symbols.extend(symbols) 580 filtered_symbols.extend(symbols)
557 grouped = self._CreateTransformed( 581 grouped = self._CreateTransformed(
558 after_syms, filtered_symbols=filtered_symbols, 582 after_syms, filtered_symbols=filtered_symbols,
559 section_name=self.section_name, is_sorted=False) 583 section_name=self.section_name, is_sorted=False)
560 return grouped 584 return grouped
561 585
562 def GroupBySectionName(self): 586 def GroupedBySectionName(self):
563 return self.GroupBy(lambda s: s.section_name) 587 return self.GroupedBy(lambda s: s.section_name)
564 588
565 def GroupByNamespace(self, depth=0, fallback='{global}', min_count=0): 589 def GroupedByName(self, depth=0, min_count=0):
566 """Groups by symbol namespace (as denoted by ::s). 590 """Groups by symbol name, where |depth| controls how many ::s to include.
567 591
568 Does not differentiate between C++ namespaces and C++ classes. 592 Does not differentiate between namespaces/classes/functions.
569 593
570 Args: 594 Args:
571 depth: When 0 (default), groups by entire namespace. When 1, groups by 595 depth: 0 (default): Groups by entire name. Useful for grouping templates.
572 top-level name, when 2, groups by top 2 names, etc. 596 >0: Groups by this many name parts.
573 fallback: Use this value when no namespace exists. 597 Example: 1 -> std::, 2 -> std::map
598 <0: Groups by entire name minus this many name parts
599 Example: -1 -> std::map, -2 -> std::
574 min_count: Miniumum number of symbols for a group. If fewer than this many 600 min_count: Miniumum number of symbols for a group. If fewer than this many
575 symbols end up in a group, they will not be put within a group. 601 symbols end up in a group, they will not be put within a group.
576 Use a negative value to omit symbols entirely rather than 602 Use a negative value to omit symbols entirely rather than
577 include them outside of a group. 603 include them outside of a group.
578 """ 604 """
579 def extract_namespace(symbol): 605 if depth >= 0:
580 # Remove template params. 606 extract_namespace = (
581 name = symbol.name 607 lambda s: _ExtractPrefixBeforeSeparator(s.name, '::', depth))
582 template_idx = name.find('<') 608 else:
583 if template_idx: 609 depth = -depth
584 name = name[:template_idx] 610 extract_namespace = (
611 lambda s: _ExtractSuffixAfterSeparator(s.name, '::', depth))
612 return self.GroupedBy(extract_namespace, min_count=min_count)
585 613
586 # Remove after the final :: (not part of the namespace). 614 def GroupedByPath(self, depth=0, fallback='{no path}',
587 colon_idx = name.rfind('::')
588 if colon_idx == -1:
589 return fallback
590 name = name[:colon_idx]
591
592 return _ExtractPrefixBeforeSeparator(name, '::', depth)
593 return self.GroupBy(extract_namespace, min_count=min_count)
594
595 def GroupByPath(self, depth=0, fallback='{no path}',
596 fallback_to_object_path=True, min_count=0): 615 fallback_to_object_path=True, min_count=0):
597 """Groups by source_path. 616 """Groups by source_path.
598 617
599 Args: 618 Args:
600 depth: When 0 (default), groups by entire path. When 1, groups by 619 depth: When 0 (default), groups by entire path. When 1, groups by
601 top-level directory, when 2, groups by top 2 directories, etc. 620 top-level directory, when 2, groups by top 2 directories, etc.
602 fallback: Use this value when no namespace exists. 621 fallback: Use this value when no namespace exists.
603 fallback_to_object_path: When True (default), uses object_path when 622 fallback_to_object_path: When True (default), uses object_path when
604 source_path is missing. 623 source_path is missing.
605 min_count: Miniumum number of symbols for a group. If fewer than this many 624 min_count: Miniumum number of symbols for a group. If fewer than this many
606 symbols end up in a group, they will not be put within a group. 625 symbols end up in a group, they will not be put within a group.
607 Use a negative value to omit symbols entirely rather than 626 Use a negative value to omit symbols entirely rather than
608 include them outside of a group. 627 include them outside of a group.
609 """ 628 """
610 def extract_path(symbol): 629 def extract_path(symbol):
611 path = symbol.source_path 630 path = symbol.source_path
612 if fallback_to_object_path and not path: 631 if fallback_to_object_path and not path:
613 path = symbol.object_path 632 path = symbol.object_path
614 path = path or fallback 633 path = path or fallback
615 return _ExtractPrefixBeforeSeparator(path, os.path.sep, depth) 634 return _ExtractPrefixBeforeSeparator(path, os.path.sep, depth)
616 return self.GroupBy(extract_path, min_count=min_count) 635 return self.GroupedBy(extract_path, min_count=min_count)
617 636
618 637
619 class SymbolDiff(SymbolGroup): 638 class SymbolDiff(SymbolGroup):
620 """A SymbolGroup subclass representing a diff of two other SymbolGroups. 639 """A SymbolGroup subclass representing a diff of two other SymbolGroups.
621 640
622 All Symbols contained within have a |size| which is actually the size delta. 641 All Symbols contained within have a |size| which is actually the size delta.
623 Additionally, metadata is kept about which symbols were added / removed / 642 Additionally, metadata is kept about which symbols were added / removed /
624 changed. 643 changed.
625 """ 644 """
626 __slots__ = ( 645 __slots__ = (
627 '_added_ids', 646 '_added_ids',
628 '_removed_ids', 647 '_removed_ids',
629 ) 648 )
630 649
631 def __init__(self, added, removed, similar, name=None, full_name=None, 650 def __init__(self, added, removed, similar):
632 section_name=None):
633 self._added_ids = set(id(s) for s in added) 651 self._added_ids = set(id(s) for s in added)
634 self._removed_ids = set(id(s) for s in removed) 652 self._removed_ids = set(id(s) for s in removed)
635 symbols = [] 653 symbols = []
636 symbols.extend(added) 654 symbols.extend(added)
637 symbols.extend(removed) 655 symbols.extend(removed)
638 symbols.extend(similar) 656 symbols.extend(similar)
639 super(SymbolDiff, self).__init__(symbols, name=name, full_name=full_name, 657 super(SymbolDiff, self).__init__(symbols)
640 section_name=section_name)
641 658
642 def __repr__(self): 659 def __repr__(self):
643 return '%s(%d added, %d removed, %d changed, %d unchanged, size=%d)' % ( 660 return '%s(%d added, %d removed, %d changed, %d unchanged, size=%d)' % (
644 'SymbolGroup', self.added_count, self.removed_count, self.changed_count, 661 'SymbolGroup', self.added_count, self.removed_count, self.changed_count,
645 self.unchanged_count, self.size) 662 self.unchanged_count, self.size)
646 663
647 def _CreateTransformed(self, symbols, filtered_symbols=None, name=None, 664 def _CreateTransformed(self, symbols, filtered_symbols=None, full_name=None,
648 full_name=None, section_name=None, is_sorted=None): 665 template_name=None, name=None, section_name=None,
666 is_sorted=None):
649 # Printing sorts, so short-circuit the same symbols case. 667 # Printing sorts, so short-circuit the same symbols case.
650 if len(symbols) == len(self._symbols): 668 if len(symbols) == len(self._symbols):
651 new_added_ids = self._added_ids 669 new_added_ids = self._added_ids
652 new_removed_ids = self._removed_ids 670 new_removed_ids = self._removed_ids
653 else: 671 else:
654 old_added_ids = self._added_ids 672 old_added_ids = self._added_ids
655 old_removed_ids = self._removed_ids 673 old_removed_ids = self._removed_ids
656 674
657 def get_status(sym): 675 def get_status(sym):
658 obj_id = id(sym) 676 obj_id = id(sym)
(...skipping 13 matching lines...) Expand all
672 status = get_status(sym) 690 status = get_status(sym)
673 if status == 0: 691 if status == 0:
674 new_added_ids.add(id(sym)) 692 new_added_ids.add(id(sym))
675 elif status == 1: 693 elif status == 1:
676 new_removed_ids.add(id(sym)) 694 new_removed_ids.add(id(sym))
677 695
678 ret = SymbolDiff.__new__(SymbolDiff) 696 ret = SymbolDiff.__new__(SymbolDiff)
679 ret._added_ids = new_added_ids 697 ret._added_ids = new_added_ids
680 ret._removed_ids = new_removed_ids 698 ret._removed_ids = new_removed_ids
681 super(SymbolDiff, ret).__init__( 699 super(SymbolDiff, ret).__init__(
682 symbols, filtered_symbols=filtered_symbols, name=name, 700 symbols, filtered_symbols=filtered_symbols, full_name=full_name,
683 full_name=full_name, section_name=section_name, is_sorted=is_sorted) 701 template_name=template_name, name=name, section_name=section_name,
702 is_sorted=is_sorted)
684 return ret 703 return ret
685 704
686 @property 705 @property
687 def added_count(self): 706 def added_count(self):
688 return len(self._added_ids) 707 return len(self._added_ids)
689 708
690 @property 709 @property
691 def removed_count(self): 710 def removed_count(self):
692 return len(self._removed_ids) 711 return len(self._removed_ids)
693 712
(...skipping 13 matching lines...) Expand all
707 key = id(sym) 726 key = id(sym)
708 return key not in self._added_ids and key not in self._removed_ids 727 return key not in self._added_ids and key not in self._removed_ids
709 728
710 def IsRemoved(self, sym): 729 def IsRemoved(self, sym):
711 return id(sym) in self._removed_ids 730 return id(sym) in self._removed_ids
712 731
713 def WhereNotUnchanged(self): 732 def WhereNotUnchanged(self):
714 return self.Filter(lambda s: not self.IsSimilar(s) or s.size) 733 return self.Filter(lambda s: not self.IsSimilar(s) or s.size)
715 734
716 735
717 def _ExtractPrefixBeforeSeparator(string, separator, count=1): 736 def _ExtractPrefixBeforeSeparator(string, separator, count):
718 idx = -len(separator) 737 idx = -len(separator)
719 prev_idx = None 738 prev_idx = None
720 for _ in xrange(count): 739 for _ in xrange(count):
721 idx = string.find(separator, idx + len(separator)) 740 idx = string.find(separator, idx + len(separator))
722 if idx < 0: 741 if idx < 0:
723 break 742 break
724 prev_idx = idx 743 prev_idx = idx
725 return string[:prev_idx] 744 return string[:prev_idx]
745
746
747 def _ExtractSuffixAfterSeparator(string, separator, count):
748 prev_idx = len(string) + 1
749 for _ in xrange(count):
750 idx = string.rfind(separator, 0, prev_idx - 1)
751 if idx < 0:
752 break
753 prev_idx = idx
754 return string[:prev_idx]
OLDNEW
« no previous file with comments | « tools/binary_size/libsupersize/linker_map_parser.py ('k') | tools/binary_size/libsupersize/testdata/Archive.golden » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698