benchmark/run_benchmark.py (81 lines of code) (raw):
#!/usr/bin/env python3
# Copyright 2018 The Starlark in Rust Authors.
# Copyright (c) Facebook, Inc. and its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import os
import subprocess
import tempfile
import time
from pathlib import Path
def compile_starlark():
if "CARGO_TARGET_DIR" not in os.environ:
raise Exception("Must set CARGO_TARGET_DIR, so we can find Cargo outputs")
print("Building starlark")
subprocess.run("cargo build --release --bin=starlark", shell=True, check=True)
return os.environ["CARGO_TARGET_DIR"] + "/release/starlark"
def generate_benchmarks(dir):
benchmark = Path(__file__).parent.joinpath("benchmark.py")
with open(benchmark, "r") as file:
src = file.read()
# Find all the benchmarks
benchmarks = [
x[4:-3]
for x in src.splitlines()
if x.startswith("def benchmark") and x.endswith("():")
]
outputs = {}
for benchmark in benchmarks:
# Whichever one is committed, make sure we switch it for this one
src2 = src
for x in benchmarks:
src2 = src2.replace("print(" + x + "())", "print(" + benchmark + "())")
output = Path(dir).joinpath(benchmark + ".py")
with open(output, "w") as out:
out.write(src2)
outputs[benchmark] = output
return outputs
def cmd(args):
res = subprocess.run(args, capture_output=True)
if res.returncode != 0:
raise Exception(
"Command failed: {}\nStdout: {}\nStderr: {}".format(
args, res.stdout, res.stderr
)
)
def absh(a, b, repeat):
a_time = 0
b_time = 0
runs = 0
# Run a/b repeatedly, ignoring the first loop around
for i in range(repeat + 1):
start_time = time.time()
cmd(a)
middle_time = time.time()
cmd(b)
end_time = time.time()
if i != 0:
a_time += middle_time - start_time
b_time += end_time - middle_time
runs += 1
print(".", end="", flush=True)
print("")
return (a_time / runs, b_time / runs)
def main():
parser = argparse.ArgumentParser()
parser.add_argument(
"--repeat",
default=6,
type=int,
help="How many times to repeat",
)
parser.add_argument(
"benchmarks",
nargs="*",
type=str,
help="Benchmarks to run, if not specified, all benchmarks",
)
args = parser.parse_args()
starlark = compile_starlark()
with tempfile.TemporaryDirectory() as dir:
benchmarks = generate_benchmarks(dir)
for name, file in benchmarks.items():
if len(args.benchmarks) == 0 or name in args.benchmarks:
print("Benchmarking: " + name + " ", end="", flush=True)
(py, st) = absh(("python3", file), (starlark, file), repeat=args.repeat)
print("Python3 {:.2f}s, Starlark Rust {:.2f}s".format(py, st))
if __name__ == "__main__":
main()