Peter Wen | 0cea52b | 2021-08-18 16:11:06 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Avi Drissman | 73a09d1 | 2022-09-08 20:33:38 | [diff] [blame] | 2 | # Copyright 2017 The Chromium Authors |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | """Runs resource_sizes.py on two apks and outputs the diff.""" |
| 7 | |
Raul Tambre | 9e24293b | 2019-05-12 06:11:07 | [diff] [blame] | 8 | |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 9 | import argparse |
| 10 | import json |
bsheedy | 889406d | 2018-11-01 19:43:34 | [diff] [blame] | 11 | import logging |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 12 | import os |
| 13 | import subprocess |
| 14 | import sys |
| 15 | |
| 16 | from pylib.constants import host_paths |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 17 | |
Haiyang Pan | 49830eb | 2024-06-27 20:25:41 | [diff] [blame] | 18 | with host_paths.SysPath(host_paths.BUILD_UTIL_PATH): |
| 19 | from lib.common import perf_tests_results_helper |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 20 | |
bsheedy | 889406d | 2018-11-01 19:43:34 | [diff] [blame] | 21 | with host_paths.SysPath(host_paths.TRACING_PATH): |
| 22 | from tracing.value import convert_chart_json # pylint: disable=import-error |
| 23 | |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 24 | _ANDROID_DIR = os.path.dirname(os.path.abspath(__file__)) |
Brian Sheedy | 45ea5b9 | 2019-04-16 17:37:48 | [diff] [blame] | 25 | with host_paths.SysPath(os.path.join(_ANDROID_DIR, 'gyp')): |
| 26 | from util import build_utils # pylint: disable=import-error |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 27 | |
| 28 | |
| 29 | _BASE_CHART = { |
| 30 | 'format_version': '0.1', |
| 31 | 'benchmark_name': 'resource_sizes_diff', |
| 32 | 'benchmark_description': 'APK resource size diff information', |
| 33 | 'trace_rerun_options': [], |
| 34 | 'charts': {}, |
| 35 | } |
| 36 | |
bsheedy | 889406d | 2018-11-01 19:43:34 | [diff] [blame] | 37 | _CHARTJSON_FILENAME = 'results-chart.json' |
| 38 | _HISTOGRAMS_FILENAME = 'perf_results.json' |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 39 | |
| 40 | |
| 41 | def DiffResults(chartjson, base_results, diff_results): |
| 42 | """Reports the diff between the two given results. |
| 43 | |
| 44 | Args: |
| 45 | chartjson: A dictionary that chartjson results will be placed in, or None |
| 46 | to only print results. |
| 47 | base_results: The chartjson-formatted size results of the base APK. |
| 48 | diff_results: The chartjson-formatted size results of the diff APK. |
| 49 | """ |
Ben Joyce | d782295 | 2021-08-17 17:19:03 | [diff] [blame] | 50 | for graph_title, graph in base_results['charts'].items(): |
| 51 | for trace_title, trace in graph.items(): |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 52 | perf_tests_results_helper.ReportPerfResult( |
| 53 | chartjson, graph_title, trace_title, |
| 54 | diff_results['charts'][graph_title][trace_title]['value'] |
| 55 | - trace['value'], |
| 56 | trace['units'], trace['improvement_direction'], |
| 57 | trace['important']) |
| 58 | |
| 59 | |
| 60 | def AddIntermediateResults(chartjson, base_results, diff_results): |
| 61 | """Copies the intermediate size results into the output chartjson. |
| 62 | |
| 63 | Args: |
| 64 | chartjson: A dictionary that chartjson results will be placed in. |
| 65 | base_results: The chartjson-formatted size results of the base APK. |
| 66 | diff_results: The chartjson-formatted size results of the diff APK. |
| 67 | """ |
Ben Joyce | d782295 | 2021-08-17 17:19:03 | [diff] [blame] | 68 | for graph_title, graph in base_results['charts'].items(): |
| 69 | for trace_title, trace in graph.items(): |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 70 | perf_tests_results_helper.ReportPerfResult( |
| 71 | chartjson, graph_title + '_base_apk', trace_title, |
| 72 | trace['value'], trace['units'], trace['improvement_direction'], |
| 73 | trace['important']) |
| 74 | |
| 75 | # Both base_results and diff_results should have the same charts/traces, but |
| 76 | # loop over them separately in case they don't |
Ben Joyce | d782295 | 2021-08-17 17:19:03 | [diff] [blame] | 77 | for graph_title, graph in diff_results['charts'].items(): |
| 78 | for trace_title, trace in graph.items(): |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 79 | perf_tests_results_helper.ReportPerfResult( |
| 80 | chartjson, graph_title + '_diff_apk', trace_title, |
| 81 | trace['value'], trace['units'], trace['improvement_direction'], |
| 82 | trace['important']) |
| 83 | |
| 84 | |
| 85 | def _CreateArgparser(): |
bsheedy | 852269e | 2017-09-22 19:51:10 | [diff] [blame] | 86 | def chromium_path(arg): |
| 87 | if arg.startswith('//'): |
| 88 | return os.path.join(host_paths.DIR_SOURCE_ROOT, arg[2:]) |
| 89 | return arg |
| 90 | |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 91 | argparser = argparse.ArgumentParser( |
| 92 | description='Diff resource sizes of two APKs. Arguments not listed here ' |
| 93 | 'will be passed on to both invocations of resource_sizes.py.') |
| 94 | argparser.add_argument('--chromium-output-directory-base', |
| 95 | dest='out_dir_base', |
bsheedy | 852269e | 2017-09-22 19:51:10 | [diff] [blame] | 96 | type=chromium_path, |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 97 | help='Location of the build artifacts for the base ' |
| 98 | 'APK, i.e. what the size increase/decrease will ' |
| 99 | 'be measured from.') |
| 100 | argparser.add_argument('--chromium-output-directory-diff', |
| 101 | dest='out_dir_diff', |
bsheedy | 852269e | 2017-09-22 19:51:10 | [diff] [blame] | 102 | type=chromium_path, |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 103 | help='Location of the build artifacts for the diff ' |
| 104 | 'APK.') |
| 105 | argparser.add_argument('--chartjson', |
| 106 | action='store_true', |
bsheedy | 889406d | 2018-11-01 19:43:34 | [diff] [blame] | 107 | help='DEPRECATED. Use --output-format=chartjson ' |
| 108 | 'instead.') |
| 109 | argparser.add_argument('--output-format', |
| 110 | choices=['chartjson', 'histograms'], |
| 111 | help='Output the results to a file in the given ' |
| 112 | 'format instead of printing the results.') |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 113 | argparser.add_argument('--include-intermediate-results', |
| 114 | action='store_true', |
| 115 | help='Include the results from the resource_sizes.py ' |
| 116 | 'runs in the chartjson output.') |
| 117 | argparser.add_argument('--output-dir', |
| 118 | default='.', |
bsheedy | 852269e | 2017-09-22 19:51:10 | [diff] [blame] | 119 | type=chromium_path, |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 120 | help='Directory to save chartjson to.') |
| 121 | argparser.add_argument('--base-apk', |
| 122 | required=True, |
bsheedy | 852269e | 2017-09-22 19:51:10 | [diff] [blame] | 123 | type=chromium_path, |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 124 | help='Path to the base APK, i.e. what the size ' |
| 125 | 'increase/decrease will be measured from.') |
| 126 | argparser.add_argument('--diff-apk', |
| 127 | required=True, |
bsheedy | 852269e | 2017-09-22 19:51:10 | [diff] [blame] | 128 | type=chromium_path, |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 129 | help='Path to the diff APK, i.e. the APK whose size ' |
| 130 | 'increase/decrease will be measured against the ' |
| 131 | 'base APK.') |
| 132 | return argparser |
| 133 | |
| 134 | |
| 135 | def main(): |
| 136 | args, unknown_args = _CreateArgparser().parse_known_args() |
bsheedy | 889406d | 2018-11-01 19:43:34 | [diff] [blame] | 137 | # TODO(bsheedy): Remove this once all uses of --chartjson are removed. |
| 138 | if args.chartjson: |
| 139 | args.output_format = 'chartjson' |
| 140 | |
| 141 | chartjson = _BASE_CHART.copy() if args.output_format else None |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 142 | |
| 143 | with build_utils.TempDir() as base_dir, build_utils.TempDir() as diff_dir: |
| 144 | # Run resource_sizes.py on the two APKs |
| 145 | resource_sizes_path = os.path.join(_ANDROID_DIR, 'resource_sizes.py') |
bsheedy | 889406d | 2018-11-01 19:43:34 | [diff] [blame] | 146 | shared_args = (['python', resource_sizes_path, '--output-format=chartjson'] |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 147 | + unknown_args) |
| 148 | |
| 149 | base_args = shared_args + ['--output-dir', base_dir, args.base_apk] |
| 150 | if args.out_dir_base: |
| 151 | base_args += ['--chromium-output-directory', args.out_dir_base] |
bsheedy | a9d1079 | 2017-09-23 21:47:11 | [diff] [blame] | 152 | try: |
| 153 | subprocess.check_output(base_args, stderr=subprocess.STDOUT) |
| 154 | except subprocess.CalledProcessError as e: |
Raul Tambre | 9e24293b | 2019-05-12 06:11:07 | [diff] [blame] | 155 | print(e.output) |
bsheedy | a9d1079 | 2017-09-23 21:47:11 | [diff] [blame] | 156 | raise |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 157 | |
| 158 | diff_args = shared_args + ['--output-dir', diff_dir, args.diff_apk] |
| 159 | if args.out_dir_diff: |
bsheedy | 135012ca | 2017-09-26 00:00:40 | [diff] [blame] | 160 | diff_args += ['--chromium-output-directory', args.out_dir_diff] |
bsheedy | a9d1079 | 2017-09-23 21:47:11 | [diff] [blame] | 161 | try: |
| 162 | subprocess.check_output(diff_args, stderr=subprocess.STDOUT) |
| 163 | except subprocess.CalledProcessError as e: |
Raul Tambre | 9e24293b | 2019-05-12 06:11:07 | [diff] [blame] | 164 | print(e.output) |
bsheedy | a9d1079 | 2017-09-23 21:47:11 | [diff] [blame] | 165 | raise |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 166 | |
| 167 | # Combine the separate results |
Alexander Cooper | f691b4dc | 2023-12-15 02:29:28 | [diff] [blame] | 168 | with open(os.path.join(base_dir, _CHARTJSON_FILENAME)) as base_file: |
| 169 | base_results = json.load(base_file) |
| 170 | with open(os.path.join(diff_dir, _CHARTJSON_FILENAME)) as diff_file: |
| 171 | diff_results = json.load(diff_file) |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 172 | DiffResults(chartjson, base_results, diff_results) |
| 173 | if args.include_intermediate_results: |
| 174 | AddIntermediateResults(chartjson, base_results, diff_results) |
| 175 | |
bsheedy | 889406d | 2018-11-01 19:43:34 | [diff] [blame] | 176 | if args.output_format: |
| 177 | chartjson_path = os.path.join(os.path.abspath(args.output_dir), |
| 178 | _CHARTJSON_FILENAME) |
| 179 | logging.critical('Dumping diff chartjson to %s', chartjson_path) |
| 180 | with open(chartjson_path, 'w') as outfile: |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 181 | json.dump(chartjson, outfile) |
| 182 | |
bsheedy | 889406d | 2018-11-01 19:43:34 | [diff] [blame] | 183 | if args.output_format == 'histograms': |
| 184 | histogram_result = convert_chart_json.ConvertChartJson(chartjson_path) |
| 185 | if histogram_result.returncode != 0: |
| 186 | logging.error('chartjson conversion failed with error: %s', |
| 187 | histogram_result.stdout) |
| 188 | return 1 |
| 189 | |
| 190 | histogram_path = os.path.join(os.path.abspath(args.output_dir), |
| 191 | 'perf_results.json') |
| 192 | logging.critical('Dumping diff histograms to %s', histogram_path) |
| 193 | with open(histogram_path, 'w') as json_file: |
| 194 | json_file.write(histogram_result.stdout) |
Yoshisato Yanagisawa | 0f42f10 | 2021-11-30 14:04:37 | [diff] [blame] | 195 | return 0 |
bsheedy | 889406d | 2018-11-01 19:43:34 | [diff] [blame] | 196 | |
| 197 | |
bsheedy | 20e696b | 2017-09-13 20:31:05 | [diff] [blame] | 198 | if __name__ == '__main__': |
| 199 | sys.exit(main()) |