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

Unified Diff: tools/binary_size/libsupersize/models.py

Issue 2885073002: supersize: Move [clone] from name -> flags & rewrite Cluster() (Closed)
Patch Set: review comment 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 side-by-side diff with in-line comments
Download patch
Index: tools/binary_size/libsupersize/models.py
diff --git a/tools/binary_size/libsupersize/models.py b/tools/binary_size/libsupersize/models.py
index 281e335f3c3ee76d26208e2286d713e34dcd5b31..6c70c67884513ad6c7cdca254e46c301ca557c19 100644
--- a/tools/binary_size/libsupersize/models.py
+++ b/tools/binary_size/libsupersize/models.py
@@ -30,7 +30,6 @@ import logging
import os
import re
-import cluster_symbols
import match_util
@@ -58,6 +57,7 @@ FLAG_UNLIKELY = 4
FLAG_REL = 8
FLAG_REL_LOCAL = 16
FLAG_GENERATED_SOURCE = 32
+FLAG_CLONE = 64
DIFF_STATUS_UNCHANGED = 0
DIFF_STATUS_CHANGED = 1
@@ -70,34 +70,37 @@ class SizeInfo(object):
Fields:
section_sizes: A dict of section_name -> size.
- raw_symbols: A list of all symbols, sorted by address.
- symbols: A SymbolGroup containing all symbols. By default, these are the
- same as raw_symbols, but may contain custom groupings when it is
- desirable to convey the result of a query along with section_sizes and
- metadata.
+ raw_symbols: A SymbolGroup containing all top-level symbols (no groups).
+ symbols: A SymbolGroup where symbols have been grouped by full_name (where
+ applicable). May be re-assigned when it is desirable to show custom
+ groupings while still printing metadata and section_sizes.
metadata: A dict.
"""
__slots__ = (
'section_sizes',
'raw_symbols',
- 'symbols',
+ '_symbols',
'metadata',
)
"""Root size information."""
def __init__(self, section_sizes, raw_symbols, metadata=None, symbols=None):
+ if isinstance(raw_symbols, list):
+ raw_symbols = SymbolGroup(raw_symbols)
self.section_sizes = section_sizes # E.g. {'.text': 0}
self.raw_symbols = raw_symbols
- self.symbols = symbols or SymbolGroup(raw_symbols)
+ self._symbols = symbols
self.metadata = metadata or {}
- def Clustered(self):
- """Returns a new SizeInfo with some symbols moved into subgroups.
+ @property
+ def symbols(self):
+ if self._symbols is None:
+ self._symbols = self.raw_symbols._Clustered()
+ return self._symbols
- See SymbolGroup.Clustered() for more details.
- """
- return SizeInfo(self.section_sizes, self.raw_symbols, self.metadata,
- symbols=self.symbols.Clustered())
+ @symbols.setter
+ def symbols(self, value):
+ self._symbols = value
class SizeInfoDiff(object):
@@ -105,22 +108,38 @@ class SizeInfoDiff(object):
Fields:
section_sizes: A dict of section_name -> size delta.
- symbols: A SymbolDiff with all symbols in it.
+ raw_symbols: A SymbolDiff with all top-level symbols in it (no groups).
+ symbols: A SymbolDiff where symbols have been grouped by full_name (where
+ applicable). May be re-assigned when it is desirable to show custom
+ groupings while still printing metadata and section_sizes.
before_metadata: metadata of the "before" SizeInfo.
after_metadata: metadata of the "after" SizeInfo.
"""
__slots__ = (
'section_sizes',
- 'symbols',
+ 'raw_symbols',
+ '_symbols',
'before_metadata',
'after_metadata',
)
- def __init__(self, section_sizes, symbols, before_metadata, after_metadata):
+ def __init__(self, section_sizes, raw_symbols, before_metadata,
+ after_metadata):
self.section_sizes = section_sizes
- self.symbols = symbols
+ self.raw_symbols = raw_symbols
self.before_metadata = before_metadata
self.after_metadata = after_metadata
+ self._symbols = None
+
+ @property
+ def symbols(self):
+ if self._symbols is None:
+ self._symbols = self.raw_symbols._Clustered()
+ return self._symbols
+
+ @symbols.setter
+ def symbols(self, value):
+ self._symbols = value
class BaseSymbol(object):
@@ -183,6 +202,8 @@ class BaseSymbol(object):
parts.append('rel.loc')
if flags & FLAG_GENERATED_SOURCE:
parts.append('gen')
+ if flags & FLAG_CLONE:
+ parts.append('clone')
# Not actually a part of flags, but useful to show it here.
if self.aliases:
parts.append('{} aliases'.format(self.num_aliases))
@@ -415,18 +436,6 @@ class SymbolGroup(BaseSymbol):
name=name, section_name=section_name,
is_sorted=is_sorted)
- def Clustered(self):
- """Returns a new SymbolGroup with some symbols moved into subgroups.
-
- Subgroups include:
- * Symbols that have [clone] in their name (created during inlining).
- * Star symbols (such as "** merge strings", and "** symbol gap")
-
- To view created groups:
- Print(clustered.Filter(lambda s: s.IsGroup()), recursive=True)
- """
- return self._CreateTransformed(cluster_symbols.ClusterSymbols(self))
-
def Sorted(self, cmp_func=None, key=None, reverse=False):
if cmp_func is None and key is None:
cmp_func = lambda a, b: cmp((a.IsBss(), abs(b.pss), a.name),
@@ -462,6 +471,9 @@ class SymbolGroup(BaseSymbol):
filtered_symbols=filtered_and_kept[0],
section_name=self.section_name)
+ def WhereIsGroup(self):
+ return self.Filter(lambda s: s.IsGroup())
+
def WhereSizeBiggerThan(self, min_size):
return self.Filter(lambda s: s.size >= min_size)
@@ -552,45 +564,109 @@ class SymbolGroup(BaseSymbol):
return self._CreateTransformed(
self._filtered_symbols, filtered_symbols=self._symbols, is_sorted=False)
- def GroupedBy(self, func, min_count=0):
+ def GroupedBy(self, func, min_count=0, group_factory=None):
"""Returns a SymbolGroup of SymbolGroups, indexed by |func|.
Symbols within each subgroup maintain their relative ordering.
Args:
func: Grouping function. Passed a symbol and returns a string for the
- name of the subgroup to put the symbol in. If None is returned, the
- symbol is omitted.
+ name of the subgroup to put the symbol in. If None is returned, the
+ symbol is omitted.
min_count: Miniumum number of symbols for a group. If fewer than this many
- symbols end up in a group, they will not be put within a group.
- Use a negative value to omit symbols entirely rather than
- include them outside of a group.
+ symbols end up in a group, they will not be put within a group.
+ Use a negative value to omit symbols entirely rather than
+ include them outside of a group.
+ group_factory: Function to create SymbolGroup from a list of Symbols.
"""
+ if group_factory is None:
+ group_factory = lambda token, symbols: self._CreateTransformed(
+ symbols, full_name=token, template_name=token, name=token,
+ section_name=self.section_name)
+
after_syms = []
filtered_symbols = []
- symbols_by_token = collections.defaultdict(list)
+ symbols_by_token = collections.OrderedDict()
# Index symbols by |func|.
for symbol in self:
token = func(symbol)
if token is None:
filtered_symbols.append(symbol)
- symbols_by_token[token].append(symbol)
+ else:
+ # Optimization: Store a list only when >1 symbol.
+ # Saves 200-300ms for _Clustered().
+ prev = symbols_by_token.setdefault(token, symbol)
+ if prev is not symbol:
+ if prev.__class__ == list:
+ prev.append(symbol)
+ else:
+ symbols_by_token[token] = [prev, symbol]
# Create the subgroups.
include_singles = min_count >= 0
min_count = abs(min_count)
- for token, symbols in symbols_by_token.iteritems():
- if len(symbols) >= min_count:
- after_syms.append(self._CreateTransformed(
- symbols, name=token, section_name=self.section_name,
- is_sorted=False))
- elif include_singles:
- after_syms.extend(symbols)
+ for token, symbol_or_list in symbols_by_token.iteritems():
+ count = 1
+ if symbol_or_list.__class__ == list:
+ count = len(symbol_or_list)
+
+ if count >= min_count:
+ if count == 1:
+ symbol_or_list = [symbol_or_list]
+ after_syms.append(group_factory(token, symbol_or_list))
else:
- filtered_symbols.extend(symbols)
- grouped = self._CreateTransformed(
+ target_list = after_syms if include_singles else filtered_symbols
+ if count == 1:
+ target_list.append(symbol_or_list)
+ else:
+ target_list.extend(symbol_or_list)
+
+ return self._CreateTransformed(
after_syms, filtered_symbols=filtered_symbols,
- section_name=self.section_name, is_sorted=False)
- return grouped
+ section_name=self.section_name)
+
+ def _Clustered(self):
+ """Returns a new SymbolGroup with some symbols moved into subgroups.
+
+ Method is private since it only ever makes sense to call it from
+ SizeInfo.symbols.
+
+ The main function of clustering is to put symbols that were broken into
+ multiple parts under a group so that they once again look like a single
+ symbol. It also groups together symbols like "** merge strings".
+
+ To view created groups:
+ Print(size_info.symbols.WhereIsGroup())
+ """
+ def cluster_func(symbol):
+ name = symbol.full_name
+ if not name:
+ # min_count=2 will ensure order is maintained while not being grouped.
+ # "&" to distinguish from real symbol names, id() to ensure uniqueness.
+ return '&' + hex(id(symbol))
+ if name.startswith('*'):
+ # "symbol gap 3" -> "symbol gaps"
+ name = re.sub(r'\s+\d+( \(.*\))?$', 's', name)
+ return name
+
+ # Use a custom factory to fill in name & template_name.
+ def group_factory(full_name, symbols):
+ sym = symbols[0]
+ if full_name.startswith('*'):
+ return self._CreateTransformed(
+ symbols, full_name=full_name, template_name=full_name,
+ name=full_name, section_name=sym.section_name)
+ return self._CreateTransformed(
+ symbols, full_name=full_name, template_name=sym.template_name,
+ name=sym.name, section_name=sym.section_name)
+
+ # A full second faster to cluster per-section. Plus, don't need create
+ # (section_name, name) tuples in cluster_func.
+ ret = []
+ for section in self.GroupedBySectionName():
+ ret.extend(section.GroupedBy(
+ cluster_func, min_count=2, group_factory=group_factory))
+
+ return self._CreateTransformed(ret)
def GroupedBySectionName(self):
return self.GroupedBy(lambda s: s.section_name)
« no previous file with comments | « tools/binary_size/libsupersize/integration_test.py ('k') | tools/binary_size/libsupersize/testdata/Archive.golden » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698