blob: e98b06db759a7ce682d170fbe348ba9827063820 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2019 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Prints the large commits given a .csv file from a telemetry size graph."""
# Our version of pylint doesn't know about python3 yet.
# pylint: disable=unexpected-keyword-arg
import argparse
import collections
import csv
import json
import os
import posixpath
import logging
import multiprocessing.dummy
import subprocess
import sys
import tempfile
import zipfile
_DIR_SOURCE_ROOT = os.path.normpath(
os.path.join(os.path.dirname(__file__), '../..'))
sys.path.insert(1, os.path.join(_DIR_SOURCE_ROOT, 'build/android/pylib'))
from utils import app_bundle_utils
_GSUTIL = os.path.join(_DIR_SOURCE_ROOT, 'third_party/depot_tools/gsutil.py')
_RESOURCE_SIZES = os.path.join(_DIR_SOURCE_ROOT,
'build/android/resource_sizes.py')
_AAPT2 = os.path.join(_DIR_SOURCE_ROOT,
'third_party/android_build_tools/aapt2/aapt2')
_KEYSTORE = os.path.join(_DIR_SOURCE_ROOT,
'build/android/chromium-debug.keystore')
_KEYSTORE_PASSWORD = 'chromium'
_KEYSTORE_ALIAS = 'chromiumdebugkey'
class _Artifact(object):
def __init__(self, prefix, name, staging_dir):
self.name = name
self._gs_url = posixpath.join(prefix, name)
self._path = os.path.join(staging_dir, name)
self._resource_sizes_json = None
os.makedirs(os.path.dirname(self._path), exist_ok=True)
def FetchAndMeasure(self):
args = [_GSUTIL, 'cp', self._gs_url, self._path]
logging.warning(' '.join(args))
if not os.path.exists(self._path):
subprocess.check_call(args)
path_to_measure = self._path
if self.name.endswith('.aab'):
path_to_measure += '.apks'
app_bundle_utils.GenerateBundleApks(self._path,
path_to_measure,
_AAPT2,
_KEYSTORE,
_KEYSTORE_PASSWORD,
_KEYSTORE_ALIAS,
minimal=True)
args = [
_RESOURCE_SIZES,
'--output-format',
'chartjson',
'--output-file',
'-',
path_to_measure,
]
logging.warning(' '.join(args))
self._resource_sizes_json = json.loads(subprocess.check_output(args))
def GetCompressedSize(self):
return self._resource_sizes_json['charts']['TransferSize'][
'Transfer size (deflate)']['value']
def GetApkSize(self):
return self._resource_sizes_json['charts']['InstallSize']['APK size'][
'value']
def GetAndroidGoSize(self):
return self._resource_sizes_json['charts']['InstallSize'][
'Estimated installed size (Android Go)']['value']
def AddSize(self, metrics):
metrics[self.name] = self.GetApkSize()
def AddMethodCount(self, metrics):
metrics[self.name + ' (method count)'] = self._resource_sizes_json[
'charts']['Dex']['unique methods']['value']
def AddDfmSizes(self, metrics):
for k, v in sorted(self._resource_sizes_json['charts'].items()):
if k.startswith('DFM_'):
metrics['DFM: ' + k[4:]] = v['Size with hindi']['value']
def PrintLibraryCompression(self):
with zipfile.ZipFile(self._path) as z:
for info in z.infolist():
if info.filename.endswith('.so'):
sys.stdout.write('{}/{} compressed: {} uncompressed: {}\n'.format(
self.name, posixpath.basename(info.filename), info.compress_size,
info.file_size))
def _DumpCsv(metrics):
csv_writer = csv.DictWriter(
sys.stdout, fieldnames=list(metrics.keys()), delimiter='\t')
csv_writer.writeheader()
csv_writer.writerow(metrics)
def _DownloadAndAnalyze(signed_prefix, unsigned_prefix, staging_dir):
artifacts = []
def make_artifact(name, prefix=signed_prefix):
artifacts.append(_Artifact(prefix, name, staging_dir))
return artifacts[-1]
webview = make_artifact('arm/AndroidWebviewStable.aab')
webview64 = make_artifact('arm_64/AndroidWebviewStable.aab')
chrome_modern = make_artifact('arm/ChromeModernStable.aab')
chrome_modern64 = make_artifact('arm_64/ChromeModernStable.aab')
monochrome = make_artifact('arm/MonochromeStable.aab')
monochrome64 = make_artifact('arm_64/MonochromeStable.aab')
trichrome_chrome = make_artifact('arm/TrichromeChromeGoogleStable.aab')
trichrome_webview = make_artifact('arm/TrichromeWebViewGoogleStable.aab')
trichrome_library = make_artifact('arm/TrichromeLibraryGoogleStable.apk')
trichrome64_chrome = make_artifact('arm_64/TrichromeChromeGoogleStable.aab')
trichrome64_webview = make_artifact('arm_64/TrichromeWebViewGoogleStable.aab')
trichrome64_library = make_artifact('arm_64/TrichromeLibraryGoogleStable.apk')
trichrome_system_apks = [
make_artifact('arm/TrichromeWebViewGoogleSystemStable.apk'),
make_artifact('arm/TrichromeLibraryGoogleSystemStable.apk'),
make_artifact(
'arm/for-signing-only/TrichromeChromeGoogleSystemStable.apk',
prefix=unsigned_prefix),
]
trichrome_system_stubs = [
make_artifact('arm/TrichromeWebViewGoogleSystemStubStable.apk'),
make_artifact('arm/TrichromeLibraryGoogleSystemStubStable.apk'),
make_artifact(
'arm/for-signing-only/TrichromeChromeGoogleSystemStubStable.apk',
prefix=unsigned_prefix),
]
# Download and run resource_sizes.py concurrently.
pool = multiprocessing.dummy.Pool()
pool.map(_Artifact.FetchAndMeasure, artifacts)
pool.close()
# Add metrics in the order that we want them in the .csv output.
metrics = collections.OrderedDict()
chrome_modern.AddSize(metrics)
chrome_modern64.AddSize(metrics)
webview.AddSize(metrics)
webview64.AddSize(metrics)
monochrome.AddSize(metrics)
monochrome64.AddSize(metrics)
trichrome_chrome.AddSize(metrics)
trichrome_webview.AddSize(metrics)
trichrome_library.AddSize(metrics)
# Separate where spreadsheet has computed columns for easier copy/paste.
_DumpCsv(metrics)
metrics = collections.OrderedDict()
trichrome64_chrome.AddSize(metrics)
trichrome64_webview.AddSize(metrics)
trichrome64_library.AddSize(metrics)
_DumpCsv(metrics)
metrics = collections.OrderedDict()
webview.PrintLibraryCompression()
# AndroidGo size exists only for webview & library.
go_install_size = (
trichrome_chrome.GetApkSize() + trichrome_webview.GetAndroidGoSize() +
trichrome_library.GetAndroidGoSize())
metrics['Android Go (TriChrome) Install Size'] = go_install_size
system_apks_size = sum(x.GetCompressedSize() for x in trichrome_system_apks)
stubs_sizes = sum(x.GetApkSize() for x in trichrome_system_stubs)
metrics['Android Go (Trichrome) Compressed System Image'] = (
system_apks_size + stubs_sizes)
monochrome.AddMethodCount(metrics)
# Separate where spreadsheet has computed columns for easier copy/paste.
_DumpCsv(metrics)
metrics = collections.OrderedDict()
trichrome_chrome.AddDfmSizes(metrics)
_DumpCsv(metrics)
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--version', required=True, help='e.g.: "75.0.3770.143"')
parser.add_argument(
'--signed-bucket',
required=True,
help='GCS bucket to find files in. (e.g. "gs://bucket/subdir")')
parser.add_argument('--keep-files',
action='store_true',
help='Do not delete downloaded files.')
options = parser.parse_args()
signed_prefix = posixpath.join(options.signed_bucket, options.version)
unsigned_prefix = signed_prefix.replace('signed', 'unsigned')
with tempfile.TemporaryDirectory() as staging_dir:
if options.keep_files:
staging_dir = 'milestone_apk_sizes-staging'
os.makedirs(staging_dir, exist_ok=True)
_DownloadAndAnalyze(signed_prefix, unsigned_prefix, staging_dir)
if options.keep_files:
print('Saved files to', staging_dir)
if __name__ == '__main__':
main()