Skip to content

Commit 9e9befa

Browse files
committed
Speed up recursive type check (#14326)
Use a faster type query visitor and reuse visitor across calls. This should speed up type checking slightly. My measurements show a ~0.5% improvement, but it may be below the noise floor.
1 parent 4e32da8 commit 9e9befa

File tree

1 file changed

+101
-0
lines changed

1 file changed

+101
-0
lines changed

misc/perf_compare.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""Compare performance of mypyc-compiled mypy between two or more commits/branches.
2+
3+
Simple usage:
4+
5+
python misc/perf_compare.py my-branch master
6+
7+
What this does:
8+
9+
* Create a temp clone of the mypy repo for each target commit
10+
* Checkout a target commit in each of the clones
11+
* Compile mypyc in each of the clones in parallel
12+
* Create another temp clone of the mypy repo as the code to self check
13+
* Self check with each of the compiled mypys N times
14+
* Report the average runtimes and relative performance
15+
"""
16+
17+
from __future__ import annotations
18+
19+
import argparse
20+
import glob
21+
import os
22+
import shutil
23+
import statistics
24+
import subprocess
25+
import sys
26+
import threading
27+
import time
28+
29+
30+
def build_mypy(target_dir: str) -> None:
31+
env = os.environ.copy()
32+
env["CC"] = "clang"
33+
env["MYPYC_OPT_LEVEL"] = "2"
34+
cmd = ["python3", "setup.py", "--use-mypyc", "build_ext", "--inplace"]
35+
subprocess.run(cmd, env=env, check=True, cwd=target_dir)
36+
37+
38+
def clone(target_dir: str, commit: str | None) -> None:
39+
repo_dir = os.getcwd()
40+
if os.path.isdir(target_dir):
41+
print(f"{target_dir} exists: deleting")
42+
input()
43+
shutil.rmtree(target_dir)
44+
print(f"cloning mypy to {target_dir}")
45+
subprocess.run(["git", "clone", repo_dir, target_dir], check=True)
46+
if commit:
47+
subprocess.run(["git", "checkout", commit], check=True, cwd=target_dir)
48+
49+
50+
def run_benchmark(compiled_dir: str, check_dir: str) -> float:
51+
env = os.environ.copy()
52+
env["PYTHONPATH"] = os.path.abspath(compiled_dir)
53+
cmd = ["python3", "-m", "mypy", "--config-file", "mypy_self_check.ini"]
54+
cmd += glob.glob("mypy/*.py", root_dir=check_dir)
55+
cmd += glob.glob("mypy/*/*.py", root_dir=check_dir)
56+
t0 = time.time()
57+
subprocess.run(cmd, cwd=check_dir, env=env)
58+
return time.time() - t0
59+
60+
61+
def main() -> None:
62+
parser = argparse.ArgumentParser()
63+
parser.add_argument("commit", nargs="+")
64+
args = parser.parse_args()
65+
commits = args.commit
66+
num_bench = 2
67+
68+
if not os.path.isdir(".git") or not os.path.isdir("mypyc"):
69+
sys.exit("error: Run this the mypy repo root")
70+
71+
build_threads = []
72+
target_dirs = []
73+
for i, commit in enumerate(commits):
74+
target_dir = f"mypy.{i}.tmpdir"
75+
target_dirs.append(target_dir)
76+
clone(target_dir, commit)
77+
t = threading.Thread(target=lambda: build_mypy(target_dir))
78+
t.start()
79+
build_threads.append(t)
80+
81+
self_check_dir = "mypy.self.tmpdir"
82+
clone(self_check_dir, None)
83+
84+
for t in build_threads:
85+
t.join()
86+
87+
print(f"built mypy at {len(commits)} commits")
88+
89+
results: dict[str, list[float]] = {}
90+
for i in range(num_bench):
91+
for i, commit in enumerate(commits):
92+
tt = run_benchmark(target_dirs[i], self_check_dir)
93+
results.setdefault(commit, []).append(tt)
94+
95+
for commit in commits:
96+
tt = statistics.mean(results[commit])
97+
print(f"commit: {tt:.1f}s")
98+
99+
100+
if __name__ == "__main__":
101+
main()

0 commit comments

Comments
 (0)