blob: fb451c4ff790fd65ad1f7d0e940efb7ca458b7c5 [file]
#!/usr/bin/env fuchsia-vendored-python
# Copyright 2025 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Runs multiple builds and gathers their edge weights for merging
This script configures and builds the following:
- core.x64-release
- core.x64-asan
- core.arm64-release
- core.arm64-hwasan
with all buildbot test bundles included, and saves the ninja logs
as edge weights, and then produces a merged set of ninja edge
weights that can be checked in as 'merged_measured_weights.csv'
This script should be run from the root fuchsia dir.
"""
import dataclasses
import os
import shutil
import subprocess
import sys
from pathlib import Path
_SCRIPT_DIR = os.path.dirname(__file__)
sys.path.insert(0, _SCRIPT_DIR)
from merge_weights_files import merge_weights_files_finding_max
from ninjalog_to_weights import convert_log_to_weights
@dataclasses.dataclass
class BuildConfig:
product: str
board: str
compilation_mode: str
optimize: str | None = None
variants: list[str] | None = None
def name(self) -> str:
variant_str = ("-" + "-".join(self.variants)) if self.variants else ""
return (
f"{self.product}.{self.board}-{self.compilation_mode}{variant_str}"
)
# Labels to add to the respectively named groups
HOST_LABELS = [
"//bundles/buildbot/host",
"//bundles/infra/build",
"//bundles/infra/test",
"//tools/gn_desc",
]
TEST_LABELS = [
"//bundles/buildbot/core",
"//bundles/buildbot/core:hermetic_tests",
"//bundles/buildbot/core:e2e_tests",
]
def main() -> int:
if os.environ.get("FUCHSIA_DIR") != os.getcwd():
print(
"ERROR: This should be run from the Fuchsia checkout directory.",
file=sys.stderr,
)
return -1
build_configs = [
BuildConfig("core", "x64", "release"),
BuildConfig(
"core",
"x64",
"debug",
"sanitizer",
["asan-ubsan", "host_asan-ubsan"],
),
BuildConfig("core", "arm64", "release"),
BuildConfig(
"core",
"arm64",
"debug",
"sanitizer",
["hwasan-ubsan", "host_asan-ubsan"],
),
]
weights_files: list[Path] = []
for build_config in build_configs:
# Prepare a clean, empty build dir using the config
out_dir = Path("out/edge_weights")
setup_build_dir(out_dir, build_config)
# Run the build
subprocess.run(["fx", "build"], check=True)
# Convert the logfile to a csv full of weights (in ms)
weights_file = Path(build_config.name() + ".weights.csv")
weights_files.append(weights_file)
convert_log_to_weights(out_dir / ".ninja_log", weights_file, 60000)
# Merge all the weights together and replace the checked-in merged
# file with the result.
merge_weights_files_finding_max(
weights_files,
Path("build/weights/merged_measured_weights.csv"),
)
return 0
def setup_build_dir(outdir: Path, build_config: BuildConfig) -> None:
"""Run fx set for a given configuration
Runs fx set to prepare a build dir with the given configuration.
The `outdir` must be a Path object, typically a subdirectory of the
Fuchsia checkout root, such as 'out/edge_weights'.
"""
print(f" preparing outdir: {outdir}")
print(f" emptying...")
if outdir.exists():
shutil.rmtree(outdir)
# setup the build environment
cmd: list[str] = [
"fx",
"--dir",
str(outdir),
"set",
f"{build_config.product}.{build_config.board}",
f"--{build_config.compilation_mode}",
"--rbe-mode",
"off",
]
if build_config.variants:
cmd.extend(
[
"--include-clippy=false",
'--args=optimize="sanitizer"',
"--variant",
",".join(build_config.variants),
]
)
cmd.extend(
[
"--with-host",
",".join(HOST_LABELS),
"--with-test",
",".join(TEST_LABELS),
]
)
print(f" setting... {' '.join(cmd)}")
subprocess.run(cmd, check=True)
if __name__ == "__main__":
sys.exit(main())