xref: /aosp_15_r20/external/toolchain-utils/pgo_tools/ensure_pgo_is_a_win.py (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
1#!/usr/bin/env python3
2# Copyright 2023 The ChromiumOS Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""Reports how much performance win (in user time) PGO is for LLVM.
7
8**This script is meant to be run from inside of the chroot.**
9
10This is mostly intended to run regularly on Chrotomation, as it's just a super
11thin wrapper around `benchmark_pgo_profiles.py`.
12"""
13
14import argparse
15import logging
16import sys
17from typing import List
18
19import benchmark_pgo_profiles
20import pgo_tools
21
22
23NO_PROFILE = benchmark_pgo_profiles.SpecialProfile.NONE
24DEFAULT_PROFILE = benchmark_pgo_profiles.SpecialProfile.REMOTE
25
26
27def calculate_pgo_speedup(
28    no_profile: benchmark_pgo_profiles.RunData,
29    default_profile: benchmark_pgo_profiles.RunData,
30) -> float:
31    """Returns the speedup attained by applying PGO.
32
33    Returns:
34        Percentage performance difference. If LLVM with PGO takes 100 seconds
35        to run the benchmark, and LLVM without PGO takes 150, this will return
36        1.5, since 150/100 == 1.5x speedup.
37    """
38    assert default_profile.user_time != 0, "pgo has a user time of 0?"
39    return no_profile.user_time / default_profile.user_time
40
41
42def main(argv: List[str]):
43    logging.basicConfig(
44        format=">> %(asctime)s: %(levelname)s: %(filename)s:%(lineno)d: "
45        "%(message)s",
46        level=logging.INFO,
47    )
48
49    parser = argparse.ArgumentParser(
50        description=__doc__,
51        formatter_class=argparse.RawDescriptionHelpFormatter,
52    )
53    parser.add_argument(
54        "--minimum-speedup",
55        type=float,
56        help="""
57        If the win of PGO is less than this, fail. Specified as an integer
58        (--minimum-speedup=1.2 means speedup must be at least 1.2x).
59        """,
60    )
61    opts = parser.parse_args(argv)
62    minimum_speedup = opts.minimum_speedup
63
64    pgo_tools.exit_if_not_in_chroot()
65
66    run_results = benchmark_pgo_profiles.run_benchmark(
67        # It's likely safe to assume that a fast LLVM without ThinLTO is fast
68        # with ThinLTO.
69        use_thinlto=False,
70        profiles=[
71            NO_PROFILE,
72            DEFAULT_PROFILE,
73        ],
74    )
75    assert (
76        len(run_results) == 2
77    ), f"Unexpected number of run results: {len(run_results)}"
78
79    pgo_speedup = calculate_pgo_speedup(
80        no_profile=run_results[0], default_profile=run_results[1]
81    )
82    logging.info("Speedup of PGO is %.2fx", pgo_speedup)
83    if minimum_speedup is not None and minimum_speedup > pgo_speedup:
84        sys.exit(
85            f"Minimum speedup of {minimum_speedup} is greater than "
86            f"observed speedup of {pgo_speedup}. Exiting with error."
87        )
88
89
90if __name__ == "__main__":
91    main(sys.argv[1:])
92