diff --git a/tools/binary_size/libsupersize/archive.py b/tools/binary_size/libsupersize/archive.py index b1da8c7fec1351..e5efbeca5dfbf6 100644 --- a/tools/binary_size/libsupersize/archive.py +++ b/tools/binary_size/libsupersize/archive.py @@ -725,9 +725,9 @@ def _ExtendSectionRange(section_range_by_name, section_name, delta_size): section_range_by_name[section_name] = (prev_address, prev_size + delta_size) -def CreateMetadata(map_path, elf_path, apk_path, minimal_apks_path, - tool_prefix, output_directory, linker_name): - """Creates metadata dict. +def CreateMetadata(map_path, elf_path, apk_path, minimal_apks_path, tool_prefix, + output_directory, linker_name, build_config): + """Creates metadata dict while updating |build_config|. Args: map_path: Path to the linker .map(.gz) file to parse. @@ -738,6 +738,8 @@ def CreateMetadata(map_path, elf_path, apk_path, minimal_apks_path, tool_prefix: Prefix for c++filt & nm. output_directory: Build output directory. linker_name: A coded linker name (see linker_map_parser.py). + builg_config: Common build configurations to update or to undergo + consistency checks. Returns: A dict mapping string costants to values, or None if empty. Performs @@ -748,21 +750,31 @@ def CreateMetadata(map_path, elf_path, apk_path, minimal_apks_path, """ assert not (apk_path and minimal_apks_path) logging.debug('Constructing metadata') + + def update_build_config(key, value): + if key in build_config: + old_value = build_config[key] + if value != old_value: + raise ValueError('Inconsistent {}: {} (was {})'.format( + key, value, old_value)) + else: + build_config[key] = value + metadata = {} if output_directory: shorten_path = lambda path: os.path.relpath(path, output_directory) gn_args = _ParseGnArgs(os.path.join(output_directory, 'args.gn')) - metadata[models.METADATA_GN_ARGS] = gn_args + update_build_config(models.BUILD_CONFIG_GN_ARGS, gn_args) else: shorten_path = os.path.basename if tool_prefix: relative_tool_prefix = path_util.ToToolsSrcRootRelative(tool_prefix) - metadata[models.METADATA_TOOL_PREFIX] = relative_tool_prefix + update_build_config(models.BUILD_CONFIG_TOOL_PREFIX, relative_tool_prefix) if linker_name: - metadata[models.METADATA_LINKER_NAME] = linker_name + update_build_config(models.BUILD_CONFIG_LINKER_NAME, linker_name) # Deduce GIT revision. path_candidates = [elf_path, apk_path, minimal_apks_path] @@ -774,8 +786,7 @@ def CreateMetadata(map_path, elf_path, apk_path, minimal_apks_path, if dirname: git_rev = _DetectGitRevision(dirname) if git_rev: - metadata[models.METADATA_GIT_REVISION] = git_rev - break + update_build_config(models.BUILD_CONFIG_GIT_REVISION, git_rev) if elf_path: metadata[models.METADATA_ELF_FILENAME] = shorten_path(elf_path) @@ -1405,6 +1416,7 @@ def _AddUnattributedSectionSymbols(raw_symbols, section_ranges): def CreateSectionSizesAndSymbols(knobs=None, opts=None, + metadata=None, map_path=None, tool_prefix=None, output_directory=None, @@ -1413,7 +1425,6 @@ def CreateSectionSizesAndSymbols(knobs=None, mapping_path=None, resources_pathmap_path=None, track_string_literals=True, - metadata=None, apk_so_path=None, pak_files=None, pak_info_file=None, @@ -1424,6 +1435,7 @@ def CreateSectionSizesAndSymbols(knobs=None, Args: knobs: Instance of SectionSizeKnobs. opts: Instance of ContainerArchiveOptions. + metadata: Metadata dict from CreateMetadata(). map_path: Path to the linker .map(.gz) file to parse. tool_prefix: Prefix for c++filt & nm (required). output_directory: Build output directory. If None, source_paths and symbol @@ -1436,7 +1448,6 @@ def CreateSectionSizesAndSymbols(knobs=None, resource paths to shortened resource paths. track_string_literals: Whether to break down "** merge string" sections into smaller symbols (requires output_directory). - metadata: Metadata dict from CreateMetadata(). apk_so_path: Path to an .so file within an APK file. pak_files: List of paths to .pak files. pak_info_file: Path to a .pak.info file. @@ -1600,7 +1611,8 @@ def CreateSectionSizesAndSymbols(knobs=None, return section_sizes, raw_symbols -def CreateSizeInfo(section_sizes_list, +def CreateSizeInfo(build_config, + section_sizes_list, raw_symbols_list, metadata_list, normalize_names=True): @@ -1621,7 +1633,10 @@ def CreateSizeInfo(section_sizes_list, raw_symbols = raw_symbols_list[0] metadata = metadata_list[0] - return models.SizeInfo(section_sizes, raw_symbols, metadata=metadata) + return models.SizeInfo(build_config, + section_sizes, + raw_symbols, + metadata=metadata) def _DetectGitRevision(directory): @@ -1927,7 +1942,6 @@ def _Inner(sub_args, apk_prefix, apk_path): apk_so_path, elf_path, map_path, resources_pathmap_path, linker_name, size_info_prefix) - # Process each container. # If needed, extract .apk file to a temp file and process that instead. if args.minimal_apks_file: with zip_util.UnzipToTemp(args.minimal_apks_file, _APKS_MAIN_APK) as temp: @@ -1958,6 +1972,7 @@ def Run(args, on_config_error): knobs = SectionSizeKnobs() + build_config = {} metadata_list = [] section_sizes_list = [] raw_symbols_list = [] @@ -1969,10 +1984,11 @@ def Run(args, on_config_error): # may be an extracted temporary file. metadata = CreateMetadata(map_path, elf_path, args.apk_file, args.minimal_apks_file, tool_prefix, - output_directory, linker_name) + output_directory, linker_name, build_config) section_sizes, raw_symbols = CreateSectionSizesAndSymbols( knobs=knobs, opts=opts, + metadata=metadata, map_path=map_path, tool_prefix=tool_prefix, elf_path=elf_path, @@ -1981,7 +1997,6 @@ def Run(args, on_config_error): output_directory=output_directory, resources_pathmap_path=resources_pathmap_path, track_string_literals=args.track_string_literals, - metadata=metadata, apk_so_path=apk_so_path, pak_files=args.pak_file, pak_info_file=args.pak_info_file, @@ -1992,18 +2007,18 @@ def Run(args, on_config_error): section_sizes_list.append(section_sizes) raw_symbols_list.append(raw_symbols) - size_info = CreateSizeInfo( - section_sizes_list, - raw_symbols_list, - metadata_list, - normalize_names=False) + size_info = CreateSizeInfo(build_config, + section_sizes_list, + raw_symbols_list, + metadata_list, + normalize_names=False) if logging.getLogger().isEnabledFor(logging.DEBUG): for line in describe.DescribeSizeInfoCoverage(size_info): logging.debug(line) logging.info('Recorded info for %d symbols', len(size_info.raw_symbols)) - logging.info('Recording metadata: \n %s', '\n '.join( - describe.DescribeMetadata(size_info.metadata))) + logging.info('Recording metadata: \n %s', + '\n '.join(describe.DescribeDict(size_info.metadata))) logging.info('Saving result to %s', args.size_file) file_format.SaveSizeInfo( diff --git a/tools/binary_size/libsupersize/console.py b/tools/binary_size/libsupersize/console.py index f8ef12e0b6269c..5cef3ecd5b87a9 100644 --- a/tools/binary_size/libsupersize/console.py +++ b/tools/binary_size/libsupersize/console.py @@ -126,8 +126,7 @@ def _ReadStringLiterals(self, thing=None, all_rodata=False, elf_path=None): return [] size_info = self._SizeInfoForSymbol(first_sym) tool_prefix = self._ToolPrefixForSymbol(size_info) - elf_path = self._ElfPathForSymbol( - size_info, tool_prefix, elf_path) + elf_path = self._ElfPathForSymbol(size_info, tool_prefix, elf_path) return string_extract.ReadStringLiterals( thing, elf_path, tool_prefix, all_rodata=all_rodata) @@ -243,7 +242,8 @@ def _CsvFunc(self, obj=None, verbose=False, use_pager=None, to_file=None): def _ToolPrefixForSymbol(self, size_info): tool_prefix = self._tool_prefix_finder.Tentative() - orig_tool_prefix = size_info.metadata.get(models.METADATA_TOOL_PREFIX) + orig_tool_prefix = size_info.build_config.get( + models.BUILD_CONFIG_TOOL_PREFIX) if orig_tool_prefix: orig_tool_prefix = path_util.FromToolsSrcRootRelative(orig_tool_prefix) if os.path.exists(path_util.GetObjDumpPath(orig_tool_prefix)): @@ -489,7 +489,7 @@ def Run(args, on_config_error): output_directory_finder = path_util.OutputDirectoryFinder( value=args.output_directory, any_path_within_output_directory=args.inputs[0]) - linker_name = size_infos[-1].metadata.get(models.METADATA_LINKER_NAME) + linker_name = size_infos[-1].build_config.get(models.BUILD_CONFIG_LINKER_NAME) tool_prefix_finder = path_util.ToolPrefixFinder( value=args.tool_prefix, output_directory_finder=output_directory_finder, diff --git a/tools/binary_size/libsupersize/describe.py b/tools/binary_size/libsupersize/describe.py index 83eb04ddb6ab17..2e5e93f105d073 100644 --- a/tools/binary_size/libsupersize/describe.py +++ b/tools/binary_size/libsupersize/describe.py @@ -489,27 +489,28 @@ def _DescribeDeltaSymbolGroup(self, delta_group): group_desc = self._DescribeSymbolGroup(delta_group) return itertools.chain(diff_summary_desc, path_delta_desc, group_desc) - def _DescribeDeltaSizeInfo(self, diff): - common_metadata = { - k: v - for k, v in diff.before.metadata.items() - if diff.after.metadata.get(k) == v - } - before_metadata = { + def _DescribeDeltaDict(self, data_name, before_dict, after_dict): + common_items = { k: v - for k, v in diff.before.metadata.items() if k not in common_metadata + for k, v in before_dict.items() if after_dict.get(k) == v } - after_metadata = { + before_items = { k: v - for k, v in diff.after.metadata.items() if k not in common_metadata + for k, v in before_dict.items() if k not in common_items } - metadata_desc = itertools.chain( - ('Common Metadata:',), - (' %s' % line for line in DescribeMetadata(common_metadata)), - ('Old Metadata:',), - (' %s' % line for line in DescribeMetadata(before_metadata)), - ('New Metadata:',), - (' %s' % line for line in DescribeMetadata(after_metadata))) + after_items = {k: v for k, v in after_dict.items() if k not in common_items} + return itertools.chain( + ('Common %s:' % data_name, ), (' %s' % line + for line in DescribeDict(common_items)), + ('Old %s:' % data_name, ), (' %s' % line + for line in DescribeDict(before_items)), + ('New %s:' % data_name, ), (' %s' % line + for line in DescribeDict(after_items))) + + def _DescribeDeltaSizeInfo(self, diff): + metadata_desc = self._DescribeDeltaDict('Metadata', + diff.before.metadata_legacy, + diff.after.metadata_legacy) unsummed_sections, summed_sections = diff.ClassifySections() section_desc = self._DescribeSectionSizes(unsummed_sections, summed_sections, @@ -518,9 +519,10 @@ def _DescribeDeltaSizeInfo(self, diff): return itertools.chain(metadata_desc, section_desc, ('',), group_desc) def _DescribeSizeInfo(self, size_info): + # Support legacy output by reporting |build_config| as part of metadata. metadata_desc = itertools.chain( - ('Metadata:',), - (' %s' % line for line in DescribeMetadata(size_info.metadata))) + ('Metadata:', ), + (' %s' % line for line in DescribeDict(size_info.metadata_legacy))) unsummed_sections, summed_sections = size_info.ClassifySections() section_desc = self._DescribeSectionSizes(unsummed_sections, summed_sections, @@ -744,16 +746,25 @@ def _UtcToLocal(utc): return utc + offset -def DescribeMetadata(metadata): - display_dict = metadata.copy() - timestamp = display_dict.get(models.METADATA_ELF_MTIME) - if timestamp: - timestamp_obj = datetime.datetime.utcfromtimestamp(timestamp) - display_dict[models.METADATA_ELF_MTIME] = ( - _UtcToLocal(timestamp_obj).strftime('%Y-%m-%d %H:%M:%S')) - gn_args = display_dict.get(models.METADATA_GN_ARGS) - if gn_args: - display_dict[models.METADATA_GN_ARGS] = ' '.join(gn_args) +def DescribeDict(input_dict): + display_dict = {} + for k, v in input_dict.items(): + if k == models.METADATA_ELF_MTIME: + timestamp_obj = datetime.datetime.utcfromtimestamp(v) + display_dict[k] = ( + _UtcToLocal(timestamp_obj).strftime('%Y-%m-%d %H:%M:%S')) + elif isinstance(v, str): + display_dict[k] = v + elif isinstance(v, list): + if v: + if isinstance(v[0], str): + display_dict[k] = ' '.join(str(t) for t in v) + else: + display_dict[k] = repr(v) + else: + display_dict[k] = '' + else: + display_dict[k] = repr(v) return sorted('%s=%s' % t for t in display_dict.items()) diff --git a/tools/binary_size/libsupersize/diff_test.py b/tools/binary_size/libsupersize/diff_test.py index 80a4d8996e66d2..0d641c4c6ecb1f 100755 --- a/tools/binary_size/libsupersize/diff_test.py +++ b/tools/binary_size/libsupersize/diff_test.py @@ -31,6 +31,7 @@ def _SetName(symbol, full_name, name=None): def _CreateSizeInfo(aliases=None): + build_config = {} section_sizes = {'.text': 100, '.bss': 40} TEXT = models.SECTION_TEXT symbols = [ @@ -46,7 +47,7 @@ def _CreateSizeInfo(aliases=None): syms = symbols[tup[0]:tup[1]] for sym in syms: sym.aliases = syms - return models.SizeInfo(section_sizes, symbols) + return models.SizeInfo(build_config, section_sizes, symbols) class DiffTest(unittest.TestCase): @@ -55,27 +56,27 @@ def testIdentity(self): size_info1 = _CreateSizeInfo() size_info2 = _CreateSizeInfo() d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) - self.assertEquals(0, d.raw_symbols.padding) + self.assertEqual((0, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) + self.assertEqual(0, d.raw_symbols.padding) def testSimple_Add(self): size_info1 = _CreateSizeInfo() size_info2 = _CreateSizeInfo() size_info1.raw_symbols -= [size_info1.raw_symbols[0]] d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 1, 0), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(10, d.raw_symbols.size) - self.assertEquals(0, d.raw_symbols.padding) + self.assertEqual((0, 1, 0), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(10, d.raw_symbols.size) + self.assertEqual(0, d.raw_symbols.padding) def testSimple_Delete(self): size_info1 = _CreateSizeInfo() size_info2 = _CreateSizeInfo() size_info2.raw_symbols -= [size_info2.raw_symbols[0]] d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 0, 1), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(-10, d.raw_symbols.size) - self.assertEquals(0, d.raw_symbols.padding) + self.assertEqual((0, 0, 1), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(-10, d.raw_symbols.size) + self.assertEqual(0, d.raw_symbols.padding) def testSimple_Change(self): size_info1 = _CreateSizeInfo() @@ -84,9 +85,9 @@ def testSimple_Change(self): size_info2.raw_symbols[0].padding += 20 size_info2.raw_symbols[-1].size += 11 d = diff.Diff(size_info1, size_info2) - self.assertEquals((2, 1, 0), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(22, d.raw_symbols.size) - self.assertEquals(20, d.raw_symbols.padding) + self.assertEqual((2, 1, 0), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(22, d.raw_symbols.size) + self.assertEqual(20, d.raw_symbols.padding) def testDontMatchAcrossSections(self): size_info1 = _CreateSizeInfo() @@ -98,32 +99,32 @@ def testDontMatchAcrossSections(self): _MakeSym(models.SECTION_RODATA, 11, 'asdf', name='Hello'), ] d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 1, 1), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) + self.assertEqual((0, 1, 1), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) def testAliases_Remove(self): size_info1 = _CreateSizeInfo(aliases=[(0, 3)]) size_info2 = _CreateSizeInfo(aliases=[(0, 2)]) d = diff.Diff(size_info1, size_info2) # Aliases cause all sizes to change. - self.assertEquals((3, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) + self.assertEqual((3, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) def testAliases_Add(self): size_info1 = _CreateSizeInfo(aliases=[(0, 2)]) size_info2 = _CreateSizeInfo(aliases=[(0, 3)]) d = diff.Diff(size_info1, size_info2) # Aliases cause all sizes to change. - self.assertEquals((3, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) + self.assertEqual((3, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) def testAliases_ChangeGroup(self): size_info1 = _CreateSizeInfo(aliases=[(0, 2), (2, 5)]) size_info2 = _CreateSizeInfo(aliases=[(0, 3), (3, 5)]) d = diff.Diff(size_info1, size_info2) # Aliases cause all sizes to change. - self.assertEquals((4, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) + self.assertEqual((4, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) def testStarSymbolNormalization(self): size_info1 = _CreateSizeInfo() @@ -131,8 +132,8 @@ def testStarSymbolNormalization(self): size_info2 = _CreateSizeInfo() _SetName(size_info2.raw_symbols[0], '* symbol gap 2 (end of section)') d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) + self.assertEqual((0, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) def testNumberNormalization(self): TEXT = models.SECTION_TEXT @@ -151,8 +152,8 @@ def testNumberNormalization(self): _MakeSym(TEXT, 44, 'a', name='.L.ref.tmp.137'), ] d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) + self.assertEqual((0, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) def testChangedParams(self): # Ensure that params changes match up so long as path doesn't change. @@ -163,8 +164,8 @@ def testChangedParams(self): size_info2.raw_symbols[0].full_name = 'Foo(bool)' size_info2.raw_symbols[0].name = 'Foo' d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) + self.assertEqual((0, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) def testChangedPaths_Native(self): # Ensure that non-globally-unique symbols are not matched when path changes. @@ -172,8 +173,8 @@ def testChangedPaths_Native(self): size_info2 = _CreateSizeInfo() size_info2.raw_symbols[1].object_path = 'asdf' d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 1, 1), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) + self.assertEqual((0, 1, 1), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) def testChangedPaths_StringLiterals(self): # Ensure that string literals are not matched up. @@ -183,8 +184,8 @@ def testChangedPaths_StringLiterals(self): size_info2.raw_symbols[0].full_name = models.STRING_LITERAL_NAME size_info2.raw_symbols[0].object_path = 'asdf' d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 1, 1), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) + self.assertEqual((0, 1, 1), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) def testChangedPaths_Java(self): # Ensure that Java symbols are matched up. @@ -192,8 +193,8 @@ def testChangedPaths_Java(self): size_info2 = _CreateSizeInfo() size_info2.raw_symbols[0].object_path = 'asdf' d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) + self.assertEqual((0, 0, 0), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) def testChangedPaths_ChangedParams(self): # Ensure that path changes are not matched when params also change. @@ -205,8 +206,8 @@ def testChangedPaths_ChangedParams(self): size_info2.raw_symbols[0].name = 'Foo' size_info2.raw_symbols[0].object_path = 'asdf' d = diff.Diff(size_info1, size_info2) - self.assertEquals((0, 1, 1), d.raw_symbols.CountsByDiffStatus()[1:]) - self.assertEquals(0, d.raw_symbols.size) + self.assertEqual((0, 1, 1), d.raw_symbols.CountsByDiffStatus()[1:]) + self.assertEqual(0, d.raw_symbols.size) diff --git a/tools/binary_size/libsupersize/file_format.py b/tools/binary_size/libsupersize/file_format.py index 20b5ec11383ab6..28120dba66655f 100644 --- a/tools/binary_size/libsupersize/file_format.py +++ b/tools/binary_size/libsupersize/file_format.py @@ -253,17 +253,25 @@ def _SaveSizeInfoToFile(size_info, w.WriteLine(_SERIALIZATION_VERSION) # JSON header fields fields = { - 'metadata': size_info.metadata, 'section_sizes': size_info.section_sizes, 'has_components': True, 'has_padding': include_padding, } + # Preserve old format: Combine build_config and metadata. + metadata = size_info.metadata + for key in models.BUILD_CONFIG_KEYS: + if key in size_info.build_config: + if not metadata: + metadata = {} + metadata[key] = size_info.build_config[key] + fields['metadata'] = metadata + fields_str = json.dumps(fields, indent=2, sort_keys=True) w.WriteLine(str(len(fields_str))) w.WriteLine(fields_str) w.LogSize('header') # For libchrome: 570 bytes. - # Store a single copy of all paths and have them referenced by index. + # Store a single copy of all paths and reference them by index. unique_path_tuples = sorted( set((s.object_path, s.source_path) for s in raw_symbols)) path_tuples = {tup: i for i, tup in enumerate(unique_path_tuples)} @@ -381,7 +389,16 @@ def _LoadSizeInfoFromFile(file_obj, size_path): fields = json.loads(json_str) section_sizes = fields['section_sizes'] + + # Parse old format, but separate data into build_config and metadata. + build_config = {} metadata = fields.get('metadata') + if metadata: + for key in models.BUILD_CONFIG_KEYS: + if key in metadata: + build_config[key] = metadata[key] + del metadata[key] + has_components = fields.get('has_components', False) has_padding = fields.get('has_padding', False) @@ -505,7 +522,10 @@ def read_numeric(delta=False): if not has_padding: CalculatePadding(raw_symbols) - return models.SizeInfo(section_sizes, raw_symbols, metadata=metadata, + return models.SizeInfo(build_config, + section_sizes, + raw_symbols, + metadata=metadata, size_path=size_path) diff --git a/tools/binary_size/libsupersize/integration_test.py b/tools/binary_size/libsupersize/integration_test.py index 805ea14945aee1..4cf9f22dfa0505 100755 --- a/tools/binary_size/libsupersize/integration_test.py +++ b/tools/binary_size/libsupersize/integration_test.py @@ -210,25 +210,27 @@ def _CloneSizeInfo(self, use_output_directory=True, use_elf=True, pak_info_file = _TEST_PAK_INFO_PATH linker_name = 'gold' with _AddMocksToPath(): + build_config = {} metadata = archive.CreateMetadata(_TEST_MAP_PATH, elf_path, apk_path, minimal_apks_path, _TEST_TOOL_PREFIX, - output_directory, linker_name) + output_directory, linker_name, + build_config) section_sizes, raw_symbols = archive.CreateSectionSizesAndSymbols( knobs=knobs, opts=opts, + metadata=metadata, map_path=_TEST_MAP_PATH, tool_prefix=_TEST_TOOL_PREFIX, - elf_path=elf_path, output_directory=output_directory, + elf_path=elf_path, apk_path=apk_path or extracted_minimal_apk_path, apk_so_path=apk_so_path, - metadata=metadata, pak_files=pak_files, pak_info_file=pak_info_file, linker_name=linker_name, size_info_prefix=size_info_prefix) IntegrationTest.cached_size_info[cache_key] = archive.CreateSizeInfo( - [section_sizes], [raw_symbols], [metadata]) + build_config, [section_sizes], [raw_symbols], [metadata]) return copy.deepcopy(IntegrationTest.cached_size_info[cache_key]) def _DoArchive(self, @@ -301,11 +303,15 @@ def _DoArchiveTest(self, sym_strs = (repr(sym) for sym in size_info.symbols) stats = describe.DescribeSizeInfoCoverage(size_info) - if size_info.metadata: - metadata = describe.DescribeMetadata(size_info.metadata) + # Merge the its metadata into build_config. + merged_data = size_info.build_config.copy() + for k, v in size_info.metadata.items(): + merged_data[k] = v + if merged_data: + merged_data_desc = describe.DescribeDict(merged_data) else: - metadata = [] - return itertools.chain(metadata, stats, sym_strs) + merged_data_desc = [] + return itertools.chain(merged_data_desc, stats, sym_strs) @_CompareWithGolden() def test_Archive(self): @@ -395,8 +401,9 @@ def test_Idempotent(self): def test_Diff_Basic(self): size_info1 = self._CloneSizeInfo(use_elf=False, use_pak=True) size_info2 = self._CloneSizeInfo(use_elf=False, use_pak=True) - size_info1.metadata = {"foo": 1, "bar": [1,2,3], "baz": "yes"} - size_info2.metadata = {"foo": 1, "bar": [1,3], "baz": "yes"} + size_info2.build_config['git_revision'] = 'xyz789' + size_info1.metadata = {"foo": 1, "bar": [1, 2, 3], "baz": "yes"} + size_info2.metadata = {"foo": 1, "bar": [1, 3], "baz": "yes"} size_info1.raw_symbols -= size_info1.raw_symbols[:2] size_info2.raw_symbols -= size_info2.raw_symbols[-3:] diff --git a/tools/binary_size/libsupersize/models.py b/tools/binary_size/libsupersize/models.py index b680274b8c2330..9e7053a9ea99e5 100644 --- a/tools/binary_size/libsupersize/models.py +++ b/tools/binary_size/libsupersize/models.py @@ -37,7 +37,18 @@ import match_util -METADATA_GIT_REVISION = 'git_revision' +BUILD_CONFIG_GIT_REVISION = 'git_revision' +BUILD_CONFIG_GN_ARGS = 'gn_args' +BUILD_CONFIG_LINKER_NAME = 'linker_name' +BUILD_CONFIG_TOOL_PREFIX = 'tool_prefix' # Path relative to SRC_ROOT. + +BUILD_CONFIG_KEYS = ( + BUILD_CONFIG_GIT_REVISION, + BUILD_CONFIG_GN_ARGS, + BUILD_CONFIG_LINKER_NAME, + BUILD_CONFIG_TOOL_PREFIX, +) + METADATA_APK_FILENAME = 'apk_file_name' # Path relative to output_directory. METADATA_APK_SIZE = 'apk_size' # File size of apk in bytes. METADATA_MAP_FILENAME = 'map_file_name' # Path relative to output_directory. @@ -46,9 +57,6 @@ METADATA_ELF_MTIME = 'elf_mtime' # int timestamp in utc. METADATA_ELF_BUILD_ID = 'elf_build_id' METADATA_ELF_RELOCATIONS_COUNT = 'elf_relocations_count' -METADATA_GN_ARGS = 'gn_args' -METADATA_LINKER_NAME = 'linker_name' -METADATA_TOOL_PREFIX = 'tool_prefix' # Path relative to SRC_ROOT. # New sections should also be added to the SuperSize UI. SECTION_BSS = '.bss' @@ -195,6 +203,7 @@ class BaseSizeInfo(object): """Base class for SizeInfo and DeltaSizeInfo. Fields: + build_config: A dict of build configurations. section_sizes: A dict of section_name -> size. raw_symbols: A SymbolGroup containing all top-level symbols (no groups). symbols: A SymbolGroup of all symbols, where symbols have been @@ -205,6 +214,7 @@ class BaseSizeInfo(object): pak_symbols: Subset of |symbols| that are from pak files. """ __slots__ = ( + 'build_config', 'section_sizes', 'raw_symbols', '_symbols', @@ -213,9 +223,10 @@ class BaseSizeInfo(object): '_classified_sections', ) - def __init__(self, section_sizes, raw_symbols, symbols=None): + def __init__(self, build_config, section_sizes, raw_symbols, symbols=None): if isinstance(raw_symbols, list): raw_symbols = SymbolGroup(raw_symbols) + self.build_config = build_config self.section_sizes = section_sizes # E.g. {SECTION_TEXT: 0} self.raw_symbols = raw_symbols self._symbols = symbols @@ -267,12 +278,29 @@ class SizeInfo(BaseSizeInfo): 'size_path', ) - def __init__(self, section_sizes, raw_symbols, metadata=None, symbols=None, + def __init__(self, + build_config, + section_sizes, + raw_symbols, + metadata=None, + symbols=None, size_path=None): - super(SizeInfo, self).__init__(section_sizes, raw_symbols, symbols=symbols) + super(SizeInfo, self).__init__(build_config, + section_sizes, + raw_symbols, + symbols=symbols) self.metadata = metadata or {} self.size_path = size_path + @property + def metadata_legacy(self): + """Returns |metadata| fused with |build_config|.""" + metadata = self.metadata.copy() + for k, v in self.build_config.items(): + assert k not in metadata + metadata[k] = v + return metadata + class DeltaSizeInfo(BaseSizeInfo): """What you get when you Diff() two SizeInfo objects. @@ -287,7 +315,7 @@ class DeltaSizeInfo(BaseSizeInfo): ) def __init__(self, before, after, section_sizes, raw_symbols): - super(DeltaSizeInfo, self).__init__(section_sizes, raw_symbols) + super(DeltaSizeInfo, self).__init__(None, section_sizes, raw_symbols) self.before = before self.after = after diff --git a/tools/binary_size/libsupersize/testdata/Console.golden b/tools/binary_size/libsupersize/testdata/Console.golden index adbbf2c009a676..21052a86f09fa2 100644 --- a/tools/binary_size/libsupersize/testdata/Console.golden +++ b/tools/binary_size/libsupersize/testdata/Console.golden @@ -1,12 +1,12 @@ ******************************************************************************** Entering interactive Python shell. Quick reference: -SizeInfo: ClassifySections, metadata, native_symbols, pak_symbols, raw_symbols, section_sizes, size_path, symbols +SizeInfo: ClassifySections, build_config, metadata, metadata_legacy, native_symbols, pak_symbols, raw_symbols, section_sizes, size_path, symbols Symbol: FlagsString, IsBss, IsDelta, IsDex, IsGeneratedByToolchain, IsGroup, IsNameUnique, IsNative, IsOther, IsOverhead, IsPak, IsStringLiteral, IterLeafSymbols, SetName, address, aliases, component, end_address, flags, full_name, generated_source, is_anonymous, name, num_aliases, object_path, padding, padding_pss, pss, pss_without_padding, section, section_name, size, size_without_padding, source_path, template_name SymbolGroup (extends Symbol): CountUniqueSymbols, Filter, GroupedBy, GroupedByAliases, GroupedByComponent, GroupedByFullName, GroupedByName, GroupedByPath, GroupedBySectionName, Inverted, IterUniqueSymbols, Sorted, SortedByAddress, SortedByCount, SortedByName, WhereAddressInRange, WhereComponentMatches, WhereFullNameMatches, WhereGeneratedByToolchain, WhereHasAnyAttribution, WhereHasComponent, WhereHasFlag, WhereHasPath, WhereInSection, WhereIsDex, WhereIsGroup, WhereIsNative, WhereIsPak, WhereIsTemplate, WhereMatches, WhereNameMatches, WhereObjectPathMatches, WherePathMatches, WherePssBiggerThan, WhereSizeBiggerThan, WhereSourceIsGenerated, WhereSourcePathMatches, WhereTemplateNameMatches, index, is_default_sorted -DeltaSizeInfo: ClassifySections, after, before, native_symbols, pak_symbols, raw_symbols, section_sizes, symbols +DeltaSizeInfo: ClassifySections, after, before, build_config, native_symbols, pak_symbols, raw_symbols, section_sizes, symbols DeltaSymbol (extends Symbol): after_symbol, before_symbol, diff_status DeltaSymbolGroup (extends SymbolGroup): CountsByDiffStatus, WhereDiffStatusIs, diff_status diff --git a/tools/binary_size/libsupersize/testdata/Diff_Basic.golden b/tools/binary_size/libsupersize/testdata/Diff_Basic.golden index f7a9e058226837..216bd9713fa6ef 100644 --- a/tools/binary_size/libsupersize/testdata/Diff_Basic.golden +++ b/tools/binary_size/libsupersize/testdata/Diff_Basic.golden @@ -1,10 +1,15 @@ Common Metadata: baz=yes foo=1 + gn_args=var1=true var2="foo" + linker_name=gold + tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/ Old Metadata: bar=[1, 2, 3] + git_revision=abc123 New Metadata: bar=[1, 3] + git_revision=xyz789 Section Sizes (Total=0 bytes (0 bytes)): .bss: 0 bytes (0 bytes) (not included in totals)