xref: /aosp_15_r20/external/grpc-grpc/tools/profiling/bloat/bloat_diff.py (revision cc02d7e222339f7a4f6ba5f422e6413f4bd931f2)
1*cc02d7e2SAndroid Build Coastguard Worker#!/usr/bin/env python3
2*cc02d7e2SAndroid Build Coastguard Worker#
3*cc02d7e2SAndroid Build Coastguard Worker# Copyright 2017 gRPC authors.
4*cc02d7e2SAndroid Build Coastguard Worker#
5*cc02d7e2SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*cc02d7e2SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*cc02d7e2SAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*cc02d7e2SAndroid Build Coastguard Worker#
9*cc02d7e2SAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
10*cc02d7e2SAndroid Build Coastguard Worker#
11*cc02d7e2SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*cc02d7e2SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*cc02d7e2SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*cc02d7e2SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*cc02d7e2SAndroid Build Coastguard Worker# limitations under the License.
16*cc02d7e2SAndroid Build Coastguard Worker
17*cc02d7e2SAndroid Build Coastguard Workerimport argparse
18*cc02d7e2SAndroid Build Coastguard Workerimport csv
19*cc02d7e2SAndroid Build Coastguard Workerimport glob
20*cc02d7e2SAndroid Build Coastguard Workerimport math
21*cc02d7e2SAndroid Build Coastguard Workerimport multiprocessing
22*cc02d7e2SAndroid Build Coastguard Workerimport os
23*cc02d7e2SAndroid Build Coastguard Workerimport pathlib
24*cc02d7e2SAndroid Build Coastguard Workerimport shutil
25*cc02d7e2SAndroid Build Coastguard Workerimport subprocess
26*cc02d7e2SAndroid Build Coastguard Workerimport sys
27*cc02d7e2SAndroid Build Coastguard Worker
28*cc02d7e2SAndroid Build Coastguard Workersys.path.append(
29*cc02d7e2SAndroid Build Coastguard Worker    os.path.join(
30*cc02d7e2SAndroid Build Coastguard Worker        os.path.dirname(sys.argv[0]), "..", "..", "run_tests", "python_utils"
31*cc02d7e2SAndroid Build Coastguard Worker    )
32*cc02d7e2SAndroid Build Coastguard Worker)
33*cc02d7e2SAndroid Build Coastguard Workerimport check_on_pr
34*cc02d7e2SAndroid Build Coastguard Worker
35*cc02d7e2SAndroid Build Coastguard Workerargp = argparse.ArgumentParser(description="Perform diff on microbenchmarks")
36*cc02d7e2SAndroid Build Coastguard Worker
37*cc02d7e2SAndroid Build Coastguard Workerargp.add_argument(
38*cc02d7e2SAndroid Build Coastguard Worker    "-d",
39*cc02d7e2SAndroid Build Coastguard Worker    "--diff_base",
40*cc02d7e2SAndroid Build Coastguard Worker    type=str,
41*cc02d7e2SAndroid Build Coastguard Worker    help="Commit or branch to compare the current one to",
42*cc02d7e2SAndroid Build Coastguard Worker)
43*cc02d7e2SAndroid Build Coastguard Worker
44*cc02d7e2SAndroid Build Coastguard Workerargp.add_argument("-j", "--jobs", type=int, default=multiprocessing.cpu_count())
45*cc02d7e2SAndroid Build Coastguard Worker
46*cc02d7e2SAndroid Build Coastguard Workerargs = argp.parse_args()
47*cc02d7e2SAndroid Build Coastguard Worker
48*cc02d7e2SAndroid Build Coastguard Worker# the libraries for which check bloat difference is calculated
49*cc02d7e2SAndroid Build Coastguard WorkerLIBS = [
50*cc02d7e2SAndroid Build Coastguard Worker    "libgrpc.so",
51*cc02d7e2SAndroid Build Coastguard Worker    "libgrpc++.so",
52*cc02d7e2SAndroid Build Coastguard Worker]
53*cc02d7e2SAndroid Build Coastguard Worker
54*cc02d7e2SAndroid Build Coastguard Worker
55*cc02d7e2SAndroid Build Coastguard Workerdef _build(output_dir):
56*cc02d7e2SAndroid Build Coastguard Worker    """Perform the cmake build under the output_dir."""
57*cc02d7e2SAndroid Build Coastguard Worker    shutil.rmtree(output_dir, ignore_errors=True)
58*cc02d7e2SAndroid Build Coastguard Worker    subprocess.check_call("mkdir -p %s" % output_dir, shell=True, cwd=".")
59*cc02d7e2SAndroid Build Coastguard Worker    subprocess.check_call(
60*cc02d7e2SAndroid Build Coastguard Worker        [
61*cc02d7e2SAndroid Build Coastguard Worker            "cmake",
62*cc02d7e2SAndroid Build Coastguard Worker            "-DgRPC_BUILD_TESTS=OFF",
63*cc02d7e2SAndroid Build Coastguard Worker            "-DBUILD_SHARED_LIBS=ON",
64*cc02d7e2SAndroid Build Coastguard Worker            "-DCMAKE_BUILD_TYPE=RelWithDebInfo",
65*cc02d7e2SAndroid Build Coastguard Worker            '-DCMAKE_C_FLAGS="-gsplit-dwarf"',
66*cc02d7e2SAndroid Build Coastguard Worker            '-DCMAKE_CXX_FLAGS="-gsplit-dwarf"',
67*cc02d7e2SAndroid Build Coastguard Worker            "..",
68*cc02d7e2SAndroid Build Coastguard Worker        ],
69*cc02d7e2SAndroid Build Coastguard Worker        cwd=output_dir,
70*cc02d7e2SAndroid Build Coastguard Worker    )
71*cc02d7e2SAndroid Build Coastguard Worker    subprocess.check_call("make -j%d" % args.jobs, shell=True, cwd=output_dir)
72*cc02d7e2SAndroid Build Coastguard Worker
73*cc02d7e2SAndroid Build Coastguard Worker
74*cc02d7e2SAndroid Build Coastguard Workerdef _rank_diff_bytes(diff_bytes):
75*cc02d7e2SAndroid Build Coastguard Worker    """Determine how significant diff_bytes is, and return a simple integer representing that"""
76*cc02d7e2SAndroid Build Coastguard Worker    mul = 1
77*cc02d7e2SAndroid Build Coastguard Worker    if diff_bytes < 0:
78*cc02d7e2SAndroid Build Coastguard Worker        mul = -1
79*cc02d7e2SAndroid Build Coastguard Worker        diff_bytes = -diff_bytes
80*cc02d7e2SAndroid Build Coastguard Worker    if diff_bytes < 2 * 1024:
81*cc02d7e2SAndroid Build Coastguard Worker        return 0
82*cc02d7e2SAndroid Build Coastguard Worker    if diff_bytes < 16 * 1024:
83*cc02d7e2SAndroid Build Coastguard Worker        return 1 * mul
84*cc02d7e2SAndroid Build Coastguard Worker    if diff_bytes < 128 * 1024:
85*cc02d7e2SAndroid Build Coastguard Worker        return 2 * mul
86*cc02d7e2SAndroid Build Coastguard Worker    return 3 * mul
87*cc02d7e2SAndroid Build Coastguard Worker
88*cc02d7e2SAndroid Build Coastguard Worker
89*cc02d7e2SAndroid Build Coastguard Worker_build("bloat_diff_new")
90*cc02d7e2SAndroid Build Coastguard Worker
91*cc02d7e2SAndroid Build Coastguard Workerif args.diff_base:
92*cc02d7e2SAndroid Build Coastguard Worker    where_am_i = (
93*cc02d7e2SAndroid Build Coastguard Worker        subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"])
94*cc02d7e2SAndroid Build Coastguard Worker        .decode()
95*cc02d7e2SAndroid Build Coastguard Worker        .strip()
96*cc02d7e2SAndroid Build Coastguard Worker    )
97*cc02d7e2SAndroid Build Coastguard Worker    # checkout the diff base (="old")
98*cc02d7e2SAndroid Build Coastguard Worker    subprocess.check_call(["git", "checkout", args.diff_base])
99*cc02d7e2SAndroid Build Coastguard Worker    subprocess.check_call(["git", "submodule", "update"])
100*cc02d7e2SAndroid Build Coastguard Worker    try:
101*cc02d7e2SAndroid Build Coastguard Worker        _build("bloat_diff_old")
102*cc02d7e2SAndroid Build Coastguard Worker    finally:
103*cc02d7e2SAndroid Build Coastguard Worker        # restore the original revision (="new")
104*cc02d7e2SAndroid Build Coastguard Worker        subprocess.check_call(["git", "checkout", where_am_i])
105*cc02d7e2SAndroid Build Coastguard Worker        subprocess.check_call(["git", "submodule", "update"])
106*cc02d7e2SAndroid Build Coastguard Worker
107*cc02d7e2SAndroid Build Coastguard Workerpathlib.Path("bloaty-build").mkdir(exist_ok=True)
108*cc02d7e2SAndroid Build Coastguard Workersubprocess.check_call(
109*cc02d7e2SAndroid Build Coastguard Worker    ["cmake", "-G", "Unix Makefiles", "../third_party/bloaty"],
110*cc02d7e2SAndroid Build Coastguard Worker    cwd="bloaty-build",
111*cc02d7e2SAndroid Build Coastguard Worker)
112*cc02d7e2SAndroid Build Coastguard Workersubprocess.check_call("make -j%d" % args.jobs, shell=True, cwd="bloaty-build")
113*cc02d7e2SAndroid Build Coastguard Worker
114*cc02d7e2SAndroid Build Coastguard Workertext = ""
115*cc02d7e2SAndroid Build Coastguard Workerdiff_size = 0
116*cc02d7e2SAndroid Build Coastguard Workerfor lib in LIBS:
117*cc02d7e2SAndroid Build Coastguard Worker    text += (
118*cc02d7e2SAndroid Build Coastguard Worker        "****************************************************************\n\n"
119*cc02d7e2SAndroid Build Coastguard Worker    )
120*cc02d7e2SAndroid Build Coastguard Worker    text += lib + "\n\n"
121*cc02d7e2SAndroid Build Coastguard Worker    old_version = glob.glob("bloat_diff_old/%s" % lib)
122*cc02d7e2SAndroid Build Coastguard Worker    new_version = glob.glob("bloat_diff_new/%s" % lib)
123*cc02d7e2SAndroid Build Coastguard Worker    for filename in [old_version, new_version]:
124*cc02d7e2SAndroid Build Coastguard Worker        if filename:
125*cc02d7e2SAndroid Build Coastguard Worker            subprocess.check_call(
126*cc02d7e2SAndroid Build Coastguard Worker                "strip %s -o %s.stripped" % (filename[0], filename[0]),
127*cc02d7e2SAndroid Build Coastguard Worker                shell=True,
128*cc02d7e2SAndroid Build Coastguard Worker            )
129*cc02d7e2SAndroid Build Coastguard Worker    assert len(new_version) == 1
130*cc02d7e2SAndroid Build Coastguard Worker    cmd = "bloaty-build/bloaty -d compileunits,symbols"
131*cc02d7e2SAndroid Build Coastguard Worker    if old_version:
132*cc02d7e2SAndroid Build Coastguard Worker        assert len(old_version) == 1
133*cc02d7e2SAndroid Build Coastguard Worker        text += subprocess.check_output(
134*cc02d7e2SAndroid Build Coastguard Worker            "%s -n 0 --debug-file=%s --debug-file=%s %s.stripped -- %s.stripped"
135*cc02d7e2SAndroid Build Coastguard Worker            % (
136*cc02d7e2SAndroid Build Coastguard Worker                cmd,
137*cc02d7e2SAndroid Build Coastguard Worker                new_version[0],
138*cc02d7e2SAndroid Build Coastguard Worker                old_version[0],
139*cc02d7e2SAndroid Build Coastguard Worker                new_version[0],
140*cc02d7e2SAndroid Build Coastguard Worker                old_version[0],
141*cc02d7e2SAndroid Build Coastguard Worker            ),
142*cc02d7e2SAndroid Build Coastguard Worker            shell=True,
143*cc02d7e2SAndroid Build Coastguard Worker        ).decode()
144*cc02d7e2SAndroid Build Coastguard Worker        sections = [
145*cc02d7e2SAndroid Build Coastguard Worker            x
146*cc02d7e2SAndroid Build Coastguard Worker            for x in csv.reader(
147*cc02d7e2SAndroid Build Coastguard Worker                subprocess.check_output(
148*cc02d7e2SAndroid Build Coastguard Worker                    "bloaty-build/bloaty -n 0 --csv %s -- %s"
149*cc02d7e2SAndroid Build Coastguard Worker                    % (new_version[0], old_version[0]),
150*cc02d7e2SAndroid Build Coastguard Worker                    shell=True,
151*cc02d7e2SAndroid Build Coastguard Worker                )
152*cc02d7e2SAndroid Build Coastguard Worker                .decode()
153*cc02d7e2SAndroid Build Coastguard Worker                .splitlines()
154*cc02d7e2SAndroid Build Coastguard Worker            )
155*cc02d7e2SAndroid Build Coastguard Worker        ]
156*cc02d7e2SAndroid Build Coastguard Worker        print(sections)
157*cc02d7e2SAndroid Build Coastguard Worker        for section in sections[1:]:
158*cc02d7e2SAndroid Build Coastguard Worker            # skip debug sections for bloat severity calculation
159*cc02d7e2SAndroid Build Coastguard Worker            if section[0].startswith(".debug"):
160*cc02d7e2SAndroid Build Coastguard Worker                continue
161*cc02d7e2SAndroid Build Coastguard Worker            # skip dynamic loader sections too
162*cc02d7e2SAndroid Build Coastguard Worker            if section[0].startswith(".dyn"):
163*cc02d7e2SAndroid Build Coastguard Worker                continue
164*cc02d7e2SAndroid Build Coastguard Worker            diff_size += int(section[2])
165*cc02d7e2SAndroid Build Coastguard Worker    else:
166*cc02d7e2SAndroid Build Coastguard Worker        text += subprocess.check_output(
167*cc02d7e2SAndroid Build Coastguard Worker            "%s %s.stripped -n 0 --debug-file=%s"
168*cc02d7e2SAndroid Build Coastguard Worker            % (cmd, new_version[0], new_version[0]),
169*cc02d7e2SAndroid Build Coastguard Worker            shell=True,
170*cc02d7e2SAndroid Build Coastguard Worker        ).decode()
171*cc02d7e2SAndroid Build Coastguard Worker    text += "\n\n"
172*cc02d7e2SAndroid Build Coastguard Worker
173*cc02d7e2SAndroid Build Coastguard Workerseverity = _rank_diff_bytes(diff_size)
174*cc02d7e2SAndroid Build Coastguard Workerprint("SEVERITY: %d" % severity)
175*cc02d7e2SAndroid Build Coastguard Worker
176*cc02d7e2SAndroid Build Coastguard Workerprint(text)
177*cc02d7e2SAndroid Build Coastguard Workercheck_on_pr.check_on_pr("Bloat Difference", "```\n%s\n```" % text)
178*cc02d7e2SAndroid Build Coastguard Workercheck_on_pr.label_significance_on_pr("bloat", severity)
179