Joshua Haberman | 7907ed9 | 2021-10-06 19:21:00 -0700 | [diff] [blame] | 1 | #!/usr/bin/python3 |
Joshua Haberman | e59d2c8 | 2021-04-05 10:47:53 -0700 | [diff] [blame] | 2 | # |
Adam Cozzette | 5aca728 | 2023-08-07 10:01:08 -0700 | [diff] [blame] | 3 | # Protocol Buffers - Google's data interchange format |
| 4 | # Copyright 2023 Google LLC. All rights reserved. |
| 5 | # https://developers.google.com/protocol-buffers/ |
Joshua Haberman | e59d2c8 | 2021-04-05 10:47:53 -0700 | [diff] [blame] | 6 | # |
| 7 | # Redistribution and use in source and binary forms, with or without |
Adam Cozzette | 5aca728 | 2023-08-07 10:01:08 -0700 | [diff] [blame] | 8 | # modification, are permitted provided that the following conditions are |
| 9 | # met: |
Joshua Haberman | e59d2c8 | 2021-04-05 10:47:53 -0700 | [diff] [blame] | 10 | # |
Adam Cozzette | 5aca728 | 2023-08-07 10:01:08 -0700 | [diff] [blame] | 11 | # * Redistributions of source code must retain the above copyright |
| 12 | # notice, this list of conditions and the following disclaimer. |
| 13 | # * Redistributions in binary form must reproduce the above |
| 14 | # copyright notice, this list of conditions and the following disclaimer |
| 15 | # in the documentation and/or other materials provided with the |
| 16 | # distribution. |
| 17 | # * Neither the name of Google LLC nor the names of its |
| 18 | # contributors may be used to endorse or promote products derived from |
| 19 | # this software without specific prior written permission. |
| 20 | # |
| 21 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 22 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 23 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 24 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 25 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 26 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 27 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 28 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 29 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 30 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 31 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Joshua Haberman | e59d2c8 | 2021-04-05 10:47:53 -0700 | [diff] [blame] | 32 | |
Joshua Haberman | 5741eb9 | 2020-09-14 12:45:59 -0700 | [diff] [blame] | 33 | """Benchmarks the current working directory against a given baseline. |
Joshua Haberman | 08b6d2d | 2020-04-06 07:56:41 -0700 | [diff] [blame] | 34 | |
Joshua Haberman | 5741eb9 | 2020-09-14 12:45:59 -0700 | [diff] [blame] | 35 | This script benchmarks both size and speed. Sample output: |
| 36 | """ |
| 37 | |
| 38 | import contextlib |
Joshua Haberman | 08b6d2d | 2020-04-06 07:56:41 -0700 | [diff] [blame] | 39 | import json |
Joshua Haberman | 5741eb9 | 2020-09-14 12:45:59 -0700 | [diff] [blame] | 40 | import os |
Joshua Haberman | 08b6d2d | 2020-04-06 07:56:41 -0700 | [diff] [blame] | 41 | import re |
Joshua Haberman | 5741eb9 | 2020-09-14 12:45:59 -0700 | [diff] [blame] | 42 | import subprocess |
| 43 | import sys |
| 44 | import tempfile |
| 45 | |
| 46 | @contextlib.contextmanager |
| 47 | def GitWorktree(commit): |
| 48 | tmpdir = tempfile.mkdtemp() |
Joshua Haberman | a202ce9 | 2020-09-18 12:45:46 -0700 | [diff] [blame] | 49 | subprocess.run(['git', 'worktree', 'add', '-q', '-d', tmpdir, commit], check=True) |
Joshua Haberman | 5741eb9 | 2020-09-14 12:45:59 -0700 | [diff] [blame] | 50 | cwd = os.getcwd() |
| 51 | os.chdir(tmpdir) |
| 52 | try: |
| 53 | yield tmpdir |
| 54 | finally: |
| 55 | os.chdir(cwd) |
| 56 | subprocess.run(['git', 'worktree', 'remove', tmpdir], check=True) |
Joshua Haberman | 08b6d2d | 2020-04-06 07:56:41 -0700 | [diff] [blame] | 57 | |
| 58 | def Run(cmd): |
| 59 | subprocess.check_call(cmd, shell=True) |
| 60 | |
Joshua Haberman | 358fa14 | 2020-11-12 12:36:26 -0800 | [diff] [blame] | 61 | def Benchmark(outbase, bench_cpu=True, runs=12, fasttable=False): |
Joshua Haberman | 08b6d2d | 2020-04-06 07:56:41 -0700 | [diff] [blame] | 62 | tmpfile = "/tmp/bench-output.json" |
| 63 | Run("rm -rf {}".format(tmpfile)) |
Joshua Haberman | 358fa14 | 2020-11-12 12:36:26 -0800 | [diff] [blame] | 64 | #Run("CC=clang bazel test ...") |
| 65 | if fasttable: |
| 66 | extra_args = " --//:fasttable_enabled=true" |
| 67 | else: |
| 68 | extra_args = "" |
Joshua Haberman | 08b6d2d | 2020-04-06 07:56:41 -0700 | [diff] [blame] | 69 | |
Joshua Haberman | b58d2a0 | 2020-10-11 17:56:57 -0700 | [diff] [blame] | 70 | if bench_cpu: |
Joshua Haberman | 358fa14 | 2020-11-12 12:36:26 -0800 | [diff] [blame] | 71 | Run("CC=clang bazel build -c opt --copt=-march=native benchmarks:benchmark" + extra_args) |
Joshua Haberman | 77c0381 | 2021-10-04 18:29:32 -0700 | [diff] [blame] | 72 | Run("./bazel-bin/benchmarks/benchmark --benchmark_out_format=json --benchmark_out={} --benchmark_repetitions={} --benchmark_min_time=0.05 --benchmark_enable_random_interleaving=true".format(tmpfile, runs)) |
Joshua Haberman | b58d2a0 | 2020-10-11 17:56:57 -0700 | [diff] [blame] | 73 | with open(tmpfile) as f: |
| 74 | bench_json = json.load(f) |
| 75 | |
| 76 | # Translate into the format expected by benchstat. |
Joshua Haberman | 77c0381 | 2021-10-04 18:29:32 -0700 | [diff] [blame] | 77 | txt_filename = outbase + ".txt" |
| 78 | with open(txt_filename, "w") as f: |
Joshua Haberman | b58d2a0 | 2020-10-11 17:56:57 -0700 | [diff] [blame] | 79 | for run in bench_json["benchmarks"]: |
Joshua Haberman | 77c0381 | 2021-10-04 18:29:32 -0700 | [diff] [blame] | 80 | if run["run_type"] == "aggregate": |
| 81 | continue |
Joshua Haberman | 9abf8e0 | 2020-11-14 21:00:06 -0800 | [diff] [blame] | 82 | name = run["name"] |
| 83 | name = name.replace(" ", "") |
| 84 | name = re.sub(r'^BM_', 'Benchmark', name) |
Joshua Haberman | b58d2a0 | 2020-10-11 17:56:57 -0700 | [diff] [blame] | 85 | values = (name, run["iterations"], run["cpu_time"]) |
| 86 | print("{} {} {} ns/op".format(*values), file=f) |
Joshua Haberman | 77c0381 | 2021-10-04 18:29:32 -0700 | [diff] [blame] | 87 | Run("sort {} -o {} ".format(txt_filename, txt_filename)) |
Joshua Haberman | b58d2a0 | 2020-10-11 17:56:57 -0700 | [diff] [blame] | 88 | |
Joshua Haberman | 970c645 | 2022-03-08 17:44:06 -0800 | [diff] [blame] | 89 | Run("CC=clang bazel build -c opt --copt=-g --copt=-march=native :conformance_upb" |
| 90 | + extra_args) |
Joshua Haberman | 8405436 | 2022-03-06 10:44:47 -0800 | [diff] [blame] | 91 | Run("cp -f bazel-bin/conformance_upb {}.bin".format(outbase)) |
Joshua Haberman | 9b31e8f | 2020-09-13 17:51:27 -0700 | [diff] [blame] | 92 | |
Joshua Haberman | 08b6d2d | 2020-04-06 07:56:41 -0700 | [diff] [blame] | 93 | |
Joshua Haberman | 5097825 | 2021-11-05 00:31:38 +0000 | [diff] [blame] | 94 | baseline = "main" |
Joshua Haberman | c358829 | 2021-02-22 15:30:37 -0800 | [diff] [blame] | 95 | bench_cpu = True |
Joshua Haberman | 358fa14 | 2020-11-12 12:36:26 -0800 | [diff] [blame] | 96 | fasttable = False |
Joshua Haberman | 5741eb9 | 2020-09-14 12:45:59 -0700 | [diff] [blame] | 97 | |
| 98 | if len(sys.argv) > 1: |
| 99 | baseline = sys.argv[1] |
| 100 | |
| 101 | # Quickly verify that the baseline exists. |
| 102 | with GitWorktree(baseline): |
| 103 | pass |
| 104 | |
| 105 | # Benchmark our current directory first, since it's more likely to be broken. |
Joshua Haberman | 358fa14 | 2020-11-12 12:36:26 -0800 | [diff] [blame] | 106 | Benchmark("/tmp/new", bench_cpu, fasttable=fasttable) |
Joshua Haberman | 5741eb9 | 2020-09-14 12:45:59 -0700 | [diff] [blame] | 107 | |
| 108 | # Benchmark the baseline. |
| 109 | with GitWorktree(baseline): |
Joshua Haberman | 358fa14 | 2020-11-12 12:36:26 -0800 | [diff] [blame] | 110 | Benchmark("/tmp/old", bench_cpu, fasttable=fasttable) |
Joshua Haberman | 9b31e8f | 2020-09-13 17:51:27 -0700 | [diff] [blame] | 111 | |
| 112 | print() |
| 113 | print() |
Joshua Haberman | 08b6d2d | 2020-04-06 07:56:41 -0700 | [diff] [blame] | 114 | |
Joshua Haberman | b58d2a0 | 2020-10-11 17:56:57 -0700 | [diff] [blame] | 115 | if bench_cpu: |
| 116 | Run("~/go/bin/benchstat /tmp/old.txt /tmp/new.txt") |
Joshua Haberman | 9b31e8f | 2020-09-13 17:51:27 -0700 | [diff] [blame] | 117 | |
| 118 | print() |
| 119 | print() |
| 120 | |
| 121 | Run("objcopy --strip-debug /tmp/old.bin /tmp/old.bin.stripped") |
| 122 | Run("objcopy --strip-debug /tmp/new.bin /tmp/new.bin.stripped") |
| 123 | Run("~/code/bloaty/bloaty /tmp/new.bin.stripped -- /tmp/old.bin.stripped --debug-file=/tmp/old.bin --debug-file=/tmp/new.bin -d compileunits,symbols") |