blob: 0f9a96935c54c0971c6e555cc2c293d7798f12e8 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2025 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Script that runs multiple benchmarks on multiple emulators.
This script assumes that it will be run from the source dir (i.e. //). It is
best to run this on a new repository created from scratch and removed after
each time.
"""
import argparse
import dataclasses
import itertools
from pprint import pformat
import random
import time
import subprocess
import sys
from typing import Optional
start_time = time.time()
DEBUG = False
def _log(message: str):
print(f"timeall.py-{time.time() - start_time:.0f}s: {message}",
file=sys.stderr)
def run_command(command: list[str]) -> str:
_log(f'Running: {" ".join(command)}')
process = subprocess.run(command,
capture_output=True,
text=True,
check=True)
_log(process.stderr)
return process.stdout
def run_command_with_repeat(command: list[str], repeat: int,
outdir_name: str) -> Optional[str]:
_log(f"Running with {repeat=}")
for idx in range(repeat):
try:
return run_command(command)
except subprocess.CalledProcessError as e:
_log("Stdout:")
_log(e.stdout)
_log("Stderr:")
_log(e.stderr)
if idx != repeat - 1:
_log(f"Repeating... {idx + 1}/{repeat}")
run_command(["gn", "clean", outdir_name])
return None
@dataclasses.dataclass(frozen=True)
class Options:
benchmark: str = "module_java_internal_nosig"
i: bool = False # incremental_install
n: bool = False # no_component_build
s: bool = False # server
e: str = "" # emulator
def run_benchmark(options: Options):
outdir_name = f"out/Debug"
cmd = [
"tools/android/build_speed/benchmark.py",
"-vv",
options.benchmark,
"-C",
outdir_name,
"--target",
"chrome_apk",
]
if options.e:
cmd.extend(["--emulator", options.e])
else:
# Default to 64-bit.
cmd.append("--build-64bit")
if not options.i:
cmd.append("--no-incremental-install")
if options.n:
cmd.append("--no-component-build")
if not options.s:
cmd.append("--no-server")
_log(f"Start {options=}")
output = run_command_with_repeat(cmd,
repeat=3 if not DEBUG else 1,
outdir_name=outdir_name)
assert output is not None
print(output, end="", flush=True)
_log(f"Done {options=}")
def run_benchmarks(bos: list[Options], **kwargs):
for o in bos:
run_benchmark(dataclasses.replace(o, **kwargs))
def main():
global DEBUG
argparser = argparse.ArgumentParser()
argparser.add_argument("--debug", action="store_true")
args = argparser.parse_args()
DEBUG = args.debug
benchmarks = [
"chrome_nosig",
"base_sig",
"module_internal_nosig",
]
if args.debug:
benchmarks = [benchmarks[0]]
else:
random.shuffle(benchmarks)
# Only compare two benchmarks each time.
benchmarks = benchmarks[:2]
emulators = [ # base options
"android_31_google_apis_x64_local.textpb",
"android_33_google_apis_x64_local.textpb",
"android_34_google_apis_x64_local.textpb",
]
if args.debug:
emulators = [emulators[0]]
else:
random.shuffle(emulators)
# Only compare two emulator each time.
emulators = emulators[:2]
bos = [
Options(benchmark=benchmark, e=emulator, i=i, n=n, s=s)
for benchmark, emulator, i, n, s in itertools.product(
benchmarks, emulators, [True, False], [True, False], [True, False])
]
# shuffle bos
if not args.debug:
random.shuffle(bos)
_log(pformat(bos))
run_benchmarks(bos=bos)
if __name__ == "__main__":
main()