tools/binary_size/libsupersize/file_format.py
def _SaveSizeInfoToFile(size_info,
                        file_obj,
                        include_padding=False,
                        sparse_symbols=None):
  """Saves size info to a .size file.

  Args:
    size_info: Data to write to the file
    file_obj: File opened for writing.
    include_padding: Whether to save padding data, useful if adding a subset of
      symbols.
    sparse_symbols: If present, only save these symbols to the file.
  """
  if sparse_symbols is not None:
    # Any aliases of sparse symbols must also be included, or else file
    # parsing will attribute symbols that happen to follow an incomplete alias
    # group to that alias group.
    raw_symbols = _ExpandSparseSymbols(sparse_symbols)
  else:
    raw_symbols = size_info.raw_symbols

  num_containers = len(size_info.containers)
  has_multi_containers = (num_containers > 1)

  file_obj.write(_COMMON_HEADER)
  if has_multi_containers:
    file_obj.write(_SIZE_HEADER_MULTI_CONTAINER)
  else:
    file_obj.write(_SIZE_HEADER_SINGLE_CONTAINER)

  # JSON header fields
  fields = {
      'has_components': True,
      'has_padding': include_padding,
  }

  if has_multi_containers:
    # Write using new format.
    assert len(set(c.name for c in size_info.containers)) == num_containers, (
        'Container names must be distinct.')
    fields['build_config'] = size_info.build_config
    fields['containers'] = [{
        'name': c.name,
        'metadata': c.metadata,
        'section_sizes': c.section_sizes,
    } for c in size_info.containers]
  else:
    # Write using old format.
    fields['metadata'] = size_info.metadata_legacy
    fields['section_sizes'] = size_info.containers[0].section_sizes

  fields_str = json.dumps(fields, indent=2, sort_keys=True)

  w = _Writer(file_obj)
  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 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)}
  w.WriteLine(str(len(unique_path_tuples)))
  for pair in unique_path_tuples:
    w.WriteLine('%s\t%s' % pair)
  w.LogSize('paths')  # For libchrome, adds 200kb.

  # Store a single copy of all components and have them referenced by index.
  unique_components = sorted(set(s.component for s in raw_symbols))
  components = {comp: i for i, comp in enumerate(unique_components)}
  w.WriteLine(str(len(unique_components)))
  for comp in unique_components:
    w.WriteLine(comp)
  w.LogSize('components')

  # Symbol counts by "segments", defined as (container, section) tuples.
  symbol_group_by_segment = raw_symbols.GroupedByContainerAndSectionName()
  if has_multi_containers:
    container_name_to_index = {
        c.name: i
        for i, c in enumerate(size_info.containers)
    }
    w.WriteLine('\t'.join('<%d>%s' %
                          (container_name_to_index[g.name[0]], g.name[1])
                          for g in symbol_group_by_segment))
  else:
    w.WriteLine('\t'.join(g.name[1] for g in symbol_group_by_segment))
  w.WriteLine('\t'.join(str(len(g)) for g in symbol_group_by_segment))

  def gen_delta(gen, prev_value=0):
    """Adapts a generator of numbers to deltas."""
    for value in gen:
      yield value - prev_value
      prev_value = value

  def write_groups(func, delta=False):
    """Write func(symbol) for each symbol in each symbol group.

    Each line written represents one symbol group in |symbol_group_by_segment|.
    The values in each line are space separated and are the result of calling
    |func| with the Nth symbol in the group.

    If |delta| is True, the differences in values are written instead."""
    for group in symbol_group_by_segment:
      gen = map(func, group)
      w.WriteNumberList(gen_delta(gen) if delta else gen)

  write_groups(lambda s: s.address, delta=True)
  w.LogSize('addresses')  # For libchrome, adds 300kb.

  write_groups(lambda s: s.size if s.IsOverhead() else s.size_without_padding)
  w.LogSize('sizes')  # For libchrome, adds 300kb

  # Padding for non-padding-only symbols is recalculated from addresses on
  # load, so we only need to write it if we're writing a subset of symbols.
  if include_padding:
    write_groups(lambda s: s.padding)
    w.LogSize('paddings')  # For libchrome, adds 300kb

  write_groups(
      lambda s: path_tuples[(s.object_path, s.source_path)], delta=True)
  w.LogSize('path indices')  # For libchrome: adds 125kb.

  write_groups(lambda s: components[s.component], delta=True)
  w.LogSize('component indices')

  prev_aliases = None
  for group in symbol_group_by_segment:
    for symbol in group:
      w.WriteString(symbol.full_name)
      if symbol.aliases and symbol.aliases is not prev_aliases:
        w.WriteString('\t0%x' % symbol.num_aliases)
      prev_aliases = symbol.aliases
      if symbol.flags:
        w.WriteString('\t%x' % symbol.flags)
      w.WriteBytes(b'\n')
  w.LogSize('names (final)')  # For libchrome: adds 3.5mb.
Saves size info to a .size file.

  Args:
    size_info: Data to write to the file
    file_obj: File opened for writing.
    include_padding: Whether to save padding data, useful if adding a subset of
      symbols.
    sparse_symbols: If present, only save these symbols to the file.
  
Saves size info to a .size file.
Saves size info to a . size file .
def _SaveSizeInfoToFile(size_info,
                        file_obj,
                        include_padding=False,
                        sparse_symbols=None):
  if sparse_symbols is not None:
    raw_symbols = _ExpandSparseSymbols(sparse_symbols)
  else:
    raw_symbols = size_info.raw_symbols
  num_containers = len(size_info.containers)
  has_multi_containers = (num_containers > 1)
  file_obj.write(_COMMON_HEADER)
  if has_multi_containers:
    file_obj.write(_SIZE_HEADER_MULTI_CONTAINER)
  else:
    file_obj.write(_SIZE_HEADER_SINGLE_CONTAINER)
  fields = {
      'has_components': True,
      'has_padding': include_padding,
  }
  if has_multi_containers:
    assert len(set(c.name for c in size_info.containers)) == num_containers, (
        'Container names must be distinct.')
    fields['build_config'] = size_info.build_config
    fields['containers'] = [{
        'name': c.name,
        'metadata': c.metadata,
        'section_sizes': c.section_sizes,
    } for c in size_info.containers]
  else:
    fields['metadata'] = size_info.metadata_legacy
    fields['section_sizes'] = size_info.containers[0].section_sizes
  fields_str = json.dumps(fields, indent=2, sort_keys=True)
  w = _Writer(file_obj)
  w.WriteLine(str(len(fields_str)))
  w.WriteLine(fields_str)
  w.LogSize('header')  
  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)}
  w.WriteLine(str(len(unique_path_tuples)))
  for pair in unique_path_tuples:
    w.WriteLine('%s\t%s' % pair)
  w.LogSize('paths')  
  unique_components = sorted(set(s.component for s in raw_symbols))
  components = {comp: i for i, comp in enumerate(unique_components)}
  w.WriteLine(str(len(unique_components)))
  for comp in unique_components:
    w.WriteLine(comp)
  w.LogSize('components')
  symbol_group_by_segment = raw_symbols.GroupedByContainerAndSectionName()
  if has_multi_containers:
    container_name_to_index = {
        c.name: i
        for i, c in enumerate(size_info.containers)
    }
    w.WriteLine('\t'.join('<%d>%s' %
                          (container_name_to_index[g.name[0]], g.name[1])
                          for g in symbol_group_by_segment))
  else:
    w.WriteLine('\t'.join(g.name[1] for g in symbol_group_by_segment))
  w.WriteLine('\t'.join(str(len(g)) for g in symbol_group_by_segment))
  def gen_delta(gen, prev_value=0):
    for value in gen:
      yield value - prev_value
      prev_value = value
  def write_groups(func, delta=False):
    for group in symbol_group_by_segment:
      gen = map(func, group)
      w.WriteNumberList(gen_delta(gen) if delta else gen)
  write_groups(lambda s: s.address, delta=True)
  w.LogSize('addresses')  
  write_groups(lambda s: s.size if s.IsOverhead() else s.size_without_padding)
  w.LogSize('sizes')  
  if include_padding:
    write_groups(lambda s: s.padding)
    w.LogSize('paddings')  
  write_groups(
      lambda s: path_tuples[(s.object_path, s.source_path)], delta=True)
  w.LogSize('path indices')  
  write_groups(lambda s: components[s.component], delta=True)
  w.LogSize('component indices')
  prev_aliases = None
  for group in symbol_group_by_segment:
    for symbol in group:
      w.WriteString(symbol.full_name)
      if symbol.aliases and symbol.aliases is not prev_aliases:
        w.WriteString('\t0%x' % symbol.num_aliases)
      prev_aliases = symbol.aliases
      if symbol.flags:
        w.WriteString('\t%x' % symbol.flags)
      w.WriteBytes(b'\n')
  w.LogSize('names (final)')  
def _SaveSizeInfoToFile ( size_info , file_obj , include_padding = False , sparse_symbols = None ) : if sparse_symbols is not None : raw_symbols = _ExpandSparseSymbols ( sparse_symbols ) else : raw_symbols = size_info . raw_symbols num_containers = len ( size_info . containers ) has_multi_containers = ( num_containers > 1 ) file_obj . write ( _COMMON_HEADER ) if has_multi_containers : file_obj . write ( _SIZE_HEADER_MULTI_CONTAINER ) else : file_obj . write ( _SIZE_HEADER_SINGLE_CONTAINER ) fields = { 'has_components' : True , 'has_padding' : include_padding , } if has_multi_containers : assert len ( set ( c . name for c in size_info . containers ) ) == num_containers , ( 'Container names must be distinct.' ) fields [ 'build_config' ] = size_info . build_config fields [ 'containers' ] = [ { 'name' : c . name , 'metadata' : c . metadata , 'section_sizes' : c . section_sizes , } for c in size_info . containers ] else : fields [ 'metadata' ] = size_info . metadata_legacy fields [ 'section_sizes' ] = size_info . containers [ 0 ] . section_sizes fields_str = json . dumps ( fields , indent = 2 , sort_keys = True ) w = _Writer ( file_obj ) w . WriteLine ( str ( len ( fields_str ) ) ) w . WriteLine ( fields_str ) w . LogSize ( 'header' ) 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 ) } w . WriteLine ( str ( len ( unique_path_tuples ) ) ) for pair in unique_path_tuples : w . WriteLine ( '%s\t%s' % pair ) w . LogSize ( 'paths' ) unique_components = sorted ( set ( s . component for s in raw_symbols ) ) components = { comp : i for i , comp in enumerate ( unique_components ) } w . WriteLine ( str ( len ( unique_components ) ) ) for comp in unique_components : w . WriteLine ( comp ) w . LogSize ( 'components' ) symbol_group_by_segment = raw_symbols . GroupedByContainerAndSectionName ( ) if has_multi_containers : container_name_to_index = { c . name : i for i , c in enumerate ( size_info . containers ) } w . WriteLine ( '\t' . join ( '<%d>%s' % ( container_name_to_index [ g . name [ 0 ] ] , g . name [ 1 ] ) for g in symbol_group_by_segment ) ) else : w . WriteLine ( '\t' . join ( g . name [ 1 ] for g in symbol_group_by_segment ) ) w . WriteLine ( '\t' . join ( str ( len ( g ) ) for g in symbol_group_by_segment ) ) def gen_delta ( gen , prev_value = 0 ) : """Adapts a generator of numbers to deltas.""" for value in gen : yield value - prev_value prev_value = value def write_groups ( func , delta = False ) : """Write func(symbol) for each symbol in each symbol group.

    Each line written represents one symbol group in |symbol_group_by_segment|.
    The values in each line are space separated and are the result of calling
    |func| with the Nth symbol in the group.

    If |delta| is True, the differences in values are written instead.""" for group in symbol_group_by_segment : gen = map ( func , group ) w . WriteNumberList ( gen_delta ( gen ) if delta else gen ) write_groups ( lambda s : s . address , delta = True ) w . LogSize ( 'addresses' ) write_groups ( lambda s : s . size if s . IsOverhead ( ) else s . size_without_padding ) w . LogSize ( 'sizes' ) if include_padding : write_groups ( lambda s : s . padding ) w . LogSize ( 'paddings' ) write_groups ( lambda s : path_tuples [ ( s . object_path , s . source_path ) ] , delta = True ) w . LogSize ( 'path indices' ) write_groups ( lambda s : components [ s . component ] , delta = True ) w . LogSize ( 'component indices' ) prev_aliases = None for group in symbol_group_by_segment : for symbol in group : w . WriteString ( symbol . full_name ) if symbol . aliases and symbol . aliases is not prev_aliases : w . WriteString ( '\t0%x' % symbol . num_aliases ) prev_aliases = symbol . aliases if symbol . flags : w . WriteString ( '\t%x' % symbol . flags ) w . WriteBytes ( b'\n' ) w . LogSize ( 'names (final)' )
Saves size info to a .size file.
Saves size info to a . size file .
"""Saves size info to a .size file.

  Args:
    size_info: Data to write to the file
    file_obj: File opened for writing.
    include_padding: Whether to save padding data, useful if adding a subset of
      symbols.
    sparse_symbols: If present, only save these symbols to the file.
  """ # Any aliases of sparse symbols must also be included, or else file # parsing will attribute symbols that happen to follow an incomplete alias # group to that alias group. # JSON header fields # Write using new format. # Write using old format. # For libchrome: 570 bytes. # Store a single copy of all paths and reference them by index. # For libchrome, adds 200kb. # Store a single copy of all components and have them referenced by index. # Symbol counts by "segments", defined as (container, section) tuples. """Adapts a generator of numbers to deltas.""" """Write func(symbol) for each symbol in each symbol group.

    Each line written represents one symbol group in |symbol_group_by_segment|.
    The values in each line are space separated and are the result of calling
    |func| with the Nth symbol in the group.

    If |delta| is True, the differences in values are written instead.""" # For libchrome, adds 300kb. # For libchrome, adds 300kb # Padding for non-padding-only symbols is recalculated from addresses on # load, so we only need to write it if we're writing a subset of symbols. # For libchrome, adds 300kb # For libchrome: adds 125kb. # For libchrome: adds 3.5mb.
size_info
Data to write to the file
Data to write to the file
file_obj
File opened for writing.
File opened for writing .
include_padding
Whether to save padding data, useful if adding a subset of
symbols.
Whether to save padding data useful if adding a subset of symbols .
sparse_symbols
If present, only save these symbols to the file.
If present only save these symbols to the file .