@@ -44,13 +44,15 @@ def build_mypy(target_dir: str) -> None:
4444 subprocess .run (cmd , env = env , check = True , cwd = target_dir )
4545
4646
47- def clone (target_dir : str , commit : str | None ) -> None :
48- heading (f"Cloning mypy to { target_dir } " )
49- repo_dir = os .getcwd ()
47+ def clone (target_dir : str , commit : str | None , repo_source : str | None = None ) -> None :
48+ source_name = repo_source or "mypy"
49+ heading (f"Cloning { source_name } to { target_dir } " )
50+ if repo_source is None :
51+ repo_source = os .getcwd ()
5052 if os .path .isdir (target_dir ):
5153 print (f"{ target_dir } exists: deleting" )
5254 shutil .rmtree (target_dir )
53- subprocess .run (["git" , "clone" , repo_dir , target_dir ], check = True )
55+ subprocess .run (["git" , "clone" , repo_source , target_dir ], check = True )
5456 if commit :
5557 subprocess .run (["git" , "checkout" , commit ], check = True , cwd = target_dir )
5658
@@ -64,7 +66,7 @@ def edit_python_file(fnam: str) -> None:
6466
6567
6668def run_benchmark (
67- compiled_dir : str , check_dir : str , * , incremental : bool , code : str | None
69+ compiled_dir : str , check_dir : str , * , incremental : bool , code : str , foreign : bool | None
6870) -> float :
6971 cache_dir = os .path .join (compiled_dir , ".mypy_cache" )
7072 if os .path .isdir (cache_dir ) and not incremental :
@@ -76,6 +78,8 @@ def run_benchmark(
7678 cmd = [sys .executable , "-m" , "mypy" ]
7779 if code :
7880 cmd += ["-c" , code ]
81+ elif foreign :
82+ pass
7983 else :
8084 cmd += ["--config-file" , os .path .join (abschk , "mypy_self_check.ini" )]
8185 cmd += glob .glob (os .path .join (abschk , "mypy/*.py" ))
@@ -86,18 +90,28 @@ def run_benchmark(
8690 edit_python_file (os .path .join (abschk , "mypy/test/testcheck.py" ))
8791 t0 = time .time ()
8892 # Ignore errors, since some commits being measured may generate additional errors.
89- subprocess .run (cmd , cwd = compiled_dir , env = env )
93+ if foreign :
94+ subprocess .run (cmd , cwd = check_dir , env = env )
95+ else :
96+ subprocess .run (cmd , cwd = compiled_dir , env = env )
9097 return time .time () - t0
9198
9299
93100def main () -> None :
94- parser = argparse .ArgumentParser ()
101+ whole_program_time_0 = time .time ()
102+ parser = argparse .ArgumentParser (epilog = "Remember: you usually want the first argument to this command to be 'master'." )
95103 parser .add_argument (
96104 "--incremental" ,
97105 default = False ,
98106 action = "store_true" ,
99107 help = "measure incremental run (fully cached)" ,
100108 )
109+ parser .add_argument (
110+ "--dont-setup" ,
111+ default = False ,
112+ action = "store_true" ,
113+ help = "don't make the dirs or compile mypy, just run the performance measurement benchmark" ,
114+ )
101115 parser .add_argument (
102116 "--num-runs" ,
103117 metavar = "N" ,
@@ -112,6 +126,14 @@ def main() -> None:
112126 type = int ,
113127 help = "set maximum number of parallel builds (default=8)" ,
114128 )
129+ parser .add_argument (
130+ "-r" ,
131+ metavar = "FOREIGN_REPOSITORY" ,
132+ default = None ,
133+ type = str ,
134+ help = "measure time to type check the project at FOREIGN_REPOSITORY instead of mypy self-check; " +
135+ "provided value must be the URL or path of a git repo" ,
136+ )
115137 parser .add_argument (
116138 "-c" ,
117139 metavar = "CODE" ,
@@ -122,10 +144,12 @@ def main() -> None:
122144 parser .add_argument ("commit" , nargs = "+" , help = "git revision to measure (e.g. branch name)" )
123145 args = parser .parse_args ()
124146 incremental : bool = args .incremental
147+ dont_setup : bool = args .dont_setup
125148 commits = args .commit
126149 num_runs : int = args .num_runs + 1
127150 max_workers : int = args .j
128151 code : str | None = args .c
152+ foreign_repo : str | None = args .r
129153
130154 if not (os .path .isdir (".git" ) and os .path .isdir ("mypyc" )):
131155 sys .exit ("error: Run this the mypy repo root" )
@@ -134,20 +158,28 @@ def main() -> None:
134158 for i , commit in enumerate (commits ):
135159 target_dir = f"mypy.{ i } .tmpdir"
136160 target_dirs .append (target_dir )
137- clone (target_dir , commit )
161+ if not dont_setup :
162+ clone (target_dir , commit )
138163
139- self_check_dir = "mypy.self.tmpdir"
140- clone (self_check_dir , commits [0 ])
164+ if foreign_repo :
165+ check_dir = "mypy.foreign.tmpdir"
166+ if not dont_setup :
167+ clone (check_dir , None , foreign_repo )
168+ else :
169+ check_dir = "mypy.self.tmpdir"
170+ if not dont_setup :
171+ clone (check_dir , commits [0 ])
141172
142- heading ("Compiling mypy" )
143- print ("(This will take a while...)" )
173+ if not dont_setup :
174+ heading ("Compiling mypy" )
175+ print ("(This will take a while...)" )
144176
145- with ThreadPoolExecutor (max_workers = max_workers ) as executor :
146- futures = [executor .submit (build_mypy , target_dir ) for target_dir in target_dirs ]
147- for future in as_completed (futures ):
148- future .result ()
177+ with ThreadPoolExecutor (max_workers = max_workers ) as executor :
178+ futures = [executor .submit (build_mypy , target_dir ) for target_dir in target_dirs ]
179+ for future in as_completed (futures ):
180+ future .result ()
149181
150- print (f"Finished compiling mypy ({ len (commits )} builds)" )
182+ print (f"Finished compiling mypy ({ len (commits )} builds)" )
151183
152184 heading ("Performing measurements" )
153185
@@ -160,7 +192,7 @@ def main() -> None:
160192 items = list (enumerate (commits ))
161193 random .shuffle (items )
162194 for i , commit in items :
163- tt = run_benchmark (target_dirs [i ], self_check_dir , incremental = incremental , code = code )
195+ tt = run_benchmark (target_dirs [i ], check_dir , incremental = incremental , code = code , foreign = bool ( foreign_repo ) )
164196 # Don't record the first warm-up run
165197 if n > 0 :
166198 print (f"{ commit } : t={ tt :.3f} s" )
@@ -171,16 +203,19 @@ def main() -> None:
171203 first = - 1.0
172204 for commit in commits :
173205 tt = statistics .mean (results [commit ])
174- s = statistics .stdev (results [commit ])
206+ #pstdev (instead of stdev) is used here primarily to accommodate the case where num_runs=1
207+ s = statistics .pstdev (results [commit ]) if len (results [commit ]) > 1 else 0
175208 if first < 0 :
176209 delta = "0.0%"
177210 first = tt
178211 else :
179212 d = (tt / first ) - 1
180213 delta = f"{ d :+.1%} "
181- print (f"{ commit :<25} { tt :.3f} s ({ delta } ) | stdev { s } " )
214+ print (f"{ commit :<25} { tt :.3f} s ({ delta } ) | stdev { s :.3f} s " )
215+
216+ print (f"Total time taken by the benchmarking program (including any setup): { time .time () - whole_program_time_0 :.2f} s" )
182217
183- shutil .rmtree (self_check_dir )
218+ shutil .rmtree (check_dir )
184219 for target_dir in target_dirs :
185220 shutil .rmtree (target_dir )
186221
0 commit comments