| Index: build/android/resource_sizes.py
 | 
| diff --git a/build/android/resource_sizes.py b/build/android/resource_sizes.py
 | 
| index b38d6475eaa5bd0f959580c8673a355fe746847c..57cd0c0f9ccb304e550365b9cebf2f8b3b6d40a5 100755
 | 
| --- a/build/android/resource_sizes.py
 | 
| +++ b/build/android/resource_sizes.py
 | 
| @@ -24,6 +24,7 @@ import zlib
 | 
|  
 | 
|  import devil_chromium
 | 
|  from devil.utils import cmd_helper
 | 
| +import method_count
 | 
|  from pylib import constants
 | 
|  from pylib.constants import host_paths
 | 
|  
 | 
| @@ -37,6 +38,7 @@ with host_paths.SysPath(_GRIT_PATH, 1):
 | 
|  with host_paths.SysPath(host_paths.BUILD_COMMON_PATH):
 | 
|    import perf_tests_results_helper # pylint: disable=import-error
 | 
|  
 | 
| +
 | 
|  # Python had a bug in zipinfo parsing that triggers on ChromeModern.apk
 | 
|  # https://bugs.python.org/issue14315
 | 
|  def _PatchedDecodeExtra(self):
 | 
| @@ -354,29 +356,53 @@ def _GetResourceIdNameMap():
 | 
|    return id_name_map
 | 
|  
 | 
|  
 | 
| -def PrintStaticInitializersCount(so_with_symbols_path, chartjson=None):
 | 
| -  """Emits the performance result for static initializers found in the provided
 | 
| -     shared library. Additionally, files for which static initializers were
 | 
| -     found are printed on the standard output.
 | 
| +def _PrintStaticInitializersCountFromApk(apk_filename, chartjson=None):
 | 
| +  print 'Finding static initializers (can take a minute)'
 | 
| +  with zipfile.ZipFile(apk_filename) as z:
 | 
| +    infolist = z.infolist()
 | 
| +  out_dir = constants.GetOutDirectory()
 | 
| +  si_count = 0
 | 
| +  for zip_info in infolist:
 | 
| +    # Check file size to account for placeholder libraries.
 | 
| +    if zip_info.filename.endswith('.so') and zip_info.file_size > 0:
 | 
| +      unstripped_path = os.path.join(out_dir, 'lib.unstripped',
 | 
| +                                     os.path.basename(zip_info.filename))
 | 
| +      if os.path.exists(unstripped_path):
 | 
| +        si_count += _PrintStaticInitializersCount(unstripped_path)
 | 
| +      else:
 | 
| +        raise Exception('Unstripped .so not found. Looked here: %s',
 | 
| +                        unstripped_path)
 | 
| +  ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', si_count,
 | 
| +                   'count')
 | 
| +
 | 
| +
 | 
| +def _PrintStaticInitializersCount(so_with_symbols_path):
 | 
| +  """Counts the number of static initializers in the given shared library.
 | 
| +     Additionally, files for which static initializers were found are printed
 | 
| +     on the standard output.
 | 
|  
 | 
|       Args:
 | 
|         so_with_symbols_path: Path to the unstripped libchrome.so file.
 | 
| +
 | 
| +     Returns:
 | 
| +       The number of static initializers found.
 | 
|    """
 | 
|    # GetStaticInitializers uses get-static-initializers.py to get a list of all
 | 
|    # static initializers. This does not work on all archs (particularly arm).
 | 
|    # TODO(rnephew): Get rid of warning when crbug.com/585588 is fixed.
 | 
|    si_count = CountStaticInitializers(so_with_symbols_path)
 | 
|    static_initializers = GetStaticInitializers(so_with_symbols_path)
 | 
| -  if si_count != len(static_initializers):
 | 
| +  static_initializers_count = len(static_initializers) - 1  # Minus summary.
 | 
| +  if si_count != static_initializers_count:
 | 
|      print ('There are %d files with static initializers, but '
 | 
|             'dump-static-initializers found %d:' %
 | 
| -           (si_count, len(static_initializers)))
 | 
| +           (si_count, static_initializers_count))
 | 
|    else:
 | 
| -    print 'Found %d files with static initializers:' % si_count
 | 
| +    print '%s - Found %d files with static initializers:' % (
 | 
| +        os.path.basename(so_with_symbols_path), si_count)
 | 
|    print '\n'.join(static_initializers)
 | 
|  
 | 
| -  ReportPerfResult(chartjson, 'StaticInitializersCount', 'count',
 | 
| -                   si_count, 'count')
 | 
| +  return si_count
 | 
|  
 | 
|  def _FormatBytes(byts):
 | 
|    """Pretty-print a number of bytes."""
 | 
| @@ -400,20 +426,34 @@ def _CalculateCompressedSize(file_path):
 | 
|    return total_size
 | 
|  
 | 
|  
 | 
| +def _PrintDexAnalysis(apk_filename, chartjson=None):
 | 
| +  sizes = method_count.ExtractSizesFromZip(apk_filename)
 | 
| +
 | 
| +  graph_title = os.path.basename(apk_filename) + '_Dex'
 | 
| +  dex_metrics = method_count.CONTRIBUTORS_TO_DEX_CACHE
 | 
| +  for key, label in dex_metrics.iteritems():
 | 
| +    ReportPerfResult(chartjson, graph_title, label, sizes[key], 'entries')
 | 
| +
 | 
| +  graph_title = '%sCache' % graph_title
 | 
| +  ReportPerfResult(chartjson, graph_title, 'DexCache', sizes['dex_cache_size'],
 | 
| +                   'bytes')
 | 
| +
 | 
| +
 | 
|  def main(argv):
 | 
|    usage = """Usage: %prog [options] file1 file2 ...
 | 
|  
 | 
|  Pass any number of files to graph their sizes. Any files with the extension
 | 
|  '.apk' will be broken down into their components on a separate graph."""
 | 
|    option_parser = optparse.OptionParser(usage=usage)
 | 
| -  option_parser.add_option('--so-path', help='Path to libchrome.so.')
 | 
| +  option_parser.add_option('--so-path',
 | 
| +                           help='Obsolete. Pass .so as positional arg instead.')
 | 
|    option_parser.add_option('--so-with-symbols-path',
 | 
| -                           help='Path to libchrome.so with symbols.')
 | 
| +                           help='Mostly obsolete. Use .so within .apk instead.')
 | 
|    option_parser.add_option('--min-pak-resource-size', type='int',
 | 
|                             default=20*1024,
 | 
|                             help='Minimum byte size of displayed pak resources.')
 | 
|    option_parser.add_option('--build_type', dest='build_type', default='Debug',
 | 
| -                           help='Sets the build type, default is Debug.')
 | 
| +                           help='Obsoleted by --chromium-output-directory.')
 | 
|    option_parser.add_option('--chromium-output-directory',
 | 
|                             help='Location of the build artifacts. '
 | 
|                                  'Takes precidence over --build_type.')
 | 
| @@ -444,8 +484,9 @@ Pass any number of files to graph their sizes. Any files with the extension
 | 
|    devil_chromium.Initialize()
 | 
|  
 | 
|    if options.so_with_symbols_path:
 | 
| -    PrintStaticInitializersCount(
 | 
| -        options.so_with_symbols_path, chartjson=chartjson)
 | 
| +    si_count = _PrintStaticInitializersCount(options.so_with_symbols_path)
 | 
| +    ReportPerfResult(chartjson, 'StaticInitializersCount', 'count', si_count,
 | 
| +                     'count')
 | 
|  
 | 
|    PrintResourceSizes(files, chartjson=chartjson)
 | 
|  
 | 
| @@ -453,6 +494,9 @@ Pass any number of files to graph their sizes. Any files with the extension
 | 
|      if f.endswith('.apk'):
 | 
|        PrintApkAnalysis(f, chartjson=chartjson)
 | 
|        PrintPakAnalysis(f, options.min_pak_resource_size)
 | 
| +      _PrintDexAnalysis(f, chartjson=chartjson)
 | 
| +      if not options.so_with_symbols_path:
 | 
| +        _PrintStaticInitializersCountFromApk(f, chartjson=chartjson)
 | 
|  
 | 
|    if chartjson:
 | 
|      results_path = os.path.join(options.output_dir, 'results-chart.json')
 | 
| 
 |